blob: 0197ad5fbfc49f151cdf36e03652b017aa8af2e2 [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
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,
200 repo_url=options.repo_url)
Lann Martin10f3ee92018-08-22 15:48:10 -0600201
202 if options.copy_repo:
Don Garrett903fedc2018-11-02 17:04:26 -0700203 repo.PreLoad(options.copy_repo)
Lann Martin10f3ee92018-08-22 15:48:10 -0600204
Don Garrett903fedc2018-11-02 17:04:26 -0700205 if repository.IsARepoRoot(options.repo_root):
206 repo.BuildRootGitCleanup(prune_all=True)
Lann Martin10f3ee92018-08-22 15:48:10 -0600207
Don Garrett903fedc2018-11-02 17:04:26 -0700208 repo.Sync(local_manifest=local_manifest, detach=True)
209
Don Garrett115df402018-11-09 14:43:42 -0800210 if options.gerrit_patches:
211 patches = gerrit.GetGerritPatchInfo(options.gerrit_patches)
212 # TODO: Extract patches from manifest synced.
213
214 helper_pool = patch_series.HelperPool.SimpleCreate(
215 cros_internal=not options.external, cros=True)
216
217 series = patch_series.PatchSeries(
218 path=options.repo_root, helper_pool=helper_pool, forced_manifest=None)
219
Don Garrettf3976f92018-12-20 12:46:47 -0800220 _, failed_tot, failed_inflight = series.Apply(patches)
221
222 failed = failed_tot + failed_inflight
223 if failed:
224 logging.error('Failed to apply: %s', ', '.join(str(p) for p in failed))
225 return 1