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 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 self._config_dict = {} | 210 self._config_dict = {} |
211 self._deps_hooks = [] | 211 self._deps_hooks = [] |
212 | 212 |
213 def SetConfig(self, content): | 213 def SetConfig(self, content): |
214 self._config_dict = {} | 214 self._config_dict = {} |
215 self.config_content = content | 215 self.config_content = content |
216 try: | 216 try: |
217 exec(content, self._config_dict) | 217 exec(content, self._config_dict) |
218 except SyntaxError, e: | 218 except SyntaxError, e: |
219 try: | 219 try: |
220 __pychecker__ = 'no-objattrs' | |
221 # Try to construct a human readable error message | 220 # Try to construct a human readable error message |
222 error_message = [ | 221 error_message = [ |
223 'There is a syntax error in your configuration file.', | 222 'There is a syntax error in your configuration file.', |
224 'Line #%s, character %s:' % (e.lineno, e.offset), | 223 'Line #%s, character %s:' % (e.lineno, e.offset), |
225 '"%s"' % re.sub(r'[\r\n]*$', '', e.text) ] | 224 '"%s"' % re.sub(r'[\r\n]*$', '', e.text) ] |
226 except: | 225 except: |
227 # Something went wrong, re-raise the original exception | 226 # Something went wrong, re-raise the original exception |
228 raise e | 227 raise e |
229 else: | 228 else: |
230 # Raise a new exception with the human readable message: | 229 # Raise a new exception with the human readable message: |
231 raise gclient_utils.Error('\n'.join(error_message)) | 230 raise gclient_utils.Error('\n'.join(error_message)) |
232 | 231 |
233 def SaveConfig(self): | 232 def SaveConfig(self): |
234 gclient_utils.FileWrite(os.path.join(self._root_dir, | 233 gclient_utils.FileWrite(os.path.join(self.root_dir(), |
235 self._options.config_filename), | 234 self._options.config_filename), |
236 self.config_content) | 235 self.config_content) |
237 | 236 |
238 def _LoadConfig(self): | 237 def _LoadConfig(self): |
239 client_source = gclient_utils.FileRead( | 238 client_source = gclient_utils.FileRead( |
240 os.path.join(self._root_dir, self._options.config_filename)) | 239 os.path.join(self.root_dir(), self._options.config_filename)) |
241 self.SetConfig(client_source) | 240 self.SetConfig(client_source) |
242 | 241 |
243 def GetVar(self, key, default=None): | 242 def GetVar(self, key, default=None): |
244 return self._config_dict.get(key, default) | 243 return self._config_dict.get(key, default) |
245 | 244 |
246 @staticmethod | 245 @staticmethod |
247 def LoadCurrentConfig(options, from_dir=None): | 246 def LoadCurrentConfig(options, from_dir=None): |
248 """Searches for and loads a .gclient file relative to the current working | 247 """Searches for and loads a .gclient file relative to the current working |
249 dir. | 248 dir. |
250 | 249 |
(...skipping 27 matching lines...) Expand all Loading... |
278 | 277 |
279 Args: | 278 Args: |
280 entries: A sequence of solution names. | 279 entries: A sequence of solution names. |
281 """ | 280 """ |
282 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It | 281 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It |
283 # makes testing a bit too fun. | 282 # makes testing a bit too fun. |
284 result = pprint.pformat(entries, 2) | 283 result = pprint.pformat(entries, 2) |
285 if result.startswith('{\''): | 284 if result.startswith('{\''): |
286 result = '{ \'' + result[2:] | 285 result = '{ \'' + result[2:] |
287 text = "entries = \\\n" + result + '\n' | 286 text = "entries = \\\n" + result + '\n' |
288 file_path = os.path.join(self._root_dir, self._options.entries_filename) | 287 file_path = os.path.join(self.root_dir(), self._options.entries_filename) |
289 gclient_utils.FileWrite(file_path, text) | 288 gclient_utils.FileWrite(file_path, text) |
290 | 289 |
291 def _ReadEntries(self): | 290 def _ReadEntries(self): |
292 """Read the .gclient_entries file for the given client. | 291 """Read the .gclient_entries file for the given client. |
293 | 292 |
294 Args: | 293 Args: |
295 client: The client for which the entries file should be read. | 294 client: The client for which the entries file should be read. |
296 | 295 |
297 Returns: | 296 Returns: |
298 A sequence of solution names, which will be empty if there is the | 297 A sequence of solution names, which will be empty if there is the |
299 entries file hasn't been created yet. | 298 entries file hasn't been created yet. |
300 """ | 299 """ |
301 scope = {} | 300 scope = {} |
302 filename = os.path.join(self._root_dir, self._options.entries_filename) | 301 filename = os.path.join(self.root_dir(), self._options.entries_filename) |
303 if not os.path.exists(filename): | 302 if not os.path.exists(filename): |
304 return [] | 303 return [] |
305 exec(gclient_utils.FileRead(filename), scope) | 304 exec(gclient_utils.FileRead(filename), scope) |
306 return scope["entries"] | 305 return scope["entries"] |
307 | 306 |
308 def _ParseSolutionDeps(self, solution_name, solution_deps_content, | 307 def _ParseSolutionDeps(self, solution_name, solution_deps_content, |
309 custom_vars, parse_hooks): | 308 custom_vars, parse_hooks): |
310 """Parses the DEPS file for the specified solution. | 309 """Parses the DEPS file for the specified solution. |
311 | 310 |
312 Args: | 311 Args: |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 elif isinstance(url, str): | 427 elif isinstance(url, str): |
429 parsed_url = urlparse.urlparse(url) | 428 parsed_url = urlparse.urlparse(url) |
430 scheme = parsed_url[0] | 429 scheme = parsed_url[0] |
431 if not scheme: | 430 if not scheme: |
432 # A relative url. Fetch the real base. | 431 # A relative url. Fetch the real base. |
433 path = parsed_url[2] | 432 path = parsed_url[2] |
434 if path[0] != "/": | 433 if path[0] != "/": |
435 raise gclient_utils.Error( | 434 raise gclient_utils.Error( |
436 "relative DEPS entry \"%s\" must begin with a slash" % d) | 435 "relative DEPS entry \"%s\" must begin with a slash" % d) |
437 # Create a scm just to query the full url. | 436 # Create a scm just to query the full url. |
438 scm = gclient_scm.CreateSCM(solution["url"], self._root_dir, | 437 scm = gclient_scm.CreateSCM(solution["url"], self.root_dir(), |
439 None) | 438 None) |
440 url = scm.FullUrlForRelativeUrl(url) | 439 url = scm.FullUrlForRelativeUrl(url) |
441 if d in deps and deps[d] != url: | 440 if d in deps and deps[d] != url: |
442 raise gclient_utils.Error( | 441 raise gclient_utils.Error( |
443 "Solutions have conflicting versions of dependency \"%s\"" % d) | 442 "Solutions have conflicting versions of dependency \"%s\"" % d) |
444 if d in solution_urls and solution_urls[d] != url: | 443 if d in solution_urls and solution_urls[d] != url: |
445 raise gclient_utils.Error( | 444 raise gclient_utils.Error( |
446 "Dependency \"%s\" conflicts with specified solution" % d) | 445 "Dependency \"%s\" conflicts with specified solution" % d) |
447 # Grab the dependency. | 446 # Grab the dependency. |
448 deps[d] = url | 447 deps[d] = url |
(...skipping 11 matching lines...) Expand all Loading... |
460 # interpreter. | 459 # interpreter. |
461 command[0] = sys.executable | 460 command[0] = sys.executable |
462 | 461 |
463 if '$matching_files' in command: | 462 if '$matching_files' in command: |
464 splice_index = command.index('$matching_files') | 463 splice_index = command.index('$matching_files') |
465 command[splice_index:splice_index + 1] = matching_file_list | 464 command[splice_index:splice_index + 1] = matching_file_list |
466 | 465 |
467 # Use a discrete exit status code of 2 to indicate that a hook action | 466 # Use a discrete exit status code of 2 to indicate that a hook action |
468 # failed. Users of this script may wish to treat hook action failures | 467 # failed. Users of this script may wish to treat hook action failures |
469 # differently from VC failures. | 468 # differently from VC failures. |
470 gclient_utils.SubprocessCall(command, self._root_dir, fail_status=2) | 469 gclient_utils.SubprocessCall(command, self.root_dir(), fail_status=2) |
471 | 470 |
472 def _RunHooks(self, command, file_list, is_using_git): | 471 def _RunHooks(self, command, file_list, is_using_git): |
473 """Evaluates all hooks, running actions as needed. | 472 """Evaluates all hooks, running actions as needed. |
474 """ | 473 """ |
475 # Hooks only run for these command types. | 474 # Hooks only run for these command types. |
476 if not command in ('update', 'revert', 'runhooks'): | 475 if not command in ('update', 'revert', 'runhooks'): |
477 return | 476 return |
478 | 477 |
479 # Hooks only run when --nohooks is not specified | 478 # Hooks only run when --nohooks is not specified |
480 if self._options.nohooks: | 479 if self._options.nohooks: |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 deps_file = solution.get("deps_file", self.DEPS_FILE) | 566 deps_file = solution.get("deps_file", self.DEPS_FILE) |
568 if '/' in deps_file or '\\' in deps_file: | 567 if '/' in deps_file or '\\' in deps_file: |
569 raise gclient_utils.Error('deps_file name must not be a path, just a ' | 568 raise gclient_utils.Error('deps_file name must not be a path, just a ' |
570 'filename.') | 569 'filename.') |
571 if name in entries: | 570 if name in entries: |
572 raise gclient_utils.Error("solution %s specified more than once" % name) | 571 raise gclient_utils.Error("solution %s specified more than once" % name) |
573 url = solution["url"] | 572 url = solution["url"] |
574 entries[name] = url | 573 entries[name] = url |
575 if run_scm and url: | 574 if run_scm and url: |
576 self._options.revision = revision_overrides.get(name) | 575 self._options.revision = revision_overrides.get(name) |
577 scm = gclient_scm.CreateSCM(url, self._root_dir, name) | 576 scm = gclient_scm.CreateSCM(url, self.root_dir(), name) |
578 scm.RunCommand(command, self._options, args, file_list) | 577 scm.RunCommand(command, self._options, args, file_list) |
579 file_list = [os.path.join(name, f.strip()) for f in file_list] | 578 file_list = [os.path.join(name, f.strip()) for f in file_list] |
580 self._options.revision = None | 579 self._options.revision = None |
581 try: | 580 try: |
582 deps_content = gclient_utils.FileRead( | 581 deps_content = gclient_utils.FileRead( |
583 os.path.join(self._root_dir, name, deps_file)) | 582 os.path.join(self.root_dir(), name, deps_file)) |
584 except IOError, e: | 583 except IOError, e: |
585 if e.errno != errno.ENOENT: | 584 if e.errno != errno.ENOENT: |
586 raise | 585 raise |
587 deps_content = "" | 586 deps_content = "" |
588 entries_deps_content[name] = deps_content | 587 entries_deps_content[name] = deps_content |
589 | 588 |
590 # Process the dependencies next (sort alphanumerically to ensure that | 589 # Process the dependencies next (sort alphanumerically to ensure that |
591 # containing directories get populated first and for readability) | 590 # containing directories get populated first and for readability) |
592 deps = self._ParseAllDeps(entries, entries_deps_content) | 591 deps = self._ParseAllDeps(entries, entries_deps_content) |
593 deps_to_process = deps.keys() | 592 deps_to_process = deps.keys() |
594 deps_to_process.sort() | 593 deps_to_process.sort() |
595 | 594 |
596 # First pass for direct dependencies. | 595 # First pass for direct dependencies. |
597 if command == 'update' and not self._options.verbose: | 596 if command == 'update' and not self._options.verbose: |
598 pm = Progress('Syncing projects', len(deps_to_process)) | 597 pm = Progress('Syncing projects', len(deps_to_process)) |
599 for d in deps_to_process: | 598 for d in deps_to_process: |
600 if command == 'update' and not self._options.verbose: | 599 if command == 'update' and not self._options.verbose: |
601 pm.update() | 600 pm.update() |
602 if type(deps[d]) == str: | 601 if type(deps[d]) == str: |
603 url = deps[d] | 602 url = deps[d] |
604 entries[d] = url | 603 entries[d] = url |
605 if run_scm: | 604 if run_scm: |
606 self._options.revision = revision_overrides.get(d) | 605 self._options.revision = revision_overrides.get(d) |
607 scm = gclient_scm.CreateSCM(url, self._root_dir, d) | 606 scm = gclient_scm.CreateSCM(url, self.root_dir(), d) |
608 scm.RunCommand(command, self._options, args, file_list) | 607 scm.RunCommand(command, self._options, args, file_list) |
609 self._options.revision = None | 608 self._options.revision = None |
610 elif isinstance(deps[d], self.FileImpl): | 609 elif isinstance(deps[d], self.FileImpl): |
611 file_dep = deps[d] | 610 file_dep = deps[d] |
612 self._options.revision = file_dep.GetRevision() | 611 self._options.revision = file_dep.GetRevision() |
613 if run_scm: | 612 if run_scm: |
614 scm = gclient_scm.CreateSCM(file_dep.GetPath(), self._root_dir, d) | 613 scm = gclient_scm.CreateSCM(file_dep.GetPath(), self.root_dir(), d) |
615 scm.RunCommand("updatesingle", self._options, | 614 scm.RunCommand("updatesingle", self._options, |
616 args + [file_dep.GetFilename()], file_list) | 615 args + [file_dep.GetFilename()], file_list) |
617 | 616 |
618 if command == 'update' and not self._options.verbose: | 617 if command == 'update' and not self._options.verbose: |
619 pm.end() | 618 pm.end() |
620 | 619 |
621 # Second pass for inherited deps (via the From keyword) | 620 # Second pass for inherited deps (via the From keyword) |
622 for d in deps_to_process: | 621 for d in deps_to_process: |
623 if isinstance(deps[d], self.FromImpl): | 622 if isinstance(deps[d], self.FromImpl): |
624 filename = os.path.join(self._root_dir, | 623 filename = os.path.join(self.root_dir(), |
625 deps[d].module_name, | 624 deps[d].module_name, |
626 self.DEPS_FILE) | 625 self.DEPS_FILE) |
627 content = gclient_utils.FileRead(filename) | 626 content = gclient_utils.FileRead(filename) |
628 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}, | 627 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}, |
629 False) | 628 False) |
630 # Getting the URL from the sub_deps file can involve having to resolve | 629 # Getting the URL from the sub_deps file can involve having to resolve |
631 # a File() or having to resolve a relative URL. To resolve relative | 630 # a File() or having to resolve a relative URL. To resolve relative |
632 # URLs, we need to pass in the orignal sub deps URL. | 631 # URLs, we need to pass in the orignal sub deps URL. |
633 sub_deps_base_url = deps[deps[d].module_name] | 632 sub_deps_base_url = deps[deps[d].module_name] |
634 url = deps[d].GetUrl(d, sub_deps_base_url, self._root_dir, sub_deps) | 633 url = deps[d].GetUrl(d, sub_deps_base_url, self.root_dir(), sub_deps) |
635 entries[d] = url | 634 entries[d] = url |
636 if run_scm: | 635 if run_scm: |
637 self._options.revision = revision_overrides.get(d) | 636 self._options.revision = revision_overrides.get(d) |
638 scm = gclient_scm.CreateSCM(url, self._root_dir, d) | 637 scm = gclient_scm.CreateSCM(url, self.root_dir(), d) |
639 scm.RunCommand(command, self._options, args, file_list) | 638 scm.RunCommand(command, self._options, args, file_list) |
640 self._options.revision = None | 639 self._options.revision = None |
641 | 640 |
642 # Convert all absolute paths to relative. | 641 # Convert all absolute paths to relative. |
643 for i in range(len(file_list)): | 642 for i in range(len(file_list)): |
644 # TODO(phajdan.jr): We should know exactly when the paths are absolute. | 643 # TODO(phajdan.jr): We should know exactly when the paths are absolute. |
645 # It depends on the command being executed (like runhooks vs sync). | 644 # It depends on the command being executed (like runhooks vs sync). |
646 if not os.path.isabs(file_list[i]): | 645 if not os.path.isabs(file_list[i]): |
647 continue | 646 continue |
648 | 647 |
649 prefix = os.path.commonprefix([self._root_dir.lower(), | 648 prefix = os.path.commonprefix([self.root_dir().lower(), |
650 file_list[i].lower()]) | 649 file_list[i].lower()]) |
651 file_list[i] = file_list[i][len(prefix):] | 650 file_list[i] = file_list[i][len(prefix):] |
652 | 651 |
653 # Strip any leading path separators. | 652 # Strip any leading path separators. |
654 while file_list[i].startswith('\\') or file_list[i].startswith('/'): | 653 while file_list[i].startswith('\\') or file_list[i].startswith('/'): |
655 file_list[i] = file_list[i][1:] | 654 file_list[i] = file_list[i][1:] |
656 | 655 |
657 is_using_git = gclient_utils.IsUsingGit(self._root_dir, entries.keys()) | 656 is_using_git = gclient_utils.IsUsingGit(self.root_dir(), entries.keys()) |
658 self._RunHooks(command, file_list, is_using_git) | 657 self._RunHooks(command, file_list, is_using_git) |
659 | 658 |
660 if command == 'update': | 659 if command == 'update': |
661 # Notify the user if there is an orphaned entry in their working copy. | 660 # Notify the user if there is an orphaned entry in their working copy. |
662 # Only delete the directory if there are no changes in it, and | 661 # Only delete the directory if there are no changes in it, and |
663 # delete_unversioned_trees is set to true. | 662 # delete_unversioned_trees is set to true. |
664 prev_entries = self._ReadEntries() | 663 prev_entries = self._ReadEntries() |
665 for entry in prev_entries: | 664 for entry in prev_entries: |
666 # Fix path separator on Windows. | 665 # Fix path separator on Windows. |
667 entry_fixed = entry.replace('/', os.path.sep) | 666 entry_fixed = entry.replace('/', os.path.sep) |
668 e_dir = os.path.join(self._root_dir, entry_fixed) | 667 e_dir = os.path.join(self.root_dir(), entry_fixed) |
669 # Use entry and not entry_fixed there. | 668 # Use entry and not entry_fixed there. |
670 if entry not in entries and os.path.exists(e_dir): | 669 if entry not in entries and os.path.exists(e_dir): |
671 modified_files = False | 670 modified_files = False |
672 if isinstance(prev_entries, list): | 671 if isinstance(prev_entries, list): |
673 # old .gclient_entries format was list, now dict | 672 # old .gclient_entries format was list, now dict |
674 modified_files = gclient_scm.scm.SVN.CaptureStatus(e_dir) | 673 modified_files = gclient_scm.scm.SVN.CaptureStatus(e_dir) |
675 else: | 674 else: |
676 file_list = [] | 675 file_list = [] |
677 scm = gclient_scm.CreateSCM(prev_entries[entry], self._root_dir, | 676 scm = gclient_scm.CreateSCM(prev_entries[entry], self.root_dir(), |
678 entry_fixed) | 677 entry_fixed) |
679 scm.status(self._options, [], file_list) | 678 scm.status(self._options, [], file_list) |
680 modified_files = file_list != [] | 679 modified_files = file_list != [] |
681 if not self._options.delete_unversioned_trees or modified_files: | 680 if not self._options.delete_unversioned_trees or modified_files: |
682 # There are modified files in this entry. Keep warning until | 681 # There are modified files in this entry. Keep warning until |
683 # removed. | 682 # removed. |
684 print(("\nWARNING: \"%s\" is no longer part of this client. " | 683 print(("\nWARNING: \"%s\" is no longer part of this client. " |
685 "It is recommended that you manually remove it.\n") % | 684 "It is recommended that you manually remove it.\n") % |
686 entry_fixed) | 685 entry_fixed) |
687 else: | 686 else: |
688 # Delete the entry | 687 # Delete the entry |
689 print("\n________ deleting \'%s\' " + | 688 print("\n________ deleting \'%s\' " + |
690 "in \'%s\'") % (entry_fixed, self._root_dir) | 689 "in \'%s\'") % (entry_fixed, self.root_dir()) |
691 gclient_utils.RemoveDirectory(e_dir) | 690 gclient_utils.RemoveDirectory(e_dir) |
692 # record the current list of entries for next time | 691 # record the current list of entries for next time |
693 self._SaveEntries(entries) | 692 self._SaveEntries(entries) |
694 return 0 | 693 return 0 |
695 | 694 |
696 def PrintRevInfo(self): | 695 def PrintRevInfo(self): |
697 """Output revision info mapping for the client and its dependencies. | 696 """Output revision info mapping for the client and its dependencies. |
698 | 697 |
699 This allows the capture of an overall "revision" for the source tree that | 698 This allows the capture of an overall "revision" for the source tree that |
700 can be used to reproduce the same tree in the future. It is only useful for | 699 can be used to reproduce the same tree in the future. It is only useful for |
701 "unpinned dependencies", i.e. DEPS/deps references without a svn revision | 700 "unpinned dependencies", i.e. DEPS/deps references without a svn revision |
702 number or a git hash. A git branch name isn't "pinned" since the actual | 701 number or a git hash. A git branch name isn't "pinned" since the actual |
703 commit can change. | 702 commit can change. |
704 | 703 |
705 The --snapshot option allows creating a .gclient file to reproduce the tree. | 704 The --snapshot option allows creating a .gclient file to reproduce the tree. |
706 """ | 705 """ |
707 solutions = self.GetVar("solutions") | 706 solutions = self.GetVar("solutions") |
708 if not solutions: | 707 if not solutions: |
709 raise gclient_utils.Error("No solution specified") | 708 raise gclient_utils.Error("No solution specified") |
710 | 709 |
711 # Inner helper to generate base url and rev tuple | 710 # Inner helper to generate base url and rev tuple |
712 def GetURLAndRev(name, original_url): | 711 def GetURLAndRev(name, original_url): |
713 url, _ = gclient_utils.SplitUrlRevision(original_url) | 712 url, _ = gclient_utils.SplitUrlRevision(original_url) |
714 scm = gclient_scm.CreateSCM(original_url, self._root_dir, name) | 713 scm = gclient_scm.CreateSCM(original_url, self.root_dir(), name) |
715 return (url, scm.revinfo(self._options, [], None)) | 714 return (url, scm.revinfo(self._options, [], None)) |
716 | 715 |
717 # text of the snapshot gclient file | 716 # text of the snapshot gclient file |
718 new_gclient = "" | 717 new_gclient = "" |
719 # Dictionary of { path : SCM url } to ensure no duplicate solutions | 718 # Dictionary of { path : SCM url } to ensure no duplicate solutions |
720 solution_names = {} | 719 solution_names = {} |
721 entries = {} | 720 entries = {} |
722 entries_deps_content = {} | 721 entries_deps_content = {} |
723 # Run on the base solutions first. | 722 # Run on the base solutions first. |
724 for solution in solutions: | 723 for solution in solutions: |
725 # Dictionary of { path : SCM url } to describe the gclient checkout | 724 # Dictionary of { path : SCM url } to describe the gclient checkout |
726 name = solution["name"] | 725 name = solution["name"] |
727 if name in solution_names: | 726 if name in solution_names: |
728 raise gclient_utils.Error("solution %s specified more than once" % name) | 727 raise gclient_utils.Error("solution %s specified more than once" % name) |
729 (url, rev) = GetURLAndRev(name, solution["url"]) | 728 (url, rev) = GetURLAndRev(name, solution["url"]) |
730 entries[name] = "%s@%s" % (url, rev) | 729 entries[name] = "%s@%s" % (url, rev) |
731 solution_names[name] = "%s@%s" % (url, rev) | 730 solution_names[name] = "%s@%s" % (url, rev) |
732 deps_file = solution.get("deps_file", self.DEPS_FILE) | 731 deps_file = solution.get("deps_file", self.DEPS_FILE) |
733 if '/' in deps_file or '\\' in deps_file: | 732 if '/' in deps_file or '\\' in deps_file: |
734 raise gclient_utils.Error('deps_file name must not be a path, just a ' | 733 raise gclient_utils.Error('deps_file name must not be a path, just a ' |
735 'filename.') | 734 'filename.') |
736 try: | 735 try: |
737 deps_content = gclient_utils.FileRead( | 736 deps_content = gclient_utils.FileRead( |
738 os.path.join(self._root_dir, name, deps_file)) | 737 os.path.join(self.root_dir(), name, deps_file)) |
739 except IOError, e: | 738 except IOError, e: |
740 if e.errno != errno.ENOENT: | 739 if e.errno != errno.ENOENT: |
741 raise | 740 raise |
742 deps_content = "" | 741 deps_content = "" |
743 entries_deps_content[name] = deps_content | 742 entries_deps_content[name] = deps_content |
744 | 743 |
745 # Process the dependencies next (sort alphanumerically to ensure that | 744 # Process the dependencies next (sort alphanumerically to ensure that |
746 # containing directories get populated first and for readability) | 745 # containing directories get populated first and for readability) |
747 deps = self._ParseAllDeps(entries, entries_deps_content) | 746 deps = self._ParseAllDeps(entries, entries_deps_content) |
748 deps_to_process = deps.keys() | 747 deps_to_process = deps.keys() |
749 deps_to_process.sort() | 748 deps_to_process.sort() |
750 | 749 |
751 # First pass for direct dependencies. | 750 # First pass for direct dependencies. |
752 for d in deps_to_process: | 751 for d in deps_to_process: |
753 if type(deps[d]) == str: | 752 if type(deps[d]) == str: |
754 (url, rev) = GetURLAndRev(d, deps[d]) | 753 (url, rev) = GetURLAndRev(d, deps[d]) |
755 entries[d] = "%s@%s" % (url, rev) | 754 entries[d] = "%s@%s" % (url, rev) |
756 | 755 |
757 # Second pass for inherited deps (via the From keyword) | 756 # Second pass for inherited deps (via the From keyword) |
758 for d in deps_to_process: | 757 for d in deps_to_process: |
759 if isinstance(deps[d], self.FromImpl): | 758 if isinstance(deps[d], self.FromImpl): |
760 deps_parent_url = entries[deps[d].module_name] | 759 deps_parent_url = entries[deps[d].module_name] |
761 if deps_parent_url.find("@") < 0: | 760 if deps_parent_url.find("@") < 0: |
762 raise gclient_utils.Error("From %s missing revisioned url" % | 761 raise gclient_utils.Error("From %s missing revisioned url" % |
763 deps[d].module_name) | 762 deps[d].module_name) |
764 content = gclient_utils.FileRead(os.path.join( | 763 content = gclient_utils.FileRead(os.path.join( |
765 self._root_dir, | 764 self.root_dir(), |
766 deps[d].module_name, | 765 deps[d].module_name, |
767 self.DEPS_FILE)) | 766 self.DEPS_FILE)) |
768 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}, | 767 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}, |
769 False) | 768 False) |
770 (url, rev) = GetURLAndRev(d, sub_deps[d]) | 769 (url, rev) = GetURLAndRev(d, sub_deps[d]) |
771 entries[d] = "%s@%s" % (url, rev) | 770 entries[d] = "%s@%s" % (url, rev) |
772 | 771 |
773 # Build the snapshot configuration string | 772 # Build the snapshot configuration string |
774 if self._options.snapshot: | 773 if self._options.snapshot: |
775 url = entries.pop(name) | 774 url = entries.pop(name) |
776 custom_deps = ",\n ".join(["\"%s\": \"%s\"" % (x, entries[x]) | 775 custom_deps = ",\n ".join(["\"%s\": \"%s\"" % (x, entries[x]) |
777 for x in sorted(entries.keys())]) | 776 for x in sorted(entries.keys())]) |
778 | 777 |
779 new_gclient += self.DEFAULT_SNAPSHOT_SOLUTION_TEXT % { | 778 new_gclient += self.DEFAULT_SNAPSHOT_SOLUTION_TEXT % { |
780 'solution_name': name, | 779 'solution_name': name, |
781 'solution_url': url, | 780 'solution_url': url, |
782 'safesync_url' : "", | 781 'safesync_url' : "", |
783 'solution_deps': custom_deps, | 782 'solution_deps': custom_deps, |
784 } | 783 } |
785 else: | 784 else: |
786 print(";\n".join(["%s: %s" % (x, entries[x]) | 785 print(";\n".join(["%s: %s" % (x, entries[x]) |
787 for x in sorted(entries.keys())])) | 786 for x in sorted(entries.keys())])) |
788 | 787 |
789 # Print the snapshot configuration file | 788 # Print the snapshot configuration file |
790 if self._options.snapshot: | 789 if self._options.snapshot: |
791 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient} | 790 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient} |
792 snapclient = GClient(self._root_dir, self._options) | 791 snapclient = GClient(self.root_dir(), self._options) |
793 snapclient.SetConfig(config) | 792 snapclient.SetConfig(config) |
794 print(snapclient.config_content) | 793 print(snapclient.config_content) |
795 | 794 |
| 795 def root_dir(self): |
| 796 return self._root_dir |
| 797 |
796 | 798 |
797 #### gclient commands. | 799 #### gclient commands. |
798 | 800 |
799 | 801 |
800 def CMDcleanup(parser, args): | 802 def CMDcleanup(parser, args): |
801 """Cleans up all working copies. | 803 """Cleans up all working copies. |
802 | 804 |
803 Mostly svn-specific. Simply runs 'svn cleanup' for each module. | 805 Mostly svn-specific. Simply runs 'svn cleanup' for each module. |
804 """ | 806 """ |
805 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", | 807 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1139 return CMDhelp(parser, argv) | 1141 return CMDhelp(parser, argv) |
1140 except gclient_utils.Error, e: | 1142 except gclient_utils.Error, e: |
1141 print >> sys.stderr, 'Error: %s' % str(e) | 1143 print >> sys.stderr, 'Error: %s' % str(e) |
1142 return 1 | 1144 return 1 |
1143 | 1145 |
1144 | 1146 |
1145 if '__main__' == __name__: | 1147 if '__main__' == __name__: |
1146 sys.exit(Main(sys.argv[1:])) | 1148 sys.exit(Main(sys.argv[1:])) |
1147 | 1149 |
1148 # vim: ts=2:sw=2:tw=80:et: | 1150 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |