blob: 8d52d813a38e33768712c0e5021cfc855faed0be [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
58 manifest_group.add_argument(
59 '--external', action='store_true', default=False,
60 help='Sync to the external version of a manifest. Switch from '
61 'manifest-versions-internal to manifest-versions for buildspecs. '
62 'Not usable with --manifest.')
63
Don Garrett115df402018-11-09 14:43:42 -080064 patch_group = parser.add_argument_group(
65 'Patch',
66 description='Which patches should be included with the build?')
67 patch_group.add_argument(
68 '-g', '--gerrit-patches', action='split_extend', default=[],
69 metavar='Id1 *int_Id2...IdN',
70 help='Space-separated list of short-form Gerrit '
71 "Change-Id's or change numbers to patch. "
72 "Please prepend '*' to internal Change-Id's")
73
Don Garrett903fedc2018-11-02 17:04:26 -070074 resources_group = parser.add_argument_group(
75 'Resources',
76 description='External resources that might be needed.')
77
78 resources_group.add_argument(
79 '--manifest-versions-int', type='path',
80 help='Directory for internal manifest versions checkout. '
81 'May be refreshed.')
82
83 resources_group.add_argument(
84 '--manifest-versions-ext', type='path',
85 help='Directory for internal manifest versions checkout. '
86 'May be refreshed.')
87
88 optimization_group = parser.add_argument_group(
89 'Optimization',
90 description='Hints provided to possibly speed up initial sync.')
91
92 optimization_group.add_argument(
93 '--copy-repo', type='path',
94 help='Path to an existing repo root. Used to preload the local '
95 "checkout if the local checkout doesn't exist.")
96 optimization_group.add_argument(
97 '--git-cache-dir', type='path',
98 help='Git cache directory to use.')
99
Lann Martin10f3ee92018-08-22 15:48:10 -0600100 return parser
101
102
Don Garrett903fedc2018-11-02 17:04:26 -0700103def PrepareManifestVersions(options):
104 """Select manifest-versions checkout to use, and update it.
105
106 Looks at command line options to decide which manifest-versions checkout to
107 use, and updates (or creates) it as needed.
108
109 Args:
110 options: Parsed command line options.
111
112 Returns:
113 Full path to manifest-versions directory to use for this sync.
114
115 Raises:
116 AssertionError: If the needed manifest-versions path wasn't con the
117 command line.
118 """
119 site_params = config_lib.GetSiteParams()
120
121 if options.external:
122 assert options.manifest_versions_ext, '--manifest-versions-ext required.'
123 manifest_versions_url = site_params.MANIFEST_VERSIONS_GOB_URL
124 manifest_versions_path = options.manifest_versions_ext
125 else:
126 assert options.manifest_versions_int, '--manifest-versions-int required.'
127 manifest_versions_url = site_params.MANIFEST_VERSIONS_INT_GOB_URL
128 manifest_versions_path = options.manifest_versions_int
129
130 # Resolve buildspecs against a current manifest versions value.
131 manifest_version.RefreshManifestCheckout(
132 manifest_versions_path, manifest_versions_url)
133
134 return manifest_versions_path
135
136
137def ResolveLocalManifestPath(options):
138 """Based on command line options, decide what local manifest file to use.
139
140 Args:
141 options: Our parsed command line options.
142
143 Returns:
144 Path to local manifest file to use, or None for no file.
145 """
146 if options.manifest_file:
147 # If the user gives us an explicit local manifest file, use it.
148 return options.manifest_file
149
150 elif options.buildspec:
151 # Buildspec builds use a manifest file from manifest_versions. We do NOT
152 # use manifest_versions as the manifest git repo, because it's so large that
153 # sync time would be a major performance problem.
154 manifest_versions_path = PrepareManifestVersions(options)
155 return manifest_version.ResolveBuildspec(
156 manifest_versions_path, options.buildspec)
157
158 elif options.version:
159 # Versions are a short hand version of a buildspec.
160 manifest_versions_path = PrepareManifestVersions(options)
161 return manifest_version.ResolveBuildspecVersion(
162 manifest_versions_path, options.version)
163
164 elif options.branch:
165 # Branch checkouts use our normal manifest repos, not a local manifest file.
166 return None
167
168 else:
169 assert False, 'No sync options specified. Should not be possible.'
170
171
Lann Martin10f3ee92018-08-22 15:48:10 -0600172def main(argv):
173 parser = GetParser()
174 options = parser.parse_args(argv)
175 options.Freeze()
176
Don Garrett903fedc2018-11-02 17:04:26 -0700177 local_manifest = ResolveLocalManifestPath(options)
178
179 if local_manifest:
180 logging.info('Using local_manifest: %s', local_manifest)
181
182 if options.external:
183 manifest_url = config_lib.GetSiteParams().MANIFEST_URL
184 else:
185 manifest_url = config_lib.GetSiteParams().MANIFEST_INT_URL
186
187 osutils.SafeMakedirs(options.repo_root)
188 repo = repository.RepoRepository(
189 manifest_repo_url=manifest_url,
190 directory=options.repo_root,
191 branch=options.branch,
192 git_cache_dir=options.git_cache_dir)
Lann Martin10f3ee92018-08-22 15:48:10 -0600193
194 if options.copy_repo:
Don Garrett903fedc2018-11-02 17:04:26 -0700195 repo.PreLoad(options.copy_repo)
Lann Martin10f3ee92018-08-22 15:48:10 -0600196
Don Garrett903fedc2018-11-02 17:04:26 -0700197 if repository.IsARepoRoot(options.repo_root):
198 repo.BuildRootGitCleanup(prune_all=True)
Lann Martin10f3ee92018-08-22 15:48:10 -0600199
Don Garrett903fedc2018-11-02 17:04:26 -0700200 repo.Sync(local_manifest=local_manifest, detach=True)
201
Don Garrett115df402018-11-09 14:43:42 -0800202 if options.gerrit_patches:
203 patches = gerrit.GetGerritPatchInfo(options.gerrit_patches)
204 # TODO: Extract patches from manifest synced.
205
206 helper_pool = patch_series.HelperPool.SimpleCreate(
207 cros_internal=not options.external, cros=True)
208
209 series = patch_series.PatchSeries(
210 path=options.repo_root, helper_pool=helper_pool, forced_manifest=None)
211
Don Garrettf3976f92018-12-20 12:46:47 -0800212 _, failed_tot, failed_inflight = series.Apply(patches)
213
214 failed = failed_tot + failed_inflight
215 if failed:
216 logging.error('Failed to apply: %s', ', '.join(str(p) for p in failed))
217 return 1