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

Side by Side Diff: gclient.py

Issue 2839008: Make the DEPS parsing saner. (Closed)
Patch Set: Take 3. fixes issue with double-parsed DEPS Created 10 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
« 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/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 """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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 self.parent = parent 159 self.parent = parent
160 self.name = name 160 self.name = name
161 self.url = url 161 self.url = url
162 # These 2 are only set in .gclient and not in DEPS files. 162 # These 2 are only set in .gclient and not in DEPS files.
163 self.safesync_url = safesync_url 163 self.safesync_url = safesync_url
164 self.custom_vars = custom_vars or {} 164 self.custom_vars = custom_vars or {}
165 self.custom_deps = custom_deps or {} 165 self.custom_deps = custom_deps or {}
166 self.deps_hooks = [] 166 self.deps_hooks = []
167 self.dependencies = [] 167 self.dependencies = []
168 self.deps_file = deps_file or self.DEPS_FILE 168 self.deps_file = deps_file or self.DEPS_FILE
169 self.deps_parsed = False
170 self.direct_reference = False
169 171
170 # Sanity checks 172 # Sanity checks
171 if not self.name and self.parent: 173 if not self.name and self.parent:
172 raise gclient_utils.Error('Dependency without name') 174 raise gclient_utils.Error('Dependency without name')
173 if not isinstance(self.url, 175 if not isinstance(self.url,
174 (basestring, self.FromImpl, self.FileImpl, None.__class__)): 176 (basestring, self.FromImpl, self.FileImpl, None.__class__)):
175 raise gclient_utils.Error('dependency url must be either a string, None, ' 177 raise gclient_utils.Error('dependency url must be either a string, None, '
176 'File() or From() instead of %s' % 178 'File() or From() instead of %s' %
177 self.url.__class__.__name__) 179 self.url.__class__.__name__)
178 if '/' in self.deps_file or '\\' in self.deps_file: 180 if '/' in self.deps_file or '\\' in self.deps_file:
179 raise gclient_utils.Error('deps_file name must not be a path, just a ' 181 raise gclient_utils.Error('deps_file name must not be a path, just a '
180 'filename. %s' % self.deps_file) 182 'filename. %s' % self.deps_file)
181 183
182 def _ParseSolutionDeps(self, solution_name, solution_deps_content, 184 def ParseDepsFile(self, direct_reference):
183 custom_vars, parse_hooks): 185 """Parses the DEPS file for this dependency."""
184 """Parses the DEPS file for the specified solution. 186 if direct_reference:
187 # Maybe it was referenced earlier by a From() keyword but it's now
188 # directly referenced.
189 self.direct_reference = direct_reference
190 self.deps_parsed = True
191 filepath = os.path.join(self.root_dir(), self.name, self.deps_file)
192 if not os.path.isfile(filepath):
193 return {}
194 deps_content = gclient_utils.FileRead(filepath)
185 195
186 Args: 196 # Eval the content.
187 solution_name: The name of the solution to query. 197 # One thing is unintuitive, vars= {} must happen before Var() use.
188 solution_deps_content: Content of the DEPS file for the solution
189 custom_vars: A dict of vars to override any vars defined in the DEPS file.
190
191 Returns:
192 A dict mapping module names (as relative paths) to URLs or an empty
193 dict if the solution does not have a DEPS file.
194 """
195 # Skip empty
196 if not solution_deps_content:
197 return {}
198 # Eval the content
199 local_scope = {} 198 local_scope = {}
200 var = self.VarImpl(custom_vars, local_scope) 199 var = self.VarImpl(self.custom_vars, local_scope)
201 global_scope = { 200 global_scope = {
202 "File": self.FileImpl, 201 'File': self.FileImpl,
203 "From": self.FromImpl, 202 'From': self.FromImpl,
204 "Var": var.Lookup, 203 'Var': var.Lookup,
205 "deps_os": {}, 204 'deps_os': {},
206 } 205 }
207 exec(solution_deps_content, global_scope, local_scope) 206 exec(deps_content, global_scope, local_scope)
208 deps = local_scope.get("deps", {}) 207 deps = local_scope.get('deps', {})
209
210 # load os specific dependencies if defined. these dependencies may 208 # load os specific dependencies if defined. these dependencies may
211 # override or extend the values defined by the 'deps' member. 209 # override or extend the values defined by the 'deps' member.
212 if "deps_os" in local_scope: 210 if 'deps_os' in local_scope:
213 if self._options.deps_os is not None: 211 for deps_os_key in self.enforced_os():
214 deps_to_include = self._options.deps_os.split(",") 212 os_deps = local_scope['deps_os'].get(deps_os_key, {})
215 if "all" in deps_to_include: 213 if len(self.enforced_os()) > 1:
216 deps_to_include = list(set(self.DEPS_OS_CHOICES.itervalues())) 214 # Ignore any conflict when including deps for more than one
217 else:
218 deps_to_include = [self.DEPS_OS_CHOICES.get(sys.platform, "unix")]
219
220 deps_to_include = set(deps_to_include)
221 for deps_os_key in deps_to_include:
222 os_deps = local_scope["deps_os"].get(deps_os_key, {})
223 if len(deps_to_include) > 1:
224 # Ignore any overrides when including deps for more than one
225 # platform, so we collect the broadest set of dependencies available. 215 # platform, so we collect the broadest set of dependencies available.
226 # We may end up with the wrong revision of something for our 216 # We may end up with the wrong revision of something for our
227 # platform, but this is the best we can do. 217 # platform, but this is the best we can do.
228 deps.update([x for x in os_deps.items() if not x[0] in deps]) 218 deps.update([x for x in os_deps.items() if not x[0] in deps])
229 else: 219 else:
230 deps.update(os_deps) 220 deps.update(os_deps)
231 221
232 if 'hooks' in local_scope and parse_hooks: 222 self.deps_hooks.extend(local_scope.get('hooks', []))
233 # TODO(maruel): Temporary Hack. Since this function is misplaced, find the 223
234 # right 'self' to add the hooks. 224 # If a line is in custom_deps, but not in the solution, we want to append
235 for d in self.dependencies: 225 # this line to the solution.
236 if d.name == solution_name: 226 for d in self.custom_deps:
237 d.deps_hooks.extend(local_scope['hooks']) 227 if d not in deps:
238 break 228 deps[d] = self.custom_deps[d]
239 229
240 # If use_relative_paths is set in the DEPS file, regenerate 230 # If use_relative_paths is set in the DEPS file, regenerate
241 # the dictionary using paths relative to the directory containing 231 # the dictionary using paths relative to the directory containing
242 # the DEPS file. 232 # the DEPS file.
243 if local_scope.get('use_relative_paths'): 233 use_relative_paths = local_scope.get('use_relative_paths', False)
234 if use_relative_paths:
244 rel_deps = {} 235 rel_deps = {}
245 for d, url in deps.items(): 236 for d, url in deps.items():
246 # normpath is required to allow DEPS to use .. in their 237 # normpath is required to allow DEPS to use .. in their
247 # dependency local path. 238 # dependency local path.
248 rel_deps[os.path.normpath(os.path.join(solution_name, d))] = url 239 rel_deps[os.path.normpath(os.path.join(self.name, d))] = url
249 return rel_deps 240 deps = rel_deps
250 else: 241 # TODO(maruel): Add these dependencies into self.dependencies.
251 return deps 242 return deps
252 243
253 def _ParseAllDeps(self, solution_urls, solution_deps_content): 244 def _ParseAllDeps(self, solution_urls):
254 """Parse the complete list of dependencies for the client. 245 """Parse the complete list of dependencies for the client.
255 246
256 Args: 247 Args:
257 solution_urls: A dict mapping module names (as relative paths) to URLs 248 solution_urls: A dict mapping module names (as relative paths) to URLs
258 corresponding to the solutions specified by the client. This parameter 249 corresponding to the solutions specified by the client. This parameter
259 is passed as an optimization. 250 is passed as an optimization.
260 solution_deps_content: A dict mapping module names to the content
261 of their DEPS files
262 251
263 Returns: 252 Returns:
264 A dict mapping module names (as relative paths) to URLs corresponding 253 A dict mapping module names (as relative paths) to URLs corresponding
265 to the entire set of dependencies to checkout for the given client. 254 to the entire set of dependencies to checkout for the given client.
266 255
267 Raises: 256 Raises:
268 Error: If a dependency conflicts with another dependency or of a solution. 257 Error: If a dependency conflicts with another dependency or of a solution.
269 """ 258 """
270 deps = {} 259 deps = {}
271 for solution in self.dependencies: 260 for solution in self.dependencies:
272 solution_deps = self._ParseSolutionDeps( 261 solution_deps = solution.ParseDepsFile(True)
273 solution.name,
274 solution_deps_content[solution.name],
275 solution.custom_vars,
276 True)
277 262
278 # If a line is in custom_deps, but not in the solution, we want to append 263 # If a line is in custom_deps, but not in the solution, we want to append
279 # this line to the solution. 264 # this line to the solution.
280 for d in solution.custom_deps: 265 for d in solution.custom_deps:
281 if d not in solution_deps: 266 if d not in solution_deps:
282 solution_deps[d] = solution.custom_deps[d] 267 solution_deps[d] = solution.custom_deps[d]
283 268
284 for d in solution_deps: 269 for d in solution_deps:
285 if d in solution.custom_deps: 270 if d in solution.custom_deps:
286 # Dependency is overriden. 271 # Dependency is overriden.
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 return 357 return
373 358
374 # Run hooks on the basis of whether the files from the gclient operation 359 # Run hooks on the basis of whether the files from the gclient operation
375 # match each hook's pattern. 360 # match each hook's pattern.
376 for hook_dict in hooks: 361 for hook_dict in hooks:
377 pattern = re.compile(hook_dict['pattern']) 362 pattern = re.compile(hook_dict['pattern'])
378 matching_file_list = [f for f in file_list if pattern.search(f)] 363 matching_file_list = [f for f in file_list if pattern.search(f)]
379 if matching_file_list: 364 if matching_file_list:
380 self._RunHookAction(hook_dict, matching_file_list) 365 self._RunHookAction(hook_dict, matching_file_list)
381 366
367 def root_dir(self):
368 return self.parent.root_dir()
369
370 def enforced_os(self):
371 return self.parent.enforced_os()
372
382 373
383 class GClient(Dependency): 374 class GClient(Dependency):
384 """Main gclient checkout root where .gclient resides.""" 375 """Main gclient checkout root where .gclient resides."""
385 SUPPORTED_COMMANDS = [ 376 SUPPORTED_COMMANDS = [
386 'cleanup', 'diff', 'export', 'pack', 'revert', 'status', 'update', 377 'cleanup', 'diff', 'export', 'pack', 'revert', 'status', 'update',
387 'runhooks' 378 'runhooks'
388 ] 379 ]
389 380
390 DEPS_OS_CHOICES = { 381 DEPS_OS_CHOICES = {
391 "win32": "win", 382 "win32": "win",
(...skipping 29 matching lines...) Expand all
421 412
422 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\ 413 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\
423 # Snapshot generated with gclient revinfo --snapshot 414 # Snapshot generated with gclient revinfo --snapshot
424 solutions = [ 415 solutions = [
425 %(solution_list)s 416 %(solution_list)s
426 ] 417 ]
427 """) 418 """)
428 419
429 def __init__(self, root_dir, options): 420 def __init__(self, root_dir, options):
430 Dependency.__init__(self, None, None, None) 421 Dependency.__init__(self, None, None, None)
422 self._options = options
423 if options.deps_os:
424 enforced_os = options.deps_os.split(',')
425 else:
426 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')]
427 if 'all' in enforced_os:
428 enforced_os = self.DEPS_OS_CHOICES.itervalues()
429 self._enforced_os = list(set(enforced_os))
431 self._root_dir = root_dir 430 self._root_dir = root_dir
432 self._options = options
433 self.config_content = None 431 self.config_content = None
434 432
435 def SetConfig(self, content): 433 def SetConfig(self, content):
436 assert self.dependencies == [] 434 assert self.dependencies == []
437 config_dict = {} 435 config_dict = {}
438 self.config_content = content 436 self.config_content = content
439 try: 437 try:
440 exec(content, config_dict) 438 exec(content, config_dict)
441 except SyntaxError, e: 439 except SyntaxError, e:
442 try: 440 try:
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
560 if not self.dependencies: 558 if not self.dependencies:
561 raise gclient_utils.Error("No solution specified") 559 raise gclient_utils.Error("No solution specified")
562 revision_overrides = self._EnforceRevisions() 560 revision_overrides = self._EnforceRevisions()
563 561
564 # When running runhooks --force, there's no need to consult the SCM. 562 # When running runhooks --force, there's no need to consult the SCM.
565 # All known hooks are expected to run unconditionally regardless of working 563 # All known hooks are expected to run unconditionally regardless of working
566 # copy state, so skip the SCM status check. 564 # copy state, so skip the SCM status check.
567 run_scm = not (command == 'runhooks' and self._options.force) 565 run_scm = not (command == 'runhooks' and self._options.force)
568 566
569 entries = {} 567 entries = {}
570 entries_deps_content = {}
571 file_list = [] 568 file_list = []
572 # Run on the base solutions first. 569 # Run on the base solutions first.
573 for solution in self.dependencies: 570 for solution in self.dependencies:
574 name = solution.name 571 name = solution.name
575 if name in entries: 572 if name in entries:
576 raise gclient_utils.Error("solution %s specified more than once" % name) 573 raise gclient_utils.Error("solution %s specified more than once" % name)
577 url = solution.url 574 url = solution.url
578 entries[name] = url 575 entries[name] = url
579 if run_scm and url: 576 if run_scm and url:
580 self._options.revision = revision_overrides.get(name) 577 self._options.revision = revision_overrides.get(name)
581 scm = gclient_scm.CreateSCM(url, self.root_dir(), name) 578 scm = gclient_scm.CreateSCM(url, self.root_dir(), name)
582 scm.RunCommand(command, self._options, args, file_list) 579 scm.RunCommand(command, self._options, args, file_list)
583 file_list = [os.path.join(name, f.strip()) for f in file_list] 580 file_list = [os.path.join(name, f.strip()) for f in file_list]
584 self._options.revision = None 581 self._options.revision = None
585 try:
586 deps_content = gclient_utils.FileRead(
587 os.path.join(self.root_dir(), name, solution.deps_file))
588 except IOError, e:
589 if e.errno != errno.ENOENT:
590 raise
591 deps_content = ""
592 entries_deps_content[name] = deps_content
593 582
594 # Process the dependencies next (sort alphanumerically to ensure that 583 # Process the dependencies next (sort alphanumerically to ensure that
595 # containing directories get populated first and for readability) 584 # containing directories get populated first and for readability)
596 deps = self._ParseAllDeps(entries, entries_deps_content) 585 deps = self._ParseAllDeps(entries)
597 deps_to_process = deps.keys() 586 deps_to_process = deps.keys()
598 deps_to_process.sort() 587 deps_to_process.sort()
599 588
600 # First pass for direct dependencies. 589 # First pass for direct dependencies.
601 if command == 'update' and not self._options.verbose: 590 if command == 'update' and not self._options.verbose:
602 pm = Progress('Syncing projects', len(deps_to_process)) 591 pm = Progress('Syncing projects', len(deps_to_process))
603 for d in deps_to_process: 592 for d in deps_to_process:
604 if command == 'update' and not self._options.verbose: 593 if command == 'update' and not self._options.verbose:
605 pm.update() 594 pm.update()
606 if type(deps[d]) == str: 595 if type(deps[d]) == str:
(...skipping 11 matching lines...) Expand all
618 scm = gclient_scm.CreateSCM(file_dep.GetPath(), self.root_dir(), d) 607 scm = gclient_scm.CreateSCM(file_dep.GetPath(), self.root_dir(), d)
619 scm.RunCommand("updatesingle", self._options, 608 scm.RunCommand("updatesingle", self._options,
620 args + [file_dep.GetFilename()], file_list) 609 args + [file_dep.GetFilename()], file_list)
621 610
622 if command == 'update' and not self._options.verbose: 611 if command == 'update' and not self._options.verbose:
623 pm.end() 612 pm.end()
624 613
625 # Second pass for inherited deps (via the From keyword) 614 # Second pass for inherited deps (via the From keyword)
626 for d in deps_to_process: 615 for d in deps_to_process:
627 if isinstance(deps[d], self.FromImpl): 616 if isinstance(deps[d], self.FromImpl):
628 filename = os.path.join(self.root_dir(),
629 deps[d].module_name,
630 self.DEPS_FILE)
631 content = gclient_utils.FileRead(filename)
632 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {},
633 False)
634 # Getting the URL from the sub_deps file can involve having to resolve 617 # Getting the URL from the sub_deps file can involve having to resolve
635 # a File() or having to resolve a relative URL. To resolve relative 618 # a File() or having to resolve a relative URL. To resolve relative
636 # URLs, we need to pass in the orignal sub deps URL. 619 # URLs, we need to pass in the orignal sub deps URL.
637 sub_deps_base_url = deps[deps[d].module_name] 620 sub_deps_base_url = deps[deps[d].module_name]
621 sub_deps = Dependency(self, deps[d].module_name, sub_deps_base_url
622 ).ParseDepsFile(False)
638 url = deps[d].GetUrl(d, sub_deps_base_url, self.root_dir(), sub_deps) 623 url = deps[d].GetUrl(d, sub_deps_base_url, self.root_dir(), sub_deps)
639 entries[d] = url 624 entries[d] = url
640 if run_scm: 625 if run_scm:
641 self._options.revision = revision_overrides.get(d) 626 self._options.revision = revision_overrides.get(d)
642 scm = gclient_scm.CreateSCM(url, self.root_dir(), d) 627 scm = gclient_scm.CreateSCM(url, self.root_dir(), d)
643 scm.RunCommand(command, self._options, args, file_list) 628 scm.RunCommand(command, self._options, args, file_list)
644 self._options.revision = None 629 self._options.revision = None
645 630
646 # Convert all absolute paths to relative. 631 # Convert all absolute paths to relative.
647 for i in range(len(file_list)): 632 for i in range(len(file_list)):
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 def GetURLAndRev(name, original_url): 700 def GetURLAndRev(name, original_url):
716 url, _ = gclient_utils.SplitUrlRevision(original_url) 701 url, _ = gclient_utils.SplitUrlRevision(original_url)
717 scm = gclient_scm.CreateSCM(original_url, self.root_dir(), name) 702 scm = gclient_scm.CreateSCM(original_url, self.root_dir(), name)
718 return (url, scm.revinfo(self._options, [], None)) 703 return (url, scm.revinfo(self._options, [], None))
719 704
720 # text of the snapshot gclient file 705 # text of the snapshot gclient file
721 new_gclient = "" 706 new_gclient = ""
722 # Dictionary of { path : SCM url } to ensure no duplicate solutions 707 # Dictionary of { path : SCM url } to ensure no duplicate solutions
723 solution_names = {} 708 solution_names = {}
724 entries = {} 709 entries = {}
725 entries_deps_content = {}
726 # Run on the base solutions first. 710 # Run on the base solutions first.
727 for solution in self.dependencies: 711 for solution in self.dependencies:
728 # Dictionary of { path : SCM url } to describe the gclient checkout 712 # Dictionary of { path : SCM url } to describe the gclient checkout
729 name = solution.name 713 name = solution.name
730 if name in solution_names: 714 if name in solution_names:
731 raise gclient_utils.Error("solution %s specified more than once" % name) 715 raise gclient_utils.Error("solution %s specified more than once" % name)
732 (url, rev) = GetURLAndRev(name, solution.url) 716 (url, rev) = GetURLAndRev(name, solution.url)
733 entries[name] = "%s@%s" % (url, rev) 717 entries[name] = "%s@%s" % (url, rev)
734 solution_names[name] = "%s@%s" % (url, rev) 718 solution_names[name] = "%s@%s" % (url, rev)
735 deps_file = solution.deps_file
736 if '/' in deps_file or '\\' in deps_file:
737 raise gclient_utils.Error('deps_file name must not be a path, just a '
738 'filename.')
739 try:
740 deps_content = gclient_utils.FileRead(
741 os.path.join(self.root_dir(), name, deps_file))
742 except IOError, e:
743 if e.errno != errno.ENOENT:
744 raise
745 deps_content = ""
746 entries_deps_content[name] = deps_content
747 719
748 # Process the dependencies next (sort alphanumerically to ensure that 720 # Process the dependencies next (sort alphanumerically to ensure that
749 # containing directories get populated first and for readability) 721 # containing directories get populated first and for readability)
750 deps = self._ParseAllDeps(entries, entries_deps_content) 722 deps = self._ParseAllDeps(entries)
751 deps_to_process = deps.keys() 723 deps_to_process = deps.keys()
752 deps_to_process.sort() 724 deps_to_process.sort()
753 725
754 # First pass for direct dependencies. 726 # First pass for direct dependencies.
755 for d in deps_to_process: 727 for d in deps_to_process:
756 if type(deps[d]) == str: 728 if type(deps[d]) == str:
757 (url, rev) = GetURLAndRev(d, deps[d]) 729 (url, rev) = GetURLAndRev(d, deps[d])
758 entries[d] = "%s@%s" % (url, rev) 730 entries[d] = "%s@%s" % (url, rev)
759 731
760 # Second pass for inherited deps (via the From keyword) 732 # Second pass for inherited deps (via the From keyword)
761 for d in deps_to_process: 733 for d in deps_to_process:
762 if isinstance(deps[d], self.FromImpl): 734 if isinstance(deps[d], self.FromImpl):
763 deps_parent_url = entries[deps[d].module_name] 735 deps_parent_url = entries[deps[d].module_name]
764 if deps_parent_url.find("@") < 0: 736 if deps_parent_url.find("@") < 0:
765 raise gclient_utils.Error("From %s missing revisioned url" % 737 raise gclient_utils.Error("From %s missing revisioned url" %
766 deps[d].module_name) 738 deps[d].module_name)
767 content = gclient_utils.FileRead(os.path.join( 739 sub_deps_base_url = deps[deps[d].module_name]
768 self.root_dir(), 740 sub_deps = Dependency(self, deps[d].module_name, sub_deps_base_url
769 deps[d].module_name, 741 ).ParseDepsFile(False)
770 self.DEPS_FILE)) 742 url = deps[d].GetUrl(d, sub_deps_base_url, self.root_dir(), sub_deps)
771 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}, 743 (url, rev) = GetURLAndRev(d, url)
772 False)
773 (url, rev) = GetURLAndRev(d, sub_deps[d])
774 entries[d] = "%s@%s" % (url, rev) 744 entries[d] = "%s@%s" % (url, rev)
775 745
776 # Build the snapshot configuration string 746 # Build the snapshot configuration string
777 if self._options.snapshot: 747 if self._options.snapshot:
778 url = entries.pop(name) 748 url = entries.pop(name)
779 custom_deps = ",\n ".join(["\"%s\": \"%s\"" % (x, entries[x]) 749 custom_deps = ",\n ".join(["\"%s\": \"%s\"" % (x, entries[x])
780 for x in sorted(entries.keys())]) 750 for x in sorted(entries.keys())])
781 751
782 new_gclient += self.DEFAULT_SNAPSHOT_SOLUTION_TEXT % { 752 new_gclient += self.DEFAULT_SNAPSHOT_SOLUTION_TEXT % {
783 'solution_name': name, 753 'solution_name': name,
784 'solution_url': url, 754 'solution_url': url,
785 'safesync_url' : "", 755 'safesync_url' : "",
786 'solution_deps': custom_deps, 756 'solution_deps': custom_deps,
787 } 757 }
788 else: 758 else:
789 print(";\n".join(["%s: %s" % (x, entries[x]) 759 print(";\n".join(["%s: %s" % (x, entries[x])
790 for x in sorted(entries.keys())])) 760 for x in sorted(entries.keys())]))
791 761
792 # Print the snapshot configuration file 762 # Print the snapshot configuration file
793 if self._options.snapshot: 763 if self._options.snapshot:
794 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient} 764 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient}
795 snapclient = GClient(self.root_dir(), self._options) 765 snapclient = GClient(self.root_dir(), self._options)
796 snapclient.SetConfig(config) 766 snapclient.SetConfig(config)
797 print(snapclient.config_content) 767 print(snapclient.config_content)
798 768
799 def root_dir(self): 769 def root_dir(self):
800 return self._root_dir 770 return self._root_dir
801 771
772 def enforced_os(self):
773 return self._enforced_os
774
802 775
803 #### gclient commands. 776 #### gclient commands.
804 777
805 778
806 def CMDcleanup(parser, args): 779 def CMDcleanup(parser, args):
807 """Cleans up all working copies. 780 """Cleans up all working copies.
808 781
809 Mostly svn-specific. Simply runs 'svn cleanup' for each module. 782 Mostly svn-specific. Simply runs 'svn cleanup' for each module.
810 """ 783 """
811 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', 784 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
1145 return CMDhelp(parser, argv) 1118 return CMDhelp(parser, argv)
1146 except gclient_utils.Error, e: 1119 except gclient_utils.Error, e:
1147 print >> sys.stderr, 'Error: %s' % str(e) 1120 print >> sys.stderr, 'Error: %s' % str(e)
1148 return 1 1121 return 1
1149 1122
1150 1123
1151 if '__main__' == __name__: 1124 if '__main__' == __name__:
1152 sys.exit(Main(sys.argv[1:])) 1125 sys.exit(Main(sys.argv[1:]))
1153 1126
1154 # vim: ts=2:sw=2:tw=80:et: 1127 # 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