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

Side by Side Diff: gclient.py

Issue 8059011: Dependency.url is also immutable. Convert more member as properties (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: merge _FindDependencies into __init__ Created 9 years, 2 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 | no next file » | 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 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 129
130 def Lookup(self, var_name): 130 def Lookup(self, var_name):
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 DependencySettings(object): 139 class DependencySettings(GClientKeywords):
140 """Immutable configuration settings.""" 140 """Immutable configuration settings."""
141 def __init__( 141 def __init__(
142 self, parent, safesync_url, managed, custom_deps, custom_vars, 142 self, parent, url, safesync_url, managed, custom_deps, custom_vars,
143 deps_file, should_process): 143 deps_file, should_process):
144 GClientKeywords.__init__(self)
145
144 # These are not mutable: 146 # These are not mutable:
145 self._parent = parent 147 self._parent = parent
146 self._safesync_url = safesync_url 148 self._safesync_url = safesync_url
147 self._deps_file = deps_file 149 self._deps_file = deps_file
150 self._url = url
148 # 'managed' determines whether or not this dependency is synced/updated by 151 # 'managed' determines whether or not this dependency is synced/updated by
149 # gclient after gclient checks it out initially. The difference between 152 # gclient after gclient checks it out initially. The difference between
150 # 'managed' and 'should_process' is that the user specifies 'managed' via 153 # 'managed' and 'should_process' is that the user specifies 'managed' via
151 # the --unmanaged command-line flag or a .gclient config, where 154 # the --unmanaged command-line flag or a .gclient config, where
152 # 'should_process' is dynamically set by gclient if it goes over its 155 # 'should_process' is dynamically set by gclient if it goes over its
153 # recursion limit and controls gclient's behavior so it does not misbehave. 156 # recursion limit and controls gclient's behavior so it does not misbehave.
154 self._managed = managed 157 self._managed = managed
155 self._should_process = should_process 158 self._should_process = should_process
156 159
157 # These are only set in .gclient and not in DEPS files. 160 # These are only set in .gclient and not in DEPS files.
158 self._custom_vars = custom_vars or {} 161 self._custom_vars = custom_vars or {}
159 self._custom_deps = custom_deps or {} 162 self._custom_deps = custom_deps or {}
160 163
164 # Post process the url to remove trailing slashes.
165 if isinstance(self._url, basestring):
166 # urls are sometime incorrectly written as proto://host/path/@rev. Replace
167 # it to proto://host/path@rev.
168 if self._url.count('@') > 1:
169 raise gclient_utils.Error('Invalid url "%s"' % self._url)
170 self._url = self._url.replace('/@', '@')
171 elif not isinstance(self._url,
172 (self.FromImpl, self.FileImpl, None.__class__)):
173 raise gclient_utils.Error(
174 ('dependency url must be either a string, None, '
175 'File() or From() instead of %s') % self._url.__class__.__name__)
161 if '/' in self._deps_file or '\\' in self._deps_file: 176 if '/' in self._deps_file or '\\' in self._deps_file:
162 raise gclient_utils.Error('deps_file name must not be a path, just a ' 177 raise gclient_utils.Error('deps_file name must not be a path, just a '
163 'filename. %s' % self._deps_file) 178 'filename. %s' % self._deps_file)
164 179
165 @property 180 @property
166 def deps_file(self): 181 def deps_file(self):
167 """Immutable so no need to lock.""" 182 """Immutable so no need to lock."""
168 return self._deps_file 183 return self._deps_file
169 184
170 @property 185 @property
(...skipping 19 matching lines...) Expand all
190 @property 205 @property
191 def custom_vars(self): 206 def custom_vars(self):
192 """Immutable so no need to lock.""" 207 """Immutable so no need to lock."""
193 return self._custom_vars.copy() 208 return self._custom_vars.copy()
194 209
195 @property 210 @property
196 def custom_deps(self): 211 def custom_deps(self):
197 """Immutable so no need to lock.""" 212 """Immutable so no need to lock."""
198 return self._custom_deps.copy() 213 return self._custom_deps.copy()
199 214
215 @property
216 def url(self):
217 return self._url
200 218
201 class Dependency(GClientKeywords, gclient_utils.WorkItem, DependencySettings): 219
220 class Dependency(gclient_utils.WorkItem, DependencySettings):
202 """Object that represents a dependency checkout.""" 221 """Object that represents a dependency checkout."""
203 222
204 def __init__(self, parent, name, url, safesync_url, managed, custom_deps, 223 def __init__(self, parent, name, url, safesync_url, managed, custom_deps,
205 custom_vars, deps_file, should_process): 224 custom_vars, deps_file, should_process):
206 GClientKeywords.__init__(self)
207 gclient_utils.WorkItem.__init__(self, name) 225 gclient_utils.WorkItem.__init__(self, name)
208 DependencySettings.__init__( 226 DependencySettings.__init__(
209 self, parent, safesync_url, managed, custom_deps, custom_vars, 227 self, parent, url, safesync_url, managed, custom_deps, custom_vars,
210 deps_file, should_process) 228 deps_file, should_process)
211 229
212 # This is in both .gclient and DEPS files: 230 # This is in both .gclient and DEPS files:
213 self.url = url 231 self._deps_hooks = []
214
215 self.deps_hooks = []
216 232
217 # Calculates properties: 233 # Calculates properties:
218 self.parsed_url = None 234 self._parsed_url = None
219 self._dependencies = [] 235 self._dependencies = []
220 # A cache of the files affected by the current operation, necessary for 236 # A cache of the files affected by the current operation, necessary for
221 # hooks. 237 # hooks.
222 self._file_list = [] 238 self._file_list = []
223 # If it is not set to True, the dependency wasn't processed for its child 239 # If it is not set to True, the dependency wasn't processed for its child
224 # dependency, i.e. its DEPS wasn't read. 240 # dependency, i.e. its DEPS wasn't read.
225 self.deps_parsed = False 241 self._deps_parsed = False
226 # This dependency has been processed, i.e. checked out 242 # This dependency has been processed, i.e. checked out
227 self.processed = False 243 self._processed = False
228 # This dependency had its hook run 244 # This dependency had its hook run
229 self.hooks_ran = False 245 self._hooks_ran = False
230 246
231 # Post process the url to remove trailing slashes. 247 # Setup self.requirements and find any other dependency who would have self
232 if isinstance(self.url, basestring): 248 # as a requirement.
233 # urls are sometime incorrectly written as proto://host/path/@rev. Replace
234 # it to proto://host/path@rev.
235 if self.url.count('@') > 1:
236 raise gclient_utils.Error('Invalid url "%s"' % self.url)
237 self.url = self.url.replace('/@', '@')
238 249
239 self._FindDependencies()
240
241 # Sanity checks
242 if not self.name and self.parent:
243 raise gclient_utils.Error('Dependency without name')
244 if not isinstance(self.url,
245 (basestring, self.FromImpl, self.FileImpl, None.__class__)):
246 raise gclient_utils.Error('dependency url must be either a string, None, '
247 'File() or From() instead of %s' %
248 self.url.__class__.__name__)
249
250 def _FindDependencies(self):
251 """Setup self.requirements and find any other dependency who would have self
252 as a requirement.
253 """
254 # self.parent is implicitly a requirement. This will be recursive by 250 # self.parent is implicitly a requirement. This will be recursive by
255 # definition. 251 # definition.
256 if self.parent and self.parent.name: 252 if self.parent and self.parent.name:
257 self._requirements.add(self.parent.name) 253 self._requirements.add(self.parent.name)
258 254
259 # For a tree with at least 2 levels*, the leaf node needs to depend 255 # For a tree with at least 2 levels*, the leaf node needs to depend
260 # on the level higher up in an orderly way. 256 # on the level higher up in an orderly way.
261 # This becomes messy for >2 depth as the DEPS file format is a dictionary, 257 # This becomes messy for >2 depth as the DEPS file format is a dictionary,
262 # thus unsorted, while the .gclient format is a list thus sorted. 258 # thus unsorted, while the .gclient format is a list thus sorted.
263 # 259 #
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 # Step 2: Find any requirements self may impose. 292 # Step 2: Find any requirements self may impose.
297 if obj.name.startswith(posixpath.join(self.name, '')): 293 if obj.name.startswith(posixpath.join(self.name, '')):
298 try: 294 try:
299 # Access to a protected member _requirements of a client class 295 # Access to a protected member _requirements of a client class
300 # pylint: disable=W0212 296 # pylint: disable=W0212
301 obj.lock.acquire() 297 obj.lock.acquire()
302 obj._requirements.add(self.name) 298 obj._requirements.add(self.name)
303 finally: 299 finally:
304 obj.lock.release() 300 obj.lock.release()
305 301
302 if not self.name and self.parent:
303 raise gclient_utils.Error('Dependency without name')
304
306 def LateOverride(self, url): 305 def LateOverride(self, url):
307 """Resolves the parsed url from url. 306 """Resolves the parsed url from url.
308 307
309 Manages From() keyword accordingly. Do not touch self.parsed_url nor 308 Manages From() keyword accordingly. Do not touch self.parsed_url nor
310 self.url because it may called with other urls due to From().""" 309 self.url because it may called with other urls due to From()."""
311 assert self.parsed_url == None or not self.should_process, self.parsed_url 310 assert self.parsed_url == None or not self.should_process, self.parsed_url
312 overriden_url = self.get_custom_deps(self.name, url) 311 overriden_url = self.get_custom_deps(self.name, url)
313 if overriden_url != url: 312 if overriden_url != url:
314 logging.info('%s, %s was overriden to %s' % (self.name, url, 313 logging.info('%s, %s was overriden to %s' % (self.name, url,
315 overriden_url)) 314 overriden_url))
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 return None 367 return None
369 else: 368 else:
370 raise gclient_utils.Error('Unkown url type') 369 raise gclient_utils.Error('Unkown url type')
371 370
372 def ParseDepsFile(self): 371 def ParseDepsFile(self):
373 """Parses the DEPS file for this dependency.""" 372 """Parses the DEPS file for this dependency."""
374 assert self.processed == True 373 assert self.processed == True
375 if self.deps_parsed: 374 if self.deps_parsed:
376 logging.debug('%s was already parsed' % self.name) 375 logging.debug('%s was already parsed' % self.name)
377 return 376 return
378 self.deps_parsed = True
379 # One thing is unintuitive, vars= {} must happen before Var() use. 377 # One thing is unintuitive, vars= {} must happen before Var() use.
380 local_scope = {} 378 local_scope = {}
381 var = self.VarImpl(self.custom_vars, local_scope) 379 var = self.VarImpl(self.custom_vars, local_scope)
382 global_scope = { 380 global_scope = {
383 'File': self.FileImpl, 381 'File': self.FileImpl,
384 'From': self.FromImpl, 382 'From': self.FromImpl,
385 'Var': var.Lookup, 383 'Var': var.Lookup,
386 'deps_os': {}, 384 'deps_os': {},
387 } 385 }
388 filepath = os.path.join(self.root.root_dir, self.name, self.deps_file) 386 filepath = os.path.join(self.root.root_dir, self.name, self.deps_file)
(...skipping 17 matching lines...) Expand all
406 os_deps = local_scope['deps_os'].get(deps_os_key, {}) 404 os_deps = local_scope['deps_os'].get(deps_os_key, {})
407 if len(enforced_os) > 1: 405 if len(enforced_os) > 1:
408 # Ignore any conflict when including deps for more than one 406 # Ignore any conflict when including deps for more than one
409 # platform, so we collect the broadest set of dependencies 407 # platform, so we collect the broadest set of dependencies
410 # available. We may end up with the wrong revision of something for 408 # available. We may end up with the wrong revision of something for
411 # our platform, but this is the best we can do. 409 # our platform, but this is the best we can do.
412 deps.update([x for x in os_deps.items() if not x[0] in deps]) 410 deps.update([x for x in os_deps.items() if not x[0] in deps])
413 else: 411 else:
414 deps.update(os_deps) 412 deps.update(os_deps)
415 413
416 self.deps_hooks.extend(local_scope.get('hooks', [])) 414 self._deps_hooks.extend(local_scope.get('hooks', []))
417 415
418 # If a line is in custom_deps, but not in the solution, we want to append 416 # If a line is in custom_deps, but not in the solution, we want to append
419 # this line to the solution. 417 # this line to the solution.
420 for d in self.custom_deps: 418 for d in self.custom_deps:
421 if d not in deps: 419 if d not in deps:
422 deps[d] = self.custom_deps[d] 420 deps[d] = self.custom_deps[d]
423 421
424 # If use_relative_paths is set in the DEPS file, regenerate 422 # If use_relative_paths is set in the DEPS file, regenerate
425 # the dictionary using paths relative to the directory containing 423 # the dictionary using paths relative to the directory containing
426 # the DEPS file. 424 # the DEPS file.
(...skipping 23 matching lines...) Expand all
450 #should_process = False 448 #should_process = False
451 continue 449 continue
452 else: 450 else:
453 raise gclient_utils.Error( 451 raise gclient_utils.Error(
454 'Dependency %s specified more than once:\n %s\nvs\n %s' % 452 'Dependency %s specified more than once:\n %s\nvs\n %s' %
455 (name, tree[name].hierarchy(), self.hierarchy())) 453 (name, tree[name].hierarchy(), self.hierarchy()))
456 self._dependencies.append( 454 self._dependencies.append(
457 Dependency( 455 Dependency(
458 self, name, url, None, None, None, None, 456 self, name, url, None, None, None, None,
459 self.deps_file, should_process)) 457 self.deps_file, should_process))
458 self._deps_parsed = True
460 logging.debug('Loaded: %s' % str(self)) 459 logging.debug('Loaded: %s' % str(self))
461 460
462 # Arguments number differs from overridden method 461 # Arguments number differs from overridden method
463 # pylint: disable=W0221 462 # pylint: disable=W0221
464 def run(self, revision_overrides, command, args, work_queue, options): 463 def run(self, revision_overrides, command, args, work_queue, options):
465 """Runs 'command' before parsing the DEPS in case it's a initial checkout 464 """Runs 'command' before parsing the DEPS in case it's a initial checkout
466 or a revert.""" 465 or a revert."""
467 466
468 def maybeGetParentRevision(options): 467 def maybeGetParentRevision(options):
469 """If we are performing an update and --transitive is set, set the 468 """If we are performing an update and --transitive is set, set the
(...skipping 28 matching lines...) Expand all
498 (options.revision, revision)) 497 (options.revision, revision))
499 revision_overrides[self.name] = revision 498 revision_overrides[self.name] = revision
500 499
501 assert self._file_list == [] 500 assert self._file_list == []
502 if not self.should_process: 501 if not self.should_process:
503 return 502 return
504 # When running runhooks, there's no need to consult the SCM. 503 # When running runhooks, there's no need to consult the SCM.
505 # All known hooks are expected to run unconditionally regardless of working 504 # All known hooks are expected to run unconditionally regardless of working
506 # copy state, so skip the SCM status check. 505 # copy state, so skip the SCM status check.
507 run_scm = command not in ('runhooks', None) 506 run_scm = command not in ('runhooks', None)
508 self.parsed_url = self.LateOverride(self.url) 507 self._parsed_url = self.LateOverride(self.url)
509 if run_scm and self.parsed_url: 508 if run_scm and self.parsed_url:
510 if isinstance(self.parsed_url, self.FileImpl): 509 if isinstance(self.parsed_url, self.FileImpl):
511 # Special support for single-file checkout. 510 # Special support for single-file checkout.
512 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): 511 if not command in (None, 'cleanup', 'diff', 'pack', 'status'):
513 options.revision = self.parsed_url.GetRevision() 512 options.revision = self.parsed_url.GetRevision()
514 scm = gclient_scm.SVNWrapper(self.parsed_url.GetPath(), 513 scm = gclient_scm.SVNWrapper(self.parsed_url.GetPath(),
515 self.root.root_dir, 514 self.root.root_dir,
516 self.name) 515 self.name)
517 scm.RunCommand('updatesingle', options, 516 scm.RunCommand('updatesingle', options,
518 args + [self.parsed_url.GetFilename()], 517 args + [self.parsed_url.GetFilename()],
(...skipping 16 matching lines...) Expand all
535 # It depends on the command being executed (like runhooks vs sync). 534 # It depends on the command being executed (like runhooks vs sync).
536 if not os.path.isabs(self._file_list[i]): 535 if not os.path.isabs(self._file_list[i]):
537 continue 536 continue
538 prefix = os.path.commonprefix( 537 prefix = os.path.commonprefix(
539 [self.root.root_dir.lower(), self._file_list[i].lower()]) 538 [self.root.root_dir.lower(), self._file_list[i].lower()])
540 self._file_list[i] = self._file_list[i][len(prefix):] 539 self._file_list[i] = self._file_list[i][len(prefix):]
541 # Strip any leading path separators. 540 # Strip any leading path separators.
542 while (self._file_list[i].startswith('\\') or 541 while (self._file_list[i].startswith('\\') or
543 self._file_list[i].startswith('/')): 542 self._file_list[i].startswith('/')):
544 self._file_list[i] = self._file_list[i][1:] 543 self._file_list[i] = self._file_list[i][1:]
545 self.processed = True 544 self._processed = True
546 if self.recursion_limit: 545 if self.recursion_limit:
547 # Then we can parse the DEPS file. 546 # Then we can parse the DEPS file.
548 self.ParseDepsFile() 547 self.ParseDepsFile()
549 548
550 # Parse the dependencies of this dependency. 549 # Parse the dependencies of this dependency.
551 for s in self.dependencies: 550 for s in self.dependencies:
552 work_queue.enqueue(s) 551 work_queue.enqueue(s)
553 552
554 def RunHooksRecursively(self, options): 553 def RunHooksRecursively(self, options):
555 """Evaluates all hooks, running actions as needed. run() 554 """Evaluates all hooks, running actions as needed. run()
(...skipping 23 matching lines...) Expand all
579 if matching_file_list: 578 if matching_file_list:
580 self._RunHookAction(hook_dict, matching_file_list) 579 self._RunHookAction(hook_dict, matching_file_list)
581 for s in self.dependencies: 580 for s in self.dependencies:
582 s.RunHooksRecursively(options) 581 s.RunHooksRecursively(options)
583 582
584 def _RunHookAction(self, hook_dict, matching_file_list): 583 def _RunHookAction(self, hook_dict, matching_file_list):
585 """Runs the action from a single hook.""" 584 """Runs the action from a single hook."""
586 # A single DEPS file can specify multiple hooks so this function can be 585 # A single DEPS file can specify multiple hooks so this function can be
587 # called multiple times on a single Dependency. 586 # called multiple times on a single Dependency.
588 #assert self.hooks_ran == False 587 #assert self.hooks_ran == False
589 self.hooks_ran = True 588 self._hooks_ran = True
590 logging.debug(hook_dict) 589 logging.debug(hook_dict)
591 logging.debug(matching_file_list) 590 logging.debug(matching_file_list)
592 command = hook_dict['action'][:] 591 command = hook_dict['action'][:]
593 if command[0] == 'python': 592 if command[0] == 'python':
594 # If the hook specified "python" as the first item, the action is a 593 # If the hook specified "python" as the first item, the action is a
595 # Python script. Run it by starting a new copy of the same 594 # Python script. Run it by starting a new copy of the same
596 # interpreter. 595 # interpreter.
597 command[0] = sys.executable 596 command[0] = sys.executable
598 597
599 if '$matching_files' in command: 598 if '$matching_files' in command:
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 633
635 Immutable so no need to lock. 634 Immutable so no need to lock.
636 """ 635 """
637 return max(self.parent.recursion_limit - 1, 0) 636 return max(self.parent.recursion_limit - 1, 0)
638 637
639 @property 638 @property
640 def dependencies(self): 639 def dependencies(self):
641 return tuple(self._dependencies) 640 return tuple(self._dependencies)
642 641
643 @property 642 @property
643 def deps_hooks(self):
644 return tuple(self._deps_hooks)
645
646 @property
647 def parsed_url(self):
648 return self._parsed_url
649
650 @property
651 def deps_parsed(self):
652 return self._deps_parsed
653
654 @property
655 def processed(self):
656 return self._processed
657
658 @property
659 def hooks_ran(self):
660 return self._hooks_ran
661
662 @property
644 def file_list(self): 663 def file_list(self):
645 result = self._file_list[:] 664 result = self._file_list[:]
646 for d in self.dependencies: 665 for d in self.dependencies:
647 result.extend(d.file_list) 666 result.extend(d.file_list)
648 return tuple(result) 667 return tuple(result)
649 668
650 def __str__(self): 669 def __str__(self):
651 out = [] 670 out = []
652 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', 671 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps',
653 'custom_vars', 'deps_hooks', 'file_list', 'should_process', 672 'custom_vars', 'deps_hooks', 'file_list', 'should_process',
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
768 s.get('safesync_url', None), 787 s.get('safesync_url', None),
769 s.get('managed', True), 788 s.get('managed', True),
770 s.get('custom_deps', {}), 789 s.get('custom_deps', {}),
771 s.get('custom_vars', {}), 790 s.get('custom_vars', {}),
772 s.get('deps_file', 'DEPS'), 791 s.get('deps_file', 'DEPS'),
773 True)) 792 True))
774 except KeyError: 793 except KeyError:
775 raise gclient_utils.Error('Invalid .gclient file. Solution is ' 794 raise gclient_utils.Error('Invalid .gclient file. Solution is '
776 'incomplete: %s' % s) 795 'incomplete: %s' % s)
777 # .gclient can have hooks. 796 # .gclient can have hooks.
778 self.deps_hooks = config_dict.get('hooks', []) 797 self._deps_hooks = config_dict.get('hooks', [])
779 self.deps_parsed = True 798 self._deps_parsed = True
780 799
781 def SaveConfig(self): 800 def SaveConfig(self):
782 gclient_utils.FileWrite(os.path.join(self.root_dir, 801 gclient_utils.FileWrite(os.path.join(self.root_dir,
783 self._options.config_filename), 802 self._options.config_filename),
784 self.config_content) 803 self.config_content)
785 804
786 @staticmethod 805 @staticmethod
787 def LoadCurrentConfig(options): 806 def LoadCurrentConfig(options):
788 """Searches for and loads a .gclient file relative to the current working 807 """Searches for and loads a .gclient file relative to the current working
789 dir. Returns a GClient object.""" 808 dir. Returns a GClient object."""
(...skipping 649 matching lines...) Expand 10 before | Expand all | Expand 10 after
1439 except (gclient_utils.Error, subprocess2.CalledProcessError), e: 1458 except (gclient_utils.Error, subprocess2.CalledProcessError), e:
1440 print >> sys.stderr, 'Error: %s' % str(e) 1459 print >> sys.stderr, 'Error: %s' % str(e)
1441 return 1 1460 return 1
1442 1461
1443 1462
1444 if '__main__' == __name__: 1463 if '__main__' == __name__:
1445 fix_encoding.fix_encoding() 1464 fix_encoding.fix_encoding()
1446 sys.exit(Main(sys.argv[1:])) 1465 sys.exit(Main(sys.argv[1:]))
1447 1466
1448 # vim: ts=2:sw=2:tw=80:et: 1467 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698