The Android Open Source Project | cf31fe9 | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 1 | # Copyright (C) 2008 The Android Open Source Project |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | |
Mike Frysinger | 8dbc07a | 2021-02-18 23:37:33 -0500 | [diff] [blame] | 15 | import functools |
Mike Frysinger | 6447733 | 2023-08-21 21:20:32 -0400 | [diff] [blame] | 16 | from typing import NamedTuple |
Simran Basi | b9a1b73 | 2015-08-20 12:19:28 -0700 | [diff] [blame] | 17 | |
Mike Frysinger | 6447733 | 2023-08-21 21:20:32 -0400 | [diff] [blame] | 18 | from command import Command |
| 19 | from command import DEFAULT_LOCAL_JOBS |
| 20 | from error import RepoExitError |
The Android Open Source Project | cf31fe9 | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 21 | from git_command import git |
Mike Frysinger | 6447733 | 2023-08-21 21:20:32 -0400 | [diff] [blame] | 22 | from git_config import IsImmutable |
Shawn O. Pearce | 0f0dfa3 | 2009-04-18 14:53:39 -0700 | [diff] [blame] | 23 | from progress import Progress |
Jason Chang | 8914b1f | 2023-05-26 12:44:50 -0700 | [diff] [blame] | 24 | from project import Project |
Aravind Vasudevan | 5771897 | 2023-09-06 18:01:20 +0000 | [diff] [blame] | 25 | from repo_logging import RepoLogger |
| 26 | |
| 27 | |
| 28 | logger = RepoLogger(__file__) |
Jason Chang | 1a3612f | 2023-08-08 14:12:53 -0700 | [diff] [blame] | 29 | |
| 30 | |
| 31 | class ExecuteOneResult(NamedTuple): |
| 32 | project: Project |
| 33 | error: Exception |
| 34 | |
| 35 | |
| 36 | class StartError(RepoExitError): |
| 37 | """Exit error for failed start command.""" |
The Android Open Source Project | cf31fe9 | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 38 | |
David Pursehouse | 819827a | 2020-02-12 15:20:19 +0900 | [diff] [blame] | 39 | |
The Android Open Source Project | cf31fe9 | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 40 | class Start(Command): |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 41 | COMMON = True |
| 42 | helpSummary = "Start a new branch for development" |
| 43 | helpUsage = """ |
Ficus Kirkpatrick | 6f6cd77 | 2009-04-22 17:27:12 -0700 | [diff] [blame] | 44 | %prog <newbranchname> [--all | <project>...] |
Shawn O. Pearce | 06e556d | 2009-04-18 11:19:01 -0700 | [diff] [blame] | 45 | """ |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 46 | helpDescription = """ |
Shawn O. Pearce | 06e556d | 2009-04-18 11:19:01 -0700 | [diff] [blame] | 47 | '%prog' begins a new branch of development, starting from the |
| 48 | revision specified in the manifest. |
The Android Open Source Project | cf31fe9 | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 49 | """ |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 50 | PARALLEL_JOBS = DEFAULT_LOCAL_JOBS |
The Android Open Source Project | cf31fe9 | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 51 | |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 52 | def _Options(self, p): |
| 53 | p.add_option( |
| 54 | "--all", |
| 55 | dest="all", |
| 56 | action="store_true", |
| 57 | help="begin branch in all projects", |
| 58 | ) |
| 59 | p.add_option( |
| 60 | "-r", |
| 61 | "--rev", |
| 62 | "--revision", |
| 63 | dest="revision", |
| 64 | help="point branch at this revision instead of upstream", |
| 65 | ) |
| 66 | p.add_option( |
| 67 | "--head", |
| 68 | "--HEAD", |
| 69 | dest="revision", |
| 70 | action="store_const", |
| 71 | const="HEAD", |
| 72 | help="abbreviation for --rev HEAD", |
| 73 | ) |
Ficus Kirkpatrick | 6f6cd77 | 2009-04-22 17:27:12 -0700 | [diff] [blame] | 74 | |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 75 | def ValidateOptions(self, opt, args): |
| 76 | if not args: |
| 77 | self.Usage() |
The Android Open Source Project | cf31fe9 | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 78 | |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 79 | nb = args[0] |
| 80 | if not git.check_ref_format("heads/%s" % nb): |
| 81 | self.OptionParser.error("'%s' is not a valid name" % nb) |
The Android Open Source Project | cf31fe9 | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 82 | |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 83 | def _ExecuteOne(self, revision, nb, project): |
| 84 | """Start one project.""" |
| 85 | # If the current revision is immutable, such as a SHA1, a tag or |
| 86 | # a change, then we can't push back to it. Substitute with |
| 87 | # dest_branch, if defined; or with manifest default revision instead. |
| 88 | branch_merge = "" |
Jason Chang | 1a3612f | 2023-08-08 14:12:53 -0700 | [diff] [blame] | 89 | error = None |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 90 | if IsImmutable(project.revisionExpr): |
| 91 | if project.dest_branch: |
| 92 | branch_merge = project.dest_branch |
| 93 | else: |
| 94 | branch_merge = self.manifest.default.revisionExpr |
Mike Frysinger | 8dbc07a | 2021-02-18 23:37:33 -0500 | [diff] [blame] | 95 | |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 96 | try: |
Jason Chang | 1a3612f | 2023-08-08 14:12:53 -0700 | [diff] [blame] | 97 | project.StartBranch( |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 98 | nb, branch_merge=branch_merge, revision=revision |
| 99 | ) |
| 100 | except Exception as e: |
Aravind Vasudevan | 5771897 | 2023-09-06 18:01:20 +0000 | [diff] [blame] | 101 | logger.error("error: unable to checkout %s: %s", project.name, e) |
Jason Chang | 1a3612f | 2023-08-08 14:12:53 -0700 | [diff] [blame] | 102 | error = e |
| 103 | return ExecuteOneResult(project, error) |
Mike Frysinger | 8dbc07a | 2021-02-18 23:37:33 -0500 | [diff] [blame] | 104 | |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 105 | def Execute(self, opt, args): |
| 106 | nb = args[0] |
Jason Chang | 1a3612f | 2023-08-08 14:12:53 -0700 | [diff] [blame] | 107 | err_projects = [] |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 108 | err = [] |
| 109 | projects = [] |
| 110 | if not opt.all: |
| 111 | projects = args[1:] |
| 112 | if len(projects) < 1: |
| 113 | projects = ["."] # start it in the local project by default |
Ficus Kirkpatrick | 6f6cd77 | 2009-04-22 17:27:12 -0700 | [diff] [blame] | 114 | |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 115 | all_projects = self.GetProjects( |
| 116 | projects, |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 117 | all_manifests=not opt.this_manifest_only, |
| 118 | ) |
Dan Willemsen | 04197a5 | 2015-10-07 16:53:10 -0700 | [diff] [blame] | 119 | |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 120 | def _ProcessResults(_pool, pm, results): |
Jason Chang | 1a3612f | 2023-08-08 14:12:53 -0700 | [diff] [blame] | 121 | for result in results: |
| 122 | if result.error: |
| 123 | err_projects.append(result.project) |
| 124 | err.append(result.error) |
Gavin Mak | 551285f | 2023-05-04 04:48:43 +0000 | [diff] [blame] | 125 | pm.update(msg="") |
Dan Willemsen | 5ea32d1 | 2015-09-08 13:27:20 -0700 | [diff] [blame] | 126 | |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 127 | self.ExecuteInParallel( |
| 128 | opt.jobs, |
| 129 | functools.partial(self._ExecuteOne, opt.revision, nb), |
| 130 | all_projects, |
| 131 | callback=_ProcessResults, |
| 132 | output=Progress( |
Jason R. Coombs | b32ccbb | 2023-09-29 11:04:49 -0400 | [diff] [blame] | 133 | f"Starting {nb}", len(all_projects), quiet=opt.quiet |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 134 | ), |
| 135 | ) |
Shawn O. Pearce | 0a389e9 | 2009-04-10 16:21:18 -0700 | [diff] [blame] | 136 | |
Jason Chang | 1a3612f | 2023-08-08 14:12:53 -0700 | [diff] [blame] | 137 | if err_projects: |
| 138 | for p in err_projects: |
Aravind Vasudevan | 5771897 | 2023-09-06 18:01:20 +0000 | [diff] [blame] | 139 | logger.error( |
| 140 | "error: %s/: cannot start %s", |
| 141 | p.RelPath(local=opt.this_manifest_only), |
| 142 | nb, |
Gavin Mak | ea2e330 | 2023-03-11 06:46:20 +0000 | [diff] [blame] | 143 | ) |
Josip Sokcevic | 131fc96 | 2023-05-12 17:00:46 -0700 | [diff] [blame] | 144 | msg_fmt = "cannot start %d project(s)" |
Jason Chang | 1a3612f | 2023-08-08 14:12:53 -0700 | [diff] [blame] | 145 | self.git_event_log.ErrorEvent( |
| 146 | msg_fmt % (len(err_projects)), msg_fmt |
| 147 | ) |
| 148 | raise StartError(aggregate_errors=err) |