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

Side by Side Diff: gclient.py

Issue 2807003: More work toward refactoring. Simplify LoadCurrentConfig() and convert most " with '. (Closed)
Patch Set: 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 | 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/python 1 #!/usr/bin/python
2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """A wrapper script to manage a set of client modules in different SCM. 6 """Meta checkout manager supporting both Subversion and GIT.
7
8 This script is intended to be used to help basic management of client
9 program sources residing in one or more Subversion modules and Git
10 repositories, along with other modules it depends on, also in Subversion or Git,
11 but possibly on multiple respositories, making a wrapper system apparently
12 necessary.
13 7
14 Files 8 Files
15 .gclient : Current client configuration, written by 'config' command. 9 .gclient : Current client configuration, written by 'config' command.
16 Format is a Python script defining 'solutions', a list whose 10 Format is a Python script defining 'solutions', a list whose
17 entries each are maps binding the strings "name" and "url" 11 entries each are maps binding the strings "name" and "url"
18 to strings specifying the name and location of the client 12 to strings specifying the name and location of the client
19 module, as well as "custom_deps" to a map similar to the DEPS 13 module, as well as "custom_deps" to a map similar to the DEPS
20 file below. 14 file below.
21 .gclient_entries : A cache constructed by 'update' command. Format is a 15 .gclient_entries : A cache constructed by 'update' command. Format is a
22 Python script defining 'entries', a list of the names 16 Python script defining 'entries', a list of the names
23 of all modules in the client 17 of all modules in the client
24 <module>/DEPS : Python script defining var 'deps' as a map from each requisite 18 <module>/DEPS : Python script defining var 'deps' as a map from each requisite
25 submodule name to a URL where it can be found (via one SCM) 19 submodule name to a URL where it can be found (via one SCM)
26 20
27 Hooks 21 Hooks
28 .gclient and DEPS files may optionally contain a list named "hooks" to 22 .gclient and DEPS files may optionally contain a list named "hooks" to
29 allow custom actions to be performed based on files that have changed in the 23 allow custom actions to be performed based on files that have changed in the
30 working copy as a result of a "sync"/"update" or "revert" operation. This 24 working copy as a result of a "sync"/"update" or "revert" operation. This
31 could be prevented by using --nohooks (hooks run by default). Hooks can also 25 can be prevented by using --nohooks (hooks run by default). Hooks can also
32 be forced to run with the "runhooks" operation. If "sync" is run with 26 be forced to run with the "runhooks" operation. If "sync" is run with
33 --force, all known hooks will run regardless of the state of the working 27 --force, all known hooks will run regardless of the state of the working
34 copy. 28 copy.
35 29
36 Each item in a "hooks" list is a dict, containing these two keys: 30 Each item in a "hooks" list is a dict, containing these two keys:
37 "pattern" The associated value is a string containing a regular 31 "pattern" The associated value is a string containing a regular
38 expression. When a file whose pathname matches the expression 32 expression. When a file whose pathname matches the expression
39 is checked out, updated, or reverted, the hook's "action" will 33 is checked out, updated, or reverted, the hook's "action" will
40 run. 34 run.
41 "action" A list describing a command to run along with its arguments, if 35 "action" A list describing a command to run along with its arguments, if
42 any. An action command will run at most one time per gclient 36 any. An action command will run at most one time per gclient
43 invocation, regardless of how many files matched the pattern. 37 invocation, regardless of how many files matched the pattern.
44 The action is executed in the same directory as the .gclient 38 The action is executed in the same directory as the .gclient
45 file. If the first item in the list is the string "python", 39 file. If the first item in the list is the string "python",
46 the current Python interpreter (sys.executable) will be used 40 the current Python interpreter (sys.executable) will be used
47 to run the command. If the list contains string "$matching_files" 41 to run the command. If the list contains string "$matching_files"
48 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
49 by the list of matching files. 43 by the list of matching files.
50 44
51 Example: 45 Example:
52 hooks = [ 46 hooks = [
53 { "pattern": "\\.(gif|jpe?g|pr0n|png)$", 47 { "pattern": "\\.(gif|jpe?g|pr0n|png)$",
54 "action": ["python", "image_indexer.py", "--all"]}, 48 "action": ["python", "image_indexer.py", "--all"]},
55 ] 49 ]
56 """ 50 """
57 51
58 __version__ = "0.4" 52 __version__ = "0.4.1"
59 53
60 import errno 54 import errno
61 import logging 55 import logging
62 import optparse 56 import optparse
63 import os 57 import os
64 import pprint 58 import pprint
65 import re 59 import re
66 import sys 60 import sys
67 import urlparse 61 import urlparse
68 import urllib 62 import urllib
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 if var_name in self._custom_vars: 145 if var_name in self._custom_vars:
152 return self._custom_vars[var_name] 146 return self._custom_vars[var_name]
153 elif var_name in self._local_scope.get("vars", {}): 147 elif var_name in self._local_scope.get("vars", {}):
154 return self._local_scope["vars"][var_name] 148 return self._local_scope["vars"][var_name]
155 raise gclient_utils.Error("Var is not defined: %s" % var_name) 149 raise gclient_utils.Error("Var is not defined: %s" % var_name)
156 150
157 151
158 class Dependency(GClientKeywords): 152 class Dependency(GClientKeywords):
159 """Object that represents a dependency checkout.""" 153 """Object that represents a dependency checkout."""
160 DEPS_FILE = 'DEPS' 154 DEPS_FILE = 'DEPS'
155
161 def __init__(self, parent, name, url, safesync_url=None, custom_deps=None, 156 def __init__(self, parent, name, url, safesync_url=None, custom_deps=None,
162 custom_vars=None, deps_file=None): 157 custom_vars=None, deps_file=None):
163 GClientKeywords.__init__(self) 158 GClientKeywords.__init__(self)
164 self.parent = parent 159 self.parent = parent
165 self.name = name 160 self.name = name
166 self.url = url 161 self.url = url
167 # 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.
168 self.safesync_url = safesync_url 163 self.safesync_url = safesync_url
169 self.custom_vars = custom_vars or {} 164 self.custom_vars = custom_vars or {}
170 self.custom_deps = custom_deps or {} 165 self.custom_deps = custom_deps or {}
166 self.deps_hooks = []
171 self.dependencies = [] 167 self.dependencies = []
172 self.deps_file = deps_file or self.DEPS_FILE 168 self.deps_file = deps_file or self.DEPS_FILE
173 self._deps_hooks = []
174 169
175 # Sanity checks 170 # Sanity checks
176 if not self.name and self.parent: 171 if not self.name and self.parent:
177 raise gclient_utils.Error('Dependency without name') 172 raise gclient_utils.Error('Dependency without name')
178 if not isinstance(self.url, 173 if not isinstance(self.url,
179 (basestring, self.FromImpl, self.FileImpl, None.__class__)): 174 (basestring, self.FromImpl, self.FileImpl, None.__class__)):
180 raise gclient_utils.Error('dependency url must be either a string, None, ' 175 raise gclient_utils.Error('dependency url must be either a string, None, '
181 'File() or From() instead of %s' % 176 'File() or From() instead of %s' %
182 self.url.__class__.__name__) 177 self.url.__class__.__name__)
183 if '/' in self.deps_file or '\\' in self.deps_file: 178 if '/' in self.deps_file or '\\' in self.deps_file:
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 ] 226 ]
232 """) 227 """)
233 228
234 def __init__(self, root_dir, options): 229 def __init__(self, root_dir, options):
235 Dependency.__init__(self, None, None, None) 230 Dependency.__init__(self, None, None, None)
236 self._root_dir = root_dir 231 self._root_dir = root_dir
237 self._options = options 232 self._options = options
238 self.config_content = None 233 self.config_content = None
239 234
240 def SetConfig(self, content): 235 def SetConfig(self, content):
236 assert self.dependencies == []
241 config_dict = {} 237 config_dict = {}
242 self.config_content = content 238 self.config_content = content
243 try: 239 try:
244 exec(content, config_dict) 240 exec(content, config_dict)
245 except SyntaxError, e: 241 except SyntaxError, e:
246 try: 242 try:
247 # Try to construct a human readable error message 243 # Try to construct a human readable error message
248 error_message = [ 244 error_message = [
249 'There is a syntax error in your configuration file.', 245 'There is a syntax error in your configuration file.',
250 'Line #%s, character %s:' % (e.lineno, e.offset), 246 'Line #%s, character %s:' % (e.lineno, e.offset),
251 '"%s"' % re.sub(r'[\r\n]*$', '', e.text) ] 247 '"%s"' % re.sub(r'[\r\n]*$', '', e.text) ]
252 except: 248 except:
253 # Something went wrong, re-raise the original exception 249 # Something went wrong, re-raise the original exception
254 raise e 250 raise e
255 else: 251 else:
256 # Raise a new exception with the human readable message: 252 # Raise a new exception with the human readable message:
257 raise gclient_utils.Error('\n'.join(error_message)) 253 raise gclient_utils.Error('\n'.join(error_message))
258 for s in config_dict.get('solutions', []): 254 for s in config_dict.get('solutions', []):
259 self.dependencies.append(Dependency( 255 self.dependencies.append(Dependency(
260 self, s['name'], s['url'], 256 self, s['name'], s['url'],
261 s.get('safesync_url', None), 257 s.get('safesync_url', None),
262 s.get('custom_deps', {}), 258 s.get('custom_deps', {}),
263 s.get('custom_vars', {}))) 259 s.get('custom_vars', {})))
264 # .gclient can have hooks. 260 # .gclient can have hooks.
265 self._deps_hooks = config_dict.get('hooks', []) 261 self.deps_hooks = config_dict.get('hooks', [])
266 262
267 def SaveConfig(self): 263 def SaveConfig(self):
268 gclient_utils.FileWrite(os.path.join(self.root_dir(), 264 gclient_utils.FileWrite(os.path.join(self.root_dir(),
269 self._options.config_filename), 265 self._options.config_filename),
270 self.config_content) 266 self.config_content)
271 267
272 def _LoadConfig(self):
273 client_source = gclient_utils.FileRead(
274 os.path.join(self.root_dir(), self._options.config_filename))
275 self.SetConfig(client_source)
276
277 @staticmethod 268 @staticmethod
278 def LoadCurrentConfig(options, from_dir=None): 269 def LoadCurrentConfig(options):
279 """Searches for and loads a .gclient file relative to the current working 270 """Searches for and loads a .gclient file relative to the current working
280 dir. 271 dir. Returns a GClient object."""
281 272 path = gclient_utils.FindGclientRoot(os.getcwd(), options.config_filename)
282 Returns: 273 if not path:
283 A dict representing the contents of the .gclient file or an empty dict if 274 return None
284 the .gclient file doesn't exist.
285 """
286 if not from_dir:
287 from_dir = os.curdir
288 path = os.path.realpath(from_dir)
289 while not os.path.exists(os.path.join(path, options.config_filename)):
290 split_path = os.path.split(path)
291 if not split_path[1]:
292 return None
293 path = split_path[0]
294 client = GClient(path, options) 275 client = GClient(path, options)
295 client._LoadConfig() 276 client.SetConfig(gclient_utils.FileRead(
277 os.path.join(path, options.config_filename)))
296 return client 278 return client
297 279
298 def SetDefaultConfig(self, solution_name, solution_url, safesync_url): 280 def SetDefaultConfig(self, solution_name, solution_url, safesync_url):
299 self.SetConfig(self.DEFAULT_CLIENT_FILE_TEXT % { 281 self.SetConfig(self.DEFAULT_CLIENT_FILE_TEXT % {
300 'solution_name': solution_name, 282 'solution_name': solution_name,
301 'solution_url': solution_url, 283 'solution_url': solution_url,
302 'safesync_url' : safesync_url, 284 'safesync_url' : safesync_url,
303 }) 285 })
304 286
305 def _SaveEntries(self, entries): 287 def _SaveEntries(self, entries):
306 """Creates a .gclient_entries file to record the list of unique checkouts. 288 """Creates a .gclient_entries file to record the list of unique checkouts.
307 289
308 The .gclient_entries file lives in the same directory as .gclient. 290 The .gclient_entries file lives in the same directory as .gclient.
309 291
310 Args: 292 Args:
311 entries: A sequence of solution names. 293 entries: A sequence of solution names.
312 """ 294 """
313 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It 295 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It
314 # makes testing a bit too fun. 296 # makes testing a bit too fun.
315 result = pprint.pformat(entries, 2) 297 result = pprint.pformat(entries, 2)
316 if result.startswith('{\''): 298 if result.startswith('{\''):
317 result = '{ \'' + result[2:] 299 result = '{ \'' + result[2:]
318 text = "entries = \\\n" + result + '\n' 300 text = "entries = \\\n" + result + '\n'
319 file_path = os.path.join(self.root_dir(), self._options.entries_filename) 301 file_path = os.path.join(self.root_dir(), self._options.entries_filename)
320 gclient_utils.FileWrite(file_path, text) 302 gclient_utils.FileWrite(file_path, text)
321 303
322 def _ReadEntries(self): 304 def _ReadEntries(self):
323 """Read the .gclient_entries file for the given client. 305 """Read the .gclient_entries file for the given client.
324 306
325 Args:
326 client: The client for which the entries file should be read.
327
328 Returns: 307 Returns:
329 A sequence of solution names, which will be empty if there is the 308 A sequence of solution names, which will be empty if there is the
330 entries file hasn't been created yet. 309 entries file hasn't been created yet.
331 """ 310 """
332 scope = {} 311 scope = {}
333 filename = os.path.join(self.root_dir(), self._options.entries_filename) 312 filename = os.path.join(self.root_dir(), self._options.entries_filename)
334 if not os.path.exists(filename): 313 if not os.path.exists(filename):
335 return [] 314 return []
336 exec(gclient_utils.FileRead(filename), scope) 315 exec(gclient_utils.FileRead(filename), scope)
337 return scope["entries"] 316 return scope['entries']
338 317
339 def _ParseSolutionDeps(self, solution_name, solution_deps_content, 318 def _ParseSolutionDeps(self, solution_name, solution_deps_content,
340 custom_vars, parse_hooks): 319 custom_vars, parse_hooks):
341 """Parses the DEPS file for the specified solution. 320 """Parses the DEPS file for the specified solution.
342 321
343 Args: 322 Args:
344 solution_name: The name of the solution to query. 323 solution_name: The name of the solution to query.
345 solution_deps_content: Content of the DEPS file for the solution 324 solution_deps_content: Content of the DEPS file for the solution
346 custom_vars: A dict of vars to override any vars defined in the DEPS file. 325 custom_vars: A dict of vars to override any vars defined in the DEPS file.
347 326
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 # platform, but this is the best we can do. 363 # platform, but this is the best we can do.
385 deps.update([x for x in os_deps.items() if not x[0] in deps]) 364 deps.update([x for x in os_deps.items() if not x[0] in deps])
386 else: 365 else:
387 deps.update(os_deps) 366 deps.update(os_deps)
388 367
389 if 'hooks' in local_scope and parse_hooks: 368 if 'hooks' in local_scope and parse_hooks:
390 # TODO(maruel): Temporary Hack. Since this function is misplaced, find the 369 # TODO(maruel): Temporary Hack. Since this function is misplaced, find the
391 # right 'self' to add the hooks. 370 # right 'self' to add the hooks.
392 for d in self.dependencies: 371 for d in self.dependencies:
393 if d.name == solution_name: 372 if d.name == solution_name:
394 d._deps_hooks.extend(local_scope['hooks']) 373 d.deps_hooks.extend(local_scope['hooks'])
395 break 374 break
396 375
397 # If use_relative_paths is set in the DEPS file, regenerate 376 # If use_relative_paths is set in the DEPS file, regenerate
398 # the dictionary using paths relative to the directory containing 377 # the dictionary using paths relative to the directory containing
399 # the DEPS file. 378 # the DEPS file.
400 if local_scope.get('use_relative_paths'): 379 if local_scope.get('use_relative_paths'):
401 rel_deps = {} 380 rel_deps = {}
402 for d, url in deps.items(): 381 for d, url in deps.items():
403 # normpath is required to allow DEPS to use .. in their 382 # normpath is required to allow DEPS to use .. in their
404 # dependency local path. 383 # dependency local path.
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 """ 487 """
509 # Hooks only run for these command types. 488 # Hooks only run for these command types.
510 if not command in ('update', 'revert', 'runhooks'): 489 if not command in ('update', 'revert', 'runhooks'):
511 return 490 return
512 491
513 # Hooks only run when --nohooks is not specified 492 # Hooks only run when --nohooks is not specified
514 if self._options.nohooks: 493 if self._options.nohooks:
515 return 494 return
516 495
517 # Get any hooks from the .gclient file. 496 # Get any hooks from the .gclient file.
518 hooks = self._deps_hooks[:] 497 hooks = self.deps_hooks[:]
519 # Add any hooks found in DEPS files. 498 # Add any hooks found in DEPS files.
520 for d in self.dependencies: 499 for d in self.dependencies:
521 hooks.extend(d._deps_hooks) 500 hooks.extend(d.deps_hooks)
522 501
523 # If "--force" was specified, run all hooks regardless of what files have 502 # If "--force" was specified, run all hooks regardless of what files have
524 # changed. If the user is using git, then we don't know what files have 503 # changed. If the user is using git, then we don't know what files have
525 # changed so we always run all hooks. 504 # changed so we always run all hooks.
526 if self._options.force or is_using_git: 505 if self._options.force or is_using_git:
527 for hook_dict in hooks: 506 for hook_dict in hooks:
528 self._RunHookAction(hook_dict, []) 507 self._RunHookAction(hook_dict, [])
529 return 508 return
530 509
531 # Run hooks on the basis of whether the files from the gclient operation 510 # Run hooks on the basis of whether the files from the gclient operation
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 print >> sys.stderr, ('Please fix your script, having invalid ' 543 print >> sys.stderr, ('Please fix your script, having invalid '
565 '--revision flags will soon considered an error.') 544 '--revision flags will soon considered an error.')
566 else: 545 else:
567 revision_overrides[sol] = rev 546 revision_overrides[sol] = rev
568 index += 1 547 index += 1
569 return revision_overrides 548 return revision_overrides
570 549
571 def RunOnDeps(self, command, args): 550 def RunOnDeps(self, command, args):
572 """Runs a command on each dependency in a client and its dependencies. 551 """Runs a command on each dependency in a client and its dependencies.
573 552
574 The module's dependencies are specified in its top-level DEPS files.
575
576 Args: 553 Args:
577 command: The command to use (e.g., 'status' or 'diff') 554 command: The command to use (e.g., 'status' or 'diff')
578 args: list of str - extra arguments to add to the command line. 555 args: list of str - extra arguments to add to the command line.
579
580 Raises:
581 Error: If the client has conflicting entries.
582 """ 556 """
583 if not command in self.SUPPORTED_COMMANDS: 557 if not command in self.SUPPORTED_COMMANDS:
584 raise gclient_utils.Error("'%s' is an unsupported command" % command) 558 raise gclient_utils.Error("'%s' is an unsupported command" % command)
585 559
586 if not self.dependencies: 560 if not self.dependencies:
587 raise gclient_utils.Error("No solution specified") 561 raise gclient_utils.Error("No solution specified")
588 revision_overrides = self._EnforceRevisions() 562 revision_overrides = self._EnforceRevisions()
589 563
590 # When running runhooks --force, there's no need to consult the SCM. 564 # When running runhooks --force, there's no need to consult the SCM.
591 # All known hooks are expected to run unconditionally regardless of working 565 # All known hooks are expected to run unconditionally regardless of working
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 801
828 802
829 #### gclient commands. 803 #### gclient commands.
830 804
831 805
832 def CMDcleanup(parser, args): 806 def CMDcleanup(parser, args):
833 """Cleans up all working copies. 807 """Cleans up all working copies.
834 808
835 Mostly svn-specific. Simply runs 'svn cleanup' for each module. 809 Mostly svn-specific. Simply runs 'svn cleanup' for each module.
836 """ 810 """
837 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", 811 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
838 help="override deps for the specified (comma-separated) " 812 help='override deps for the specified (comma-separated) '
839 "platform(s); 'all' will process all deps_os " 813 'platform(s); \'all\' will process all deps_os '
840 "references") 814 'references')
841 (options, args) = parser.parse_args(args) 815 (options, args) = parser.parse_args(args)
842 client = GClient.LoadCurrentConfig(options) 816 client = GClient.LoadCurrentConfig(options)
843 if not client: 817 if not client:
844 raise gclient_utils.Error("client not configured; see 'gclient config'") 818 raise gclient_utils.Error('client not configured; see \'gclient config\'')
845 if options.verbose: 819 if options.verbose:
846 # Print out the .gclient file. This is longer than if we just printed the 820 # Print out the .gclient file. This is longer than if we just printed the
847 # client dict, but more legible, and it might contain helpful comments. 821 # client dict, but more legible, and it might contain helpful comments.
848 print(client.config_content) 822 print(client.config_content)
849 return client.RunOnDeps('cleanup', args) 823 return client.RunOnDeps('cleanup', args)
850 824
851 825
852 @attr('usage', '[url] [safesync url]') 826 @attr('usage', '[url] [safesync url]')
853 def CMDconfig(parser, args): 827 def CMDconfig(parser, args):
854 """Create a .gclient file in the current directory. 828 """Create a .gclient file in the current directory.
855 829
856 This specifies the configuration for further commands. After update/sync, 830 This specifies the configuration for further commands. After update/sync,
857 top-level DEPS files in each module are read to determine dependent 831 top-level DEPS files in each module are read to determine dependent
858 modules to operate on as well. If optional [url] parameter is 832 modules to operate on as well. If optional [url] parameter is
859 provided, then configuration is read from a specified Subversion server 833 provided, then configuration is read from a specified Subversion server
860 URL. 834 URL.
861 """ 835 """
862 parser.add_option("--spec", 836 parser.add_option('--spec',
863 help="create a gclient file containing the provided " 837 help='create a gclient file containing the provided '
864 "string. Due to Cygwin/Python brokenness, it " 838 'string. Due to Cygwin/Python brokenness, it '
865 "probably can't contain any newlines.") 839 'probably can\'t contain any newlines.')
866 parser.add_option("--name", 840 parser.add_option('--name',
867 help="overrides the default name for the solution") 841 help='overrides the default name for the solution')
868 (options, args) = parser.parse_args(args) 842 (options, args) = parser.parse_args(args)
869 if ((options.spec and args) or len(args) > 2 or 843 if ((options.spec and args) or len(args) > 2 or
870 (not options.spec and not args)): 844 (not options.spec and not args)):
871 parser.error('Inconsistent arguments. Use either --spec or one or 2 args') 845 parser.error('Inconsistent arguments. Use either --spec or one or 2 args')
872 846
873 if os.path.exists(options.config_filename): 847 if os.path.exists(options.config_filename):
874 raise gclient_utils.Error("%s file already exists in the current directory" 848 raise gclient_utils.Error('%s file already exists in the current directory'
875 % options.config_filename) 849 % options.config_filename)
876 client = GClient('.', options) 850 client = GClient('.', options)
877 if options.spec: 851 if options.spec:
878 client.SetConfig(options.spec) 852 client.SetConfig(options.spec)
879 else: 853 else:
880 base_url = args[0].rstrip('/') 854 base_url = args[0].rstrip('/')
881 if not options.name: 855 if not options.name:
882 name = base_url.split("/")[-1] 856 name = base_url.split('/')[-1]
883 else: 857 else:
884 # specify an alternate relpath for the given URL. 858 # specify an alternate relpath for the given URL.
885 name = options.name 859 name = options.name
886 safesync_url = "" 860 safesync_url = ''
887 if len(args) > 1: 861 if len(args) > 1:
888 safesync_url = args[1] 862 safesync_url = args[1]
889 client.SetDefaultConfig(name, base_url, safesync_url) 863 client.SetDefaultConfig(name, base_url, safesync_url)
890 client.SaveConfig() 864 client.SaveConfig()
891 return 0 865 return 0
892 866
893 867
894 def CMDexport(parser, args): 868 def CMDexport(parser, args):
895 """Wrapper for svn export for all managed directories.""" 869 """Wrapper for svn export for all managed directories."""
896 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", 870 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
897 help="override deps for the specified (comma-separated) " 871 help='override deps for the specified (comma-separated) '
898 "platform(s); 'all' will process all deps_os " 872 'platform(s); \'all\' will process all deps_os '
899 "references") 873 'references')
900 (options, args) = parser.parse_args(args) 874 (options, args) = parser.parse_args(args)
901 if len(args) != 1: 875 if len(args) != 1:
902 raise gclient_utils.Error("Need directory name") 876 raise gclient_utils.Error('Need directory name')
903 client = GClient.LoadCurrentConfig(options) 877 client = GClient.LoadCurrentConfig(options)
904 878
905 if not client: 879 if not client:
906 raise gclient_utils.Error("client not configured; see 'gclient config'") 880 raise gclient_utils.Error('client not configured; see \'gclient config\'')
907 881
908 if options.verbose: 882 if options.verbose:
909 # Print out the .gclient file. This is longer than if we just printed the 883 # Print out the .gclient file. This is longer than if we just printed the
910 # client dict, but more legible, and it might contain helpful comments. 884 # client dict, but more legible, and it might contain helpful comments.
911 print(client.config_content) 885 print(client.config_content)
912 return client.RunOnDeps('export', args) 886 return client.RunOnDeps('export', args)
913 887
914 888
915 @attr('epilog', """Example: 889 @attr('epilog', """Example:
916 gclient pack > patch.txt 890 gclient pack > patch.txt
917 generate simple patch for configured client and dependences 891 generate simple patch for configured client and dependences
918 """) 892 """)
919 def CMDpack(parser, args): 893 def CMDpack(parser, args):
920 """Generate a patch which can be applied at the root of the tree. 894 """Generate a patch which can be applied at the root of the tree.
921 895
922 Internally, runs 'svn diff'/'git diff' on each checked out module and 896 Internally, runs 'svn diff'/'git diff' on each checked out module and
923 dependencies, and performs minimal postprocessing of the output. The 897 dependencies, and performs minimal postprocessing of the output. The
924 resulting patch is printed to stdout and can be applied to a freshly 898 resulting patch is printed to stdout and can be applied to a freshly
925 checked out tree via 'patch -p0 < patchfile'. 899 checked out tree via 'patch -p0 < patchfile'.
926 """ 900 """
927 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", 901 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
928 help="override deps for the specified (comma-separated) " 902 help='override deps for the specified (comma-separated) '
929 "platform(s); 'all' will process all deps_os " 903 'platform(s); \'all\' will process all deps_os '
930 "references") 904 'references')
931 (options, args) = parser.parse_args(args) 905 (options, args) = parser.parse_args(args)
932 client = GClient.LoadCurrentConfig(options) 906 client = GClient.LoadCurrentConfig(options)
933 if not client: 907 if not client:
934 raise gclient_utils.Error("client not configured; see 'gclient config'") 908 raise gclient_utils.Error('client not configured; see \'gclient config\'')
935 if options.verbose: 909 if options.verbose:
936 # Print out the .gclient file. This is longer than if we just printed the 910 # Print out the .gclient file. This is longer than if we just printed the
937 # client dict, but more legible, and it might contain helpful comments. 911 # client dict, but more legible, and it might contain helpful comments.
938 print(client.config_content) 912 print(client.config_content)
939 return client.RunOnDeps('pack', args) 913 return client.RunOnDeps('pack', args)
940 914
941 915
942 def CMDstatus(parser, args): 916 def CMDstatus(parser, args):
943 """Show modification status for every dependencies.""" 917 """Show modification status for every dependencies."""
944 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", 918 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
945 help="override deps for the specified (comma-separated) " 919 help='override deps for the specified (comma-separated) '
946 "platform(s); 'all' will process all deps_os " 920 'platform(s); \'all\' will process all deps_os '
947 "references") 921 'references')
948 (options, args) = parser.parse_args(args) 922 (options, args) = parser.parse_args(args)
949 client = GClient.LoadCurrentConfig(options) 923 client = GClient.LoadCurrentConfig(options)
950 if not client: 924 if not client:
951 raise gclient_utils.Error("client not configured; see 'gclient config'") 925 raise gclient_utils.Error('client not configured; see \'gclient config\'')
952 if options.verbose: 926 if options.verbose:
953 # Print out the .gclient file. This is longer than if we just printed the 927 # Print out the .gclient file. This is longer than if we just printed the
954 # client dict, but more legible, and it might contain helpful comments. 928 # client dict, but more legible, and it might contain helpful comments.
955 print(client.config_content) 929 print(client.config_content)
956 return client.RunOnDeps('status', args) 930 return client.RunOnDeps('status', args)
957 931
958 932
959 @attr('epilog', """Examples: 933 @attr('epilog', """Examples:
960 gclient sync 934 gclient sync
961 update files from SCM according to current configuration, 935 update files from SCM according to current configuration,
962 *for modules which have changed since last update or sync* 936 *for modules which have changed since last update or sync*
963 gclient sync --force 937 gclient sync --force
964 update files from SCM according to current configuration, for 938 update files from SCM according to current configuration, for
965 all modules (useful for recovering files deleted from local copy) 939 all modules (useful for recovering files deleted from local copy)
966 gclient sync --revision src@31000 940 gclient sync --revision src@31000
967 update src directory to r31000 941 update src directory to r31000
968 """) 942 """)
969 def CMDsync(parser, args): 943 def CMDsync(parser, args):
970 """Checkout/update all modules.""" 944 """Checkout/update all modules."""
971 parser.add_option("-f", "--force", action="store_true", 945 parser.add_option('-f', '--force', action='store_true',
972 help="force update even for unchanged modules") 946 help='force update even for unchanged modules')
973 parser.add_option("-n", "--nohooks", action="store_true", 947 parser.add_option('-n', '--nohooks', action='store_true',
974 help="don't run hooks after the update is complete") 948 help='don\'t run hooks after the update is complete')
975 parser.add_option("-r", "--revision", action="append", 949 parser.add_option('-r', '--revision', action='append',
976 dest="revisions", metavar="REV", default=[], 950 dest='revisions', metavar='REV', default=[],
977 help="Enforces revision/hash for the solutions with the " 951 help='Enforces revision/hash for the solutions with the '
978 "format src@rev. The src@ part is optional and can be " 952 'format src@rev. The src@ part is optional and can be '
979 "skipped. -r can be used multiple times when .gclient " 953 'skipped. -r can be used multiple times when .gclient '
980 "has multiple solutions configured and will work even " 954 'has multiple solutions configured and will work even '
981 "if the src@ part is skipped.") 955 'if the src@ part is skipped.')
982 parser.add_option("-H", "--head", action="store_true", 956 parser.add_option('-H', '--head', action='store_true',
983 help="skips any safesync_urls specified in " 957 help='skips any safesync_urls specified in '
984 "configured solutions and sync to head instead") 958 'configured solutions and sync to head instead')
985 parser.add_option("-D", "--delete_unversioned_trees", action="store_true", 959 parser.add_option('-D', '--delete_unversioned_trees', action='store_true',
986 help="delete any unexpected unversioned trees " 960 help='delete any unexpected unversioned trees '
987 "that are in the checkout") 961 'that are in the checkout')
988 parser.add_option("-R", "--reset", action="store_true", 962 parser.add_option('-R', '--reset', action='store_true',
989 help="resets any local changes before updating (git only)") 963 help='resets any local changes before updating (git only)')
990 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", 964 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
991 help="override deps for the specified (comma-separated) " 965 help='override deps for the specified (comma-separated) '
992 "platform(s); 'all' will process all deps_os " 966 'platform(s); \'all\' will process all deps_os '
993 "references") 967 'references')
994 parser.add_option("-m", "--manually_grab_svn_rev", action="store_true", 968 parser.add_option('-m', '--manually_grab_svn_rev', action='store_true',
995 help="Skip svn up whenever possible by requesting " 969 help='Skip svn up whenever possible by requesting '
996 "actual HEAD revision from the repository") 970 'actual HEAD revision from the repository')
997 (options, args) = parser.parse_args(args) 971 (options, args) = parser.parse_args(args)
998 client = GClient.LoadCurrentConfig(options) 972 client = GClient.LoadCurrentConfig(options)
999 973
1000 if not client: 974 if not client:
1001 raise gclient_utils.Error("client not configured; see 'gclient config'") 975 raise gclient_utils.Error('client not configured; see \'gclient config\'')
1002 976
1003 if options.revisions and options.head: 977 if options.revisions and options.head:
1004 # TODO(maruel): Make it a parser.error if it doesn't break any builder. 978 # TODO(maruel): Make it a parser.error if it doesn't break any builder.
1005 print("Warning: you cannot use both --head and --revision") 979 print('Warning: you cannot use both --head and --revision')
1006 980
1007 if options.verbose: 981 if options.verbose:
1008 # Print out the .gclient file. This is longer than if we just printed the 982 # Print out the .gclient file. This is longer than if we just printed the
1009 # client dict, but more legible, and it might contain helpful comments. 983 # client dict, but more legible, and it might contain helpful comments.
1010 print(client.config_content) 984 print(client.config_content)
1011 return client.RunOnDeps('update', args) 985 return client.RunOnDeps('update', args)
1012 986
1013 987
1014 def CMDupdate(parser, args): 988 def CMDupdate(parser, args):
1015 """Alias for the sync command. Deprecated.""" 989 """Alias for the sync command. Deprecated."""
1016 return CMDsync(parser, args) 990 return CMDsync(parser, args)
1017 991
1018 def CMDdiff(parser, args): 992 def CMDdiff(parser, args):
1019 """Displays local diff for every dependencies.""" 993 """Displays local diff for every dependencies."""
1020 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", 994 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
1021 help="override deps for the specified (comma-separated) " 995 help='override deps for the specified (comma-separated) '
1022 "platform(s); 'all' will process all deps_os " 996 'platform(s); \'all\' will process all deps_os '
1023 "references") 997 'references')
1024 (options, args) = parser.parse_args(args) 998 (options, args) = parser.parse_args(args)
1025 client = GClient.LoadCurrentConfig(options) 999 client = GClient.LoadCurrentConfig(options)
1026 if not client: 1000 if not client:
1027 raise gclient_utils.Error("client not configured; see 'gclient config'") 1001 raise gclient_utils.Error('client not configured; see \'gclient config\'')
1028 if options.verbose: 1002 if options.verbose:
1029 # Print out the .gclient file. This is longer than if we just printed the 1003 # Print out the .gclient file. This is longer than if we just printed the
1030 # client dict, but more legible, and it might contain helpful comments. 1004 # client dict, but more legible, and it might contain helpful comments.
1031 print(client.config_content) 1005 print(client.config_content)
1032 return client.RunOnDeps('diff', args) 1006 return client.RunOnDeps('diff', args)
1033 1007
1034 1008
1035 def CMDrevert(parser, args): 1009 def CMDrevert(parser, args):
1036 """Revert all modifications in every dependencies.""" 1010 """Revert all modifications in every dependencies."""
1037 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", 1011 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
1038 help="override deps for the specified (comma-separated) " 1012 help='override deps for the specified (comma-separated) '
1039 "platform(s); 'all' will process all deps_os " 1013 'platform(s); \'all\' will process all deps_os '
1040 "references") 1014 'references')
1041 parser.add_option("-n", "--nohooks", action="store_true", 1015 parser.add_option('-n', '--nohooks', action='store_true',
1042 help="don't run hooks after the revert is complete") 1016 help='don\'t run hooks after the revert is complete')
1043 (options, args) = parser.parse_args(args) 1017 (options, args) = parser.parse_args(args)
1044 # --force is implied. 1018 # --force is implied.
1045 options.force = True 1019 options.force = True
1046 client = GClient.LoadCurrentConfig(options) 1020 client = GClient.LoadCurrentConfig(options)
1047 if not client: 1021 if not client:
1048 raise gclient_utils.Error("client not configured; see 'gclient config'") 1022 raise gclient_utils.Error('client not configured; see \'gclient config\'')
1049 return client.RunOnDeps('revert', args) 1023 return client.RunOnDeps('revert', args)
1050 1024
1051 1025
1052 def CMDrunhooks(parser, args): 1026 def CMDrunhooks(parser, args):
1053 """Runs hooks for files that have been modified in the local working copy.""" 1027 """Runs hooks for files that have been modified in the local working copy."""
1054 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", 1028 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
1055 help="override deps for the specified (comma-separated) " 1029 help='override deps for the specified (comma-separated) '
1056 "platform(s); 'all' will process all deps_os " 1030 'platform(s); \'all\' will process all deps_os '
1057 "references") 1031 'references')
1058 parser.add_option("-f", "--force", action="store_true", default=True, 1032 parser.add_option('-f', '--force', action='store_true', default=True,
1059 help="Deprecated. No effect.") 1033 help='Deprecated. No effect.')
1060 (options, args) = parser.parse_args(args) 1034 (options, args) = parser.parse_args(args)
1061 client = GClient.LoadCurrentConfig(options) 1035 client = GClient.LoadCurrentConfig(options)
1062 if not client: 1036 if not client:
1063 raise gclient_utils.Error("client not configured; see 'gclient config'") 1037 raise gclient_utils.Error('client not configured; see \'gclient config\'')
1064 if options.verbose: 1038 if options.verbose:
1065 # Print out the .gclient file. This is longer than if we just printed the 1039 # Print out the .gclient file. This is longer than if we just printed the
1066 # client dict, but more legible, and it might contain helpful comments. 1040 # client dict, but more legible, and it might contain helpful comments.
1067 print(client.config_content) 1041 print(client.config_content)
1068 options.force = True 1042 options.force = True
1069 options.nohooks = False 1043 options.nohooks = False
1070 return client.RunOnDeps('runhooks', args) 1044 return client.RunOnDeps('runhooks', args)
1071 1045
1072 1046
1073 def CMDrevinfo(parser, args): 1047 def CMDrevinfo(parser, args):
1074 """Output revision info mapping for the client and its dependencies. 1048 """Output revision info mapping for the client and its dependencies.
1075 1049
1076 This allows the capture of an overall "revision" for the source tree that 1050 This allows the capture of an overall 'revision' for the source tree that
1077 can be used to reproduce the same tree in the future. It is only useful for 1051 can be used to reproduce the same tree in the future. It is only useful for
1078 "unpinned dependencies", i.e. DEPS/deps references without a svn revision 1052 'unpinned dependencies', i.e. DEPS/deps references without a svn revision
1079 number or a git hash. A git branch name isn't "pinned" since the actual 1053 number or a git hash. A git branch name isn't 'pinned' since the actual
1080 commit can change. 1054 commit can change.
1081 """ 1055 """
1082 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', 1056 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
1083 help='override deps for the specified (comma-separated) ' 1057 help='override deps for the specified (comma-separated) '
1084 'platform(s); \'all\' will process all deps_os ' 1058 'platform(s); \'all\' will process all deps_os '
1085 'references') 1059 'references')
1086 parser.add_option('-s', '--snapshot', action='store_true', 1060 parser.add_option('-s', '--snapshot', action='store_true',
1087 help='creates a snapshot .gclient file of the current ' 1061 help='creates a snapshot .gclient file of the current '
1088 'version of all repositories to reproduce the tree, ' 1062 'version of all repositories to reproduce the tree, '
1089 'implies -a') 1063 'implies -a')
1090 (options, args) = parser.parse_args(args) 1064 (options, args) = parser.parse_args(args)
1091 client = GClient.LoadCurrentConfig(options) 1065 client = GClient.LoadCurrentConfig(options)
1092 if not client: 1066 if not client:
1093 raise gclient_utils.Error("client not configured; see 'gclient config'") 1067 raise gclient_utils.Error('client not configured; see \'gclient config\'')
1094 client.PrintRevInfo() 1068 client.PrintRevInfo()
1095 return 0 1069 return 0
1096 1070
1097 1071
1098 def Command(name): 1072 def Command(name):
1099 return getattr(sys.modules[__name__], 'CMD' + name, None) 1073 return getattr(sys.modules[__name__], 'CMD' + name, None)
1100 1074
1101 1075
1102 def CMDhelp(parser, args): 1076 def CMDhelp(parser, args):
1103 """Prints list of commands or help for a specific command.""" 1077 """Prints list of commands or help for a specific command."""
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
1171 return CMDhelp(parser, argv) 1145 return CMDhelp(parser, argv)
1172 except gclient_utils.Error, e: 1146 except gclient_utils.Error, e:
1173 print >> sys.stderr, 'Error: %s' % str(e) 1147 print >> sys.stderr, 'Error: %s' % str(e)
1174 return 1 1148 return 1
1175 1149
1176 1150
1177 if '__main__' == __name__: 1151 if '__main__' == __name__:
1178 sys.exit(Main(sys.argv[1:])) 1152 sys.exit(Main(sys.argv[1:]))
1179 1153
1180 # vim: ts=2:sw=2:tw=80:et: 1154 # 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