diff options
Diffstat (limited to 'command.py')
-rw-r--r-- | command.py | 84 |
1 files changed, 70 insertions, 14 deletions
@@ -61,13 +61,21 @@ class Command(object): | |||
61 | # it is the number of parallel jobs to default to. | 61 | # it is the number of parallel jobs to default to. |
62 | PARALLEL_JOBS = None | 62 | PARALLEL_JOBS = None |
63 | 63 | ||
64 | # Whether this command supports Multi-manifest. If False, then main.py will | ||
65 | # iterate over the manifests and invoke the command once per (sub)manifest. | ||
66 | # This is only checked after calling ValidateOptions, so that partially | ||
67 | # migrated subcommands can set it to False. | ||
68 | MULTI_MANIFEST_SUPPORT = True | ||
69 | |||
64 | def __init__(self, repodir=None, client=None, manifest=None, gitc_manifest=None, | 70 | def __init__(self, repodir=None, client=None, manifest=None, gitc_manifest=None, |
65 | git_event_log=None): | 71 | git_event_log=None, outer_client=None, outer_manifest=None): |
66 | self.repodir = repodir | 72 | self.repodir = repodir |
67 | self.client = client | 73 | self.client = client |
74 | self.outer_client = outer_client or client | ||
68 | self.manifest = manifest | 75 | self.manifest = manifest |
69 | self.gitc_manifest = gitc_manifest | 76 | self.gitc_manifest = gitc_manifest |
70 | self.git_event_log = git_event_log | 77 | self.git_event_log = git_event_log |
78 | self.outer_manifest = outer_manifest | ||
71 | 79 | ||
72 | # Cache for the OptionParser property. | 80 | # Cache for the OptionParser property. |
73 | self._optparse = None | 81 | self._optparse = None |
@@ -135,6 +143,18 @@ class Command(object): | |||
135 | type=int, default=self.PARALLEL_JOBS, | 143 | type=int, default=self.PARALLEL_JOBS, |
136 | help=f'number of jobs to run in parallel (default: {default})') | 144 | help=f'number of jobs to run in parallel (default: {default})') |
137 | 145 | ||
146 | m = p.add_option_group('Multi-manifest options') | ||
147 | m.add_option('--outer-manifest', action='store_true', | ||
148 | help='operate starting at the outermost manifest') | ||
149 | m.add_option('--no-outer-manifest', dest='outer_manifest', | ||
150 | action='store_false', default=None, | ||
151 | help='do not operate on outer manifests') | ||
152 | m.add_option('--this-manifest-only', action='store_true', default=None, | ||
153 | help='only operate on this (sub)manifest') | ||
154 | m.add_option('--no-this-manifest-only', '--all-manifests', | ||
155 | dest='this_manifest_only', action='store_false', | ||
156 | help='operate on this manifest and its submanifests') | ||
157 | |||
138 | def _Options(self, p): | 158 | def _Options(self, p): |
139 | """Initialize the option parser with subcommand-specific options.""" | 159 | """Initialize the option parser with subcommand-specific options.""" |
140 | 160 | ||
@@ -252,16 +272,19 @@ class Command(object): | |||
252 | return project | 272 | return project |
253 | 273 | ||
254 | def GetProjects(self, args, manifest=None, groups='', missing_ok=False, | 274 | def GetProjects(self, args, manifest=None, groups='', missing_ok=False, |
255 | submodules_ok=False): | 275 | submodules_ok=False, all_manifests=False): |
256 | """A list of projects that match the arguments. | 276 | """A list of projects that match the arguments. |
257 | """ | 277 | """ |
258 | if not manifest: | 278 | if all_manifests: |
259 | manifest = self.manifest | 279 | if not manifest: |
260 | all_projects_list = manifest.projects | 280 | manifest = self.manifest.outer_client |
281 | all_projects_list = manifest.all_projects | ||
282 | else: | ||
283 | if not manifest: | ||
284 | manifest = self.manifest | ||
285 | all_projects_list = manifest.projects | ||
261 | result = [] | 286 | result = [] |
262 | 287 | ||
263 | mp = manifest.manifestProject | ||
264 | |||
265 | if not groups: | 288 | if not groups: |
266 | groups = manifest.GetGroupsStr() | 289 | groups = manifest.GetGroupsStr() |
267 | groups = [x for x in re.split(r'[,\s]+', groups) if x] | 290 | groups = [x for x in re.split(r'[,\s]+', groups) if x] |
@@ -282,12 +305,19 @@ class Command(object): | |||
282 | for arg in args: | 305 | for arg in args: |
283 | # We have to filter by manifest groups in case the requested project is | 306 | # We have to filter by manifest groups in case the requested project is |
284 | # checked out multiple times or differently based on them. | 307 | # checked out multiple times or differently based on them. |
285 | projects = [project for project in manifest.GetProjectsWithName(arg) | 308 | projects = [project for project in manifest.GetProjectsWithName( |
309 | arg, all_manifests=all_manifests) | ||
286 | if project.MatchesGroups(groups)] | 310 | if project.MatchesGroups(groups)] |
287 | 311 | ||
288 | if not projects: | 312 | if not projects: |
289 | path = os.path.abspath(arg).replace('\\', '/') | 313 | path = os.path.abspath(arg).replace('\\', '/') |
290 | project = self._GetProjectByPath(manifest, path) | 314 | tree = manifest |
315 | if all_manifests: | ||
316 | # Look for the deepest matching submanifest. | ||
317 | for tree in reversed(list(manifest.all_manifests)): | ||
318 | if path.startswith(tree.topdir): | ||
319 | break | ||
320 | project = self._GetProjectByPath(tree, path) | ||
291 | 321 | ||
292 | # If it's not a derived project, update path->project mapping and | 322 | # If it's not a derived project, update path->project mapping and |
293 | # search again, as arg might actually point to a derived subproject. | 323 | # search again, as arg might actually point to a derived subproject. |
@@ -308,7 +338,8 @@ class Command(object): | |||
308 | 338 | ||
309 | for project in projects: | 339 | for project in projects: |
310 | if not missing_ok and not project.Exists: | 340 | if not missing_ok and not project.Exists: |
311 | raise NoSuchProjectError('%s (%s)' % (arg, project.relpath)) | 341 | raise NoSuchProjectError('%s (%s)' % ( |
342 | arg, project.RelPath(local=not all_manifests))) | ||
312 | if not project.MatchesGroups(groups): | 343 | if not project.MatchesGroups(groups): |
313 | raise InvalidProjectGroupsError(arg) | 344 | raise InvalidProjectGroupsError(arg) |
314 | 345 | ||
@@ -319,12 +350,22 @@ class Command(object): | |||
319 | result.sort(key=_getpath) | 350 | result.sort(key=_getpath) |
320 | return result | 351 | return result |
321 | 352 | ||
322 | def FindProjects(self, args, inverse=False): | 353 | def FindProjects(self, args, inverse=False, all_manifests=False): |
354 | """Find projects from command line arguments. | ||
355 | |||
356 | Args: | ||
357 | args: a list of (case-insensitive) strings, projects to search for. | ||
358 | inverse: a boolean, if True, then projects not matching any |args| are | ||
359 | returned. | ||
360 | all_manifests: a boolean, if True then all manifests and submanifests are | ||
361 | used. If False, then only the local (sub)manifest is used. | ||
362 | """ | ||
323 | result = [] | 363 | result = [] |
324 | patterns = [re.compile(r'%s' % a, re.IGNORECASE) for a in args] | 364 | patterns = [re.compile(r'%s' % a, re.IGNORECASE) for a in args] |
325 | for project in self.GetProjects(''): | 365 | for project in self.GetProjects('', all_manifests=all_manifests): |
366 | paths = [project.name, project.RelPath(local=not all_manifests)] | ||
326 | for pattern in patterns: | 367 | for pattern in patterns: |
327 | match = pattern.search(project.name) or pattern.search(project.relpath) | 368 | match = any(pattern.search(x) for x in paths) |
328 | if not inverse and match: | 369 | if not inverse and match: |
329 | result.append(project) | 370 | result.append(project) |
330 | break | 371 | break |
@@ -333,9 +374,24 @@ class Command(object): | |||
333 | else: | 374 | else: |
334 | if inverse: | 375 | if inverse: |
335 | result.append(project) | 376 | result.append(project) |
336 | result.sort(key=lambda project: project.relpath) | 377 | result.sort(key=lambda project: (project.manifest.path_prefix, |
378 | project.relpath)) | ||
337 | return result | 379 | return result |
338 | 380 | ||
381 | def ManifestList(self, opt): | ||
382 | """Yields all of the manifests to traverse. | ||
383 | |||
384 | Args: | ||
385 | opt: The command options. | ||
386 | """ | ||
387 | top = self.outer_manifest | ||
388 | if opt.outer_manifest is False or opt.this_manifest_only: | ||
389 | top = self.manifest | ||
390 | yield top | ||
391 | if not opt.this_manifest_only: | ||
392 | for child in top.all_children: | ||
393 | yield child | ||
394 | |||
339 | 395 | ||
340 | class InteractiveCommand(Command): | 396 | class InteractiveCommand(Command): |
341 | """Command which requires user interaction on the tty and | 397 | """Command which requires user interaction on the tty and |