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

Side by Side Diff: gclient.py

Issue 11312116: Add gclient grep for git repos (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 8 years, 1 month 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_utils.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 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 600 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 for i in range(len(file_list)): 611 for i in range(len(file_list)):
612 # It depends on the command being executed (like runhooks vs sync). 612 # It depends on the command being executed (like runhooks vs sync).
613 if not os.path.isabs(file_list[i]): 613 if not os.path.isabs(file_list[i]):
614 continue 614 continue
615 prefix = os.path.commonprefix( 615 prefix = os.path.commonprefix(
616 [self.root.root_dir.lower(), file_list[i].lower()]) 616 [self.root.root_dir.lower(), file_list[i].lower()])
617 file_list[i] = file_list[i][len(prefix):] 617 file_list[i] = file_list[i][len(prefix):]
618 # Strip any leading path separators. 618 # Strip any leading path separators.
619 while file_list[i].startswith(('\\', '/')): 619 while file_list[i].startswith(('\\', '/')):
620 file_list[i] = file_list[i][1:] 620 file_list[i] = file_list[i][1:]
621 elif command == 'recurse': 621
622 # Always parse the DEPS file.
623 self.ParseDepsFile()
624
625 self._run_is_done(file_list, parsed_url)
626
627 if self.recursion_limit:
628 # Parse the dependencies of this dependency.
629 for s in self.dependencies:
630 work_queue.enqueue(s)
631
632 if command == 'recurse':
622 if not isinstance(parsed_url, self.FileImpl): 633 if not isinstance(parsed_url, self.FileImpl):
623 # Skip file only checkout. 634 # Skip file only checkout.
624 scm = gclient_scm.GetScmName(parsed_url) 635 scm = gclient_scm.GetScmName(parsed_url)
625 if not options.scm or scm in options.scm: 636 if not options.scm or scm in options.scm:
626 cwd = os.path.normpath(os.path.join(self.root.root_dir, self.name)) 637 cwd = os.path.normpath(os.path.join(self.root.root_dir, self.name))
627 # Pass in the SCM type as an env variable 638 # Pass in the SCM type as an env variable
628 env = os.environ.copy() 639 env = os.environ.copy()
629 if scm: 640 if scm:
630 env['GCLIENT_SCM'] = scm 641 env['GCLIENT_SCM'] = scm
631 if parsed_url: 642 if parsed_url:
632 env['GCLIENT_URL'] = parsed_url 643 env['GCLIENT_URL'] = parsed_url
644 if options.prepend_dir:
645 print_stdout = False
646 def filter_fn(line):
647 items = line.split('\0')
648 if len(items) == 1:
649 match = re.match('Binary file (.*) matches$', line)
650 if match:
651 print 'Binary file %s matches' % os.path.join(
652 self.name, match.group(1))
653 else:
654 print line
655 elif len(items) == 2 and items[1]:
656 print '%s : %s' % (os.path.join(self.name, items[0]), items[1])
657 else:
658 # Multiple null bytes or a single trailing null byte indicate
659 # git is likely displaying filenames only (such as with -l)
660 print '\n'.join(os.path.join(self.name, f) for f in items if f)
661 else:
662 print_stdout = True
663 filter_fn = None
664
633 if os.path.isdir(cwd): 665 if os.path.isdir(cwd):
634 try: 666 try:
635 gclient_utils.CheckCallAndFilter( 667 gclient_utils.CheckCallAndFilter(
636 args, cwd=cwd, env=env, print_stdout=True) 668 args, cwd=cwd, env=env, print_stdout=print_stdout,
669 filter_fn=filter_fn,
670 )
637 except subprocess2.CalledProcessError: 671 except subprocess2.CalledProcessError:
638 if not options.ignore: 672 if not options.ignore:
639 raise 673 raise
640 else: 674 else:
641 print >> sys.stderr, 'Skipped missing %s' % cwd 675 print >> sys.stderr, 'Skipped missing %s' % cwd
642 676
643 # Always parse the DEPS file.
644 self.ParseDepsFile()
645
646 self._run_is_done(file_list, parsed_url)
647
648 if self.recursion_limit:
649 # Parse the dependencies of this dependency.
650 for s in self.dependencies:
651 work_queue.enqueue(s)
652 677
653 @gclient_utils.lockedmethod 678 @gclient_utils.lockedmethod
654 def _run_is_done(self, file_list, parsed_url): 679 def _run_is_done(self, file_list, parsed_url):
655 # Both these are kept for hooks that are run as a separate tree traversal. 680 # Both these are kept for hooks that are run as a separate tree traversal.
656 self._file_list = file_list 681 self._file_list = file_list
657 self._parsed_url = parsed_url 682 self._parsed_url = parsed_url
658 self._processed = True 683 self._processed = True
659 684
660 @staticmethod 685 @staticmethod
661 def GetHookAction(hook_dict, matching_file_list): 686 def GetHookAction(hook_dict, matching_file_list):
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after
1043 raise gclient_utils.Error( 1068 raise gclient_utils.Error(
1044 'It appears your safesync_url (%s) is not working properly\n' 1069 'It appears your safesync_url (%s) is not working properly\n'
1045 '(as it returned an empty response). Check your config.' % 1070 '(as it returned an empty response). Check your config.' %
1046 dep.safesync_url) 1071 dep.safesync_url)
1047 scm = gclient_scm.CreateSCM(dep.url, dep.root.root_dir, dep.name) 1072 scm = gclient_scm.CreateSCM(dep.url, dep.root.root_dir, dep.name)
1048 safe_rev = scm.GetUsableRev(rev=rev, options=self._options) 1073 safe_rev = scm.GetUsableRev(rev=rev, options=self._options)
1049 if self._options.verbose: 1074 if self._options.verbose:
1050 print('Using safesync_url revision: %s.\n' % safe_rev) 1075 print('Using safesync_url revision: %s.\n' % safe_rev)
1051 self._options.revisions.append('%s@%s' % (dep.name, safe_rev)) 1076 self._options.revisions.append('%s@%s' % (dep.name, safe_rev))
1052 1077
1053 def RunOnDeps(self, command, args): 1078 def RunOnDeps(self, command, args, ignore_requirements=False, progress=True):
1054 """Runs a command on each dependency in a client and its dependencies. 1079 """Runs a command on each dependency in a client and its dependencies.
1055 1080
1056 Args: 1081 Args:
1057 command: The command to use (e.g., 'status' or 'diff') 1082 command: The command to use (e.g., 'status' or 'diff')
1058 args: list of str - extra arguments to add to the command line. 1083 args: list of str - extra arguments to add to the command line.
1059 """ 1084 """
1060 if not self.dependencies: 1085 if not self.dependencies:
1061 raise gclient_utils.Error('No solution specified') 1086 raise gclient_utils.Error('No solution specified')
1062 revision_overrides = {} 1087 revision_overrides = {}
1063 # It's unnecessary to check for revision overrides for 'recurse'. 1088 # It's unnecessary to check for revision overrides for 'recurse'.
1064 # Save a few seconds by not calling _EnforceRevisions() in that case. 1089 # Save a few seconds by not calling _EnforceRevisions() in that case.
1065 if command not in ('diff', 'recurse', 'runhooks', 'status'): 1090 if command not in ('diff', 'recurse', 'runhooks', 'status'):
1066 revision_overrides = self._EnforceRevisions() 1091 revision_overrides = self._EnforceRevisions()
1067 pm = None 1092 pm = None
1068 # Disable progress for non-tty stdout. 1093 # Disable progress for non-tty stdout.
1069 if (sys.stdout.isatty() and not self._options.verbose): 1094 if (sys.stdout.isatty() and not self._options.verbose and progress):
1070 if command in ('update', 'revert'): 1095 if command in ('update', 'revert'):
1071 pm = Progress('Syncing projects', 1) 1096 pm = Progress('Syncing projects', 1)
1072 elif command == 'recurse': 1097 elif command == 'recurse':
1073 pm = Progress(' '.join(args), 1) 1098 pm = Progress(' '.join(args), 1)
1074 work_queue = gclient_utils.ExecutionQueue(self._options.jobs, pm) 1099 work_queue = gclient_utils.ExecutionQueue(
1100 self._options.jobs, pm, ignore_requirements=ignore_requirements)
1075 for s in self.dependencies: 1101 for s in self.dependencies:
1076 work_queue.enqueue(s) 1102 work_queue.enqueue(s)
1077 work_queue.flush(revision_overrides, command, args, options=self._options) 1103 work_queue.flush(revision_overrides, command, args, options=self._options)
1078 1104
1079 # Once all the dependencies have been processed, it's now safe to run the 1105 # Once all the dependencies have been processed, it's now safe to run the
1080 # hooks. 1106 # hooks.
1081 if not self._options.nohooks: 1107 if not self._options.nohooks:
1082 self.RunHooksRecursively(self._options) 1108 self.RunHooksRecursively(self._options)
1083 1109
1084 if command == 'update': 1110 if command == 'update':
(...skipping 27 matching lines...) Expand all
1112 entry_fixed, self.root_dir)) 1138 entry_fixed, self.root_dir))
1113 gclient_utils.RemoveDirectory(e_dir) 1139 gclient_utils.RemoveDirectory(e_dir)
1114 # record the current list of entries for next time 1140 # record the current list of entries for next time
1115 self._SaveEntries() 1141 self._SaveEntries()
1116 return 0 1142 return 0
1117 1143
1118 def PrintRevInfo(self): 1144 def PrintRevInfo(self):
1119 if not self.dependencies: 1145 if not self.dependencies:
1120 raise gclient_utils.Error('No solution specified') 1146 raise gclient_utils.Error('No solution specified')
1121 # Load all the settings. 1147 # Load all the settings.
1122 work_queue = gclient_utils.ExecutionQueue(self._options.jobs, None) 1148 work_queue = gclient_utils.ExecutionQueue(self._options.jobs, None, False)
1123 for s in self.dependencies: 1149 for s in self.dependencies:
1124 work_queue.enqueue(s) 1150 work_queue.enqueue(s)
1125 work_queue.flush({}, None, [], options=self._options) 1151 work_queue.flush({}, None, [], options=self._options)
1126 1152
1127 def GetURLAndRev(dep): 1153 def GetURLAndRev(dep):
1128 """Returns the revision-qualified SCM url for a Dependency.""" 1154 """Returns the revision-qualified SCM url for a Dependency."""
1129 if dep.parsed_url is None: 1155 if dep.parsed_url is None:
1130 return None 1156 return None
1131 if isinstance(dep.parsed_url, self.FileImpl): 1157 if isinstance(dep.parsed_url, self.FileImpl):
1132 original_url = dep.parsed_url.file_location 1158 original_url = dep.parsed_url.file_location
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1227 1253
1228 @attr('usage', '[command] [args ...]') 1254 @attr('usage', '[command] [args ...]')
1229 def CMDrecurse(parser, args): 1255 def CMDrecurse(parser, args):
1230 """Operates on all the entries. 1256 """Operates on all the entries.
1231 1257
1232 Runs a shell command on all entries. 1258 Runs a shell command on all entries.
1233 """ 1259 """
1234 # Stop parsing at the first non-arg so that these go through to the command 1260 # Stop parsing at the first non-arg so that these go through to the command
1235 parser.disable_interspersed_args() 1261 parser.disable_interspersed_args()
1236 parser.add_option('-s', '--scm', action='append', default=[], 1262 parser.add_option('-s', '--scm', action='append', default=[],
1237 help='choose scm types to operate upon') 1263 help='Choose scm types to operate upon.')
1238 parser.add_option('-i', '--ignore', action='store_true', 1264 parser.add_option('-i', '--ignore', action='store_true',
1239 help='continue processing in case of non zero return code') 1265 help='Ignore non-zero return codes from subcommands.')
1266 parser.add_option('--prepend-dir', action='store_true',
1267 help='Prepend relative dir for use with git <cmd> --null.')
1268 parser.add_option('--no-progress', action='store_true',
1269 help='Disable progress bar that shows sub-command updates')
1240 options, args = parser.parse_args(args) 1270 options, args = parser.parse_args(args)
1241 if not args: 1271 if not args:
1242 print >> sys.stderr, 'Need to supply a command!' 1272 print >> sys.stderr, 'Need to supply a command!'
1243 return 1 1273 return 1
1244 root_and_entries = gclient_utils.GetGClientRootAndEntries() 1274 root_and_entries = gclient_utils.GetGClientRootAndEntries()
1245 if not root_and_entries: 1275 if not root_and_entries:
1246 print >> sys.stderr, ( 1276 print >> sys.stderr, (
1247 'You need to run gclient sync at least once to use \'recurse\'.\n' 1277 'You need to run gclient sync at least once to use \'recurse\'.\n'
1248 'This is because .gclient_entries needs to exist and be up to date.') 1278 'This is because .gclient_entries needs to exist and be up to date.')
1249 return 1 1279 return 1
1250 1280
1251 # Normalize options.scm to a set() 1281 # Normalize options.scm to a set()
1252 scm_set = set() 1282 scm_set = set()
1253 for scm in options.scm: 1283 for scm in options.scm:
1254 scm_set.update(scm.split(',')) 1284 scm_set.update(scm.split(','))
1255 options.scm = scm_set 1285 options.scm = scm_set
1256 1286
1257 options.nohooks = True 1287 options.nohooks = True
1258 client = GClient.LoadCurrentConfig(options) 1288 client = GClient.LoadCurrentConfig(options)
1259 return client.RunOnDeps('recurse', args) 1289 return client.RunOnDeps('recurse', args, ignore_requirements=True,
1290 progress=not options.no_progress)
1260 1291
1261 1292
1262 @attr('usage', '[args ...]') 1293 @attr('usage', '[args ...]')
1263 def CMDfetch(parser, args): 1294 def CMDfetch(parser, args):
1264 """Fetches upstream commits for all modules. 1295 """Fetches upstream commits for all modules.
1265 1296
1266 Completely git-specific. Simply runs 'git fetch [args ...]' for each module. 1297 Completely git-specific. Simply runs 'git fetch [args ...]' for each module.
1267 """ 1298 """
1268 (options, args) = parser.parse_args(args) 1299 (options, args) = parser.parse_args(args)
1269 args = ['-j%d' % options.jobs, '-s', 'git', 'git', 'fetch'] + args 1300 return CMDrecurse(Parser(), [
1270 return CMDrecurse(parser, args) 1301 '--jobs=%d' % options.jobs, '--scm=git', 'git', 'fetch'] + args)
1302
1303
1304 def CMDgrep(parser, args):
1305 """Greps through git repos managed by gclient.
1306
1307 Runs 'git grep [args...]' for each module.
1308 """
1309
1310 # We can't use optparse because it will try to parse arguments sent
1311 # to git grep and throw an error. :-(
1312 if not args or re.match('(-h|--help)$', args[0]):
1313 print >> sys.stderr, (
1314 'Usage: gclient grep [-j <N>] git-grep-args...\n\n'
1315 'Example: "gclient grep -j10 -A2 RefCountedBase" runs\n"git grep '
1316 '-A2 RefCountedBase" on each of gclient\'s git\nrepos with up to '
1317 '10 jobs.\n\nBonus: page output by appending "|& less -FRSX" to the'
1318 ' end of your query.'
1319 )
1320 return 1
1321
1322 jobs_arg = ['--jobs=1']
1323 if re.match(r'(-j|--jobs=)\d+$', args[0]):
1324 jobs_arg, args = args[:1], args[1:]
1325 elif re.match(r'(-j|--jobs)$', args[0]):
1326 jobs_arg, args = args[:2], args[2:]
1327
1328 return CMDrecurse(
1329 parser,
1330 jobs_arg + ['--ignore', '--prepend-dir', '--no-progress', '--scm=git',
1331 'git', 'grep', '--null', '--color=Always'] + args)
1271 1332
1272 1333
1273 @attr('usage', '[url] [safesync url]') 1334 @attr('usage', '[url] [safesync url]')
1274 def CMDconfig(parser, args): 1335 def CMDconfig(parser, args):
1275 """Create a .gclient file in the current directory. 1336 """Create a .gclient file in the current directory.
1276 1337
1277 This specifies the configuration for further commands. After update/sync, 1338 This specifies the configuration for further commands. After update/sync,
1278 top-level DEPS files in each module are read to determine dependent 1339 top-level DEPS files in each module are read to determine dependent
1279 modules to operate on as well. If optional [url] parameter is 1340 modules to operate on as well. If optional [url] parameter is
1280 provided, then configuration is read from a specified Subversion server 1341 provided, then configuration is read from a specified Subversion server
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after
1678 except (gclient_utils.Error, subprocess2.CalledProcessError), e: 1739 except (gclient_utils.Error, subprocess2.CalledProcessError), e:
1679 print >> sys.stderr, 'Error: %s' % str(e) 1740 print >> sys.stderr, 'Error: %s' % str(e)
1680 return 1 1741 return 1
1681 1742
1682 1743
1683 if '__main__' == __name__: 1744 if '__main__' == __name__:
1684 fix_encoding.fix_encoding() 1745 fix_encoding.fix_encoding()
1685 sys.exit(Main(sys.argv[1:])) 1746 sys.exit(Main(sys.argv[1:]))
1686 1747
1687 # vim: ts=2:sw=2:tw=80:et: 1748 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « no previous file | gclient_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698