| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """A wrapper script to manage a set of client modules in different SCM. | 6 """A wrapper script to manage a set of client modules in different SCM. |
| 7 | 7 |
| 8 This script is intended to be used to help basic management of client | 8 This script is intended to be used to help basic management of client |
| 9 program sources residing in one or more Subversion modules and Git | 9 program sources residing in one or more Subversion modules and Git |
| 10 repositories, along with other modules it depends on, also in Subversion or Git, | 10 repositories, along with other modules it depends on, also in Subversion or Git, |
| (...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 # match each hook's pattern. | 499 # match each hook's pattern. |
| 500 for hook_dict in hooks: | 500 for hook_dict in hooks: |
| 501 pattern = re.compile(hook_dict['pattern']) | 501 pattern = re.compile(hook_dict['pattern']) |
| 502 matching_file_list = [f for f in file_list if pattern.search(f)] | 502 matching_file_list = [f for f in file_list if pattern.search(f)] |
| 503 if matching_file_list: | 503 if matching_file_list: |
| 504 self._RunHookAction(hook_dict, matching_file_list) | 504 self._RunHookAction(hook_dict, matching_file_list) |
| 505 | 505 |
| 506 def _EnforceRevisions(self, solutions): | 506 def _EnforceRevisions(self, solutions): |
| 507 """Checks for revision overrides.""" | 507 """Checks for revision overrides.""" |
| 508 revision_overrides = {} | 508 revision_overrides = {} |
| 509 solutions = [s['name'] for s in solutions] | 509 if self._options.head: |
| 510 if self._options.revisions: | 510 return revision_overrides |
| 511 revision = self._options.revisions[0] | 511 for s in solutions: |
| 512 # Ignore solution@ | 512 if not s.get('safesync_url', None): |
| 513 rev = revision | 513 continue |
| 514 if '@' in revision: | 514 handle = urllib.urlopen(s['safesync_url']) |
| 515 rev = revision.split('@', 1)[1] | 515 rev = handle.read().strip() |
| 516 revision_overrides[solutions[0]] = rev | 516 handle.close() |
| 517 | 517 if len(rev): |
| 518 if len(self._options.revisions) > 1: | 518 self._options.revisions.append('%s@%s' % (s['name'], rev)) |
| 519 # Enforce solution@rev format for following params. | 519 if not self._options.revisions: |
| 520 for revision in self._options.revisions[1:]: | 520 return revision_overrides |
| 521 if not '@' in revision: | 521 # --revision will take over safesync_url. |
| 522 raise gclient_utils.Error( | 522 solutions_names = [s['name'] for s in solutions] |
| 523 'Specify the full dependency when specifying a revision number ' | 523 index = 0 |
| 524 'for non-primary solution.') | 524 for revision in self._options.revisions: |
| 525 sol, rev = revision.split("@", 1) | 525 if not '@' in revision: |
| 526 # Disallow conflicting revs | 526 # Support for --revision 123 |
| 527 if revision_overrides.get(sol, rev) != rev: | 527 revision = '%s@%s' % (solutions_names[index], revision) |
| 528 raise gclient_utils.Error( | 528 sol, rev = revision.split("@", 1) |
| 529 'Conflicting revision numbers specified for %s: %s and %s.' % | 529 if not sol in solutions_names: |
| 530 (sol, revision_overrides[sol], rev)) | 530 #raise gclient_utils.Error('%s is not a valid solution.' % sol) |
| 531 if not sol in solutions: | 531 print >> sys.stderr, ('Please fix your script, having invalid ' |
| 532 raise gclient_utils.Error('%s is not a valid solution.' % sol) | 532 '--revision flags will soon considered an error.') |
| 533 else: |
| 533 revision_overrides[sol] = rev | 534 revision_overrides[sol] = rev |
| 535 index += 1 |
| 534 return revision_overrides | 536 return revision_overrides |
| 535 | 537 |
| 536 def RunOnDeps(self, command, args): | 538 def RunOnDeps(self, command, args): |
| 537 """Runs a command on each dependency in a client and its dependencies. | 539 """Runs a command on each dependency in a client and its dependencies. |
| 538 | 540 |
| 539 The module's dependencies are specified in its top-level DEPS files. | 541 The module's dependencies are specified in its top-level DEPS files. |
| 540 | 542 |
| 541 Args: | 543 Args: |
| 542 command: The command to use (e.g., 'status' or 'diff') | 544 command: The command to use (e.g., 'status' or 'diff') |
| 543 args: list of str - extra arguments to add to the command line. | 545 args: list of str - extra arguments to add to the command line. |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 935 update src directory to r31000 | 937 update src directory to r31000 |
| 936 """) | 938 """) |
| 937 def CMDsync(parser, args): | 939 def CMDsync(parser, args): |
| 938 """Checkout/update all modules.""" | 940 """Checkout/update all modules.""" |
| 939 parser.add_option("--force", action="store_true", | 941 parser.add_option("--force", action="store_true", |
| 940 help="force update even for unchanged modules") | 942 help="force update even for unchanged modules") |
| 941 parser.add_option("--nohooks", action="store_true", | 943 parser.add_option("--nohooks", action="store_true", |
| 942 help="don't run hooks after the update is complete") | 944 help="don't run hooks after the update is complete") |
| 943 parser.add_option("-r", "--revision", action="append", | 945 parser.add_option("-r", "--revision", action="append", |
| 944 dest="revisions", metavar="REV", default=[], | 946 dest="revisions", metavar="REV", default=[], |
| 945 help="Enforces revision/hash for the primary solution. " | 947 help="Enforces revision/hash for the solutions with the " |
| 946 "To modify a secondary solution, use it at least once " | 948 "format src@rev. The src@ part is optional and can be " |
| 947 "for the primary solution and then use the format " | 949 "skipped. -r can be used multiple times when .gclient " |
| 948 "solution@rev/hash, e.g. -r src@123") | 950 "has multiple solutions configured and will work even " |
| 951 "if the src@ part is skipped.") |
| 949 parser.add_option("--head", action="store_true", | 952 parser.add_option("--head", action="store_true", |
| 950 help="skips any safesync_urls specified in " | 953 help="skips any safesync_urls specified in " |
| 951 "configured solutions and sync to head instead") | 954 "configured solutions and sync to head instead") |
| 952 parser.add_option("--delete_unversioned_trees", action="store_true", | 955 parser.add_option("--delete_unversioned_trees", action="store_true", |
| 953 help="delete any unexpected unversioned trees " | 956 help="delete any unexpected unversioned trees " |
| 954 "that are in the checkout") | 957 "that are in the checkout") |
| 955 parser.add_option("--reset", action="store_true", | 958 parser.add_option("--reset", action="store_true", |
| 956 help="resets any local changes before updating (git only)") | 959 help="resets any local changes before updating (git only)") |
| 957 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", | 960 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", |
| 958 help="override deps for the specified (comma-separated) " | 961 help="override deps for the specified (comma-separated) " |
| 959 "platform(s); 'all' will process all deps_os " | 962 "platform(s); 'all' will process all deps_os " |
| 960 "references") | 963 "references") |
| 961 parser.add_option("--manually_grab_svn_rev", action="store_true", | 964 parser.add_option("--manually_grab_svn_rev", action="store_true", |
| 962 help="Skip svn up whenever possible by requesting " | 965 help="Skip svn up whenever possible by requesting " |
| 963 "actual HEAD revision from the repository") | 966 "actual HEAD revision from the repository") |
| 964 (options, args) = parser.parse_args(args) | 967 (options, args) = parser.parse_args(args) |
| 965 client = GClient.LoadCurrentConfig(options) | 968 client = GClient.LoadCurrentConfig(options) |
| 966 | 969 |
| 967 if not client: | 970 if not client: |
| 968 raise gclient_utils.Error("client not configured; see 'gclient config'") | 971 raise gclient_utils.Error("client not configured; see 'gclient config'") |
| 969 | 972 |
| 970 if not options.head: | 973 if options.revisions and options.head: |
| 971 solutions = client.GetVar('solutions') | 974 # TODO(maruel): Make it a parser.error if it doesn't break any builder. |
| 972 if solutions: | 975 print("Warning: you cannot use both --head and --revision") |
| 973 first = True | |
| 974 for s in solutions: | |
| 975 if s.get('safesync_url', None): | |
| 976 # rip through revisions and make sure we're not over-riding | |
| 977 # something that was explicitly passed | |
| 978 has_key = False | |
| 979 r_first = True | |
| 980 for r in options.revisions: | |
| 981 if (first and r_first) or r.split('@', 1)[0] == s['name']: | |
| 982 has_key = True | |
| 983 break | |
| 984 r_first = False | |
| 985 | |
| 986 if not has_key: | |
| 987 handle = urllib.urlopen(s['safesync_url']) | |
| 988 rev = handle.read().strip() | |
| 989 handle.close() | |
| 990 if len(rev): | |
| 991 options.revisions.append(s['name']+'@'+rev) | |
| 992 first = False | |
| 993 | 976 |
| 994 if options.verbose: | 977 if options.verbose: |
| 995 # Print out the .gclient file. This is longer than if we just printed the | 978 # Print out the .gclient file. This is longer than if we just printed the |
| 996 # client dict, but more legible, and it might contain helpful comments. | 979 # client dict, but more legible, and it might contain helpful comments. |
| 997 print(client.ConfigContent()) | 980 print(client.ConfigContent()) |
| 998 return client.RunOnDeps('update', args) | 981 return client.RunOnDeps('update', args) |
| 999 | 982 |
| 1000 | 983 |
| 1001 def CMDupdate(parser, args): | 984 def CMDupdate(parser, args): |
| 1002 """Alias for the sync command. Deprecated.""" | 985 """Alias for the sync command. Deprecated.""" |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1118 def Parse(args): | 1101 def Parse(args): |
| 1119 (options, args) = old_parser(args) | 1102 (options, args) = old_parser(args) |
| 1120 if options.verbose == 2: | 1103 if options.verbose == 2: |
| 1121 logging.basicConfig(level=logging.INFO) | 1104 logging.basicConfig(level=logging.INFO) |
| 1122 elif options.verbose > 2: | 1105 elif options.verbose > 2: |
| 1123 logging.basicConfig(level=logging.DEBUG) | 1106 logging.basicConfig(level=logging.DEBUG) |
| 1124 options.entries_filename = options.config_filename + "_entries" | 1107 options.entries_filename = options.config_filename + "_entries" |
| 1125 if not hasattr(options, 'revisions'): | 1108 if not hasattr(options, 'revisions'): |
| 1126 # GClient.RunOnDeps expects it even if not applicable. | 1109 # GClient.RunOnDeps expects it even if not applicable. |
| 1127 options.revisions = [] | 1110 options.revisions = [] |
| 1111 if not hasattr(options, 'head'): |
| 1112 options.head = None |
| 1128 return (options, args) | 1113 return (options, args) |
| 1129 parser.parse_args = Parse | 1114 parser.parse_args = Parse |
| 1130 # We don't want wordwrapping in epilog (usually examples) | 1115 # We don't want wordwrapping in epilog (usually examples) |
| 1131 parser.format_epilog = lambda _: parser.epilog or '' | 1116 parser.format_epilog = lambda _: parser.epilog or '' |
| 1132 if argv: | 1117 if argv: |
| 1133 command = Command(argv[0]) | 1118 command = Command(argv[0]) |
| 1134 if command: | 1119 if command: |
| 1135 # "fix" the usage and the description now that we know the subcommand. | 1120 # "fix" the usage and the description now that we know the subcommand. |
| 1136 GenUsage(parser, argv[0]) | 1121 GenUsage(parser, argv[0]) |
| 1137 return command(parser, argv[1:]) | 1122 return command(parser, argv[1:]) |
| 1138 # Not a known command. Default to help. | 1123 # Not a known command. Default to help. |
| 1139 GenUsage(parser, 'help') | 1124 GenUsage(parser, 'help') |
| 1140 return CMDhelp(parser, argv) | 1125 return CMDhelp(parser, argv) |
| 1141 | 1126 |
| 1142 | 1127 |
| 1143 if "__main__" == __name__: | 1128 if "__main__" == __name__: |
| 1144 try: | 1129 try: |
| 1145 sys.exit(Main(sys.argv[1:])) | 1130 sys.exit(Main(sys.argv[1:])) |
| 1146 except gclient_utils.Error, e: | 1131 except gclient_utils.Error, e: |
| 1147 print >> sys.stderr, "Error: %s" % str(e) | 1132 print >> sys.stderr, "Error: %s" % str(e) |
| 1148 sys.exit(1) | 1133 sys.exit(1) |
| 1149 | 1134 |
| 1150 # vim: ts=2:sw=2:tw=80:et: | 1135 # vim: ts=2:sw=2:tw=80:et: |
| OLD | NEW |