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