OLD | NEW |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # | 2 # |
3 # Copyright 2008 Google Inc. All Rights Reserved. | 3 # Copyright 2008 Google Inc. All Rights Reserved. |
4 # | 4 # |
5 # Licensed under the Apache License, Version 2.0 (the "License"); | 5 # Licensed under the Apache License, Version 2.0 (the "License"); |
6 # you may not use this file except in compliance with the License. | 6 # you may not use this file except in compliance with the License. |
7 # You may obtain a copy of the License at | 7 # You may obtain a copy of the License at |
8 # | 8 # |
9 # http://www.apache.org/licenses/LICENSE-2.0 | 9 # http://www.apache.org/licenses/LICENSE-2.0 |
10 # | 10 # |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
67 | 67 |
68 __author__ = "darinf@gmail.com (Darin Fisher)" | 68 __author__ = "darinf@gmail.com (Darin Fisher)" |
69 __version__ = "0.3.3" | 69 __version__ = "0.3.3" |
70 | 70 |
71 import errno | 71 import errno |
72 import logging | 72 import logging |
73 import optparse | 73 import optparse |
74 import os | 74 import os |
75 import pprint | 75 import pprint |
76 import re | 76 import re |
77 import stat | |
78 import sys | 77 import sys |
79 import urlparse | 78 import urlparse |
80 import urllib | 79 import urllib |
81 | 80 |
82 import gclient_scm | 81 import gclient_scm |
83 import gclient_utils | 82 import gclient_utils |
84 from gclient_utils import Error, FileRead, FileWrite | |
85 | 83 |
86 # default help text | 84 # default help text |
87 DEFAULT_USAGE_TEXT = ( | 85 DEFAULT_USAGE_TEXT = ( |
88 """usage: %prog <subcommand> [options] [--] [svn options/args...] | 86 """usage: %prog <subcommand> [options] [--] [svn options/args...] |
89 a wrapper for managing a set of client modules in svn. | 87 a wrapper for managing a set of client modules in svn. |
90 Version """ + __version__ + """ | 88 Version """ + __version__ + """ |
91 | 89 |
92 subcommands: | 90 subcommands: |
93 cleanup | 91 cleanup |
94 config | 92 config |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
305 self._config_dict = {} | 303 self._config_dict = {} |
306 self._deps_hooks = [] | 304 self._deps_hooks = [] |
307 | 305 |
308 def SetConfig(self, content): | 306 def SetConfig(self, content): |
309 self._config_dict = {} | 307 self._config_dict = {} |
310 self._config_content = content | 308 self._config_content = content |
311 try: | 309 try: |
312 exec(content, self._config_dict) | 310 exec(content, self._config_dict) |
313 except SyntaxError, e: | 311 except SyntaxError, e: |
314 try: | 312 try: |
313 __pychecker__ = 'no-objattrs' | |
315 # Try to construct a human readable error message | 314 # Try to construct a human readable error message |
316 error_message = [ | 315 error_message = [ |
317 'There is a syntax error in your configuration file.', | 316 'There is a syntax error in your configuration file.', |
318 'Line #%s, character %s:' % (e.lineno, e.offset), | 317 'Line #%s, character %s:' % (e.lineno, e.offset), |
319 '"%s"' % re.sub(r'[\r\n]*$', '', e.text) ] | 318 '"%s"' % re.sub(r'[\r\n]*$', '', e.text) ] |
320 except: | 319 except: |
321 # Something went wrong, re-raise the original exception | 320 # Something went wrong, re-raise the original exception |
322 raise e | 321 raise e |
323 else: | 322 else: |
324 # Raise a new exception with the human readable message: | 323 # Raise a new exception with the human readable message: |
325 raise Error('\n'.join(error_message)) | 324 raise gclient_utils.Error('\n'.join(error_message)) |
326 | 325 |
327 def SaveConfig(self): | 326 def SaveConfig(self): |
328 FileWrite(os.path.join(self._root_dir, self._options.config_filename), | 327 gclient_utils.FileWrite(os.path.join(self._root_dir, |
329 self._config_content) | 328 self._options.config_filename), |
329 self._config_content) | |
330 | 330 |
331 def _LoadConfig(self): | 331 def _LoadConfig(self): |
332 client_source = FileRead(os.path.join(self._root_dir, | 332 client_source = gclient_utils.FileRead( |
333 self._options.config_filename)) | 333 os.path.join(self._root_dir, self._options.config_filename)) |
334 self.SetConfig(client_source) | 334 self.SetConfig(client_source) |
335 | 335 |
336 def ConfigContent(self): | 336 def ConfigContent(self): |
337 return self._config_content | 337 return self._config_content |
338 | 338 |
339 def GetVar(self, key, default=None): | 339 def GetVar(self, key, default=None): |
340 return self._config_dict.get(key, default) | 340 return self._config_dict.get(key, default) |
341 | 341 |
342 @staticmethod | 342 @staticmethod |
343 def LoadCurrentConfig(options, from_dir=None): | 343 def LoadCurrentConfig(options, from_dir=None): |
(...skipping 26 matching lines...) Expand all Loading... | |
370 def _SaveEntries(self, entries): | 370 def _SaveEntries(self, entries): |
371 """Creates a .gclient_entries file to record the list of unique checkouts. | 371 """Creates a .gclient_entries file to record the list of unique checkouts. |
372 | 372 |
373 The .gclient_entries file lives in the same directory as .gclient. | 373 The .gclient_entries file lives in the same directory as .gclient. |
374 | 374 |
375 Args: | 375 Args: |
376 entries: A sequence of solution names. | 376 entries: A sequence of solution names. |
377 """ | 377 """ |
378 text = "entries = \\\n" + pprint.pformat(entries, 2) + '\n' | 378 text = "entries = \\\n" + pprint.pformat(entries, 2) + '\n' |
379 file_path = os.path.join(self._root_dir, self._options.entries_filename) | 379 file_path = os.path.join(self._root_dir, self._options.entries_filename) |
380 FileWrite(file_path, text) | 380 gclient_utils.FileWrite(file_path, text) |
381 | 381 |
382 def _ReadEntries(self): | 382 def _ReadEntries(self): |
383 """Read the .gclient_entries file for the given client. | 383 """Read the .gclient_entries file for the given client. |
384 | 384 |
385 Args: | 385 Args: |
386 client: The client for which the entries file should be read. | 386 client: The client for which the entries file should be read. |
387 | 387 |
388 Returns: | 388 Returns: |
389 A sequence of solution names, which will be empty if there is the | 389 A sequence of solution names, which will be empty if there is the |
390 entries file hasn't been created yet. | 390 entries file hasn't been created yet. |
391 """ | 391 """ |
392 scope = {} | 392 scope = {} |
393 filename = os.path.join(self._root_dir, self._options.entries_filename) | 393 filename = os.path.join(self._root_dir, self._options.entries_filename) |
394 if not os.path.exists(filename): | 394 if not os.path.exists(filename): |
395 return [] | 395 return [] |
396 exec(FileRead(filename), scope) | 396 exec(gclient_utils.FileRead(filename), scope) |
397 return scope["entries"] | 397 return scope["entries"] |
398 | 398 |
399 class FromImpl: | 399 class FromImpl: |
400 """Used to implement the From syntax.""" | 400 """Used to implement the From syntax.""" |
401 | 401 |
402 def __init__(self, module_name): | 402 def __init__(self, module_name): |
403 self.module_name = module_name | 403 self.module_name = module_name |
404 | 404 |
405 def __str__(self): | 405 def __str__(self): |
406 return 'From("%s")' % self.module_name | 406 return 'From("%s")' % self.module_name |
407 | 407 |
408 class _VarImpl: | 408 class _VarImpl: |
409 def __init__(self, custom_vars, local_scope): | 409 def __init__(self, custom_vars, local_scope): |
410 self._custom_vars = custom_vars | 410 self._custom_vars = custom_vars |
411 self._local_scope = local_scope | 411 self._local_scope = local_scope |
412 | 412 |
413 def Lookup(self, var_name): | 413 def Lookup(self, var_name): |
414 """Implements the Var syntax.""" | 414 """Implements the Var syntax.""" |
415 if var_name in self._custom_vars: | 415 if var_name in self._custom_vars: |
416 return self._custom_vars[var_name] | 416 return self._custom_vars[var_name] |
417 elif var_name in self._local_scope.get("vars", {}): | 417 elif var_name in self._local_scope.get("vars", {}): |
418 return self._local_scope["vars"][var_name] | 418 return self._local_scope["vars"][var_name] |
419 raise Error("Var is not defined: %s" % var_name) | 419 raise gclient_utils.Error("Var is not defined: %s" % var_name) |
420 | 420 |
421 def _ParseSolutionDeps(self, solution_name, solution_deps_content, | 421 def _ParseSolutionDeps(self, solution_name, solution_deps_content, |
422 custom_vars): | 422 custom_vars): |
423 """Parses the DEPS file for the specified solution. | 423 """Parses the DEPS file for the specified solution. |
424 | 424 |
425 Args: | 425 Args: |
426 solution_name: The name of the solution to query. | 426 solution_name: The name of the solution to query. |
427 solution_deps_content: Content of the DEPS file for the solution | 427 solution_deps_content: Content of the DEPS file for the solution |
428 custom_vars: A dict of vars to override any vars defined in the DEPS file. | 428 custom_vars: A dict of vars to override any vars defined in the DEPS file. |
429 | 429 |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
543 if d in deps and type(deps[d]) != str: | 543 if d in deps and type(deps[d]) != str: |
544 if url.module_name == deps[d].module_name: | 544 if url.module_name == deps[d].module_name: |
545 continue | 545 continue |
546 else: | 546 else: |
547 parsed_url = urlparse.urlparse(url) | 547 parsed_url = urlparse.urlparse(url) |
548 scheme = parsed_url[0] | 548 scheme = parsed_url[0] |
549 if not scheme: | 549 if not scheme: |
550 # A relative url. Fetch the real base. | 550 # A relative url. Fetch the real base. |
551 path = parsed_url[2] | 551 path = parsed_url[2] |
552 if path[0] != "/": | 552 if path[0] != "/": |
553 raise Error( | 553 raise gclient_utils.Error( |
554 "relative DEPS entry \"%s\" must begin with a slash" % d) | 554 "relative DEPS entry \"%s\" must begin with a slash" % d) |
555 # Create a scm just to query the full url. | 555 # Create a scm just to query the full url. |
556 scm = gclient_scm.CreateSCM(solution["url"], self._root_dir, | 556 scm = gclient_scm.CreateSCM(solution["url"], self._root_dir, |
557 None) | 557 None) |
558 url = scm.FullUrlForRelativeUrl(url) | 558 url = scm.FullUrlForRelativeUrl(url) |
559 if d in deps and deps[d] != url: | 559 if d in deps and deps[d] != url: |
560 raise Error( | 560 raise gclient_utils.Error( |
561 "Solutions have conflicting versions of dependency \"%s\"" % d) | 561 "Solutions have conflicting versions of dependency \"%s\"" % d) |
562 if d in solution_urls and solution_urls[d] != url: | 562 if d in solution_urls and solution_urls[d] != url: |
563 raise Error( | 563 raise gclient_utils.Error( |
564 "Dependency \"%s\" conflicts with specified solution" % d) | 564 "Dependency \"%s\" conflicts with specified solution" % d) |
565 # Grab the dependency. | 565 # Grab the dependency. |
566 deps[d] = url | 566 deps[d] = url |
567 return deps | 567 return deps |
568 | 568 |
569 def _RunHookAction(self, hook_dict, matching_file_list): | 569 def _RunHookAction(self, hook_dict, matching_file_list): |
570 """Runs the action from a single hook. | 570 """Runs the action from a single hook. |
571 """ | 571 """ |
572 command = hook_dict['action'][:] | 572 command = hook_dict['action'][:] |
573 if command[0] == 'python': | 573 if command[0] == 'python': |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
606 # changed so we always run all hooks. | 606 # changed so we always run all hooks. |
607 if self._options.force or is_using_git: | 607 if self._options.force or is_using_git: |
608 for hook_dict in hooks: | 608 for hook_dict in hooks: |
609 self._RunHookAction(hook_dict, []) | 609 self._RunHookAction(hook_dict, []) |
610 return | 610 return |
611 | 611 |
612 # Run hooks on the basis of whether the files from the gclient operation | 612 # Run hooks on the basis of whether the files from the gclient operation |
613 # match each hook's pattern. | 613 # match each hook's pattern. |
614 for hook_dict in hooks: | 614 for hook_dict in hooks: |
615 pattern = re.compile(hook_dict['pattern']) | 615 pattern = re.compile(hook_dict['pattern']) |
616 matching_file_list = [file for file in file_list if pattern.search(file)] | 616 matching_file_list = [f for f in file_list if pattern.search(f)] |
617 if matching_file_list: | 617 if matching_file_list: |
618 self._RunHookAction(hook_dict, matching_file_list) | 618 self._RunHookAction(hook_dict, matching_file_list) |
619 | 619 |
620 def RunOnDeps(self, command, args): | 620 def RunOnDeps(self, command, args): |
621 """Runs a command on each dependency in a client and its dependencies. | 621 """Runs a command on each dependency in a client and its dependencies. |
622 | 622 |
623 The module's dependencies are specified in its top-level DEPS files. | 623 The module's dependencies are specified in its top-level DEPS files. |
624 | 624 |
625 Args: | 625 Args: |
626 command: The command to use (e.g., 'status' or 'diff') | 626 command: The command to use (e.g., 'status' or 'diff') |
627 args: list of str - extra arguments to add to the command line. | 627 args: list of str - extra arguments to add to the command line. |
628 | 628 |
629 Raises: | 629 Raises: |
630 Error: If the client has conflicting entries. | 630 Error: If the client has conflicting entries. |
631 """ | 631 """ |
632 if not command in self.supported_commands: | 632 if not command in self.supported_commands: |
633 raise Error("'%s' is an unsupported command" % command) | 633 raise gclient_utils.Error("'%s' is an unsupported command" % command) |
634 | 634 |
635 # Check for revision overrides. | 635 # Check for revision overrides. |
636 revision_overrides = {} | 636 revision_overrides = {} |
637 for revision in self._options.revisions: | 637 for revision in self._options.revisions: |
638 if revision.find("@") == -1: | 638 if revision.find("@") == -1: |
639 raise Error( | 639 raise gclient_utils.Error( |
640 "Specify the full dependency when specifying a revision number.") | 640 "Specify the full dependency when specifying a revision number.") |
641 revision_elem = revision.split("@") | 641 revision_elem = revision.split("@") |
642 # Disallow conflicting revs | 642 # Disallow conflicting revs |
643 if revision_overrides.has_key(revision_elem[0]) and \ | 643 if revision_overrides.has_key(revision_elem[0]) and \ |
644 revision_overrides[revision_elem[0]] != revision_elem[1]: | 644 revision_overrides[revision_elem[0]] != revision_elem[1]: |
645 raise Error( | 645 raise gclient_utils.Error( |
646 "Conflicting revision numbers specified.") | 646 "Conflicting revision numbers specified.") |
647 revision_overrides[revision_elem[0]] = revision_elem[1] | 647 revision_overrides[revision_elem[0]] = revision_elem[1] |
648 | 648 |
649 solutions = self.GetVar("solutions") | 649 solutions = self.GetVar("solutions") |
650 if not solutions: | 650 if not solutions: |
651 raise Error("No solution specified") | 651 raise gclient_utils.Error("No solution specified") |
652 | 652 |
653 # When running runhooks --force, there's no need to consult the SCM. | 653 # When running runhooks --force, there's no need to consult the SCM. |
654 # All known hooks are expected to run unconditionally regardless of working | 654 # All known hooks are expected to run unconditionally regardless of working |
655 # copy state, so skip the SCM status check. | 655 # copy state, so skip the SCM status check. |
656 run_scm = not (command == 'runhooks' and self._options.force) | 656 run_scm = not (command == 'runhooks' and self._options.force) |
657 | 657 |
658 entries = {} | 658 entries = {} |
659 entries_deps_content = {} | 659 entries_deps_content = {} |
660 file_list = [] | 660 file_list = [] |
661 # Run on the base solutions first. | 661 # Run on the base solutions first. |
662 for solution in solutions: | 662 for solution in solutions: |
663 name = solution["name"] | 663 name = solution["name"] |
664 deps_file = solution.get("deps_file", self._options.deps_file) | 664 deps_file = solution.get("deps_file", self._options.deps_file) |
665 if '/' in deps_file or '\\' in deps_file: | 665 if '/' in deps_file or '\\' in deps_file: |
666 raise Error("deps_file name must not be a path, just a filename.") | 666 raise gclient_utils.Error('deps_file name must not be a path, just a ' |
667 'filename.') | |
667 if name in entries: | 668 if name in entries: |
668 raise Error("solution %s specified more than once" % name) | 669 raise gclient_utils.Error("solution %s specified more than once" % name) |
669 url = solution["url"] | 670 url = solution["url"] |
670 entries[name] = url | 671 entries[name] = url |
671 if run_scm and url: | 672 if run_scm and url: |
672 self._options.revision = revision_overrides.get(name) | 673 self._options.revision = revision_overrides.get(name) |
673 scm = gclient_scm.CreateSCM(url, self._root_dir, name) | 674 scm = gclient_scm.CreateSCM(url, self._root_dir, name) |
674 scm.RunCommand(command, self._options, args, file_list) | 675 scm.RunCommand(command, self._options, args, file_list) |
675 file_list = [os.path.join(name, file.strip()) for file in file_list] | 676 file_list = [os.path.join(name, f.strip()) for f in file_list] |
676 self._options.revision = None | 677 self._options.revision = None |
677 try: | 678 try: |
678 deps_content = FileRead(os.path.join(self._root_dir, name, | 679 deps_content = gclient_utils.FileRead( |
679 deps_file)) | 680 os.path.join(self._root_dir, name, deps_file)) |
680 except IOError, e: | 681 except IOError, e: |
681 if e.errno != errno.ENOENT: | 682 if e.errno != errno.ENOENT: |
682 raise | 683 raise |
683 deps_content = "" | 684 deps_content = "" |
684 entries_deps_content[name] = deps_content | 685 entries_deps_content[name] = deps_content |
685 | 686 |
686 # Process the dependencies next (sort alphanumerically to ensure that | 687 # Process the dependencies next (sort alphanumerically to ensure that |
687 # containing directories get populated first and for readability) | 688 # containing directories get populated first and for readability) |
688 deps = self._ParseAllDeps(entries, entries_deps_content) | 689 deps = self._ParseAllDeps(entries, entries_deps_content) |
689 deps_to_process = deps.keys() | 690 deps_to_process = deps.keys() |
690 deps_to_process.sort() | 691 deps_to_process.sort() |
691 | 692 |
692 # First pass for direct dependencies. | 693 # First pass for direct dependencies. |
693 for d in deps_to_process: | 694 for d in deps_to_process: |
694 if type(deps[d]) == str: | 695 if type(deps[d]) == str: |
695 url = deps[d] | 696 url = deps[d] |
696 entries[d] = url | 697 entries[d] = url |
697 if run_scm: | 698 if run_scm: |
698 self._options.revision = revision_overrides.get(d) | 699 self._options.revision = revision_overrides.get(d) |
699 scm = gclient_scm.CreateSCM(url, self._root_dir, d) | 700 scm = gclient_scm.CreateSCM(url, self._root_dir, d) |
700 scm.RunCommand(command, self._options, args, file_list) | 701 scm.RunCommand(command, self._options, args, file_list) |
701 self._options.revision = None | 702 self._options.revision = None |
702 | 703 |
703 # Second pass for inherited deps (via the From keyword) | 704 # Second pass for inherited deps (via the From keyword) |
704 for d in deps_to_process: | 705 for d in deps_to_process: |
705 if type(deps[d]) != str: | 706 if type(deps[d]) != str: |
706 sub_deps = self._ParseSolutionDeps( | 707 filename = os.path.join(self._root_dir, |
707 deps[d].module_name, | 708 deps[d].module_name, |
708 FileRead(os.path.join(self._root_dir, | 709 self._options.deps_file) |
709 deps[d].module_name, | 710 content = gclient_utils.FileRead(filename) |
710 self._options.deps_file)), | 711 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}) |
711 {}) | |
712 url = sub_deps[d] | 712 url = sub_deps[d] |
713 entries[d] = url | 713 entries[d] = url |
714 if run_scm: | 714 if run_scm: |
715 self._options.revision = revision_overrides.get(d) | 715 self._options.revision = revision_overrides.get(d) |
716 scm = gclient_scm.CreateSCM(url, self._root_dir, d) | 716 scm = gclient_scm.CreateSCM(url, self._root_dir, d) |
717 scm.RunCommand(command, self._options, args, file_list) | 717 scm.RunCommand(command, self._options, args, file_list) |
718 self._options.revision = None | 718 self._options.revision = None |
719 | 719 |
720 # Convert all absolute paths to relative. | 720 # Convert all absolute paths to relative. |
721 for i in range(len(file_list)): | 721 for i in range(len(file_list)): |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
782 NOTE: Unlike RunOnDeps this does not require a local checkout and is run | 782 NOTE: Unlike RunOnDeps this does not require a local checkout and is run |
783 on the Pulse master. It MUST NOT execute hooks. | 783 on the Pulse master. It MUST NOT execute hooks. |
784 | 784 |
785 Raises: | 785 Raises: |
786 Error: If the client has conflicting entries. | 786 Error: If the client has conflicting entries. |
787 """ | 787 """ |
788 # Check for revision overrides. | 788 # Check for revision overrides. |
789 revision_overrides = {} | 789 revision_overrides = {} |
790 for revision in self._options.revisions: | 790 for revision in self._options.revisions: |
791 if revision.find("@") < 0: | 791 if revision.find("@") < 0: |
792 raise Error( | 792 raise gclient_utils.Error( |
793 "Specify the full dependency when specifying a revision number.") | 793 "Specify the full dependency when specifying a revision number.") |
794 revision_elem = revision.split("@") | 794 revision_elem = revision.split("@") |
795 # Disallow conflicting revs | 795 # Disallow conflicting revs |
796 if revision_overrides.has_key(revision_elem[0]) and \ | 796 if revision_overrides.has_key(revision_elem[0]) and \ |
797 revision_overrides[revision_elem[0]] != revision_elem[1]: | 797 revision_overrides[revision_elem[0]] != revision_elem[1]: |
798 raise Error( | 798 raise gclient_utils.Error( |
799 "Conflicting revision numbers specified.") | 799 "Conflicting revision numbers specified.") |
800 revision_overrides[revision_elem[0]] = revision_elem[1] | 800 revision_overrides[revision_elem[0]] = revision_elem[1] |
801 | 801 |
802 solutions = self.GetVar("solutions") | 802 solutions = self.GetVar("solutions") |
803 if not solutions: | 803 if not solutions: |
804 raise Error("No solution specified") | 804 raise gclient_utils.Error("No solution specified") |
805 | 805 |
806 entries = {} | 806 entries = {} |
807 entries_deps_content = {} | 807 entries_deps_content = {} |
808 | 808 |
809 # Inner helper to generate base url and rev tuple (including honoring | 809 # Inner helper to generate base url and rev tuple (including honoring |
810 # |revision_overrides|) | 810 # |revision_overrides|) |
811 def GetURLAndRev(name, original_url): | 811 def GetURLAndRev(name, original_url): |
812 if original_url.find("@") < 0: | 812 if original_url.find("@") < 0: |
813 if revision_overrides.has_key(name): | 813 if revision_overrides.has_key(name): |
814 return (original_url, revision_overrides[name]) | 814 return (original_url, revision_overrides[name]) |
815 else: | 815 else: |
816 scm = gclient_scm.CreateSCM(solution["url"], self._root_dir, name) | 816 scm = gclient_scm.CreateSCM(solution["url"], self._root_dir, name) |
817 return (original_url, scm.revinfo(self._options, [], None)) | 817 return (original_url, scm.revinfo(self._options, [], None)) |
818 else: | 818 else: |
819 url_components = original_url.split("@") | 819 url_components = original_url.split("@") |
820 if revision_overrides.has_key(name): | 820 if revision_overrides.has_key(name): |
821 return (url_components[0], revision_overrides[name]) | 821 return (url_components[0], revision_overrides[name]) |
822 else: | 822 else: |
823 return (url_components[0], url_components[1]) | 823 return (url_components[0], url_components[1]) |
824 | 824 |
825 # Run on the base solutions first. | 825 # Run on the base solutions first. |
826 for solution in solutions: | 826 for solution in solutions: |
827 name = solution["name"] | 827 name = solution["name"] |
828 if name in entries: | 828 if name in entries: |
829 raise Error("solution %s specified more than once" % name) | 829 raise gclient_utils.Error("solution %s specified more than once" % name) |
830 (url, rev) = GetURLAndRev(name, solution["url"]) | 830 (url, rev) = GetURLAndRev(name, solution["url"]) |
831 entries[name] = "%s@%s" % (url, rev) | 831 entries[name] = "%s@%s" % (url, rev) |
832 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset) | 832 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset) |
833 entries_deps_content[name] = gclient_scm.CaptureSVN( | 833 entries_deps_content[name] = gclient_scm.CaptureSVN( |
834 ["cat", | 834 ["cat", |
835 "%s/%s@%s" % (url, | 835 "%s/%s@%s" % (url, |
836 self._options.deps_file, | 836 self._options.deps_file, |
837 rev)], | 837 rev)], |
838 os.getcwd()) | 838 os.getcwd()) |
839 | 839 |
840 # Process the dependencies next (sort alphanumerically to ensure that | 840 # Process the dependencies next (sort alphanumerically to ensure that |
841 # containing directories get populated first and for readability) | 841 # containing directories get populated first and for readability) |
842 deps = self._ParseAllDeps(entries, entries_deps_content) | 842 deps = self._ParseAllDeps(entries, entries_deps_content) |
843 deps_to_process = deps.keys() | 843 deps_to_process = deps.keys() |
844 deps_to_process.sort() | 844 deps_to_process.sort() |
845 | 845 |
846 # First pass for direct dependencies. | 846 # First pass for direct dependencies. |
847 for d in deps_to_process: | 847 for d in deps_to_process: |
848 if type(deps[d]) == str: | 848 if type(deps[d]) == str: |
849 (url, rev) = GetURLAndRev(d, deps[d]) | 849 (url, rev) = GetURLAndRev(d, deps[d]) |
850 entries[d] = "%s@%s" % (url, rev) | 850 entries[d] = "%s@%s" % (url, rev) |
851 | 851 |
852 # Second pass for inherited deps (via the From keyword) | 852 # Second pass for inherited deps (via the From keyword) |
853 for d in deps_to_process: | 853 for d in deps_to_process: |
854 if type(deps[d]) != str: | 854 if type(deps[d]) != str: |
855 deps_parent_url = entries[deps[d].module_name] | 855 deps_parent_url = entries[deps[d].module_name] |
856 if deps_parent_url.find("@") < 0: | 856 if deps_parent_url.find("@") < 0: |
857 raise Error("From %s missing revisioned url" % deps[d].module_name) | 857 raise gclient_utils.Error("From %s missing revisioned url" % |
858 deps_parent_url_components = deps_parent_url.split("@") | 858 deps[d].module_name) |
859 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset) | 859 content = gclient_utils.FileRead(os.path.join(self._root_dir, |
860 deps_parent_content = gclient_scm.CaptureSVN( | 860 deps[d].module_name, |
Dirk Pranke
2009/11/10 19:49:24
You're sure this file will already be local? (I'm
M-A Ruel
2009/11/10 20:02:23
If you look at the old code, it was running [svn c
| |
861 ["cat", | 861 self._options.deps_file)) |
862 "%s/%s@%s" % (deps_parent_url_components[0], | 862 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}) |
863 self._options.deps_file, | |
864 deps_parent_url_components[1])], | |
865 os.getcwd()) | |
866 sub_deps = self._ParseSolutionDeps( | |
867 deps[d].module_name, | |
868 FileRead(os.path.join(self._root_dir, | |
869 deps[d].module_name, | |
870 self._options.deps_file)), | |
871 {}) | |
872 (url, rev) = GetURLAndRev(d, sub_deps[d]) | 863 (url, rev) = GetURLAndRev(d, sub_deps[d]) |
873 entries[d] = "%s@%s" % (url, rev) | 864 entries[d] = "%s@%s" % (url, rev) |
874 print(";\n\n".join(["%s: %s" % (x, entries[x]) | 865 print(";\n\n".join(["%s: %s" % (x, entries[x]) |
875 for x in sorted(entries.keys())])) | 866 for x in sorted(entries.keys())])) |
876 | 867 |
877 | 868 |
878 ## gclient commands. | 869 ## gclient commands. |
879 | 870 |
880 | 871 |
881 def DoCleanup(options, args): | 872 def DoCleanup(options, args): |
882 """Handle the cleanup subcommand. | 873 """Handle the cleanup subcommand. |
883 | 874 |
884 Raises: | 875 Raises: |
885 Error: if client isn't configured properly. | 876 Error: if client isn't configured properly. |
886 """ | 877 """ |
887 client = GClient.LoadCurrentConfig(options) | 878 client = GClient.LoadCurrentConfig(options) |
888 if not client: | 879 if not client: |
889 raise Error("client not configured; see 'gclient config'") | 880 raise gclient_utils.Error("client not configured; see 'gclient config'") |
890 if options.verbose: | 881 if options.verbose: |
891 # Print out the .gclient file. This is longer than if we just printed the | 882 # Print out the .gclient file. This is longer than if we just printed the |
892 # client dict, but more legible, and it might contain helpful comments. | 883 # client dict, but more legible, and it might contain helpful comments. |
893 print(client.ConfigContent()) | 884 print(client.ConfigContent()) |
894 return client.RunOnDeps('cleanup', args) | 885 return client.RunOnDeps('cleanup', args) |
895 | 886 |
896 | 887 |
897 def DoConfig(options, args): | 888 def DoConfig(options, args): |
898 """Handle the config subcommand. | 889 """Handle the config subcommand. |
899 | 890 |
900 Args: | 891 Args: |
901 options: If options.spec set, a string providing contents of config file. | 892 options: If options.spec set, a string providing contents of config file. |
902 args: The command line args. If spec is not set, | 893 args: The command line args. If spec is not set, |
903 then args[0] is a string URL to get for config file. | 894 then args[0] is a string URL to get for config file. |
904 | 895 |
905 Raises: | 896 Raises: |
906 Error: on usage error | 897 Error: on usage error |
907 """ | 898 """ |
908 if len(args) < 1 and not options.spec: | 899 if len(args) < 1 and not options.spec: |
909 raise Error("required argument missing; see 'gclient help config'") | 900 raise gclient_utils.Error("required argument missing; see 'gclient help " |
901 "config'") | |
910 if os.path.exists(options.config_filename): | 902 if os.path.exists(options.config_filename): |
911 raise Error("%s file already exists in the current directory" % | 903 raise gclient_utils.Error("%s file already exists in the current directory" |
912 options.config_filename) | 904 % options.config_filename) |
913 client = GClient('.', options) | 905 client = GClient('.', options) |
914 if options.spec: | 906 if options.spec: |
915 client.SetConfig(options.spec) | 907 client.SetConfig(options.spec) |
916 else: | 908 else: |
917 # TODO(darin): it would be nice to be able to specify an alternate relpath | 909 # TODO(darin): it would be nice to be able to specify an alternate relpath |
918 # for the given URL. | 910 # for the given URL. |
919 base_url = args[0].rstrip('/') | 911 base_url = args[0].rstrip('/') |
920 name = base_url.split("/")[-1] | 912 name = base_url.split("/")[-1] |
921 safesync_url = "" | 913 safesync_url = "" |
922 if len(args) > 1: | 914 if len(args) > 1: |
923 safesync_url = args[1] | 915 safesync_url = args[1] |
924 client.SetDefaultConfig(name, base_url, safesync_url) | 916 client.SetDefaultConfig(name, base_url, safesync_url) |
925 client.SaveConfig() | 917 client.SaveConfig() |
926 | 918 |
927 | 919 |
928 def DoExport(options, args): | 920 def DoExport(options, args): |
929 """Handle the export subcommand. | 921 """Handle the export subcommand. |
930 | 922 |
931 Raises: | 923 Raises: |
932 Error: on usage error | 924 Error: on usage error |
933 """ | 925 """ |
934 if len(args) != 1: | 926 if len(args) != 1: |
935 raise Error("Need directory name") | 927 raise gclient_utils.Error("Need directory name") |
936 client = GClient.LoadCurrentConfig(options) | 928 client = GClient.LoadCurrentConfig(options) |
937 | 929 |
938 if not client: | 930 if not client: |
939 raise Error("client not configured; see 'gclient config'") | 931 raise gclient_utils.Error("client not configured; see 'gclient config'") |
940 | 932 |
941 if options.verbose: | 933 if options.verbose: |
942 # Print out the .gclient file. This is longer than if we just printed the | 934 # Print out the .gclient file. This is longer than if we just printed the |
943 # client dict, but more legible, and it might contain helpful comments. | 935 # client dict, but more legible, and it might contain helpful comments. |
944 print(client.ConfigContent()) | 936 print(client.ConfigContent()) |
945 return client.RunOnDeps('export', args) | 937 return client.RunOnDeps('export', args) |
946 | 938 |
947 def DoHelp(options, args): | 939 def DoHelp(options, args): |
948 """Handle the help subcommand giving help for another subcommand. | 940 """Handle the help subcommand giving help for another subcommand. |
949 | 941 |
950 Raises: | 942 Raises: |
951 Error: if the command is unknown. | 943 Error: if the command is unknown. |
952 """ | 944 """ |
945 __pychecker__ = 'unusednames=options' | |
953 if len(args) == 1 and args[0] in COMMAND_USAGE_TEXT: | 946 if len(args) == 1 and args[0] in COMMAND_USAGE_TEXT: |
954 print(COMMAND_USAGE_TEXT[args[0]]) | 947 print(COMMAND_USAGE_TEXT[args[0]]) |
955 else: | 948 else: |
956 raise Error("unknown subcommand '%s'; see 'gclient help'" % args[0]) | 949 raise gclient_utils.Error("unknown subcommand '%s'; see 'gclient help'" % |
950 args[0]) | |
957 | 951 |
958 | 952 |
959 def DoPack(options, args): | 953 def DoPack(options, args): |
960 """Handle the pack subcommand. | 954 """Handle the pack subcommand. |
961 | 955 |
962 Raises: | 956 Raises: |
963 Error: if client isn't configured properly. | 957 Error: if client isn't configured properly. |
964 """ | 958 """ |
965 client = GClient.LoadCurrentConfig(options) | 959 client = GClient.LoadCurrentConfig(options) |
966 if not client: | 960 if not client: |
967 raise Error("client not configured; see 'gclient config'") | 961 raise gclient_utils.Error("client not configured; see 'gclient config'") |
968 if options.verbose: | 962 if options.verbose: |
969 # Print out the .gclient file. This is longer than if we just printed the | 963 # Print out the .gclient file. This is longer than if we just printed the |
970 # client dict, but more legible, and it might contain helpful comments. | 964 # client dict, but more legible, and it might contain helpful comments. |
971 print(client.ConfigContent()) | 965 print(client.ConfigContent()) |
972 return client.RunOnDeps('pack', args) | 966 return client.RunOnDeps('pack', args) |
973 | 967 |
974 | 968 |
975 def DoStatus(options, args): | 969 def DoStatus(options, args): |
976 """Handle the status subcommand. | 970 """Handle the status subcommand. |
977 | 971 |
978 Raises: | 972 Raises: |
979 Error: if client isn't configured properly. | 973 Error: if client isn't configured properly. |
980 """ | 974 """ |
981 client = GClient.LoadCurrentConfig(options) | 975 client = GClient.LoadCurrentConfig(options) |
982 if not client: | 976 if not client: |
983 raise Error("client not configured; see 'gclient config'") | 977 raise gclient_utils.Error("client not configured; see 'gclient config'") |
984 if options.verbose: | 978 if options.verbose: |
985 # Print out the .gclient file. This is longer than if we just printed the | 979 # Print out the .gclient file. This is longer than if we just printed the |
986 # client dict, but more legible, and it might contain helpful comments. | 980 # client dict, but more legible, and it might contain helpful comments. |
987 print(client.ConfigContent()) | 981 print(client.ConfigContent()) |
988 return client.RunOnDeps('status', args) | 982 return client.RunOnDeps('status', args) |
989 | 983 |
990 | 984 |
991 def DoUpdate(options, args): | 985 def DoUpdate(options, args): |
992 """Handle the update and sync subcommands. | 986 """Handle the update and sync subcommands. |
993 | 987 |
994 Raises: | 988 Raises: |
995 Error: if client isn't configured properly. | 989 Error: if client isn't configured properly. |
996 """ | 990 """ |
997 client = GClient.LoadCurrentConfig(options) | 991 client = GClient.LoadCurrentConfig(options) |
998 | 992 |
999 if not client: | 993 if not client: |
1000 raise Error("client not configured; see 'gclient config'") | 994 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1001 | 995 |
1002 if not options.head: | 996 if not options.head: |
1003 solutions = client.GetVar('solutions') | 997 solutions = client.GetVar('solutions') |
1004 if solutions: | 998 if solutions: |
1005 for s in solutions: | 999 for s in solutions: |
1006 if s.get('safesync_url', ''): | 1000 if s.get('safesync_url', ''): |
1007 # rip through revisions and make sure we're not over-riding | 1001 # rip through revisions and make sure we're not over-riding |
1008 # something that was explicitly passed | 1002 # something that was explicitly passed |
1009 has_key = False | 1003 has_key = False |
1010 for r in options.revisions: | 1004 for r in options.revisions: |
(...skipping 16 matching lines...) Expand all Loading... | |
1027 | 1021 |
1028 | 1022 |
1029 def DoDiff(options, args): | 1023 def DoDiff(options, args): |
1030 """Handle the diff subcommand. | 1024 """Handle the diff subcommand. |
1031 | 1025 |
1032 Raises: | 1026 Raises: |
1033 Error: if client isn't configured properly. | 1027 Error: if client isn't configured properly. |
1034 """ | 1028 """ |
1035 client = GClient.LoadCurrentConfig(options) | 1029 client = GClient.LoadCurrentConfig(options) |
1036 if not client: | 1030 if not client: |
1037 raise Error("client not configured; see 'gclient config'") | 1031 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1038 if options.verbose: | 1032 if options.verbose: |
1039 # Print out the .gclient file. This is longer than if we just printed the | 1033 # Print out the .gclient file. This is longer than if we just printed the |
1040 # client dict, but more legible, and it might contain helpful comments. | 1034 # client dict, but more legible, and it might contain helpful comments. |
1041 print(client.ConfigContent()) | 1035 print(client.ConfigContent()) |
1042 return client.RunOnDeps('diff', args) | 1036 return client.RunOnDeps('diff', args) |
1043 | 1037 |
1044 | 1038 |
1045 def DoRevert(options, args): | 1039 def DoRevert(options, args): |
1046 """Handle the revert subcommand. | 1040 """Handle the revert subcommand. |
1047 | 1041 |
1048 Raises: | 1042 Raises: |
1049 Error: if client isn't configured properly. | 1043 Error: if client isn't configured properly. |
1050 """ | 1044 """ |
1051 client = GClient.LoadCurrentConfig(options) | 1045 client = GClient.LoadCurrentConfig(options) |
1052 if not client: | 1046 if not client: |
1053 raise Error("client not configured; see 'gclient config'") | 1047 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1054 return client.RunOnDeps('revert', args) | 1048 return client.RunOnDeps('revert', args) |
1055 | 1049 |
1056 | 1050 |
1057 def DoRunHooks(options, args): | 1051 def DoRunHooks(options, args): |
1058 """Handle the runhooks subcommand. | 1052 """Handle the runhooks subcommand. |
1059 | 1053 |
1060 Raises: | 1054 Raises: |
1061 Error: if client isn't configured properly. | 1055 Error: if client isn't configured properly. |
1062 """ | 1056 """ |
1063 client = GClient.LoadCurrentConfig(options) | 1057 client = GClient.LoadCurrentConfig(options) |
1064 if not client: | 1058 if not client: |
1065 raise Error("client not configured; see 'gclient config'") | 1059 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1066 if options.verbose: | 1060 if options.verbose: |
1067 # Print out the .gclient file. This is longer than if we just printed the | 1061 # Print out the .gclient file. This is longer than if we just printed the |
1068 # client dict, but more legible, and it might contain helpful comments. | 1062 # client dict, but more legible, and it might contain helpful comments. |
1069 print(client.ConfigContent()) | 1063 print(client.ConfigContent()) |
1070 options.force = True | 1064 options.force = True |
1071 return client.RunOnDeps('runhooks', args) | 1065 return client.RunOnDeps('runhooks', args) |
1072 | 1066 |
1073 | 1067 |
1074 def DoRevInfo(options, args): | 1068 def DoRevInfo(options, args): |
1075 """Handle the revinfo subcommand. | 1069 """Handle the revinfo subcommand. |
1076 | 1070 |
1077 Raises: | 1071 Raises: |
1078 Error: if client isn't configured properly. | 1072 Error: if client isn't configured properly. |
1079 """ | 1073 """ |
1074 __pychecker__ = 'unusednames=args' | |
1080 client = GClient.LoadCurrentConfig(options) | 1075 client = GClient.LoadCurrentConfig(options) |
1081 if not client: | 1076 if not client: |
1082 raise Error("client not configured; see 'gclient config'") | 1077 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1083 client.PrintRevInfo() | 1078 client.PrintRevInfo() |
1084 | 1079 |
1085 | 1080 |
1086 gclient_command_map = { | 1081 gclient_command_map = { |
1087 "cleanup": DoCleanup, | 1082 "cleanup": DoCleanup, |
1088 "config": DoConfig, | 1083 "config": DoConfig, |
1089 "diff": DoDiff, | 1084 "diff": DoDiff, |
1090 "export": DoExport, | 1085 "export": DoExport, |
1091 "help": DoHelp, | 1086 "help": DoHelp, |
1092 "pack": DoPack, | 1087 "pack": DoPack, |
1093 "status": DoStatus, | 1088 "status": DoStatus, |
1094 "sync": DoUpdate, | 1089 "sync": DoUpdate, |
1095 "update": DoUpdate, | 1090 "update": DoUpdate, |
1096 "revert": DoRevert, | 1091 "revert": DoRevert, |
1097 "runhooks": DoRunHooks, | 1092 "runhooks": DoRunHooks, |
1098 "revinfo" : DoRevInfo, | 1093 "revinfo" : DoRevInfo, |
1099 } | 1094 } |
1100 | 1095 |
1101 | 1096 |
1102 def DispatchCommand(command, options, args, command_map=None): | 1097 def DispatchCommand(command, options, args, command_map=None): |
1103 """Dispatches the appropriate subcommand based on command line arguments.""" | 1098 """Dispatches the appropriate subcommand based on command line arguments.""" |
1104 if command_map is None: | 1099 if command_map is None: |
1105 command_map = gclient_command_map | 1100 command_map = gclient_command_map |
1106 | 1101 |
1107 if command in command_map: | 1102 if command in command_map: |
1108 return command_map[command](options, args) | 1103 return command_map[command](options, args) |
1109 else: | 1104 else: |
1110 raise Error("unknown subcommand '%s'; see 'gclient help'" % command) | 1105 raise gclient_utils.Error("unknown subcommand '%s'; see 'gclient help'" % |
1106 command) | |
1111 | 1107 |
1112 | 1108 |
1113 def Main(argv): | 1109 def Main(argv): |
1114 """Parse command line arguments and dispatch command.""" | 1110 """Parse command line arguments and dispatch command.""" |
1115 | 1111 |
1116 option_parser = optparse.OptionParser(usage=DEFAULT_USAGE_TEXT, | 1112 option_parser = optparse.OptionParser(usage=DEFAULT_USAGE_TEXT, |
1117 version=__version__) | 1113 version=__version__) |
1118 option_parser.disable_interspersed_args() | 1114 option_parser.disable_interspersed_args() |
1119 option_parser.add_option("", "--force", action="store_true", default=False, | 1115 option_parser.add_option("", "--force", action="store_true", default=False, |
1120 help=("(update/sync only) force update even " | 1116 help=("(update/sync only) force update even " |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1178 options.entries_filename = ".gclient_entries" | 1174 options.entries_filename = ".gclient_entries" |
1179 options.deps_file = "DEPS" | 1175 options.deps_file = "DEPS" |
1180 | 1176 |
1181 options.platform = sys.platform | 1177 options.platform = sys.platform |
1182 return DispatchCommand(command, options, args) | 1178 return DispatchCommand(command, options, args) |
1183 | 1179 |
1184 | 1180 |
1185 if "__main__" == __name__: | 1181 if "__main__" == __name__: |
1186 try: | 1182 try: |
1187 result = Main(sys.argv) | 1183 result = Main(sys.argv) |
1188 except Error, e: | 1184 except gclient_utils.Error, e: |
1189 print >> sys.stderr, "Error: %s" % str(e) | 1185 print >> sys.stderr, "Error: %s" % str(e) |
1190 result = 1 | 1186 result = 1 |
1191 sys.exit(result) | 1187 sys.exit(result) |
1192 | 1188 |
1193 # vim: ts=2:sw=2:tw=80:et: | 1189 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |