Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Side by Side Diff: gclient.py

Issue 7062029: Add a --deps-file flag to gclient to allow using a deps file other than DEPS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: '' Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/fake_repos.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2011 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 """Meta checkout manager supporting both Subversion and GIT. 6 """Meta checkout manager supporting both Subversion and GIT.
7 7
8 Files 8 Files
9 .gclient : Current client configuration, written by 'config' command. 9 .gclient : Current client configuration, written by 'config' command.
10 Format is a Python script defining 'solutions', a list whose 10 Format is a Python script defining 'solutions', a list whose
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 """Implements the Var syntax.""" 131 """Implements the Var syntax."""
132 if var_name in self._custom_vars: 132 if var_name in self._custom_vars:
133 return self._custom_vars[var_name] 133 return self._custom_vars[var_name]
134 elif var_name in self._local_scope.get("vars", {}): 134 elif var_name in self._local_scope.get("vars", {}):
135 return self._local_scope["vars"][var_name] 135 return self._local_scope["vars"][var_name]
136 raise gclient_utils.Error("Var is not defined: %s" % var_name) 136 raise gclient_utils.Error("Var is not defined: %s" % var_name)
137 137
138 138
139 class Dependency(GClientKeywords, gclient_utils.WorkItem): 139 class Dependency(GClientKeywords, gclient_utils.WorkItem):
140 """Object that represents a dependency checkout.""" 140 """Object that represents a dependency checkout."""
141 DEPS_FILE = 'DEPS'
142 141
143 def __init__(self, parent, name, url, safesync_url, custom_deps, 142 def __init__(self, parent, name, url, safesync_url, custom_deps,
144 custom_vars, deps_file, should_process): 143 custom_vars, deps_file, should_process):
145 GClientKeywords.__init__(self) 144 GClientKeywords.__init__(self)
146 gclient_utils.WorkItem.__init__(self) 145 gclient_utils.WorkItem.__init__(self)
147 self.parent = parent 146 self.parent = parent
148 self.name = name 147 self.name = name
149 self.url = url 148 self.url = url
150 self.parsed_url = None 149 self.parsed_url = None
151 # These 2 are only set in .gclient and not in DEPS files. 150 # These 2 are only set in .gclient and not in DEPS files.
152 self.safesync_url = safesync_url 151 self.safesync_url = safesync_url
153 self.custom_vars = custom_vars or {} 152 self.custom_vars = custom_vars or {}
154 self.custom_deps = custom_deps or {} 153 self.custom_deps = custom_deps or {}
155 self.deps_hooks = [] 154 self.deps_hooks = []
156 self.dependencies = [] 155 self.dependencies = []
157 self.deps_file = deps_file or self.DEPS_FILE 156 self.deps_file = deps_file
158 # A cache of the files affected by the current operation, necessary for 157 # A cache of the files affected by the current operation, necessary for
159 # hooks. 158 # hooks.
160 self._file_list = [] 159 self._file_list = []
161 # If it is not set to True, the dependency wasn't processed for its child 160 # If it is not set to True, the dependency wasn't processed for its child
162 # dependency, i.e. its DEPS wasn't read. 161 # dependency, i.e. its DEPS wasn't read.
163 self.deps_parsed = False 162 self.deps_parsed = False
164 # This dependency should be processed, i.e. checked out 163 # This dependency should be processed, i.e. checked out
165 self.should_process = should_process 164 self.should_process = should_process
166 # This dependency has been processed, i.e. checked out 165 # This dependency has been processed, i.e. checked out
167 self.processed = False 166 self.processed = False
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 local_scope = {} 258 local_scope = {}
260 var = self.VarImpl(self.custom_vars, local_scope) 259 var = self.VarImpl(self.custom_vars, local_scope)
261 global_scope = { 260 global_scope = {
262 'File': self.FileImpl, 261 'File': self.FileImpl,
263 'From': self.FromImpl, 262 'From': self.FromImpl,
264 'Var': var.Lookup, 263 'Var': var.Lookup,
265 'deps_os': {}, 264 'deps_os': {},
266 } 265 }
267 filepath = os.path.join(self.root_dir(), self.name, self.deps_file) 266 filepath = os.path.join(self.root_dir(), self.name, self.deps_file)
268 if not os.path.isfile(filepath): 267 if not os.path.isfile(filepath):
269 logging.info('%s: No DEPS file found at %s' % (self.name, filepath)) 268 logging.info('%s: No %s file found at %s' % (self.name, self.deps_file,
269 filepath))
270 else: 270 else:
271 deps_content = gclient_utils.FileRead(filepath) 271 deps_content = gclient_utils.FileRead(filepath)
272 logging.debug(deps_content) 272 logging.debug(deps_content)
273 # Eval the content. 273 # Eval the content.
274 try: 274 try:
275 exec(deps_content, global_scope, local_scope) 275 exec(deps_content, global_scope, local_scope)
276 except SyntaxError, e: 276 except SyntaxError, e:
277 gclient_utils.SyntaxErrorToError(filepath, e) 277 gclient_utils.SyntaxErrorToError(filepath, e)
278 deps = local_scope.get('deps', {}) 278 deps = local_scope.get('deps', {})
279 # load os specific dependencies if defined. these dependencies may 279 # load os specific dependencies if defined. these dependencies may
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 logging.info('Won\'t process duplicate dependency %s' % tree[name]) 324 logging.info('Won\'t process duplicate dependency %s' % tree[name])
325 # In theory we could keep it as a shadow of the other one. In 325 # In theory we could keep it as a shadow of the other one. In
326 # practice, simply ignore it. 326 # practice, simply ignore it.
327 #should_process = False 327 #should_process = False
328 continue 328 continue
329 else: 329 else:
330 raise gclient_utils.Error( 330 raise gclient_utils.Error(
331 'Dependency %s specified more than once:\n %s\nvs\n %s' % 331 'Dependency %s specified more than once:\n %s\nvs\n %s' %
332 (name, tree[name].hierarchy(), self.hierarchy())) 332 (name, tree[name].hierarchy(), self.hierarchy()))
333 self.dependencies.append(Dependency(self, name, url, None, None, None, 333 self.dependencies.append(Dependency(self, name, url, None, None, None,
334 None, should_process)) 334 self.deps_file, should_process))
335 logging.debug('Loaded: %s' % str(self)) 335 logging.debug('Loaded: %s' % str(self))
336 336
337 # Arguments number differs from overridden method 337 # Arguments number differs from overridden method
338 # pylint: disable=W0221 338 # pylint: disable=W0221
339 def run(self, revision_overrides, command, args, work_queue, options): 339 def run(self, revision_overrides, command, args, work_queue, options):
340 """Runs 'command' before parsing the DEPS in case it's a initial checkout 340 """Runs 'command' before parsing the DEPS in case it's a initial checkout
341 or a revert.""" 341 or a revert."""
342 342
343 def maybeGetParentRevision(options): 343 def maybeGetParentRevision(options):
344 """If we are performing an update and --transitive is set, set the 344 """If we are performing an update and --transitive is set, set the
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 "mac": "mac", 578 "mac": "mac",
579 "unix": "unix", 579 "unix": "unix",
580 "linux": "unix", 580 "linux": "unix",
581 "linux2": "unix", 581 "linux2": "unix",
582 } 582 }
583 583
584 DEFAULT_CLIENT_FILE_TEXT = ("""\ 584 DEFAULT_CLIENT_FILE_TEXT = ("""\
585 solutions = [ 585 solutions = [
586 { "name" : "%(solution_name)s", 586 { "name" : "%(solution_name)s",
587 "url" : "%(solution_url)s", 587 "url" : "%(solution_url)s",
588 "deps_file" : "%(deps_file)s",
588 "custom_deps" : { 589 "custom_deps" : {
589 }, 590 },
590 "safesync_url": "%(safesync_url)s", 591 "safesync_url": "%(safesync_url)s",
591 }, 592 },
592 ] 593 ]
593 """) 594 """)
594 595
595 DEFAULT_SNAPSHOT_SOLUTION_TEXT = ("""\ 596 DEFAULT_SNAPSHOT_SOLUTION_TEXT = ("""\
596 { "name" : "%(solution_name)s", 597 { "name" : "%(solution_name)s",
597 "url" : "%(solution_url)s", 598 "url" : "%(solution_url)s",
599 "deps_file" : "%(deps_file)s",
598 "custom_deps" : { 600 "custom_deps" : {
599 %(solution_deps)s }, 601 %(solution_deps)s },
600 "safesync_url": "%(safesync_url)s", 602 "safesync_url": "%(safesync_url)s",
601 }, 603 },
602 """) 604 """)
603 605
604 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\ 606 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\
605 # Snapshot generated with gclient revinfo --snapshot 607 # Snapshot generated with gclient revinfo --snapshot
606 solutions = [ 608 solutions = [
607 %(solution_list)s] 609 %(solution_list)s]
608 """) 610 """)
609 611
610 def __init__(self, root_dir, options): 612 def __init__(self, root_dir, options):
611 # Do not change previous behavior. Only solution level and immediate DEPS 613 # Do not change previous behavior. Only solution level and immediate DEPS
612 # are processed. 614 # are processed.
613 self._recursion_limit = 2 615 self._recursion_limit = 2
614 Dependency.__init__(self, None, None, None, None, None, None, None, True) 616 Dependency.__init__(self, None, None, None, None, None, None, 'unused',
617 True)
615 self._options = options 618 self._options = options
616 if options.deps_os: 619 if options.deps_os:
617 enforced_os = options.deps_os.split(',') 620 enforced_os = options.deps_os.split(',')
618 else: 621 else:
619 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] 622 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')]
620 if 'all' in enforced_os: 623 if 'all' in enforced_os:
621 enforced_os = self.DEPS_OS_CHOICES.itervalues() 624 enforced_os = self.DEPS_OS_CHOICES.itervalues()
622 self._enforced_os = list(set(enforced_os)) 625 self._enforced_os = list(set(enforced_os))
623 self._root_dir = root_dir 626 self._root_dir = root_dir
624 self.config_content = None 627 self.config_content = None
(...skipping 10 matching lines...) Expand all
635 try: 638 try:
636 tree = dict((d.name, d) for d in self.tree(False)) 639 tree = dict((d.name, d) for d in self.tree(False))
637 if s['name'] in tree: 640 if s['name'] in tree:
638 raise gclient_utils.Error( 641 raise gclient_utils.Error(
639 'Dependency %s specified more than once in .gclient' % s['name']) 642 'Dependency %s specified more than once in .gclient' % s['name'])
640 self.dependencies.append(Dependency( 643 self.dependencies.append(Dependency(
641 self, s['name'], s['url'], 644 self, s['name'], s['url'],
642 s.get('safesync_url', None), 645 s.get('safesync_url', None),
643 s.get('custom_deps', {}), 646 s.get('custom_deps', {}),
644 s.get('custom_vars', {}), 647 s.get('custom_vars', {}),
645 None, 648 s.get('deps_file', 'DEPS'),
M-A Ruel 2011/05/28 22:58:23 self.deps_file?
646 True)) 649 True))
647 except KeyError: 650 except KeyError:
648 raise gclient_utils.Error('Invalid .gclient file. Solution is ' 651 raise gclient_utils.Error('Invalid .gclient file. Solution is '
649 'incomplete: %s' % s) 652 'incomplete: %s' % s)
650 # .gclient can have hooks. 653 # .gclient can have hooks.
651 self.deps_hooks = config_dict.get('hooks', []) 654 self.deps_hooks = config_dict.get('hooks', [])
652 self.deps_parsed = True 655 self.deps_parsed = True
653 656
654 def SaveConfig(self): 657 def SaveConfig(self):
655 gclient_utils.FileWrite(os.path.join(self.root_dir(), 658 gclient_utils.FileWrite(os.path.join(self.root_dir(),
656 self._options.config_filename), 659 self._options.config_filename),
657 self.config_content) 660 self.config_content)
658 661
659 @staticmethod 662 @staticmethod
660 def LoadCurrentConfig(options): 663 def LoadCurrentConfig(options):
661 """Searches for and loads a .gclient file relative to the current working 664 """Searches for and loads a .gclient file relative to the current working
662 dir. Returns a GClient object.""" 665 dir. Returns a GClient object."""
663 path = gclient_utils.FindGclientRoot(os.getcwd(), options.config_filename) 666 path = gclient_utils.FindGclientRoot(os.getcwd(), options.config_filename)
664 if not path: 667 if not path:
665 return None 668 return None
666 client = GClient(path, options) 669 client = GClient(path, options)
667 client.SetConfig(gclient_utils.FileRead( 670 client.SetConfig(gclient_utils.FileRead(
668 os.path.join(path, options.config_filename))) 671 os.path.join(path, options.config_filename)))
669 return client 672 return client
670 673
671 def SetDefaultConfig(self, solution_name, solution_url, safesync_url): 674 def SetDefaultConfig(self, solution_name, deps_file, solution_url,
675 safesync_url):
672 self.SetConfig(self.DEFAULT_CLIENT_FILE_TEXT % { 676 self.SetConfig(self.DEFAULT_CLIENT_FILE_TEXT % {
673 'solution_name': solution_name, 677 'solution_name': solution_name,
674 'solution_url': solution_url, 678 'solution_url': solution_url,
679 'deps_file': deps_file,
675 'safesync_url' : safesync_url, 680 'safesync_url' : safesync_url,
676 }) 681 })
677 682
678 def _SaveEntries(self): 683 def _SaveEntries(self):
679 """Creates a .gclient_entries file to record the list of unique checkouts. 684 """Creates a .gclient_entries file to record the list of unique checkouts.
680 685
681 The .gclient_entries file lives in the same directory as .gclient. 686 The .gclient_entries file lives in the same directory as .gclient.
682 """ 687 """
683 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It 688 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It
684 # makes testing a bit too fun. 689 # makes testing a bit too fun.
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
839 custom_deps = [] 844 custom_deps = []
840 for k in sorted(entries.keys()): 845 for k in sorted(entries.keys()):
841 if entries[k]: 846 if entries[k]:
842 # Quotes aren't escaped... 847 # Quotes aren't escaped...
843 custom_deps.append(' \"%s\": \'%s\',\n' % (k, entries[k])) 848 custom_deps.append(' \"%s\": \'%s\',\n' % (k, entries[k]))
844 else: 849 else:
845 custom_deps.append(' \"%s\": None,\n' % k) 850 custom_deps.append(' \"%s\": None,\n' % k)
846 new_gclient += self.DEFAULT_SNAPSHOT_SOLUTION_TEXT % { 851 new_gclient += self.DEFAULT_SNAPSHOT_SOLUTION_TEXT % {
847 'solution_name': d.name, 852 'solution_name': d.name,
848 'solution_url': d.url, 853 'solution_url': d.url,
854 'deps_file': d.deps_file,
849 'safesync_url' : d.safesync_url or '', 855 'safesync_url' : d.safesync_url or '',
850 'solution_deps': ''.join(custom_deps), 856 'solution_deps': ''.join(custom_deps),
851 } 857 }
852 # Print the snapshot configuration file 858 # Print the snapshot configuration file
853 print(self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient}) 859 print(self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient})
854 else: 860 else:
855 entries = {} 861 entries = {}
856 for d in self.tree(False): 862 for d in self.tree(False):
857 if self._options.actual: 863 if self._options.actual:
858 entries[d.name] = GetURLAndRev(d) 864 entries[d.name] = GetURLAndRev(d)
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
957 modules to operate on as well. If optional [url] parameter is 963 modules to operate on as well. If optional [url] parameter is
958 provided, then configuration is read from a specified Subversion server 964 provided, then configuration is read from a specified Subversion server
959 URL. 965 URL.
960 """ 966 """
961 parser.add_option('--spec', 967 parser.add_option('--spec',
962 help='create a gclient file containing the provided ' 968 help='create a gclient file containing the provided '
963 'string. Due to Cygwin/Python brokenness, it ' 969 'string. Due to Cygwin/Python brokenness, it '
964 'probably can\'t contain any newlines.') 970 'probably can\'t contain any newlines.')
965 parser.add_option('--name', 971 parser.add_option('--name',
966 help='overrides the default name for the solution') 972 help='overrides the default name for the solution')
973 parser.add_option('--deps-file', default='DEPS',
974 help='overrides the default name for the DEPS file for the'
975 'main solutions and all sub-dependencies')
976 parser.add_option('--git-deps', action='store_true',
977 help='sets the deps file to ".DEPS.git" instead of "DEPS"')
967 (options, args) = parser.parse_args(args) 978 (options, args) = parser.parse_args(args)
968 if ((options.spec and args) or len(args) > 2 or 979 if ((options.spec and args) or len(args) > 2 or
969 (not options.spec and not args)): 980 (not options.spec and not args)):
970 parser.error('Inconsistent arguments. Use either --spec or one or 2 args') 981 parser.error('Inconsistent arguments. Use either --spec or one or 2 args')
971 982
972 if os.path.exists(options.config_filename): 983 if os.path.exists(options.config_filename):
973 raise gclient_utils.Error('%s file already exists in the current directory' 984 raise gclient_utils.Error('%s file already exists in the current directory'
974 % options.config_filename) 985 % options.config_filename)
975 client = GClient('.', options) 986 client = GClient('.', options)
976 if options.spec: 987 if options.spec:
977 client.SetConfig(options.spec) 988 client.SetConfig(options.spec)
978 else: 989 else:
979 base_url = args[0].rstrip('/') 990 base_url = args[0].rstrip('/')
980 if not options.name: 991 if not options.name:
981 name = base_url.split('/')[-1] 992 name = base_url.split('/')[-1]
982 else: 993 else:
983 # specify an alternate relpath for the given URL. 994 # specify an alternate relpath for the given URL.
984 name = options.name 995 name = options.name
996 deps_file = options.deps_file
997 if options.git_deps:
998 deps_file = '.DEPS.git'
985 safesync_url = '' 999 safesync_url = ''
986 if len(args) > 1: 1000 if len(args) > 1:
987 safesync_url = args[1] 1001 safesync_url = args[1]
988 client.SetDefaultConfig(name, base_url, safesync_url) 1002 client.SetDefaultConfig(name, deps_file, base_url, safesync_url)
989 client.SaveConfig() 1003 client.SaveConfig()
990 return 0 1004 return 0
991 1005
992 1006
993 @attr('epilog', """Example: 1007 @attr('epilog', """Example:
994 gclient pack > patch.txt 1008 gclient pack > patch.txt
995 generate simple patch for configured client and dependences 1009 generate simple patch for configured client and dependences
996 """) 1010 """)
997 def CMDpack(parser, args): 1011 def CMDpack(parser, args):
998 """Generate a patch which can be applied at the root of the tree. 1012 """Generate a patch which can be applied at the root of the tree.
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
1285 except (gclient_utils.Error, subprocess2.CalledProcessError), e: 1299 except (gclient_utils.Error, subprocess2.CalledProcessError), e:
1286 print >> sys.stderr, 'Error: %s' % str(e) 1300 print >> sys.stderr, 'Error: %s' % str(e)
1287 return 1 1301 return 1
1288 1302
1289 1303
1290 if '__main__' == __name__: 1304 if '__main__' == __name__:
1291 fix_encoding.fix_encoding() 1305 fix_encoding.fix_encoding()
1292 sys.exit(Main(sys.argv[1:])) 1306 sys.exit(Main(sys.argv[1:]))
1293 1307
1294 # vim: ts=2:sw=2:tw=80:et: 1308 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « no previous file | tests/fake_repos.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698