blob: 2808210543ab479c29de53f362d3d16b26a83d0c [file] [log] [blame]
Lann Martin10f3ee92018-08-22 15:48:10 -06001# Copyright 2018 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Don Garrett903fedc2018-11-02 17:04:26 -07005"""Sync a git repository to a given manifest.
6
7This script is intended to define all of the ways that a source checkout can be
8defined for a Chrome OS builder.
9
10If a sync completes successfully, the checked out code will exactly match
11whatever manifest is defined, and no local git branches will remain. Extraneous
12files not under version management will be ignored.
13
14It is NOT safe to assume that the checkout can be further updated with
15a simple "repo sync", instead you should call this script again with
16the same options.
17"""
Lann Martin10f3ee92018-08-22 15:48:10 -060018
Don Garrett903fedc2018-11-02 17:04:26 -070019from chromite.cbuildbot import manifest_version
Don Garrett115df402018-11-09 14:43:42 -080020from chromite.cbuildbot import patch_series
Don Garrett903fedc2018-11-02 17:04:26 -070021from chromite.cbuildbot import repository
Lann Martin10f3ee92018-08-22 15:48:10 -060022from chromite.lib import commandline
Don Garrett903fedc2018-11-02 17:04:26 -070023from chromite.lib import cros_logging as logging
24from chromite.lib import config_lib
Don Garrett115df402018-11-09 14:43:42 -080025from chromite.lib import gerrit
Don Garrett903fedc2018-11-02 17:04:26 -070026from chromite.lib import osutils
Lann Martin10f3ee92018-08-22 15:48:10 -060027
28
29def GetParser():
30 """Creates the argparse parser."""
31 parser = commandline.ArgumentParser(description=__doc__)
Don Garrett903fedc2018-11-02 17:04:26 -070032
Lann Martin10f3ee92018-08-22 15:48:10 -060033 parser.add_argument('--repo-root', type='path', default='.',
34 help='Path to the repo root to sync.')
Don Garrett903fedc2018-11-02 17:04:26 -070035
36 manifest_group = parser.add_argument_group(
37 'Manifest',
38 description='What manifest do we sync?')
39
40 manifest_ex = manifest_group.add_mutually_exclusive_group()
41 manifest_ex.add_argument(
42 '--branch',
43 default='master',
44 help='Sync to top of given branch.')
45 manifest_ex.add_argument(
46 '--buildspec',
47 help='Path to manifest, relative to manifest-versions root.')
48 manifest_ex.add_argument(
49 '--version',
50 help='Shorthand for an official release buildspec. e.g. 9799.0.0')
51 manifest_ex.add_argument(
52 '--manifest-file', type='path',
53 help='Sync to an existing local manifest file.')
54
Raul E Rangel5a7c5002019-11-08 09:18:32 -070055 manifest_group.add_argument(
56 '--groups', help='manifest groups to sync.')
57
Evan Hernandezc760c712019-02-07 15:18:18 -070058 manifest_url_ex = manifest_group.add_mutually_exclusive_group()
59 manifest_url_ex.add_argument(
Don Garrett903fedc2018-11-02 17:04:26 -070060 '--external', action='store_true', default=False,
61 help='Sync to the external version of a manifest. Switch from '
62 'manifest-versions-internal to manifest-versions for buildspecs. '
63 'Not usable with --manifest.')
Evan Hernandezc760c712019-02-07 15:18:18 -070064 manifest_url_ex.add_argument(
65 '--manifest-url', help='Manually set URL to fetch repo manifest from.')
Don Garrett903fedc2018-11-02 17:04:26 -070066
Don Garrett115df402018-11-09 14:43:42 -080067 patch_group = parser.add_argument_group(
68 'Patch',
69 description='Which patches should be included with the build?')
70 patch_group.add_argument(
71 '-g', '--gerrit-patches', action='split_extend', default=[],
72 metavar='Id1 *int_Id2...IdN',
73 help='Space-separated list of short-form Gerrit '
74 "Change-Id's or change numbers to patch. "
75 "Please prepend '*' to internal Change-Id's")
76
Don Garrett903fedc2018-11-02 17:04:26 -070077 resources_group = parser.add_argument_group(
78 'Resources',
79 description='External resources that might be needed.')
80
81 resources_group.add_argument(
82 '--manifest-versions-int', type='path',
83 help='Directory for internal manifest versions checkout. '
84 'May be refreshed.')
85
86 resources_group.add_argument(
87 '--manifest-versions-ext', type='path',
88 help='Directory for internal manifest versions checkout. '
89 'May be refreshed.')
90
91 optimization_group = parser.add_argument_group(
92 'Optimization',
93 description='Hints provided to possibly speed up initial sync.')
94
95 optimization_group.add_argument(
96 '--copy-repo', type='path',
97 help='Path to an existing repo root. Used to preload the local '
98 "checkout if the local checkout doesn't exist.")
99 optimization_group.add_argument(
100 '--git-cache-dir', type='path',
101 help='Git cache directory to use.')
Evan Hernandezc831b122019-02-07 15:26:43 -0700102 optimization_group.add_argument(
103 '--repo-url', help='Repo repository location.')
Don Garrett903fedc2018-11-02 17:04:26 -0700104
Lann Martin10f3ee92018-08-22 15:48:10 -0600105 return parser
106
107
Don Garrett903fedc2018-11-02 17:04:26 -0700108def PrepareManifestVersions(options):
109 """Select manifest-versions checkout to use, and update it.
110
111 Looks at command line options to decide which manifest-versions checkout to
112 use, and updates (or creates) it as needed.
113
114 Args:
115 options: Parsed command line options.
116
117 Returns:
118 Full path to manifest-versions directory to use for this sync.
119
120 Raises:
121 AssertionError: If the needed manifest-versions path wasn't con the
122 command line.
123 """
124 site_params = config_lib.GetSiteParams()
125
126 if options.external:
127 assert options.manifest_versions_ext, '--manifest-versions-ext required.'
128 manifest_versions_url = site_params.MANIFEST_VERSIONS_GOB_URL
129 manifest_versions_path = options.manifest_versions_ext
130 else:
131 assert options.manifest_versions_int, '--manifest-versions-int required.'
132 manifest_versions_url = site_params.MANIFEST_VERSIONS_INT_GOB_URL
133 manifest_versions_path = options.manifest_versions_int
134
135 # Resolve buildspecs against a current manifest versions value.
136 manifest_version.RefreshManifestCheckout(
137 manifest_versions_path, manifest_versions_url)
138
139 return manifest_versions_path
140
141
142def ResolveLocalManifestPath(options):
143 """Based on command line options, decide what local manifest file to use.
144
145 Args:
146 options: Our parsed command line options.
147
148 Returns:
149 Path to local manifest file to use, or None for no file.
150 """
151 if options.manifest_file:
152 # If the user gives us an explicit local manifest file, use it.
153 return options.manifest_file
154
155 elif options.buildspec:
156 # Buildspec builds use a manifest file from manifest_versions. We do NOT
157 # use manifest_versions as the manifest git repo, because it's so large that
158 # sync time would be a major performance problem.
159 manifest_versions_path = PrepareManifestVersions(options)
160 return manifest_version.ResolveBuildspec(
161 manifest_versions_path, options.buildspec)
162
163 elif options.version:
164 # Versions are a short hand version of a buildspec.
165 manifest_versions_path = PrepareManifestVersions(options)
166 return manifest_version.ResolveBuildspecVersion(
167 manifest_versions_path, options.version)
168
169 elif options.branch:
170 # Branch checkouts use our normal manifest repos, not a local manifest file.
171 return None
172
173 else:
174 assert False, 'No sync options specified. Should not be possible.'
175
176
Lann Martin10f3ee92018-08-22 15:48:10 -0600177def main(argv):
178 parser = GetParser()
179 options = parser.parse_args(argv)
180 options.Freeze()
181
Don Garrett903fedc2018-11-02 17:04:26 -0700182 local_manifest = ResolveLocalManifestPath(options)
183
184 if local_manifest:
185 logging.info('Using local_manifest: %s', local_manifest)
186
Evan Hernandezc760c712019-02-07 15:18:18 -0700187 if options.manifest_url:
188 manifest_url = options.manifest_url
189 elif options.external:
Don Garrett903fedc2018-11-02 17:04:26 -0700190 manifest_url = config_lib.GetSiteParams().MANIFEST_URL
191 else:
192 manifest_url = config_lib.GetSiteParams().MANIFEST_INT_URL
193
194 osutils.SafeMakedirs(options.repo_root)
195 repo = repository.RepoRepository(
196 manifest_repo_url=manifest_url,
197 directory=options.repo_root,
198 branch=options.branch,
Evan Hernandezc831b122019-02-07 15:26:43 -0700199 git_cache_dir=options.git_cache_dir,
Raul E Rangel5a7c5002019-11-08 09:18:32 -0700200 repo_url=options.repo_url,
201 groups=options.groups)
Lann Martin10f3ee92018-08-22 15:48:10 -0600202
203 if options.copy_repo:
Don Garrett903fedc2018-11-02 17:04:26 -0700204 repo.PreLoad(options.copy_repo)
Lann Martin10f3ee92018-08-22 15:48:10 -0600205
Don Garrett903fedc2018-11-02 17:04:26 -0700206 if repository.IsARepoRoot(options.repo_root):
207 repo.BuildRootGitCleanup(prune_all=True)
Lann Martin10f3ee92018-08-22 15:48:10 -0600208
Don Garrett903fedc2018-11-02 17:04:26 -0700209 repo.Sync(local_manifest=local_manifest, detach=True)
210
Don Garrett115df402018-11-09 14:43:42 -0800211 if options.gerrit_patches:
212 patches = gerrit.GetGerritPatchInfo(options.gerrit_patches)
213 # TODO: Extract patches from manifest synced.
214
215 helper_pool = patch_series.HelperPool.SimpleCreate(
216 cros_internal=not options.external, cros=True)
217
218 series = patch_series.PatchSeries(
219 path=options.repo_root, helper_pool=helper_pool, forced_manifest=None)
220
Don Garrettf3976f92018-12-20 12:46:47 -0800221 _, failed_tot, failed_inflight = series.Apply(patches)
222
223 failed = failed_tot + failed_inflight
224 if failed:
225 logging.error('Failed to apply: %s', ', '.join(str(p) for p in failed))
226 return 1