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

Side by Side Diff: gclient.py

Issue 2828009: Move these functions to Dependency to simplify the diff later. (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 """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 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 raise gclient_utils.Error('Dependency without name') 172 raise gclient_utils.Error('Dependency without name')
173 if not isinstance(self.url, 173 if not isinstance(self.url,
174 (basestring, self.FromImpl, self.FileImpl, None.__class__)): 174 (basestring, self.FromImpl, self.FileImpl, None.__class__)):
175 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, '
176 'File() or From() instead of %s' % 176 'File() or From() instead of %s' %
177 self.url.__class__.__name__) 177 self.url.__class__.__name__)
178 if '/' in self.deps_file or '\\' in self.deps_file: 178 if '/' in self.deps_file or '\\' in self.deps_file:
179 raise gclient_utils.Error('deps_file name must not be a path, just a ' 179 raise gclient_utils.Error('deps_file name must not be a path, just a '
180 'filename. %s' % self.deps_file) 180 'filename. %s' % self.deps_file)
181 181
182
183 class GClient(Dependency):
184 """Main gclient checkout root where .gclient resides."""
185 SUPPORTED_COMMANDS = [
186 'cleanup', 'diff', 'export', 'pack', 'revert', 'status', 'update',
187 'runhooks'
188 ]
189
190 DEPS_OS_CHOICES = {
191 "win32": "win",
192 "win": "win",
193 "cygwin": "win",
194 "darwin": "mac",
195 "mac": "mac",
196 "unix": "unix",
197 "linux": "unix",
198 "linux2": "unix",
199 }
200
201 DEFAULT_CLIENT_FILE_TEXT = ("""\
202 solutions = [
203 { "name" : "%(solution_name)s",
204 "url" : "%(solution_url)s",
205 "custom_deps" : {
206 },
207 "safesync_url": "%(safesync_url)s"
208 },
209 ]
210 """)
211
212 DEFAULT_SNAPSHOT_SOLUTION_TEXT = ("""\
213 { "name" : "%(solution_name)s",
214 "url" : "%(solution_url)s",
215 "custom_deps" : {
216 %(solution_deps)s,
217 },
218 "safesync_url": "%(safesync_url)s"
219 },
220 """)
221
222 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\
223 # Snapshot generated with gclient revinfo --snapshot
224 solutions = [
225 %(solution_list)s
226 ]
227 """)
228
229 def __init__(self, root_dir, options):
230 Dependency.__init__(self, None, None, None)
231 self._root_dir = root_dir
232 self._options = options
233 self.config_content = None
234
235 def SetConfig(self, content):
236 assert self.dependencies == []
237 config_dict = {}
238 self.config_content = content
239 try:
240 exec(content, config_dict)
241 except SyntaxError, e:
242 try:
243 # Try to construct a human readable error message
244 error_message = [
245 'There is a syntax error in your configuration file.',
246 'Line #%s, character %s:' % (e.lineno, e.offset),
247 '"%s"' % re.sub(r'[\r\n]*$', '', e.text) ]
248 except:
249 # Something went wrong, re-raise the original exception
250 raise e
251 else:
252 # Raise a new exception with the human readable message:
253 raise gclient_utils.Error('\n'.join(error_message))
254 for s in config_dict.get('solutions', []):
255 self.dependencies.append(Dependency(
256 self, s['name'], s['url'],
257 s.get('safesync_url', None),
258 s.get('custom_deps', {}),
259 s.get('custom_vars', {})))
260 # .gclient can have hooks.
261 self.deps_hooks = config_dict.get('hooks', [])
262
263 def SaveConfig(self):
264 gclient_utils.FileWrite(os.path.join(self.root_dir(),
265 self._options.config_filename),
266 self.config_content)
267
268 @staticmethod
269 def LoadCurrentConfig(options):
270 """Searches for and loads a .gclient file relative to the current working
271 dir. Returns a GClient object."""
272 path = gclient_utils.FindGclientRoot(os.getcwd(), options.config_filename)
273 if not path:
274 return None
275 client = GClient(path, options)
276 client.SetConfig(gclient_utils.FileRead(
277 os.path.join(path, options.config_filename)))
278 return client
279
280 def SetDefaultConfig(self, solution_name, solution_url, safesync_url):
281 self.SetConfig(self.DEFAULT_CLIENT_FILE_TEXT % {
282 'solution_name': solution_name,
283 'solution_url': solution_url,
284 'safesync_url' : safesync_url,
285 })
286
287 def _SaveEntries(self, entries):
288 """Creates a .gclient_entries file to record the list of unique checkouts.
289
290 The .gclient_entries file lives in the same directory as .gclient.
291
292 Args:
293 entries: A sequence of solution names.
294 """
295 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It
296 # makes testing a bit too fun.
297 result = pprint.pformat(entries, 2)
298 if result.startswith('{\''):
299 result = '{ \'' + result[2:]
300 text = "entries = \\\n" + result + '\n'
301 file_path = os.path.join(self.root_dir(), self._options.entries_filename)
302 gclient_utils.FileWrite(file_path, text)
303
304 def _ReadEntries(self):
305 """Read the .gclient_entries file for the given client.
306
307 Returns:
308 A sequence of solution names, which will be empty if there is the
309 entries file hasn't been created yet.
310 """
311 scope = {}
312 filename = os.path.join(self.root_dir(), self._options.entries_filename)
313 if not os.path.exists(filename):
314 return []
315 exec(gclient_utils.FileRead(filename), scope)
316 return scope['entries']
317
318 def _ParseSolutionDeps(self, solution_name, solution_deps_content, 182 def _ParseSolutionDeps(self, solution_name, solution_deps_content,
319 custom_vars, parse_hooks): 183 custom_vars, parse_hooks):
320 """Parses the DEPS file for the specified solution. 184 """Parses the DEPS file for the specified solution.
321 185
322 Args: 186 Args:
323 solution_name: The name of the solution to query. 187 solution_name: The name of the solution to query.
324 solution_deps_content: Content of the DEPS file for the solution 188 solution_deps_content: Content of the DEPS file for the solution
325 custom_vars: A dict of vars to override any vars defined in the DEPS file. 189 custom_vars: A dict of vars to override any vars defined in the DEPS file.
326 190
327 Returns: 191 Returns:
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 return 372 return
509 373
510 # Run hooks on the basis of whether the files from the gclient operation 374 # Run hooks on the basis of whether the files from the gclient operation
511 # match each hook's pattern. 375 # match each hook's pattern.
512 for hook_dict in hooks: 376 for hook_dict in hooks:
513 pattern = re.compile(hook_dict['pattern']) 377 pattern = re.compile(hook_dict['pattern'])
514 matching_file_list = [f for f in file_list if pattern.search(f)] 378 matching_file_list = [f for f in file_list if pattern.search(f)]
515 if matching_file_list: 379 if matching_file_list:
516 self._RunHookAction(hook_dict, matching_file_list) 380 self._RunHookAction(hook_dict, matching_file_list)
517 381
382
383 class GClient(Dependency):
384 """Main gclient checkout root where .gclient resides."""
385 SUPPORTED_COMMANDS = [
386 'cleanup', 'diff', 'export', 'pack', 'revert', 'status', 'update',
387 'runhooks'
388 ]
389
390 DEPS_OS_CHOICES = {
391 "win32": "win",
392 "win": "win",
393 "cygwin": "win",
394 "darwin": "mac",
395 "mac": "mac",
396 "unix": "unix",
397 "linux": "unix",
398 "linux2": "unix",
399 }
400
401 DEFAULT_CLIENT_FILE_TEXT = ("""\
402 solutions = [
403 { "name" : "%(solution_name)s",
404 "url" : "%(solution_url)s",
405 "custom_deps" : {
406 },
407 "safesync_url": "%(safesync_url)s"
408 },
409 ]
410 """)
411
412 DEFAULT_SNAPSHOT_SOLUTION_TEXT = ("""\
413 { "name" : "%(solution_name)s",
414 "url" : "%(solution_url)s",
415 "custom_deps" : {
416 %(solution_deps)s,
417 },
418 "safesync_url": "%(safesync_url)s"
419 },
420 """)
421
422 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\
423 # Snapshot generated with gclient revinfo --snapshot
424 solutions = [
425 %(solution_list)s
426 ]
427 """)
428
429 def __init__(self, root_dir, options):
430 Dependency.__init__(self, None, None, None)
431 self._root_dir = root_dir
432 self._options = options
433 self.config_content = None
434
435 def SetConfig(self, content):
436 assert self.dependencies == []
437 config_dict = {}
438 self.config_content = content
439 try:
440 exec(content, config_dict)
441 except SyntaxError, e:
442 try:
443 # Try to construct a human readable error message
444 error_message = [
445 'There is a syntax error in your configuration file.',
446 'Line #%s, character %s:' % (e.lineno, e.offset),
447 '"%s"' % re.sub(r'[\r\n]*$', '', e.text) ]
448 except:
449 # Something went wrong, re-raise the original exception
450 raise e
451 else:
452 # Raise a new exception with the human readable message:
453 raise gclient_utils.Error('\n'.join(error_message))
454 for s in config_dict.get('solutions', []):
455 self.dependencies.append(Dependency(
456 self, s['name'], s['url'],
457 s.get('safesync_url', None),
458 s.get('custom_deps', {}),
459 s.get('custom_vars', {})))
460 # .gclient can have hooks.
461 self.deps_hooks = config_dict.get('hooks', [])
462
463 def SaveConfig(self):
464 gclient_utils.FileWrite(os.path.join(self.root_dir(),
465 self._options.config_filename),
466 self.config_content)
467
468 @staticmethod
469 def LoadCurrentConfig(options):
470 """Searches for and loads a .gclient file relative to the current working
471 dir. Returns a GClient object."""
472 path = gclient_utils.FindGclientRoot(os.getcwd(), options.config_filename)
473 if not path:
474 return None
475 client = GClient(path, options)
476 client.SetConfig(gclient_utils.FileRead(
477 os.path.join(path, options.config_filename)))
478 return client
479
480 def SetDefaultConfig(self, solution_name, solution_url, safesync_url):
481 self.SetConfig(self.DEFAULT_CLIENT_FILE_TEXT % {
482 'solution_name': solution_name,
483 'solution_url': solution_url,
484 'safesync_url' : safesync_url,
485 })
486
487 def _SaveEntries(self, entries):
488 """Creates a .gclient_entries file to record the list of unique checkouts.
489
490 The .gclient_entries file lives in the same directory as .gclient.
491
492 Args:
493 entries: A sequence of solution names.
494 """
495 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It
496 # makes testing a bit too fun.
497 result = pprint.pformat(entries, 2)
498 if result.startswith('{\''):
499 result = '{ \'' + result[2:]
500 text = "entries = \\\n" + result + '\n'
501 file_path = os.path.join(self.root_dir(), self._options.entries_filename)
502 gclient_utils.FileWrite(file_path, text)
503
504 def _ReadEntries(self):
505 """Read the .gclient_entries file for the given client.
506
507 Returns:
508 A sequence of solution names, which will be empty if there is the
509 entries file hasn't been created yet.
510 """
511 scope = {}
512 filename = os.path.join(self.root_dir(), self._options.entries_filename)
513 if not os.path.exists(filename):
514 return []
515 exec(gclient_utils.FileRead(filename), scope)
516 return scope['entries']
517
518 def _EnforceRevisions(self): 518 def _EnforceRevisions(self):
519 """Checks for revision overrides.""" 519 """Checks for revision overrides."""
520 revision_overrides = {} 520 revision_overrides = {}
521 if self._options.head: 521 if self._options.head:
522 return revision_overrides 522 return revision_overrides
523 for s in self.dependencies: 523 for s in self.dependencies:
524 if not s.safesync_url: 524 if not s.safesync_url:
525 continue 525 continue
526 handle = urllib.urlopen(s.safesync_url) 526 handle = urllib.urlopen(s.safesync_url)
527 rev = handle.read().strip() 527 rev = handle.read().strip()
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after
1145 return CMDhelp(parser, argv) 1145 return CMDhelp(parser, argv)
1146 except gclient_utils.Error, e: 1146 except gclient_utils.Error, e:
1147 print >> sys.stderr, 'Error: %s' % str(e) 1147 print >> sys.stderr, 'Error: %s' % str(e)
1148 return 1 1148 return 1
1149 1149
1150 1150
1151 if '__main__' == __name__: 1151 if '__main__' == __name__:
1152 sys.exit(Main(sys.argv[1:])) 1152 sys.exit(Main(sys.argv[1:]))
1153 1153
1154 # 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