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

Side by Side Diff: gclient.py

Issue 23753008: Add json output for gclient. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Fix nits Created 7 years, 3 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 | gclient_scm.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 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 # Files 7 # Files
8 # .gclient : Current client configuration, written by 'config' command. 8 # .gclient : Current client configuration, written by 'config' command.
9 # Format is a Python script defining 'solutions', a list whose 9 # Format is a Python script defining 'solutions', a list whose
10 # entries each are maps binding the strings "name" and "url" 10 # entries each are maps binding the strings "name" and "url"
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 # If the "target_os_only" key is also present and true, then *only* the 66 # If the "target_os_only" key is also present and true, then *only* the
67 # operating systems listed in "target_os" will be used. 67 # operating systems listed in "target_os" will be used.
68 # 68 #
69 # Example: 69 # Example:
70 # target_os = [ "ios" ] 70 # target_os = [ "ios" ]
71 # target_os_only = True 71 # target_os_only = True
72 72
73 __version__ = '0.7' 73 __version__ = '0.7'
74 74
75 import copy 75 import copy
76 import json
76 import logging 77 import logging
77 import optparse 78 import optparse
78 import os 79 import os
79 import platform 80 import platform
80 import posixpath 81 import posixpath
81 import pprint 82 import pprint
82 import re 83 import re
83 import sys 84 import sys
84 import time 85 import time
85 import urllib 86 import urllib
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 # If it is not set to True, the dependency wasn't processed for its child 295 # If it is not set to True, the dependency wasn't processed for its child
295 # dependency, i.e. its DEPS wasn't read. 296 # dependency, i.e. its DEPS wasn't read.
296 self._deps_parsed = False 297 self._deps_parsed = False
297 # This dependency has been processed, i.e. checked out 298 # This dependency has been processed, i.e. checked out
298 self._processed = False 299 self._processed = False
299 # This dependency had its hook run 300 # This dependency had its hook run
300 self._hooks_ran = False 301 self._hooks_ran = False
301 # This is the scm used to checkout self.url. It may be used by dependencies 302 # This is the scm used to checkout self.url. It may be used by dependencies
302 # to get the datetime of the revision we checked out. 303 # to get the datetime of the revision we checked out.
303 self._used_scm = None 304 self._used_scm = None
305 # The actual revision we ended up getting, or None if that information is
306 # unavailable
307 self._got_revision = None
304 308
305 if not self.name and self.parent: 309 if not self.name and self.parent:
306 raise gclient_utils.Error('Dependency without name') 310 raise gclient_utils.Error('Dependency without name')
307 311
308 @property 312 @property
309 def requirements(self): 313 def requirements(self):
310 """Calculate the list of requirements.""" 314 """Calculate the list of requirements."""
311 requirements = set() 315 requirements = set()
312 # self.parent is implicitly a requirement. This will be recursive by 316 # self.parent is implicitly a requirement. This will be recursive by
313 # definition. 317 # definition.
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
617 self._used_scm.RunCommand('updatesingle', 621 self._used_scm.RunCommand('updatesingle',
618 options, args + [parsed_url.GetFilename()], file_list) 622 options, args + [parsed_url.GetFilename()], file_list)
619 else: 623 else:
620 # Create a shallow copy to mutate revision. 624 # Create a shallow copy to mutate revision.
621 options = copy.copy(options) 625 options = copy.copy(options)
622 options.revision = revision_overrides.get(self.name) 626 options.revision = revision_overrides.get(self.name)
623 self.maybeGetParentRevision( 627 self.maybeGetParentRevision(
624 command, options, parsed_url, self.parent.name, revision_overrides) 628 command, options, parsed_url, self.parent.name, revision_overrides)
625 self._used_scm = gclient_scm.CreateSCM( 629 self._used_scm = gclient_scm.CreateSCM(
626 parsed_url, self.root.root_dir, self.name) 630 parsed_url, self.root.root_dir, self.name)
627 self._used_scm.RunCommand(command, options, args, file_list) 631 self._got_revision = self._used_scm.RunCommand(command, options, args,
632 file_list)
628 if file_list: 633 if file_list:
629 file_list = [os.path.join(self.name, f.strip()) for f in file_list] 634 file_list = [os.path.join(self.name, f.strip()) for f in file_list]
630 635
631 # TODO(phajdan.jr): We should know exactly when the paths are absolute. 636 # TODO(phajdan.jr): We should know exactly when the paths are absolute.
632 # Convert all absolute paths to relative. 637 # Convert all absolute paths to relative.
633 for i in range(len(file_list or [])): 638 for i in range(len(file_list or [])):
634 # It depends on the command being executed (like runhooks vs sync). 639 # It depends on the command being executed (like runhooks vs sync).
635 if not os.path.isabs(file_list[i]): 640 if not os.path.isabs(file_list[i]):
636 continue 641 continue
637 prefix = os.path.commonprefix( 642 prefix = os.path.commonprefix(
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
848 @gclient_utils.lockedmethod 853 @gclient_utils.lockedmethod
849 def file_list(self): 854 def file_list(self):
850 return tuple(self._file_list) 855 return tuple(self._file_list)
851 856
852 @property 857 @property
853 def used_scm(self): 858 def used_scm(self):
854 """SCMWrapper instance for this dependency or None if not processed yet.""" 859 """SCMWrapper instance for this dependency or None if not processed yet."""
855 return self._used_scm 860 return self._used_scm
856 861
857 @property 862 @property
863 @gclient_utils.lockedmethod
864 def got_revision(self):
865 return self._got_revision
866
867 @property
858 def file_list_and_children(self): 868 def file_list_and_children(self):
859 result = list(self.file_list) 869 result = list(self.file_list)
860 for d in self.dependencies: 870 for d in self.dependencies:
861 result.extend(d.file_list_and_children) 871 result.extend(d.file_list_and_children)
862 return tuple(result) 872 return tuple(result)
863 873
864 def __str__(self): 874 def __str__(self):
865 out = [] 875 out = []
866 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', 876 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps',
867 'custom_vars', 'deps_hooks', 'file_list', 'should_process', 877 'custom_vars', 'deps_hooks', 'file_list', 'should_process',
(...skipping 648 matching lines...) Expand 10 before | Expand all | Expand 10 after
1516 1526
1517 @subcommand.epilog("""Examples: 1527 @subcommand.epilog("""Examples:
1518 gclient sync 1528 gclient sync
1519 update files from SCM according to current configuration, 1529 update files from SCM according to current configuration,
1520 *for modules which have changed since last update or sync* 1530 *for modules which have changed since last update or sync*
1521 gclient sync --force 1531 gclient sync --force
1522 update files from SCM according to current configuration, for 1532 update files from SCM according to current configuration, for
1523 all modules (useful for recovering files deleted from local copy) 1533 all modules (useful for recovering files deleted from local copy)
1524 gclient sync --revision src@31000 1534 gclient sync --revision src@31000
1525 update src directory to r31000 1535 update src directory to r31000
1536
1537 JSON output format:
1538 If the --output-json option is specified, the following document structure will
1539 be emitted to the provided file. 'null' entries may occur for subprojects which
1540 are present in the gclient solution, but were not processed (due to custom_deps,
1541 os_deps, etc.)
1542
1543 {
1544 "solutions" : {
1545 "<name>": { # <name> is the posix-normalized path to the solution.
1546 "revision": [<svn rev int>|<git id hex string>|null],
1547 "scm": ["svn"|"git"|null],
1548 }
1549 }
1550 }
1526 """) 1551 """)
1527 def CMDsync(parser, args): 1552 def CMDsync(parser, args):
1528 """Checkout/update all modules.""" 1553 """Checkout/update all modules."""
1529 parser.add_option('-f', '--force', action='store_true', 1554 parser.add_option('-f', '--force', action='store_true',
1530 help='force update even for unchanged modules') 1555 help='force update even for unchanged modules')
1531 parser.add_option('-n', '--nohooks', action='store_true', 1556 parser.add_option('-n', '--nohooks', action='store_true',
1532 help='don\'t run hooks after the update is complete') 1557 help='don\'t run hooks after the update is complete')
1533 parser.add_option('-r', '--revision', action='append', 1558 parser.add_option('-r', '--revision', action='append',
1534 dest='revisions', metavar='REV', default=[], 1559 dest='revisions', metavar='REV', default=[],
1535 help='Enforces revision/hash for the solutions with the ' 1560 help='Enforces revision/hash for the solutions with the '
(...skipping 30 matching lines...) Expand all
1566 'fast-forward or rebase') 1591 'fast-forward or rebase')
1567 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', 1592 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
1568 help='override deps for the specified (comma-separated) ' 1593 help='override deps for the specified (comma-separated) '
1569 'platform(s); \'all\' will process all deps_os ' 1594 'platform(s); \'all\' will process all deps_os '
1570 'references') 1595 'references')
1571 parser.add_option('-m', '--manually_grab_svn_rev', action='store_true', 1596 parser.add_option('-m', '--manually_grab_svn_rev', action='store_true',
1572 help='Skip svn up whenever possible by requesting ' 1597 help='Skip svn up whenever possible by requesting '
1573 'actual HEAD revision from the repository') 1598 'actual HEAD revision from the repository')
1574 parser.add_option('--upstream', action='store_true', 1599 parser.add_option('--upstream', action='store_true',
1575 help='Make repo state match upstream branch.') 1600 help='Make repo state match upstream branch.')
1601 parser.add_option('--output-json',
1602 help='Output a json document to this path containing '
1603 'summary information about the sync.')
1576 (options, args) = parser.parse_args(args) 1604 (options, args) = parser.parse_args(args)
1577 client = GClient.LoadCurrentConfig(options) 1605 client = GClient.LoadCurrentConfig(options)
1578 1606
1579 if not client: 1607 if not client:
1580 raise gclient_utils.Error('client not configured; see \'gclient config\'') 1608 raise gclient_utils.Error('client not configured; see \'gclient config\'')
1581 1609
1582 if options.revisions and options.head: 1610 if options.revisions and options.head:
1583 # TODO(maruel): Make it a parser.error if it doesn't break any builder. 1611 # TODO(maruel): Make it a parser.error if it doesn't break any builder.
1584 print('Warning: you cannot use both --head and --revision') 1612 print('Warning: you cannot use both --head and --revision')
1585 1613
1586 if options.verbose: 1614 if options.verbose:
1587 # Print out the .gclient file. This is longer than if we just printed the 1615 # Print out the .gclient file. This is longer than if we just printed the
1588 # client dict, but more legible, and it might contain helpful comments. 1616 # client dict, but more legible, and it might contain helpful comments.
1589 print(client.config_content) 1617 print(client.config_content)
1590 return client.RunOnDeps('update', args) 1618 ret = client.RunOnDeps('update', args)
1619 if options.output_json:
1620 slns = {}
1621 for d in client.subtree(True):
1622 normed = d.name.replace('\\', '/').rstrip('/') + '/'
1623 slns[normed] = {
1624 'revision': d.got_revision,
1625 'scm': d.used_scm.name if d.used_scm else None,
1626 }
1627 with open(options.output_json, 'wb') as f:
1628 json.dump({'solutions': slns}, f)
1629 return ret
1591 1630
1592 1631
1593 CMDupdate = CMDsync 1632 CMDupdate = CMDsync
1594 1633
1595 1634
1596 def CMDdiff(parser, args): 1635 def CMDdiff(parser, args):
1597 """Displays local diff for every dependencies.""" 1636 """Displays local diff for every dependencies."""
1598 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', 1637 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
1599 help='override deps for the specified (comma-separated) ' 1638 help='override deps for the specified (comma-separated) '
1600 'platform(s); \'all\' will process all deps_os ' 1639 'platform(s); \'all\' will process all deps_os '
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
1797 raise 1836 raise
1798 except (gclient_utils.Error, subprocess2.CalledProcessError), e: 1837 except (gclient_utils.Error, subprocess2.CalledProcessError), e:
1799 print >> sys.stderr, 'Error: %s' % str(e) 1838 print >> sys.stderr, 'Error: %s' % str(e)
1800 return 1 1839 return 1
1801 1840
1802 1841
1803 if '__main__' == __name__: 1842 if '__main__' == __name__:
1804 sys.exit(Main(sys.argv[1:])) 1843 sys.exit(Main(sys.argv[1:]))
1805 1844
1806 # vim: ts=2:sw=2:tw=80:et: 1845 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « no previous file | gclient_scm.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698