blob: 0f92b73e990e0a02007d4f8e8a1ff026c2d6b62d [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
Chris McDonald59650c32021-07-20 15:29:28 -060019import logging
20
Don Garrett903fedc2018-11-02 17:04:26 -070021from chromite.cbuildbot import manifest_version
Don Garrett115df402018-11-09 14:43:42 -080022from chromite.cbuildbot import patch_series
Don Garrett903fedc2018-11-02 17:04:26 -070023from chromite.cbuildbot import repository
Lann Martin10f3ee92018-08-22 15:48:10 -060024from chromite.lib import commandline
Don Garrett903fedc2018-11-02 17:04:26 -070025from chromite.lib import config_lib
Don Garrett115df402018-11-09 14:43:42 -080026from chromite.lib import gerrit
Don Garrett903fedc2018-11-02 17:04:26 -070027from chromite.lib import osutils
Lann Martin10f3ee92018-08-22 15:48:10 -060028
29
30def GetParser():
31 """Creates the argparse parser."""
32 parser = commandline.ArgumentParser(description=__doc__)
Don Garrett903fedc2018-11-02 17:04:26 -070033
Lann Martin10f3ee92018-08-22 15:48:10 -060034 parser.add_argument('--repo-root', type='path', default='.',
35 help='Path to the repo root to sync.')
Don Garrett903fedc2018-11-02 17:04:26 -070036
37 manifest_group = parser.add_argument_group(
38 'Manifest',
39 description='What manifest do we sync?')
40
41 manifest_ex = manifest_group.add_mutually_exclusive_group()
42 manifest_ex.add_argument(
43 '--branch',
44 default='master',
45 help='Sync to top of given branch.')
46 manifest_ex.add_argument(
47 '--buildspec',
48 help='Path to manifest, relative to manifest-versions root.')
49 manifest_ex.add_argument(
50 '--version',
51 help='Shorthand for an official release buildspec. e.g. 9799.0.0')
52 manifest_ex.add_argument(
53 '--manifest-file', type='path',
54 help='Sync to an existing local manifest file.')
55
Raul E Rangel5a7c5002019-11-08 09:18:32 -070056 manifest_group.add_argument(
57 '--groups', help='manifest groups to sync.')
58
Evan Hernandezc760c712019-02-07 15:18:18 -070059 manifest_url_ex = manifest_group.add_mutually_exclusive_group()
60 manifest_url_ex.add_argument(
Don Garrett903fedc2018-11-02 17:04:26 -070061 '--external', action='store_true', default=False,
62 help='Sync to the external version of a manifest. Switch from '
63 'manifest-versions-internal to manifest-versions for buildspecs. '
64 'Not usable with --manifest.')
Evan Hernandezc760c712019-02-07 15:18:18 -070065 manifest_url_ex.add_argument(
66 '--manifest-url', help='Manually set URL to fetch repo manifest from.')
Don Garrett903fedc2018-11-02 17:04:26 -070067
Don Garrett115df402018-11-09 14:43:42 -080068 patch_group = parser.add_argument_group(
69 'Patch',
70 description='Which patches should be included with the build?')
71 patch_group.add_argument(
72 '-g', '--gerrit-patches', action='split_extend', default=[],
73 metavar='Id1 *int_Id2...IdN',
74 help='Space-separated list of short-form Gerrit '
75 "Change-Id's or change numbers to patch. "
76 "Please prepend '*' to internal Change-Id's")
77
Don Garrett903fedc2018-11-02 17:04:26 -070078 resources_group = parser.add_argument_group(
79 'Resources',
80 description='External resources that might be needed.')
81
82 resources_group.add_argument(
83 '--manifest-versions-int', type='path',
84 help='Directory for internal manifest versions checkout. '
85 'May be refreshed.')
86
87 resources_group.add_argument(
88 '--manifest-versions-ext', type='path',
89 help='Directory for internal manifest versions checkout. '
90 'May be refreshed.')
91
92 optimization_group = parser.add_argument_group(
93 'Optimization',
94 description='Hints provided to possibly speed up initial sync.')
95
96 optimization_group.add_argument(
97 '--copy-repo', type='path',
98 help='Path to an existing repo root. Used to preload the local '
99 "checkout if the local checkout doesn't exist.")
100 optimization_group.add_argument(
101 '--git-cache-dir', type='path',
102 help='Git cache directory to use.')
Evan Hernandezc831b122019-02-07 15:26:43 -0700103 optimization_group.add_argument(
104 '--repo-url', help='Repo repository location.')
Don Garrett903fedc2018-11-02 17:04:26 -0700105
Lann Martin10f3ee92018-08-22 15:48:10 -0600106 return parser
107
108
Don Garrett903fedc2018-11-02 17:04:26 -0700109def PrepareManifestVersions(options):
110 """Select manifest-versions checkout to use, and update it.
111
112 Looks at command line options to decide which manifest-versions checkout to
113 use, and updates (or creates) it as needed.
114
115 Args:
116 options: Parsed command line options.
117
118 Returns:
119 Full path to manifest-versions directory to use for this sync.
120
121 Raises:
122 AssertionError: If the needed manifest-versions path wasn't con the
123 command line.
124 """
125 site_params = config_lib.GetSiteParams()
126
127 if options.external:
128 assert options.manifest_versions_ext, '--manifest-versions-ext required.'
129 manifest_versions_url = site_params.MANIFEST_VERSIONS_GOB_URL
130 manifest_versions_path = options.manifest_versions_ext
131 else:
132 assert options.manifest_versions_int, '--manifest-versions-int required.'
133 manifest_versions_url = site_params.MANIFEST_VERSIONS_INT_GOB_URL
134 manifest_versions_path = options.manifest_versions_int
135
136 # Resolve buildspecs against a current manifest versions value.
137 manifest_version.RefreshManifestCheckout(
138 manifest_versions_path, manifest_versions_url)
139
140 return manifest_versions_path
141
142
143def ResolveLocalManifestPath(options):
144 """Based on command line options, decide what local manifest file to use.
145
146 Args:
147 options: Our parsed command line options.
148
149 Returns:
150 Path to local manifest file to use, or None for no file.
151 """
152 if options.manifest_file:
153 # If the user gives us an explicit local manifest file, use it.
154 return options.manifest_file
155
156 elif options.buildspec:
157 # Buildspec builds use a manifest file from manifest_versions. We do NOT
158 # use manifest_versions as the manifest git repo, because it's so large that
159 # sync time would be a major performance problem.
160 manifest_versions_path = PrepareManifestVersions(options)
161 return manifest_version.ResolveBuildspec(
162 manifest_versions_path, options.buildspec)
163
164 elif options.version:
165 # Versions are a short hand version of a buildspec.
166 manifest_versions_path = PrepareManifestVersions(options)
167 return manifest_version.ResolveBuildspecVersion(
168 manifest_versions_path, options.version)
169
170 elif options.branch:
171 # Branch checkouts use our normal manifest repos, not a local manifest file.
172 return None
173
174 else:
175 assert False, 'No sync options specified. Should not be possible.'
176
177
Lann Martin10f3ee92018-08-22 15:48:10 -0600178def main(argv):
179 parser = GetParser()
180 options = parser.parse_args(argv)
181 options.Freeze()
182
Don Garrett903fedc2018-11-02 17:04:26 -0700183 local_manifest = ResolveLocalManifestPath(options)
184
185 if local_manifest:
186 logging.info('Using local_manifest: %s', local_manifest)
187
Evan Hernandezc760c712019-02-07 15:18:18 -0700188 if options.manifest_url:
189 manifest_url = options.manifest_url
190 elif options.external:
Don Garrett903fedc2018-11-02 17:04:26 -0700191 manifest_url = config_lib.GetSiteParams().MANIFEST_URL
192 else:
193 manifest_url = config_lib.GetSiteParams().MANIFEST_INT_URL
194
195 osutils.SafeMakedirs(options.repo_root)
196 repo = repository.RepoRepository(
197 manifest_repo_url=manifest_url,
198 directory=options.repo_root,
199 branch=options.branch,
Evan Hernandezc831b122019-02-07 15:26:43 -0700200 git_cache_dir=options.git_cache_dir,
Raul E Rangel5a7c5002019-11-08 09:18:32 -0700201 repo_url=options.repo_url,
202 groups=options.groups)
Lann Martin10f3ee92018-08-22 15:48:10 -0600203
204 if options.copy_repo:
Don Garrett903fedc2018-11-02 17:04:26 -0700205 repo.PreLoad(options.copy_repo)
Lann Martin10f3ee92018-08-22 15:48:10 -0600206
Don Garrett903fedc2018-11-02 17:04:26 -0700207 repo.Sync(local_manifest=local_manifest, detach=True)
208
Don Garrett115df402018-11-09 14:43:42 -0800209 if options.gerrit_patches:
210 patches = gerrit.GetGerritPatchInfo(options.gerrit_patches)
211 # TODO: Extract patches from manifest synced.
212
213 helper_pool = patch_series.HelperPool.SimpleCreate(
214 cros_internal=not options.external, cros=True)
215
216 series = patch_series.PatchSeries(
217 path=options.repo_root, helper_pool=helper_pool, forced_manifest=None)
218
Don Garrettf3976f92018-12-20 12:46:47 -0800219 _, failed_tot, failed_inflight = series.Apply(patches)
220
221 failed = failed_tot + failed_inflight
222 if failed:
223 logging.error('Failed to apply: %s', ', '.join(str(p) for p in failed))
224 return 1