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 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 | 422 |
423 class FromImpl: | 423 class FromImpl: |
424 """Used to implement the From syntax.""" | 424 """Used to implement the From syntax.""" |
425 | 425 |
426 def __init__(self, module_name): | 426 def __init__(self, module_name): |
427 self.module_name = module_name | 427 self.module_name = module_name |
428 | 428 |
429 def __str__(self): | 429 def __str__(self): |
430 return 'From("%s")' % self.module_name | 430 return 'From("%s")' % self.module_name |
431 | 431 |
| 432 class FileImpl: |
| 433 """Used to implement the File('') syntax which lets you sync a single file |
| 434 from an SVN repo.""" |
| 435 |
| 436 def __init__(self, file_location): |
| 437 self.file_location = file_location |
| 438 |
| 439 def __str__(self): |
| 440 return 'File("%s")' % self.file_location |
| 441 |
| 442 def GetPath(self): |
| 443 return os.path.split(self.file_location)[0] |
| 444 |
| 445 def GetFilename(self): |
| 446 rev_tokens = self.file_location.split('@') |
| 447 return os.path.split(rev_tokens[0])[1] |
| 448 |
| 449 def GetRevision(self): |
| 450 rev_tokens = self.file_location.split('@') |
| 451 if len(rev_tokens) > 1: |
| 452 return rev_tokens[1] |
| 453 return None |
| 454 |
432 class _VarImpl: | 455 class _VarImpl: |
433 def __init__(self, custom_vars, local_scope): | 456 def __init__(self, custom_vars, local_scope): |
434 self._custom_vars = custom_vars | 457 self._custom_vars = custom_vars |
435 self._local_scope = local_scope | 458 self._local_scope = local_scope |
436 | 459 |
437 def Lookup(self, var_name): | 460 def Lookup(self, var_name): |
438 """Implements the Var syntax.""" | 461 """Implements the Var syntax.""" |
439 if var_name in self._custom_vars: | 462 if var_name in self._custom_vars: |
440 return self._custom_vars[var_name] | 463 return self._custom_vars[var_name] |
441 elif var_name in self._local_scope.get("vars", {}): | 464 elif var_name in self._local_scope.get("vars", {}): |
(...skipping 12 matching lines...) Expand all Loading... |
454 Returns: | 477 Returns: |
455 A dict mapping module names (as relative paths) to URLs or an empty | 478 A dict mapping module names (as relative paths) to URLs or an empty |
456 dict if the solution does not have a DEPS file. | 479 dict if the solution does not have a DEPS file. |
457 """ | 480 """ |
458 # Skip empty | 481 # Skip empty |
459 if not solution_deps_content: | 482 if not solution_deps_content: |
460 return {} | 483 return {} |
461 # Eval the content | 484 # Eval the content |
462 local_scope = {} | 485 local_scope = {} |
463 var = self._VarImpl(custom_vars, local_scope) | 486 var = self._VarImpl(custom_vars, local_scope) |
464 global_scope = {"From": self.FromImpl, "Var": var.Lookup, "deps_os": {}} | 487 global_scope = { |
| 488 "File": self.FileImpl, |
| 489 "From": self.FromImpl, |
| 490 "Var": var.Lookup, |
| 491 "deps_os": {}, |
| 492 } |
465 exec(solution_deps_content, global_scope, local_scope) | 493 exec(solution_deps_content, global_scope, local_scope) |
466 deps = local_scope.get("deps", {}) | 494 deps = local_scope.get("deps", {}) |
467 | 495 |
468 # load os specific dependencies if defined. these dependencies may | 496 # load os specific dependencies if defined. these dependencies may |
469 # override or extend the values defined by the 'deps' member. | 497 # override or extend the values defined by the 'deps' member. |
470 if "deps_os" in local_scope: | 498 if "deps_os" in local_scope: |
471 deps_os_choices = { | 499 deps_os_choices = { |
472 "win32": "win", | 500 "win32": "win", |
473 "win": "win", | 501 "win": "win", |
474 "cygwin": "win", | 502 "cygwin": "win", |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 if url is None: | 581 if url is None: |
554 continue | 582 continue |
555 else: | 583 else: |
556 url = solution_deps[d] | 584 url = solution_deps[d] |
557 # if we have a From reference dependent on another solution, then | 585 # if we have a From reference dependent on another solution, then |
558 # just skip the From reference. When we pull deps for the solution, | 586 # just skip the From reference. When we pull deps for the solution, |
559 # we will take care of this dependency. | 587 # we will take care of this dependency. |
560 # | 588 # |
561 # If multiple solutions all have the same From reference, then we | 589 # If multiple solutions all have the same From reference, then we |
562 # should only add one to our list of dependencies. | 590 # should only add one to our list of dependencies. |
563 if type(url) != str: | 591 if isinstance(url, self.FromImpl): |
564 if url.module_name in solution_urls: | 592 if url.module_name in solution_urls: |
565 # Already parsed. | 593 # Already parsed. |
566 continue | 594 continue |
567 if d in deps and type(deps[d]) != str: | 595 if d in deps and type(deps[d]) != str: |
568 if url.module_name == deps[d].module_name: | 596 if url.module_name == deps[d].module_name: |
569 continue | 597 continue |
570 else: | 598 elif isinstance(url, str): |
571 parsed_url = urlparse.urlparse(url) | 599 parsed_url = urlparse.urlparse(url) |
572 scheme = parsed_url[0] | 600 scheme = parsed_url[0] |
573 if not scheme: | 601 if not scheme: |
574 # A relative url. Fetch the real base. | 602 # A relative url. Fetch the real base. |
575 path = parsed_url[2] | 603 path = parsed_url[2] |
576 if path[0] != "/": | 604 if path[0] != "/": |
577 raise gclient_utils.Error( | 605 raise gclient_utils.Error( |
578 "relative DEPS entry \"%s\" must begin with a slash" % d) | 606 "relative DEPS entry \"%s\" must begin with a slash" % d) |
579 # Create a scm just to query the full url. | 607 # Create a scm just to query the full url. |
580 scm = gclient_scm.CreateSCM(solution["url"], self._root_dir, | 608 scm = gclient_scm.CreateSCM(solution["url"], self._root_dir, |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
721 if command == 'update' and not self._options.verbose: | 749 if command == 'update' and not self._options.verbose: |
722 pm.update() | 750 pm.update() |
723 if type(deps[d]) == str: | 751 if type(deps[d]) == str: |
724 url = deps[d] | 752 url = deps[d] |
725 entries[d] = url | 753 entries[d] = url |
726 if run_scm: | 754 if run_scm: |
727 self._options.revision = revision_overrides.get(d) | 755 self._options.revision = revision_overrides.get(d) |
728 scm = gclient_scm.CreateSCM(url, self._root_dir, d) | 756 scm = gclient_scm.CreateSCM(url, self._root_dir, d) |
729 scm.RunCommand(command, self._options, args, file_list) | 757 scm.RunCommand(command, self._options, args, file_list) |
730 self._options.revision = None | 758 self._options.revision = None |
| 759 elif isinstance(deps[d], self.FileImpl): |
| 760 file = deps[d] |
| 761 self._options.revision = file.GetRevision() |
| 762 if run_scm: |
| 763 scm = gclient_scm.CreateSCM(file.GetPath(), self._root_dir, d) |
| 764 scm.RunCommand("updatesingle", self._options, |
| 765 args + [file.GetFilename()], file_list) |
| 766 |
731 if command == 'update' and not self._options.verbose: | 767 if command == 'update' and not self._options.verbose: |
732 pm.end() | 768 pm.end() |
733 | 769 |
734 # Second pass for inherited deps (via the From keyword) | 770 # Second pass for inherited deps (via the From keyword) |
735 for d in deps_to_process: | 771 for d in deps_to_process: |
736 if type(deps[d]) != str: | 772 if isinstance(deps[d], self.FromImpl): |
737 filename = os.path.join(self._root_dir, | 773 filename = os.path.join(self._root_dir, |
738 deps[d].module_name, | 774 deps[d].module_name, |
739 self._options.deps_file) | 775 self._options.deps_file) |
740 content = gclient_utils.FileRead(filename) | 776 content = gclient_utils.FileRead(filename) |
741 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}) | 777 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}) |
742 url = sub_deps[d] | 778 url = sub_deps[d] |
743 entries[d] = url | 779 entries[d] = url |
744 if run_scm: | 780 if run_scm: |
745 self._options.revision = revision_overrides.get(d) | 781 self._options.revision = revision_overrides.get(d) |
746 scm = gclient_scm.CreateSCM(url, self._root_dir, d) | 782 scm = gclient_scm.CreateSCM(url, self._root_dir, d) |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
878 deps_to_process.sort() | 914 deps_to_process.sort() |
879 | 915 |
880 # First pass for direct dependencies. | 916 # First pass for direct dependencies. |
881 for d in deps_to_process: | 917 for d in deps_to_process: |
882 if type(deps[d]) == str: | 918 if type(deps[d]) == str: |
883 (url, rev) = GetURLAndRev(d, deps[d]) | 919 (url, rev) = GetURLAndRev(d, deps[d]) |
884 entries[d] = "%s@%s" % (url, rev) | 920 entries[d] = "%s@%s" % (url, rev) |
885 | 921 |
886 # Second pass for inherited deps (via the From keyword) | 922 # Second pass for inherited deps (via the From keyword) |
887 for d in deps_to_process: | 923 for d in deps_to_process: |
888 if type(deps[d]) != str: | 924 if isinstance(deps[d], self.FromImpl): |
889 deps_parent_url = entries[deps[d].module_name] | 925 deps_parent_url = entries[deps[d].module_name] |
890 if deps_parent_url.find("@") < 0: | 926 if deps_parent_url.find("@") < 0: |
891 raise gclient_utils.Error("From %s missing revisioned url" % | 927 raise gclient_utils.Error("From %s missing revisioned url" % |
892 deps[d].module_name) | 928 deps[d].module_name) |
893 content = gclient_utils.FileRead(os.path.join( | 929 content = gclient_utils.FileRead(os.path.join( |
894 self._root_dir, | 930 self._root_dir, |
895 deps[d].module_name, | 931 deps[d].module_name, |
896 self._options.deps_file)) | 932 self._options.deps_file)) |
897 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}) | 933 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}) |
898 (url, rev) = GetURLAndRev(d, sub_deps[d]) | 934 (url, rev) = GetURLAndRev(d, sub_deps[d]) |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1251 | 1287 |
1252 if "__main__" == __name__: | 1288 if "__main__" == __name__: |
1253 try: | 1289 try: |
1254 result = Main(sys.argv) | 1290 result = Main(sys.argv) |
1255 except gclient_utils.Error, e: | 1291 except gclient_utils.Error, e: |
1256 print >> sys.stderr, "Error: %s" % str(e) | 1292 print >> sys.stderr, "Error: %s" % str(e) |
1257 result = 1 | 1293 result = 1 |
1258 sys.exit(result) | 1294 sys.exit(result) |
1259 | 1295 |
1260 # vim: ts=2:sw=2:tw=80:et: | 1296 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |