blob: 56008f42a85703f2475d07b1e3f28ecec05a7aca [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001# 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 Frysinger8dbc07a2021-02-18 23:37:33 -050015import functools
Mike Frysinger64477332023-08-21 21:20:32 -040016from typing import NamedTuple
Simran Basib9a1b732015-08-20 12:19:28 -070017
Mike Frysinger64477332023-08-21 21:20:32 -040018from command import Command
19from command import DEFAULT_LOCAL_JOBS
20from error import RepoExitError
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070021from git_command import git
Mike Frysinger64477332023-08-21 21:20:32 -040022from git_config import IsImmutable
Shawn O. Pearce0f0dfa32009-04-18 14:53:39 -070023from progress import Progress
Jason Chang8914b1f2023-05-26 12:44:50 -070024from project import Project
Aravind Vasudevan57718972023-09-06 18:01:20 +000025from repo_logging import RepoLogger
26
27
28logger = RepoLogger(__file__)
Jason Chang1a3612f2023-08-08 14:12:53 -070029
30
31class ExecuteOneResult(NamedTuple):
32 project: Project
33 error: Exception
34
35
36class StartError(RepoExitError):
37 """Exit error for failed start command."""
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070038
David Pursehouse819827a2020-02-12 15:20:19 +090039
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070040class Start(Command):
Gavin Makea2e3302023-03-11 06:46:20 +000041 COMMON = True
42 helpSummary = "Start a new branch for development"
43 helpUsage = """
Ficus Kirkpatrick6f6cd772009-04-22 17:27:12 -070044%prog <newbranchname> [--all | <project>...]
Shawn O. Pearce06e556d2009-04-18 11:19:01 -070045"""
Gavin Makea2e3302023-03-11 06:46:20 +000046 helpDescription = """
Shawn O. Pearce06e556d2009-04-18 11:19:01 -070047'%prog' begins a new branch of development, starting from the
48revision specified in the manifest.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070049"""
Gavin Makea2e3302023-03-11 06:46:20 +000050 PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070051
Gavin Makea2e3302023-03-11 06:46:20 +000052 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 Kirkpatrick6f6cd772009-04-22 17:27:12 -070074
Gavin Makea2e3302023-03-11 06:46:20 +000075 def ValidateOptions(self, opt, args):
76 if not args:
77 self.Usage()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070078
Gavin Makea2e3302023-03-11 06:46:20 +000079 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 Projectcf31fe92008-10-21 07:00:00 -070082
Gavin Makea2e3302023-03-11 06:46:20 +000083 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 Chang1a3612f2023-08-08 14:12:53 -070089 error = None
Gavin Makea2e3302023-03-11 06:46:20 +000090 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 Frysinger8dbc07a2021-02-18 23:37:33 -050095
Gavin Makea2e3302023-03-11 06:46:20 +000096 try:
Jason Chang1a3612f2023-08-08 14:12:53 -070097 project.StartBranch(
Gavin Makea2e3302023-03-11 06:46:20 +000098 nb, branch_merge=branch_merge, revision=revision
99 )
100 except Exception as e:
Aravind Vasudevan57718972023-09-06 18:01:20 +0000101 logger.error("error: unable to checkout %s: %s", project.name, e)
Jason Chang1a3612f2023-08-08 14:12:53 -0700102 error = e
103 return ExecuteOneResult(project, error)
Mike Frysinger8dbc07a2021-02-18 23:37:33 -0500104
Gavin Makea2e3302023-03-11 06:46:20 +0000105 def Execute(self, opt, args):
106 nb = args[0]
Jason Chang1a3612f2023-08-08 14:12:53 -0700107 err_projects = []
Gavin Makea2e3302023-03-11 06:46:20 +0000108 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 Kirkpatrick6f6cd772009-04-22 17:27:12 -0700114
Gavin Makea2e3302023-03-11 06:46:20 +0000115 all_projects = self.GetProjects(
116 projects,
Gavin Makea2e3302023-03-11 06:46:20 +0000117 all_manifests=not opt.this_manifest_only,
118 )
Dan Willemsen04197a52015-10-07 16:53:10 -0700119
Gavin Makea2e3302023-03-11 06:46:20 +0000120 def _ProcessResults(_pool, pm, results):
Jason Chang1a3612f2023-08-08 14:12:53 -0700121 for result in results:
122 if result.error:
123 err_projects.append(result.project)
124 err.append(result.error)
Gavin Mak551285f2023-05-04 04:48:43 +0000125 pm.update(msg="")
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700126
Gavin Makea2e3302023-03-11 06:46:20 +0000127 self.ExecuteInParallel(
128 opt.jobs,
129 functools.partial(self._ExecuteOne, opt.revision, nb),
130 all_projects,
131 callback=_ProcessResults,
132 output=Progress(
Jason R. Coombsb32ccbb2023-09-29 11:04:49 -0400133 f"Starting {nb}", len(all_projects), quiet=opt.quiet
Gavin Makea2e3302023-03-11 06:46:20 +0000134 ),
135 )
Shawn O. Pearce0a389e92009-04-10 16:21:18 -0700136
Jason Chang1a3612f2023-08-08 14:12:53 -0700137 if err_projects:
138 for p in err_projects:
Aravind Vasudevan57718972023-09-06 18:01:20 +0000139 logger.error(
140 "error: %s/: cannot start %s",
141 p.RelPath(local=opt.this_manifest_only),
142 nb,
Gavin Makea2e3302023-03-11 06:46:20 +0000143 )
Josip Sokcevic131fc962023-05-12 17:00:46 -0700144 msg_fmt = "cannot start %d project(s)"
Jason Chang1a3612f2023-08-08 14:12:53 -0700145 self.git_event_log.ErrorEvent(
146 msg_fmt % (len(err_projects)), msg_fmt
147 )
148 raise StartError(aggregate_errors=err)