OLD | NEW |
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 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 | 307 |
308 if not self.name and self.parent: | 308 if not self.name and self.parent: |
309 raise gclient_utils.Error('Dependency without name') | 309 raise gclient_utils.Error('Dependency without name') |
310 | 310 |
311 def LateOverride(self, url): | 311 def LateOverride(self, url): |
312 """Resolves the parsed url from url. | 312 """Resolves the parsed url from url. |
313 | 313 |
314 Manages From() keyword accordingly. Do not touch self.parsed_url nor | 314 Manages From() keyword accordingly. Do not touch self.parsed_url nor |
315 self.url because it may called with other urls due to From().""" | 315 self.url because it may called with other urls due to From().""" |
316 assert self.parsed_url == None or not self.should_process, self.parsed_url | 316 assert self.parsed_url == None or not self.should_process, self.parsed_url |
317 overriden_url = self.get_custom_deps(self.name, url) | 317 parsed_url = self.get_custom_deps(self.name, url) |
318 if overriden_url != url: | 318 if parsed_url != url: |
319 logging.info('%s, %s was overriden to %s' % (self.name, url, | 319 logging.info('LateOverride(%s, %s) -> %s' % (self.name, url, parsed_url)) |
320 overriden_url)) | 320 return parsed_url |
321 return overriden_url | 321 |
322 elif isinstance(url, self.FromImpl): | 322 if isinstance(url, self.FromImpl): |
323 ref = [ | 323 ref = [ |
324 dep for dep in self.root.subtree(True) if url.module_name == dep.name | 324 dep for dep in self.root.subtree(True) if url.module_name == dep.name |
325 ] | 325 ] |
326 if not ref: | 326 if not ref: |
327 raise gclient_utils.Error('Failed to find one reference to %s. %s' % ( | 327 raise gclient_utils.Error('Failed to find one reference to %s. %s' % ( |
328 url.module_name, ref)) | 328 url.module_name, ref)) |
329 # It may happen that len(ref) > 1 but it's no big deal. | 329 # It may happen that len(ref) > 1 but it's no big deal. |
330 ref = ref[0] | 330 ref = ref[0] |
331 sub_target = url.sub_target_name or self.name | 331 sub_target = url.sub_target_name or self.name |
332 # Make sure the referenced dependency DEPS file is loaded and file the | 332 # Make sure the referenced dependency DEPS file is loaded and file the |
333 # inner referenced dependency. | 333 # inner referenced dependency. |
334 ref.ParseDepsFile() | 334 ref.ParseDepsFile() |
335 found_dep = None | 335 found_dep = None |
336 for d in ref.dependencies: | 336 for d in ref.dependencies: |
337 if d.name == sub_target: | 337 if d.name == sub_target: |
338 found_dep = d | 338 found_dep = d |
339 break | 339 break |
340 if not found_dep: | 340 if not found_dep: |
341 raise gclient_utils.Error( | 341 raise gclient_utils.Error( |
342 'Couldn\'t find %s in %s, referenced by %s (parent: %s)\n%s' % ( | 342 'Couldn\'t find %s in %s, referenced by %s (parent: %s)\n%s' % ( |
343 sub_target, ref.name, self.name, self.parent.name, | 343 sub_target, ref.name, self.name, self.parent.name, |
344 str(self.root))) | 344 str(self.root))) |
345 | 345 |
346 # Call LateOverride() again. | 346 # Call LateOverride() again. |
347 parsed_url = found_dep.LateOverride(found_dep.url) | 347 parsed_url = found_dep.LateOverride(found_dep.url) |
348 logging.info('%s, %s to %s' % (self.name, url, parsed_url)) | 348 logging.info( |
| 349 'LateOverride(%s, %s) -> %s (From)' % (self.name, url, parsed_url)) |
349 return parsed_url | 350 return parsed_url |
350 elif isinstance(url, basestring): | 351 |
| 352 if isinstance(url, basestring): |
351 parsed_url = urlparse.urlparse(url) | 353 parsed_url = urlparse.urlparse(url) |
352 if not parsed_url[0]: | 354 if not parsed_url[0]: |
353 # A relative url. Fetch the real base. | 355 # A relative url. Fetch the real base. |
354 path = parsed_url[2] | 356 path = parsed_url[2] |
355 if not path.startswith('/'): | 357 if not path.startswith('/'): |
356 raise gclient_utils.Error( | 358 raise gclient_utils.Error( |
357 'relative DEPS entry \'%s\' must begin with a slash' % url) | 359 'relative DEPS entry \'%s\' must begin with a slash' % url) |
358 # Create a scm just to query the full url. | 360 # Create a scm just to query the full url. |
359 parent_url = self.parent.parsed_url | 361 parent_url = self.parent.parsed_url |
360 if isinstance(parent_url, self.FileImpl): | 362 if isinstance(parent_url, self.FileImpl): |
361 parent_url = parent_url.file_location | 363 parent_url = parent_url.file_location |
362 scm = gclient_scm.CreateSCM(parent_url, self.root.root_dir, None) | 364 scm = gclient_scm.CreateSCM(parent_url, self.root.root_dir, None) |
363 parsed_url = scm.FullUrlForRelativeUrl(url) | 365 parsed_url = scm.FullUrlForRelativeUrl(url) |
364 else: | 366 else: |
365 parsed_url = url | 367 parsed_url = url |
366 logging.info('%s, %s -> %s' % (self.name, url, parsed_url)) | 368 logging.info('LateOverride(%s, %s) -> %s' % (self.name, url, parsed_url)) |
367 return parsed_url | 369 return parsed_url |
368 elif isinstance(url, self.FileImpl): | 370 |
369 parsed_url = url | 371 if isinstance(url, self.FileImpl): |
370 logging.info('%s, %s -> %s (File)' % (self.name, url, parsed_url)) | 372 logging.info('LateOverride(%s, %s) -> %s (File)' % (self.name, url, url)) |
371 return parsed_url | 373 return url |
372 elif url is None: | 374 |
373 return None | 375 if url is None: |
| 376 logging.info('LateOverride(%s, %s) -> %s' % (self.name, url, url)) |
| 377 return url |
374 else: | 378 else: |
375 raise gclient_utils.Error('Unkown url type') | 379 raise gclient_utils.Error('Unknown url type') |
376 | 380 |
377 def ParseDepsFile(self): | 381 def ParseDepsFile(self): |
378 """Parses the DEPS file for this dependency.""" | 382 """Parses the DEPS file for this dependency.""" |
379 assert self.processed == True | 383 assert self.processed == True |
380 if self.deps_parsed: | 384 if self.deps_parsed: |
381 logging.debug('%s was already parsed' % self.name) | 385 logging.debug('%s was already parsed' % self.name) |
382 return | 386 return |
383 # One thing is unintuitive, vars= {} must happen before Var() use. | 387 # One thing is unintuitive, vars= {} must happen before Var() use. |
384 local_scope = {} | 388 local_scope = {} |
385 var = self.VarImpl(self.custom_vars, local_scope) | 389 var = self.VarImpl(self.custom_vars, local_scope) |
386 global_scope = { | 390 global_scope = { |
387 'File': self.FileImpl, | 391 'File': self.FileImpl, |
388 'From': self.FromImpl, | 392 'From': self.FromImpl, |
389 'Var': var.Lookup, | 393 'Var': var.Lookup, |
390 'deps_os': {}, | 394 'deps_os': {}, |
391 } | 395 } |
392 filepath = os.path.join(self.root.root_dir, self.name, self.deps_file) | 396 filepath = os.path.join(self.root.root_dir, self.name, self.deps_file) |
393 if not os.path.isfile(filepath): | 397 if not os.path.isfile(filepath): |
394 logging.info('%s: No %s file found at %s' % (self.name, self.deps_file, | 398 logging.info( |
395 filepath)) | 399 'ParseDepsFile(%s): No %s file found at %s' % ( |
| 400 self.name, self.deps_file, filepath)) |
396 else: | 401 else: |
397 deps_content = gclient_utils.FileRead(filepath) | 402 deps_content = gclient_utils.FileRead(filepath) |
398 logging.debug(deps_content) | 403 logging.debug('ParseDepsFile(%s) read:\n%s' % (self.name, deps_content)) |
399 # Eval the content. | 404 # Eval the content. |
400 try: | 405 try: |
401 exec(deps_content, global_scope, local_scope) | 406 exec(deps_content, global_scope, local_scope) |
402 except SyntaxError, e: | 407 except SyntaxError, e: |
403 gclient_utils.SyntaxErrorToError(filepath, e) | 408 gclient_utils.SyntaxErrorToError(filepath, e) |
404 deps = local_scope.get('deps', {}) | 409 deps = local_scope.get('deps', {}) |
405 # load os specific dependencies if defined. these dependencies may | 410 # load os specific dependencies if defined. these dependencies may |
406 # override or extend the values defined by the 'deps' member. | 411 # override or extend the values defined by the 'deps' member. |
407 if 'deps_os' in local_scope: | 412 if 'deps_os' in local_scope: |
408 enforced_os = self.root.enforced_os | 413 enforced_os = self.root.enforced_os |
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
822 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It | 827 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It |
823 # makes testing a bit too fun. | 828 # makes testing a bit too fun. |
824 result = 'entries = {\n' | 829 result = 'entries = {\n' |
825 for entry in self.root.subtree(False): | 830 for entry in self.root.subtree(False): |
826 # Skip over File() dependencies as we can't version them. | 831 # Skip over File() dependencies as we can't version them. |
827 if not isinstance(entry.parsed_url, self.FileImpl): | 832 if not isinstance(entry.parsed_url, self.FileImpl): |
828 result += ' %s: %s,\n' % (pprint.pformat(entry.name), | 833 result += ' %s: %s,\n' % (pprint.pformat(entry.name), |
829 pprint.pformat(entry.parsed_url)) | 834 pprint.pformat(entry.parsed_url)) |
830 result += '}\n' | 835 result += '}\n' |
831 file_path = os.path.join(self.root_dir, self._options.entries_filename) | 836 file_path = os.path.join(self.root_dir, self._options.entries_filename) |
832 logging.info(result) | 837 logging.debug(result) |
833 gclient_utils.FileWrite(file_path, result) | 838 gclient_utils.FileWrite(file_path, result) |
834 | 839 |
835 def _ReadEntries(self): | 840 def _ReadEntries(self): |
836 """Read the .gclient_entries file for the given client. | 841 """Read the .gclient_entries file for the given client. |
837 | 842 |
838 Returns: | 843 Returns: |
839 A sequence of solution names, which will be empty if there is the | 844 A sequence of solution names, which will be empty if there is the |
840 entries file hasn't been created yet. | 845 entries file hasn't been created yet. |
841 """ | 846 """ |
842 scope = {} | 847 scope = {} |
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1381 parser.add_option('-v', '--verbose', action='count', default=0, | 1386 parser.add_option('-v', '--verbose', action='count', default=0, |
1382 help='Produces additional output for diagnostics. Can be ' | 1387 help='Produces additional output for diagnostics. Can be ' |
1383 'used up to three times for more logging info.') | 1388 'used up to three times for more logging info.') |
1384 parser.add_option('--gclientfile', dest='config_filename', | 1389 parser.add_option('--gclientfile', dest='config_filename', |
1385 default=os.environ.get('GCLIENT_FILE', '.gclient'), | 1390 default=os.environ.get('GCLIENT_FILE', '.gclient'), |
1386 help='Specify an alternate %default file') | 1391 help='Specify an alternate %default file') |
1387 # Integrate standard options processing. | 1392 # Integrate standard options processing. |
1388 old_parser = parser.parse_args | 1393 old_parser = parser.parse_args |
1389 def Parse(args): | 1394 def Parse(args): |
1390 (options, args) = old_parser(args) | 1395 (options, args) = old_parser(args) |
1391 level = None | 1396 level = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG][ |
1392 if options.verbose == 2: | 1397 min(options.verbose, 3)] |
1393 level = logging.INFO | |
1394 elif options.verbose > 2: | |
1395 level = logging.DEBUG | |
1396 logging.basicConfig(level=level, | 1398 logging.basicConfig(level=level, |
1397 format='%(module)s(%(lineno)d) %(funcName)s:%(message)s') | 1399 format='%(module)s(%(lineno)d) %(funcName)s:%(message)s') |
1398 options.entries_filename = options.config_filename + '_entries' | 1400 options.entries_filename = options.config_filename + '_entries' |
1399 if options.jobs < 1: | 1401 if options.jobs < 1: |
1400 parser.error('--jobs must be 1 or higher') | 1402 parser.error('--jobs must be 1 or higher') |
1401 | 1403 |
1402 # These hacks need to die. | 1404 # These hacks need to die. |
1403 if not hasattr(options, 'revisions'): | 1405 if not hasattr(options, 'revisions'): |
1404 # GClient.RunOnDeps expects it even if not applicable. | 1406 # GClient.RunOnDeps expects it even if not applicable. |
1405 options.revisions = [] | 1407 options.revisions = [] |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1451 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 1453 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
1452 print >> sys.stderr, 'Error: %s' % str(e) | 1454 print >> sys.stderr, 'Error: %s' % str(e) |
1453 return 1 | 1455 return 1 |
1454 | 1456 |
1455 | 1457 |
1456 if '__main__' == __name__: | 1458 if '__main__' == __name__: |
1457 fix_encoding.fix_encoding() | 1459 fix_encoding.fix_encoding() |
1458 sys.exit(Main(sys.argv[1:])) | 1460 sys.exit(Main(sys.argv[1:])) |
1459 | 1461 |
1460 # vim: ts=2:sw=2:tw=80:et: | 1462 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |