blob: 809df96394eb8e59524f29e8eefc8385465de39d [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
Simran Basib9a1b732015-08-20 12:19:28 -070016import os
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070017import sys
Simran Basib9a1b732015-08-20 12:19:28 -070018
Mike Frysingerb5d075d2021-03-01 00:56:38 -050019from command import Command, DEFAULT_LOCAL_JOBS
Zac Livingston9ead97b2017-06-13 08:29:04 -060020from git_config import IsImmutable
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070021from git_command import git
Simran Basib9a1b732015-08-20 12:19:28 -070022import gitc_utils
Shawn O. Pearce0f0dfa32009-04-18 14:53:39 -070023from progress import Progress
Simran Basib9a1b732015-08-20 12:19:28 -070024from project import SyncBuffer
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070025
David Pursehouse819827a2020-02-12 15:20:19 +090026
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070027class Start(Command):
Mike Frysinger4f210542021-06-14 16:05:19 -040028 COMMON = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070029 helpSummary = "Start a new branch for development"
30 helpUsage = """
Ficus Kirkpatrick6f6cd772009-04-22 17:27:12 -070031%prog <newbranchname> [--all | <project>...]
Shawn O. Pearce06e556d2009-04-18 11:19:01 -070032"""
33 helpDescription = """
34'%prog' begins a new branch of development, starting from the
35revision specified in the manifest.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070036"""
Mike Frysinger8dbc07a2021-02-18 23:37:33 -050037 PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070038
Ficus Kirkpatrick6f6cd772009-04-22 17:27:12 -070039 def _Options(self, p):
40 p.add_option('--all',
41 dest='all', action='store_true',
42 help='begin branch in all projects')
Theodore Dubois60fdc5c2019-07-30 12:14:25 -070043 p.add_option('-r', '--rev', '--revision', dest='revision',
44 help='point branch at this revision instead of upstream')
Mike Frysingerd1e4fa72021-03-23 20:27:29 -040045 p.add_option('--head', '--HEAD',
46 dest='revision', action='store_const', const='HEAD',
Theodore Dubois60fdc5c2019-07-30 12:14:25 -070047 help='abbreviation for --rev HEAD')
Ficus Kirkpatrick6f6cd772009-04-22 17:27:12 -070048
Mike Frysingerae6cb082019-08-27 01:10:59 -040049 def ValidateOptions(self, opt, args):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070050 if not args:
51 self.Usage()
52
53 nb = args[0]
54 if not git.check_ref_format('heads/%s' % nb):
Mike Frysingerae6cb082019-08-27 01:10:59 -040055 self.OptionParser.error("'%s' is not a valid name" % nb)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070056
Mike Frysingerb5d075d2021-03-01 00:56:38 -050057 def _ExecuteOne(self, revision, nb, project):
Mike Frysinger8dbc07a2021-02-18 23:37:33 -050058 """Start one project."""
59 # If the current revision is immutable, such as a SHA1, a tag or
60 # a change, then we can't push back to it. Substitute with
61 # dest_branch, if defined; or with manifest default revision instead.
62 branch_merge = ''
63 if IsImmutable(project.revisionExpr):
64 if project.dest_branch:
65 branch_merge = project.dest_branch
66 else:
67 branch_merge = self.manifest.default.revisionExpr
68
69 try:
70 ret = project.StartBranch(
Mike Frysingerb5d075d2021-03-01 00:56:38 -050071 nb, branch_merge=branch_merge, revision=revision)
Mike Frysinger8dbc07a2021-02-18 23:37:33 -050072 except Exception as e:
73 print('error: unable to checkout %s: %s' % (project.name, e), file=sys.stderr)
74 ret = False
75 return (ret, project)
76
Mike Frysingerae6cb082019-08-27 01:10:59 -040077 def Execute(self, opt, args):
78 nb = args[0]
Shawn O. Pearce0a389e92009-04-10 16:21:18 -070079 err = []
Ficus Kirkpatrick6f6cd772009-04-22 17:27:12 -070080 projects = []
81 if not opt.all:
82 projects = args[1:]
83 if len(projects) < 1:
David Pursehouse54a4e602020-02-12 14:31:05 +090084 projects = ['.'] # start it in the local project by default
Ficus Kirkpatrick6f6cd772009-04-22 17:27:12 -070085
Dan Willemsen04197a52015-10-07 16:53:10 -070086 all_projects = self.GetProjects(projects,
LaMont Jonescc879a92021-11-18 22:40:18 +000087 missing_ok=bool(self.gitc_manifest),
88 all_manifests=not opt.this_manifest_only)
Dan Willemsen04197a52015-10-07 16:53:10 -070089
90 # This must happen after we find all_projects, since GetProjects may need
91 # the local directory, which will disappear once we save the GITC manifest.
Simran Basib9a1b732015-08-20 12:19:28 -070092 if self.gitc_manifest:
Dan Willemsen04197a52015-10-07 16:53:10 -070093 gitc_projects = self.GetProjects(projects, manifest=self.gitc_manifest,
94 missing_ok=True)
95 for project in gitc_projects:
Simran Basib9a1b732015-08-20 12:19:28 -070096 if project.old_revision:
97 project.already_synced = True
98 else:
99 project.already_synced = False
100 project.old_revision = project.revisionExpr
Simran Basib9a1b732015-08-20 12:19:28 -0700101 project.revisionExpr = None
102 # Save the GITC manifest.
103 gitc_utils.save_manifest(self.gitc_manifest)
Shawn O. Pearce0f0dfa32009-04-18 14:53:39 -0700104
Dan Willemsen04197a52015-10-07 16:53:10 -0700105 # Make sure we have a valid CWD
106 if not os.path.exists(os.getcwd()):
107 os.chdir(self.manifest.topdir)
108
Mike Frysinger151701e2021-04-13 15:07:21 -0400109 pm = Progress('Syncing %s' % nb, len(all_projects), quiet=opt.quiet)
Mike Frysinger8dbc07a2021-02-18 23:37:33 -0500110 for project in all_projects:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700111 gitc_project = self.gitc_manifest.paths[project.relpath]
112 # Sync projects that have not been opened.
Simran Basib9a1b732015-08-20 12:19:28 -0700113 if not gitc_project.already_synced:
114 proj_localdir = os.path.join(self.gitc_manifest.gitc_client_dir,
115 project.relpath)
116 project.worktree = proj_localdir
117 if not os.path.exists(proj_localdir):
118 os.makedirs(proj_localdir)
119 project.Sync_NetworkHalf()
120 sync_buf = SyncBuffer(self.manifest.manifestProject.config)
121 project.Sync_LocalHalf(sync_buf)
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700122 project.revisionId = gitc_project.old_revision
Mike Frysinger8dbc07a2021-02-18 23:37:33 -0500123 pm.update()
124 pm.end()
Simran Basib9a1b732015-08-20 12:19:28 -0700125
Mike Frysingerb5d075d2021-03-01 00:56:38 -0500126 def _ProcessResults(_pool, pm, results):
Mike Frysinger8dbc07a2021-02-18 23:37:33 -0500127 for (result, project) in results:
128 if not result:
129 err.append(project)
130 pm.update()
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700131
Mike Frysingerb5d075d2021-03-01 00:56:38 -0500132 self.ExecuteInParallel(
133 opt.jobs,
134 functools.partial(self._ExecuteOne, opt.revision, nb),
135 all_projects,
136 callback=_ProcessResults,
137 output=Progress('Starting %s' % (nb,), len(all_projects), quiet=opt.quiet))
Shawn O. Pearce0a389e92009-04-10 16:21:18 -0700138
139 if err:
Shawn O. Pearce0a389e92009-04-10 16:21:18 -0700140 for p in err:
LaMont Jonescc879a92021-11-18 22:40:18 +0000141 print("error: %s/: cannot start %s" % (p.RelPath(local=opt.this_manifest_only), nb),
Sarah Owenscecd1d82012-11-01 22:59:27 -0700142 file=sys.stderr)
Shawn O. Pearce0a389e92009-04-10 16:21:18 -0700143 sys.exit(1)