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

Side by Side Diff: gclient.py

Issue 3155008: Remove semicolons from revinfo. (Closed)
Patch Set: Created 10 years, 4 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/gclient_smoketest.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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 it will be removed from the list and the list will be extended 42 it will be removed from the list and the list will be extended
43 by the list of matching files. 43 by the list of matching files.
44 44
45 Example: 45 Example:
46 hooks = [ 46 hooks = [
47 { "pattern": "\\.(gif|jpe?g|pr0n|png)$", 47 { "pattern": "\\.(gif|jpe?g|pr0n|png)$",
48 "action": ["python", "image_indexer.py", "--all"]}, 48 "action": ["python", "image_indexer.py", "--all"]},
49 ] 49 ]
50 """ 50 """
51 51
52 __version__ = "0.5.1" 52 __version__ = "0.5.2"
53 53
54 import logging 54 import logging
55 import optparse 55 import optparse
56 import os 56 import os
57 import posixpath 57 import posixpath
58 import pprint 58 import pprint
59 import re 59 import re
60 import subprocess 60 import subprocess
61 import sys 61 import sys
62 import threading 62 import threading
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 elif var_name in self._local_scope.get("vars", {}): 237 elif var_name in self._local_scope.get("vars", {}):
238 return self._local_scope["vars"][var_name] 238 return self._local_scope["vars"][var_name]
239 raise gclient_utils.Error("Var is not defined: %s" % var_name) 239 raise gclient_utils.Error("Var is not defined: %s" % var_name)
240 240
241 241
242 class Dependency(GClientKeywords, WorkItem): 242 class Dependency(GClientKeywords, WorkItem):
243 """Object that represents a dependency checkout.""" 243 """Object that represents a dependency checkout."""
244 DEPS_FILE = 'DEPS' 244 DEPS_FILE = 'DEPS'
245 245
246 def __init__(self, parent, name, url, safesync_url, custom_deps, 246 def __init__(self, parent, name, url, safesync_url, custom_deps,
247 custom_vars, deps_file): 247 custom_vars, deps_file, should_process):
248 GClientKeywords.__init__(self) 248 GClientKeywords.__init__(self)
249 self.parent = parent 249 self.parent = parent
250 self.name = name 250 self.name = name
251 self.url = url 251 self.url = url
252 self.parsed_url = None 252 self.parsed_url = None
253 # These 2 are only set in .gclient and not in DEPS files. 253 # These 2 are only set in .gclient and not in DEPS files.
254 self.safesync_url = safesync_url 254 self.safesync_url = safesync_url
255 self.custom_vars = custom_vars or {} 255 self.custom_vars = custom_vars or {}
256 self.custom_deps = custom_deps or {} 256 self.custom_deps = custom_deps or {}
257 self.deps_hooks = [] 257 self.deps_hooks = []
258 self.dependencies = [] 258 self.dependencies = []
259 self.deps_file = deps_file or self.DEPS_FILE 259 self.deps_file = deps_file or self.DEPS_FILE
260 # A cache of the files affected by the current operation, necessary for 260 # A cache of the files affected by the current operation, necessary for
261 # hooks. 261 # hooks.
262 self._file_list = [] 262 self._file_list = []
263 # If it is not set to True, the dependency wasn't processed for its child 263 # If it is not set to True, the dependency wasn't processed for its child
264 # dependency, i.e. its DEPS wasn't read. 264 # dependency, i.e. its DEPS wasn't read.
265 self.deps_parsed = False 265 self.deps_parsed = False
266 # A direct reference is dependency that is referenced by a deps, deps_os or 266 # This dependency should be processed, i.e. checked out
267 # solution. A indirect one is one that was loaded with From() or that 267 self.should_process = should_process
268 # exceeded recursion limit.
269 self.direct_reference = False
270 # This dependency has been processed, i.e. checked out 268 # This dependency has been processed, i.e. checked out
271 self.processed = False 269 self.processed = False
272 # This dependency had its hook run 270 # This dependency had its hook run
273 self.hooks_ran = False 271 self.hooks_ran = False
274 # Required dependencies to run before running this one: 272 # Required dependencies to run before running this one:
275 self.requirements = [] 273 self.requirements = []
276 if self.parent and self.parent.name: 274 if self.parent and self.parent.name:
277 self.requirements.append(self.parent.name) 275 self.requirements.append(self.parent.name)
278 if isinstance(self.url, self.FromImpl): 276 if isinstance(self.url, self.FromImpl):
279 self.requirements.append(self.url.module_name) 277 self.requirements.append(self.url.module_name)
280 278
281 # Sanity checks 279 # Sanity checks
282 if not self.name and self.parent: 280 if not self.name and self.parent:
283 raise gclient_utils.Error('Dependency without name') 281 raise gclient_utils.Error('Dependency without name')
284 if not isinstance(self.url, 282 if not isinstance(self.url,
285 (basestring, self.FromImpl, self.FileImpl, None.__class__)): 283 (basestring, self.FromImpl, self.FileImpl, None.__class__)):
286 raise gclient_utils.Error('dependency url must be either a string, None, ' 284 raise gclient_utils.Error('dependency url must be either a string, None, '
287 'File() or From() instead of %s' % 285 'File() or From() instead of %s' %
288 self.url.__class__.__name__) 286 self.url.__class__.__name__)
289 if '/' in self.deps_file or '\\' in self.deps_file: 287 if '/' in self.deps_file or '\\' in self.deps_file:
290 raise gclient_utils.Error('deps_file name must not be a path, just a ' 288 raise gclient_utils.Error('deps_file name must not be a path, just a '
291 'filename. %s' % self.deps_file) 289 'filename. %s' % self.deps_file)
292 290
293 def LateOverride(self, url): 291 def LateOverride(self, url):
294 """Resolves the parsed url from url. 292 """Resolves the parsed url from url.
295 293
296 Manages From() keyword accordingly. Do not touch self.parsed_url nor 294 Manages From() keyword accordingly. Do not touch self.parsed_url nor
297 self.url because it may called with other urls due to From().""" 295 self.url because it may called with other urls due to From()."""
296 assert self.parsed_url == None or not self.should_process, self.parsed_url
298 overriden_url = self.get_custom_deps(self.name, url) 297 overriden_url = self.get_custom_deps(self.name, url)
299 if overriden_url != url: 298 if overriden_url != url:
300 logging.info('%s, %s was overriden to %s' % (self.name, url, 299 logging.info('%s, %s was overriden to %s' % (self.name, url,
301 overriden_url)) 300 overriden_url))
302 return overriden_url 301 return overriden_url
303 elif isinstance(url, self.FromImpl): 302 elif isinstance(url, self.FromImpl):
304 ref = [dep for dep in self.tree(True) if url.module_name == dep.name] 303 ref = [dep for dep in self.tree(True) if url.module_name == dep.name]
305 if not ref: 304 if not ref:
306 raise gclient_utils.Error('Failed to find one reference to %s. %s' % ( 305 raise gclient_utils.Error('Failed to find one reference to %s. %s' % (
307 url.module_name, ref)) 306 url.module_name, ref))
308 # It may happen that len(ref) > 1 but it's no big deal. 307 # It may happen that len(ref) > 1 but it's no big deal.
309 ref = ref[0] 308 ref = ref[0]
310 sub_target = url.sub_target_name or self.name 309 sub_target = url.sub_target_name or self.name
311 # Make sure the referenced dependency DEPS file is loaded and file the 310 # Make sure the referenced dependency DEPS file is loaded and file the
312 # inner referenced dependency. 311 # inner referenced dependency.
313 ref.ParseDepsFile(False) 312 ref.ParseDepsFile()
314 found_dep = None 313 found_dep = None
315 for d in ref.dependencies: 314 for d in ref.dependencies:
316 if d.name == sub_target: 315 if d.name == sub_target:
317 found_dep = d 316 found_dep = d
318 break 317 break
319 if not found_dep: 318 if not found_dep:
320 raise gclient_utils.Error( 319 raise gclient_utils.Error(
321 'Couldn\'t find %s in %s, referenced by %s\n%s' % ( 320 'Couldn\'t find %s in %s, referenced by %s\n%s' % (
322 sub_target, ref.name, self.name, str(self.root_parent()))) 321 sub_target, ref.name, self.name, str(self.root_parent())))
323 # Call LateOverride() again. 322 # Call LateOverride() again.
(...skipping 20 matching lines...) Expand all
344 return parsed_url 343 return parsed_url
345 elif isinstance(url, self.FileImpl): 344 elif isinstance(url, self.FileImpl):
346 parsed_url = url 345 parsed_url = url
347 logging.info('%s, %s -> %s (File)' % (self.name, url, parsed_url)) 346 logging.info('%s, %s -> %s (File)' % (self.name, url, parsed_url))
348 return parsed_url 347 return parsed_url
349 elif url is None: 348 elif url is None:
350 return None 349 return None
351 else: 350 else:
352 raise gclient_utils.Error('Unkown url type') 351 raise gclient_utils.Error('Unkown url type')
353 352
354 def ParseDepsFile(self, direct_reference): 353 def ParseDepsFile(self):
355 """Parses the DEPS file for this dependency.""" 354 """Parses the DEPS file for this dependency."""
356 if direct_reference: 355 assert self.processed == True
357 # Maybe it was referenced earlier by a From() keyword but it's now
358 # directly referenced.
359 self.direct_reference = direct_reference
360 if self.deps_parsed: 356 if self.deps_parsed:
361 logging.debug('%s was already parsed' % self.name) 357 logging.debug('%s was already parsed' % self.name)
362 return 358 return
363 self.deps_parsed = True 359 self.deps_parsed = True
364 filepath = os.path.join(self.root_dir(), self.name, self.deps_file) 360 filepath = os.path.join(self.root_dir(), self.name, self.deps_file)
365 if not os.path.isfile(filepath): 361 if not os.path.isfile(filepath):
366 logging.info('%s: No DEPS file found at %s' % (self.name, filepath)) 362 logging.info('%s: No DEPS file found at %s' % (self.name, filepath))
367 return 363 return
368 deps_content = gclient_utils.FileRead(filepath) 364 deps_content = gclient_utils.FileRead(filepath)
369 logging.debug(deps_content) 365 logging.debug(deps_content)
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 # dependency local path. 412 # dependency local path.
417 rel_deps[os.path.normpath(os.path.join(self.name, d))] = url 413 rel_deps[os.path.normpath(os.path.join(self.name, d))] = url
418 deps = rel_deps 414 deps = rel_deps
419 415
420 # Convert the deps into real Dependency. 416 # Convert the deps into real Dependency.
421 for name, url in deps.iteritems(): 417 for name, url in deps.iteritems():
422 if name in [s.name for s in self.dependencies]: 418 if name in [s.name for s in self.dependencies]:
423 raise gclient_utils.Error( 419 raise gclient_utils.Error(
424 'The same name "%s" appears multiple times in the deps section' % 420 'The same name "%s" appears multiple times in the deps section' %
425 name) 421 name)
422 should_process = self.recursion_limit() and self.should_process
423 if should_process:
424 tree = dict((d.name, d) for d in self.tree(False))
425 if name in tree:
426 if url == tree[name].url:
427 logging.info('Won\'t process duplicate dependency %s' % tree[name])
428 # In theory we could keep it as a shadow of the other one. In
429 # practice, simply ignore it.
430 #should_process = False
431 continue
432 else:
433 raise gclient_utils.Error(
434 'Dependency %s specified more than once:\n %s\nvs\n %s' %
435 (name, tree[name].hierarchy(), self.hierarchy()))
426 self.dependencies.append(Dependency(self, name, url, None, None, None, 436 self.dependencies.append(Dependency(self, name, url, None, None, None,
427 None)) 437 None, should_process))
428 logging.debug('Loaded: %s' % str(self)) 438 logging.debug('Loaded: %s' % str(self))
429 439
430 def run(self, options, revision_overrides, command, args, work_queue): 440 def run(self, options, revision_overrides, command, args, work_queue):
431 """Runs 'command' before parsing the DEPS in case it's a initial checkout 441 """Runs 'command' before parsing the DEPS in case it's a initial checkout
432 or a revert.""" 442 or a revert."""
433 assert self._file_list == [] 443 assert self._file_list == []
444 if not self.should_process:
445 return
434 # When running runhooks, there's no need to consult the SCM. 446 # When running runhooks, there's no need to consult the SCM.
435 # All known hooks are expected to run unconditionally regardless of working 447 # All known hooks are expected to run unconditionally regardless of working
436 # copy state, so skip the SCM status check. 448 # copy state, so skip the SCM status check.
437 run_scm = command not in ('runhooks', None) 449 run_scm = command not in ('runhooks', None)
438 self.parsed_url = self.LateOverride(self.url) 450 self.parsed_url = self.LateOverride(self.url)
439 if run_scm and self.parsed_url: 451 if run_scm and self.parsed_url:
440 if isinstance(self.parsed_url, self.FileImpl): 452 if isinstance(self.parsed_url, self.FileImpl):
441 # Special support for single-file checkout. 453 # Special support for single-file checkout.
442 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): 454 if not command in (None, 'cleanup', 'diff', 'pack', 'status'):
443 options.revision = self.parsed_url.GetRevision() 455 options.revision = self.parsed_url.GetRevision()
444 scm = gclient_scm.SVNWrapper(self.parsed_url.GetPath(), 456 scm = gclient_scm.SVNWrapper(self.parsed_url.GetPath(),
445 self.root_dir(), 457 self.root_dir(),
446 self.name) 458 self.name)
447 scm.RunCommand('updatesingle', options, 459 scm.RunCommand('updatesingle', options,
448 args + [self.parsed_url.GetFilename()], 460 args + [self.parsed_url.GetFilename()],
449 self._file_list) 461 self._file_list)
450 else: 462 else:
451 options.revision = revision_overrides.get(self.name) 463 options.revision = revision_overrides.get(self.name)
452 scm = gclient_scm.CreateSCM(self.parsed_url, self.root_dir(), self.name) 464 scm = gclient_scm.CreateSCM(self.parsed_url, self.root_dir(), self.name)
453 scm.RunCommand(command, options, args, self._file_list) 465 scm.RunCommand(command, options, args, self._file_list)
454 self._file_list = [os.path.join(self.name, f.strip()) 466 self._file_list = [os.path.join(self.name, f.strip())
455 for f in self._file_list] 467 for f in self._file_list]
456 options.revision = None 468 options.revision = None
457 self.processed = True 469 self.processed = True
458 if self.recursion_limit(): 470 if self.recursion_limit():
459 # Then we can parse the DEPS file. 471 # Then we can parse the DEPS file.
460 self.ParseDepsFile(True) 472 self.ParseDepsFile()
461 # Adjust the implicit dependency requirement; e.g. if a DEPS file contains 473 # Adjust the implicit dependency requirement; e.g. if a DEPS file contains
462 # both src/foo and src/foo/bar, src/foo/bar is implicitly dependent of 474 # both src/foo and src/foo/bar, src/foo/bar is implicitly dependent of
463 # src/foo. Yes, it's O(n^2)... It's important to do that before 475 # src/foo. Yes, it's O(n^2)... It's important to do that before
464 # enqueueing them. 476 # enqueueing them.
465 for s in self.dependencies: 477 for s in self.dependencies:
466 for s2 in self.dependencies: 478 for s2 in self.dependencies:
467 if s is s2: 479 if s is s2:
468 continue 480 continue
469 if s.name.startswith(posixpath.join(s2.name, '')): 481 if s.name.startswith(posixpath.join(s2.name, '')):
470 s.requirements.append(s2.name) 482 s.requirements.append(s2.name)
471 483
472 # Parse the dependencies of this dependency. 484 # Parse the dependencies of this dependency.
473 for s in self.dependencies: 485 for s in self.dependencies:
474 work_queue.enqueue(s) 486 work_queue.enqueue(s)
475 487
476 def RunHooksRecursively(self, options): 488 def RunHooksRecursively(self, options):
477 """Evaluates all hooks, running actions as needed. run() 489 """Evaluates all hooks, running actions as needed. run()
478 must have been called before to load the DEPS.""" 490 must have been called before to load the DEPS."""
491 assert self.hooks_ran == False
492 if not self.should_process:
493 return
479 # If "--force" was specified, run all hooks regardless of what files have 494 # If "--force" was specified, run all hooks regardless of what files have
480 # changed. 495 # changed.
481 if self.deps_hooks and self.direct_reference: 496 if self.deps_hooks:
482 # TODO(maruel): If the user is using git or git-svn, then we don't know 497 # TODO(maruel): If the user is using git or git-svn, then we don't know
483 # what files have changed so we always run all hooks. It'd be nice to fix 498 # what files have changed so we always run all hooks. It'd be nice to fix
484 # that. 499 # that.
485 if (options.force or 500 if (options.force or
486 isinstance(self.parsed_url, self.FileImpl) or 501 isinstance(self.parsed_url, self.FileImpl) or
487 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or 502 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or
488 os.path.isdir(os.path.join(self.root_dir(), self.name, '.git'))): 503 os.path.isdir(os.path.join(self.root_dir(), self.name, '.git'))):
489 for hook_dict in self.deps_hooks: 504 for hook_dict in self.deps_hooks:
490 self._RunHookAction(hook_dict, []) 505 self._RunHookAction(hook_dict, [])
491 else: 506 else:
(...skipping 14 matching lines...) Expand all
506 file_list[i].startswith('/')): 521 file_list[i].startswith('/')):
507 file_list[i] = file_list[i][1:] 522 file_list[i] = file_list[i][1:]
508 523
509 # Run hooks on the basis of whether the files from the gclient operation 524 # Run hooks on the basis of whether the files from the gclient operation
510 # match each hook's pattern. 525 # match each hook's pattern.
511 for hook_dict in self.deps_hooks: 526 for hook_dict in self.deps_hooks:
512 pattern = re.compile(hook_dict['pattern']) 527 pattern = re.compile(hook_dict['pattern'])
513 matching_file_list = [f for f in file_list if pattern.search(f)] 528 matching_file_list = [f for f in file_list if pattern.search(f)]
514 if matching_file_list: 529 if matching_file_list:
515 self._RunHookAction(hook_dict, matching_file_list) 530 self._RunHookAction(hook_dict, matching_file_list)
516 if self.recursion_limit(): 531 for s in self.dependencies:
517 for s in self.dependencies: 532 s.RunHooksRecursively(options)
518 s.RunHooksRecursively(options)
519 533
520 def _RunHookAction(self, hook_dict, matching_file_list): 534 def _RunHookAction(self, hook_dict, matching_file_list):
521 """Runs the action from a single hook.""" 535 """Runs the action from a single hook."""
522 # A single DEPS file can specify multiple hooks so this function can be 536 # A single DEPS file can specify multiple hooks so this function can be
523 # called multiple times on a single Dependency. 537 # called multiple times on a single Dependency.
524 #assert self.hooks_ran == False 538 #assert self.hooks_ran == False
525 self.hooks_ran = True 539 self.hooks_ran = True
526 logging.debug(hook_dict) 540 logging.debug(hook_dict)
527 logging.debug(matching_file_list) 541 logging.debug(matching_file_list)
528 command = hook_dict['action'][:] 542 command = hook_dict['action'][:]
(...skipping 18 matching lines...) Expand all
547 def enforced_os(self): 561 def enforced_os(self):
548 return self.parent.enforced_os() 562 return self.parent.enforced_os()
549 563
550 def recursion_limit(self): 564 def recursion_limit(self):
551 return self.parent.recursion_limit() - 1 565 return self.parent.recursion_limit() - 1
552 566
553 def tree(self, include_all): 567 def tree(self, include_all):
554 return self.parent.tree(include_all) 568 return self.parent.tree(include_all)
555 569
556 def subtree(self, include_all): 570 def subtree(self, include_all):
571 """Breadth first"""
557 result = [] 572 result = []
558 # Add breadth-first. 573 for d in self.dependencies:
559 if self.direct_reference or include_all: 574 if d.should_process or include_all:
560 for d in self.dependencies:
561 result.append(d) 575 result.append(d)
562 for d in self.dependencies: 576 for d in self.dependencies:
563 result.extend(d.subtree(include_all)) 577 result.extend(d.subtree(include_all))
564 return result 578 return result
565 579
566 def get_custom_deps(self, name, url): 580 def get_custom_deps(self, name, url):
567 """Returns a custom deps if applicable.""" 581 """Returns a custom deps if applicable."""
568 if self.parent: 582 if self.parent:
569 url = self.parent.get_custom_deps(name, url) 583 url = self.parent.get_custom_deps(name, url)
570 # None is a valid return value to disable a dependency. 584 # None is a valid return value to disable a dependency.
571 return self.custom_deps.get(name, url) 585 return self.custom_deps.get(name, url)
572 586
573 def file_list(self): 587 def file_list(self):
574 result = self._file_list[:] 588 result = self._file_list[:]
575 for d in self.dependencies: 589 for d in self.dependencies:
576 result.extend(d.file_list()) 590 result.extend(d.file_list())
577 return result 591 return result
578 592
579 def __str__(self): 593 def __str__(self):
580 out = [] 594 out = []
581 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', 595 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps',
582 'custom_vars', 'deps_hooks', '_file_list', 'processed', 596 'custom_vars', 'deps_hooks', '_file_list', 'should_process',
583 'hooks_ran', 'deps_parsed', 'requirements', 'direct_reference'): 597 'processed', 'hooks_ran', 'deps_parsed', 'requirements'):
584 # 'deps_file' 598 # 'deps_file'
585 if self.__dict__[i]: 599 if self.__dict__[i]:
586 out.append('%s: %s' % (i, self.__dict__[i])) 600 out.append('%s: %s' % (i, self.__dict__[i]))
587 601
588 for d in self.dependencies: 602 for d in self.dependencies:
589 out.extend([' ' + x for x in str(d).splitlines()]) 603 out.extend([' ' + x for x in str(d).splitlines()])
590 out.append('') 604 out.append('')
591 return '\n'.join(out) 605 return '\n'.join(out)
592 606
593 def __repr__(self): 607 def __repr__(self):
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\ 662 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\
649 # Snapshot generated with gclient revinfo --snapshot 663 # Snapshot generated with gclient revinfo --snapshot
650 solutions = [ 664 solutions = [
651 %(solution_list)s] 665 %(solution_list)s]
652 """) 666 """)
653 667
654 def __init__(self, root_dir, options): 668 def __init__(self, root_dir, options):
655 # Do not change previous behavior. Only solution level and immediate DEPS 669 # Do not change previous behavior. Only solution level and immediate DEPS
656 # are processed. 670 # are processed.
657 self._recursion_limit = 2 671 self._recursion_limit = 2
658 Dependency.__init__(self, None, None, None, None, None, None, None) 672 Dependency.__init__(self, None, None, None, None, None, None, None, True)
659 self._options = options 673 self._options = options
660 if options.deps_os: 674 if options.deps_os:
661 enforced_os = options.deps_os.split(',') 675 enforced_os = options.deps_os.split(',')
662 else: 676 else:
663 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] 677 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')]
664 if 'all' in enforced_os: 678 if 'all' in enforced_os:
665 enforced_os = self.DEPS_OS_CHOICES.itervalues() 679 enforced_os = self.DEPS_OS_CHOICES.itervalues()
666 self._enforced_os = list(set(enforced_os)) 680 self._enforced_os = list(set(enforced_os))
667 self._root_dir = root_dir 681 self._root_dir = root_dir
668 self.config_content = None 682 self.config_content = None
669 683
670 def SetConfig(self, content): 684 def SetConfig(self, content):
671 assert self.dependencies == [] 685 assert self.dependencies == []
672 config_dict = {} 686 config_dict = {}
673 self.config_content = content 687 self.config_content = content
674 try: 688 try:
675 exec(content, config_dict) 689 exec(content, config_dict)
676 except SyntaxError, e: 690 except SyntaxError, e:
677 gclient_utils.SyntaxErrorToError('.gclient', e) 691 gclient_utils.SyntaxErrorToError('.gclient', e)
678 for s in config_dict.get('solutions', []): 692 for s in config_dict.get('solutions', []):
679 try: 693 try:
694 tree = dict((d.name, d) for d in self.tree(False))
695 if s['name'] in tree:
696 raise gclient_utils.Error(
697 'Dependency %s specified more than once in .gclient' % s['name'])
680 self.dependencies.append(Dependency( 698 self.dependencies.append(Dependency(
681 self, s['name'], s['url'], 699 self, s['name'], s['url'],
682 s.get('safesync_url', None), 700 s.get('safesync_url', None),
683 s.get('custom_deps', {}), 701 s.get('custom_deps', {}),
684 s.get('custom_vars', {}), 702 s.get('custom_vars', {}),
685 None)) 703 None,
704 True))
686 except KeyError: 705 except KeyError:
687 raise gclient_utils.Error('Invalid .gclient file. Solution is ' 706 raise gclient_utils.Error('Invalid .gclient file. Solution is '
688 'incomplete: %s' % s) 707 'incomplete: %s' % s)
689 # .gclient can have hooks. 708 # .gclient can have hooks.
690 self.deps_hooks = config_dict.get('hooks', []) 709 self.deps_hooks = config_dict.get('hooks', [])
691 self.direct_reference = True 710 self.direct_reference = True
692 self.deps_parsed = True 711 self.deps_parsed = True
693 712
694 def SaveConfig(self): 713 def SaveConfig(self):
695 gclient_utils.FileWrite(os.path.join(self.root_dir(), 714 gclient_utils.FileWrite(os.path.join(self.root_dir(),
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
887 print(self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient}) 906 print(self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient})
888 else: 907 else:
889 entries = {} 908 entries = {}
890 for d in self.tree(False): 909 for d in self.tree(False):
891 if self._options.actual: 910 if self._options.actual:
892 entries[d.name] = GetURLAndRev(d) 911 entries[d.name] = GetURLAndRev(d)
893 else: 912 else:
894 entries[d.name] = d.parsed_url 913 entries[d.name] = d.parsed_url
895 keys = sorted(entries.keys()) 914 keys = sorted(entries.keys())
896 for x in keys: 915 for x in keys:
897 line = '%s: %s' % (x, entries[x]) 916 print('%s: %s' % (x, entries[x]))
898 if x is not keys[-1]:
899 line += ';'
900 print line
901 logging.info(str(self)) 917 logging.info(str(self))
902 918
903 def ParseDepsFile(self, direct_reference): 919 def ParseDepsFile(self):
904 """No DEPS to parse for a .gclient file.""" 920 """No DEPS to parse for a .gclient file."""
905 raise gclient_utils.Error('Internal error') 921 raise gclient_utils.Error('Internal error')
906 922
907 def root_dir(self): 923 def root_dir(self):
908 """Root directory of gclient checkout.""" 924 """Root directory of gclient checkout."""
909 return self._root_dir 925 return self._root_dir
910 926
911 def enforced_os(self): 927 def enforced_os(self):
912 """What deps_os entries that are to be parsed.""" 928 """What deps_os entries that are to be parsed."""
913 return self._enforced_os 929 return self._enforced_os
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
1304 return CMDhelp(parser, argv) 1320 return CMDhelp(parser, argv)
1305 except gclient_utils.Error, e: 1321 except gclient_utils.Error, e:
1306 print >> sys.stderr, 'Error: %s' % str(e) 1322 print >> sys.stderr, 'Error: %s' % str(e)
1307 return 1 1323 return 1
1308 1324
1309 1325
1310 if '__main__' == __name__: 1326 if '__main__' == __name__:
1311 sys.exit(Main(sys.argv[1:])) 1327 sys.exit(Main(sys.argv[1:]))
1312 1328
1313 # vim: ts=2:sw=2:tw=80:et: 1329 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « no previous file | tests/gclient_smoketest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698