blob: 9ac14ffe962d89b7a392edfe4d245ea2ae7681b0 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
David Rileyc0da9d92016-02-01 12:11:01 -08002# Copyright 2016 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
6"""This module uprevs Android for cbuildbot.
7
8After calling, it prints outs ANDROID_VERSION_ATOM=(version atom string). A
9caller could then use this atom with emerge to build the newly uprevved version
10of Android e.g.
11
Shuhei Takahashi6d02c192017-04-05 14:01:24 +090012./cros_mark_android_as_stable \
13 --android_package=android-container \
14 --android_build_branch=git_mnc-dr-arc-dev \
15 --android_gts_build_branch=git_mnc-dev
16
David Rileyc0da9d92016-02-01 12:11:01 -080017Returns chromeos-base/android-container-2559197
18
19emerge-veyron_minnie-cheets =chromeos-base/android-container-2559197-r1
20"""
21
22from __future__ import print_function
23
24import filecmp
khmel@google.com778a1cd2018-04-13 11:11:58 -070025import hashlib
David Rileyc0da9d92016-02-01 12:11:01 -080026import glob
27import os
Hidehiko Abe12727dd2016-05-27 23:23:45 +090028import re
khmel@google.com778a1cd2018-04-13 11:11:58 -070029import shutil
30import tempfile
khmel@google.com96c193e2018-05-10 14:00:38 -070031import time
khmel@google.com778a1cd2018-04-13 11:11:58 -070032import subprocess
33import base64
David Rileyc0da9d92016-02-01 12:11:01 -080034
Aviv Keshetb7519e12016-10-04 00:50:00 -070035from chromite.lib import constants
David Rileyc0da9d92016-02-01 12:11:01 -080036from chromite.lib import commandline
37from chromite.lib import cros_build_lib
38from chromite.lib import cros_logging as logging
39from chromite.lib import git
40from chromite.lib import gs
41from chromite.lib import portage_util
42from chromite.scripts import cros_mark_as_stable
43
44
45# Dir where all the action happens.
46_OVERLAY_DIR = '%(srcroot)s/private-overlays/project-cheets-private/'
47
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +090048_GIT_COMMIT_MESSAGE = ('Marking latest for %(android_package)s ebuild '
David Rileyc0da9d92016-02-01 12:11:01 -080049 'with version %(android_version)s as stable.')
50
51# URLs that print lists of Android revisions between two build ids.
52_ANDROID_VERSION_URL = ('http://android-build-uber.corp.google.com/repo.html?'
53 'last_bid=%(old)s&bid=%(new)s&branch=%(branch)s')
54
55
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090056def IsBuildIdValid(bucket_url, build_branch, build_id, targets):
David Rileyc0da9d92016-02-01 12:11:01 -080057 """Checks that a specific build_id is valid.
58
59 Looks for that build_id for all builds. Confirms that the subpath can
60 be found and that the zip file is present in that subdirectory.
61
62 Args:
63 bucket_url: URL of Android build gs bucket
64 build_branch: branch of Android builds
65 build_id: A string. The Android build id number to check.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090066 targets: Dict from build key to (targe build suffix, artifact file pattern)
67 pair.
David Rileyc0da9d92016-02-01 12:11:01 -080068
69 Returns:
70 Returns subpaths dictionary if build_id is valid.
71 None if the build_id is not valid.
72 """
73 gs_context = gs.GSContext()
74 subpaths_dict = {}
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090075 for build, (target, _) in targets.iteritems():
David Rileyc0da9d92016-02-01 12:11:01 -080076 build_dir = '%s-%s' % (build_branch, target)
77 build_id_path = os.path.join(bucket_url, build_dir, build_id)
78
79 # Find name of subpath.
80 try:
81 subpaths = gs_context.List(build_id_path)
82 except gs.GSNoSuchKey:
83 logging.warn(
84 'Directory [%s] does not contain any subpath, ignoring it.',
85 build_id_path)
86 return None
87 if len(subpaths) > 1:
88 logging.warn(
89 'Directory [%s] contains more than one subpath, ignoring it.',
90 build_id_path)
91 return None
92
93 subpath_dir = subpaths[0].url.rstrip('/')
94 subpath_name = os.path.basename(subpath_dir)
95
96 # Look for a zipfile ending in the build_id number.
97 try:
Hidehiko Abe12727dd2016-05-27 23:23:45 +090098 gs_context.List(subpath_dir)
David Rileyc0da9d92016-02-01 12:11:01 -080099 except gs.GSNoSuchKey:
100 logging.warn(
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900101 'Did not find a file for build id [%s] in directory [%s].',
David Rileyc0da9d92016-02-01 12:11:01 -0800102 build_id, subpath_dir)
103 return None
104
105 # Record subpath for the build.
106 subpaths_dict[build] = subpath_name
107
108 # If we got here, it means we found an appropriate build for all platforms.
109 return subpaths_dict
110
111
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900112def GetLatestBuild(bucket_url, build_branch, targets):
David Rileyc0da9d92016-02-01 12:11:01 -0800113 """Searches the gs bucket for the latest green build.
114
115 Args:
116 bucket_url: URL of Android build gs bucket
117 build_branch: branch of Android builds
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900118 targets: Dict from build key to (targe build suffix, artifact file pattern)
119 pair.
David Rileyc0da9d92016-02-01 12:11:01 -0800120
121 Returns:
122 Tuple of (latest version string, subpaths dictionary)
123 If no latest build can be found, returns None, None
124 """
125 gs_context = gs.GSContext()
126 common_build_ids = None
127 # Find builds for each target.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900128 for target, _ in targets.itervalues():
David Rileyc0da9d92016-02-01 12:11:01 -0800129 build_dir = '-'.join((build_branch, target))
130 base_path = os.path.join(bucket_url, build_dir)
131 build_ids = []
132 for gs_result in gs_context.List(base_path):
133 # Remove trailing slashes and get the base name, which is the build_id.
134 build_id = os.path.basename(gs_result.url.rstrip('/'))
135 if not build_id.isdigit():
136 logging.warn('Directory [%s] does not look like a valid build_id.',
137 gs_result.url)
138 continue
139 build_ids.append(build_id)
140
141 # Update current list of builds.
142 if common_build_ids is None:
143 # First run, populate it with the first platform.
144 common_build_ids = set(build_ids)
145 else:
146 # Already populated, find the ones that are common.
147 common_build_ids.intersection_update(build_ids)
148
149 if common_build_ids is None:
150 logging.warn('Did not find a build_id common to all platforms.')
151 return None, None
152
153 # Otherwise, find the most recent one that is valid.
154 for build_id in sorted(common_build_ids, key=int, reverse=True):
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900155 subpaths = IsBuildIdValid(bucket_url, build_branch, build_id, targets)
David Rileyc0da9d92016-02-01 12:11:01 -0800156 if subpaths:
157 return build_id, subpaths
158
159 # If not found, no build_id is valid.
160 logging.warn('Did not find a build_id valid on all platforms.')
161 return None, None
162
163
164def FindAndroidCandidates(package_dir):
165 """Return a tuple of Android's unstable ebuild and stable ebuilds.
166
167 Args:
168 package_dir: The path to where the package ebuild is stored.
169
170 Returns:
171 Tuple [unstable_ebuild, stable_ebuilds].
172
173 Raises:
174 Exception: if no unstable ebuild exists for Android.
175 """
176 stable_ebuilds = []
177 unstable_ebuilds = []
178 for path in glob.glob(os.path.join(package_dir, '*.ebuild')):
179 ebuild = portage_util.EBuild(path)
180 if ebuild.version == '9999':
181 unstable_ebuilds.append(ebuild)
182 else:
183 stable_ebuilds.append(ebuild)
184
185 # Apply some sanity checks.
186 if not unstable_ebuilds:
187 raise Exception('Missing 9999 ebuild for %s' % package_dir)
188 if not stable_ebuilds:
189 logging.warning('Missing stable ebuild for %s' % package_dir)
190
191 return portage_util.BestEBuild(unstable_ebuilds), stable_ebuilds
192
193
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800194def _GetArcBasename(build, basename):
195 """Tweaks filenames between Android bucket and ARC++ bucket.
196
197 Android builders create build artifacts with the same name for -user and
198 -userdebug builds, which breaks the android-container ebuild (b/33072485).
199 When copying the artifacts from the Android bucket to the ARC++ bucket some
200 artifacts will be renamed from the usual pattern
201 *cheets_${ARCH}-target_files-S{VERSION}.zip to
202 cheets_${BUILD_NAME}-target_files-S{VERSION}.zip which will typically look
203 like cheets_(${LABEL})*${ARCH}_userdebug-target_files-S{VERSION}.zip.
204
205 Args:
206 build: the build being mirrored, e.g. 'X86', 'ARM', 'X86_USERDEBUG'.
207 basename: the basename of the artifact to copy.
208
209 Returns:
210 The basename of the destination.
211 """
212 if build not in constants.ARC_BUILDS_NEED_ARTIFACTS_RENAMED:
213 return basename
Yūki Ishiief1ada92018-03-27 15:46:15 +0900214 if basename in constants.ARC_ARTIFACTS_RENAME_NOT_NEEDED:
215 return basename
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800216 to_discard, sep, to_keep = basename.partition('-')
217 if not sep:
218 logging.error(('Build %s: Could not find separator "-" in artifact'
219 ' basename %s'), build, basename)
220 return basename
Bernie Thompson63ed5612017-08-16 12:27:34 -0700221 if 'cheets_' in to_discard:
222 return 'cheets_%s-%s' % (build.lower(), to_keep)
223 elif 'bertha_' in to_discard:
224 return 'bertha_%s-%s' % (build.lower(), to_keep)
225 logging.error('Build %s: Unexpected artifact basename %s',
226 build, basename)
227 return basename
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800228
229
khmel@google.com778a1cd2018-04-13 11:11:58 -0700230def PackSdkTools(build_branch, build_id, targets, arc_bucket_url):
231 """Creates static SDK tools pack from ARC++ specific bucket.
232
233 Ebuild needs archives to process binaries natively. This collects static SDK
234 tools and packs them to tbz2 archive which can referenced from Android
235 container ebuild file. Pack is placed into the same bucket where SDK tools
236 exist. If pack already exists and up to date then copying is skipped.
237 Otherwise fresh pack is copied.
238
239 Args:
240 build_branch: branch of Android builds
241 build_id: A string. The Android build id number to check.
242 targets: Dict from build key to (targe build suffix, artifact file pattern)
243 pair.
244 arc_bucket_url: URL of the target ARC build gs bucket
245 """
246
247 if not 'SDK_TOOLS' in targets:
248 return
249
250 gs_context = gs.GSContext()
251 target, pattern = targets['SDK_TOOLS']
252 build_dir = '%s-%s' % (build_branch, target)
253 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
254
255 sdk_tools_dir = tempfile.mkdtemp()
256
257 try:
258 sdk_tools_bin_dir = os.path.join(sdk_tools_dir, 'bin')
259 os.mkdir(sdk_tools_bin_dir)
260
261 for tool in gs_context.List(arc_dir):
262 if re.search(pattern, tool.url):
263 local_tool_path = os.path.join(sdk_tools_bin_dir,
264 os.path.basename(tool.url))
265 gs_context.Copy(tool.url, local_tool_path, version=0)
266 file_time = int(gs_context.Stat(tool.url).creation_time.strftime('%s'))
267 os.utime(local_tool_path, (file_time, file_time))
268
269 # Fix ./ times to make tar file stable.
270 os.utime(sdk_tools_bin_dir, (0, 0))
271
272 sdk_tools_file_name = 'sdk_tools_%s.tbz2' % build_id
273 sdk_tools_local_path = os.path.join(sdk_tools_dir, sdk_tools_file_name)
274 sdk_tools_target_path = os.path.join(arc_dir, sdk_tools_file_name)
275 subprocess.call(['tar', '--group=root:0', '--owner=root:0',
276 '--create', '--bzip2', '--sort=name',
277 '--file=%s' % sdk_tools_local_path,
278 '--directory=%s' % sdk_tools_bin_dir, '.'])
279
280 if gs_context.Exists(sdk_tools_target_path):
281 # Calculate local md5
282 md5 = hashlib.md5()
283 with open(sdk_tools_local_path, 'rb') as f:
284 while True:
285 buf = f.read(4096)
286 if not buf:
287 break
288 md5.update(buf)
289 md5_local = md5.digest()
290 # Get target md5
291 md5_target = base64.decodestring(
292 gs_context.Stat(sdk_tools_target_path).hash_md5)
293 if md5_local == md5_target:
294 logging.info('SDK tools pack %s is up to date', sdk_tools_target_path)
295 return
296 logging.warning('SDK tools pack %s invalid, removing',
297 sdk_tools_target_path)
298 gs_context.Remove(sdk_tools_target_path)
299
300 logging.info('Creating SDK tools pack %s', sdk_tools_target_path)
301 gs_context.Copy(sdk_tools_local_path, sdk_tools_target_path, version=0)
302 finally:
303 shutil.rmtree(sdk_tools_dir)
304
305
David Riley73f00d92016-02-16 18:54:20 -0800306def CopyToArcBucket(android_bucket_url, build_branch, build_id, subpaths,
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900307 targets, arc_bucket_url, acls):
David Riley73f00d92016-02-16 18:54:20 -0800308 """Copies from source Android bucket to ARC++ specific bucket.
309
310 Copies each build to the ARC bucket eliminating the subpath.
311 Applies build specific ACLs for each file.
312
313 Args:
314 android_bucket_url: URL of Android build gs bucket
315 build_branch: branch of Android builds
316 build_id: A string. The Android build id number to check.
317 subpaths: Subpath dictionary for each build to copy.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900318 targets: Dict from build key to (targe build suffix, artifact file pattern)
319 pair.
David Riley73f00d92016-02-16 18:54:20 -0800320 arc_bucket_url: URL of the target ARC build gs bucket
321 acls: ACLs dictionary for each build to copy.
322 """
323 gs_context = gs.GSContext()
324 for build, subpath in subpaths.iteritems():
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900325 target, pattern = targets[build]
David Riley73f00d92016-02-16 18:54:20 -0800326 build_dir = '%s-%s' % (build_branch, target)
327 android_dir = os.path.join(android_bucket_url, build_dir, build_id, subpath)
328 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
329
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900330 # Copy all target files from android_dir to arc_dir, setting ACLs.
331 for targetfile in gs_context.List(android_dir):
332 if re.search(pattern, targetfile.url):
333 basename = os.path.basename(targetfile.url)
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800334 arc_path = os.path.join(arc_dir, _GetArcBasename(build, basename))
David Riley73f00d92016-02-16 18:54:20 -0800335 acl = acls[build]
336 needs_copy = True
khmel@google.com96c193e2018-05-10 14:00:38 -0700337 retry_count = 2
David Riley73f00d92016-02-16 18:54:20 -0800338
khmel@google.com96c193e2018-05-10 14:00:38 -0700339 # Retry in case race condition when several boards trying to copy the
340 # same resource
341 while True:
342 # Check a pre-existing file with the original source.
343 if gs_context.Exists(arc_path):
344 if (gs_context.Stat(targetfile.url).hash_crc32c !=
345 gs_context.Stat(arc_path).hash_crc32c):
346 logging.warn('Removing incorrect file %s', arc_path)
347 gs_context.Remove(arc_path)
348 else:
349 logging.info('Skipping already copied file %s', arc_path)
350 needs_copy = False
David Riley73f00d92016-02-16 18:54:20 -0800351
khmel@google.com96c193e2018-05-10 14:00:38 -0700352 # Copy if necessary, and set the ACL unconditionally.
353 # The Stat() call above doesn't verify the ACL is correct and
354 # the ChangeACL should be relatively cheap compared to the copy.
355 # This covers the following caes:
356 # - handling an interrupted copy from a previous run.
357 # - rerunning the copy in case one of the googlestorage_acl_X.txt
358 # files changes (e.g. we add a new variant which reuses a build).
359 if needs_copy:
360 logging.info('Copying %s -> %s (acl %s)',
361 targetfile.url, arc_path, acl)
362 try:
363 gs_context.Copy(targetfile.url, arc_path, version=0)
364 except gs.GSContextPreconditionFailed as error:
365 if not retry_count:
366 raise error
367 # Retry one more time after a short delay
368 logging.warning('Will retry copying %s -> %s',
369 targetfile.url, arc_path)
370 time.sleep(5)
371 retry_count = retry_count - 1
372 continue
373 gs_context.ChangeACL(arc_path, acl_args_file=acl)
374 break
David Riley73f00d92016-02-16 18:54:20 -0800375
376
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900377def MirrorArtifacts(android_bucket_url, android_build_branch, arc_bucket_url,
378 acls, targets, version=None):
379 """Mirrors artifacts from Android bucket to ARC bucket.
380
381 First, this function identifies which build version should be copied,
382 if not given. Please see GetLatestBuild() and IsBuildIdValid() for details.
383
384 On build version identified, then copies target artifacts to the ARC bucket,
385 with setting ACLs.
386
387 Args:
388 android_bucket_url: URL of Android build gs bucket
389 android_build_branch: branch of Android builds
390 arc_bucket_url: URL of the target ARC build gs bucket
391 acls: ACLs dictionary for each build to copy.
392 targets: Dict from build key to (targe build suffix, artifact file pattern)
393 pair.
394 version: (optional) A string. The Android build id number to check.
395 If not passed, detect latest good build version.
396
397 Returns:
398 Mirrored version.
399 """
400 if version:
401 subpaths = IsBuildIdValid(
402 android_bucket_url, android_build_branch, version, targets)
403 if not subpaths:
404 logging.error('Requested build %s is not valid' % version)
405 else:
406 version, subpaths = GetLatestBuild(
407 android_bucket_url, android_build_branch, targets)
408
409 CopyToArcBucket(android_bucket_url, android_build_branch, version, subpaths,
410 targets, arc_bucket_url, acls)
khmel@google.com778a1cd2018-04-13 11:11:58 -0700411 PackSdkTools(android_build_branch, version, targets, arc_bucket_url)
412
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900413 return version
414
415
David Riley73f00d92016-02-16 18:54:20 -0800416def MakeAclDict(package_dir):
417 """Creates a dictionary of acl files for each build type.
418
419 Args:
420 package_dir: The path to where the package acl files are stored.
421
422 Returns:
423 Returns acls dictionary.
424 """
425 return dict(
426 (k, os.path.join(package_dir, v))
427 for k, v in constants.ARC_BUCKET_ACLS.items()
428 )
429
430
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700431def MakeBuildTargetDict(build_branch):
432 """Creates a dictionary of build targets.
433
Bernie Thompson63ed5612017-08-16 12:27:34 -0700434 Not all targets are common between branches, for example
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700435 sdk_google_cheets_x86 only exists on N.
436 This generates a dictionary listing the available build targets for a
437 specific branch.
438
439 Args:
440 build_branch: branch of Android builds.
441
442 Returns:
443 Returns build target dictionary.
444
445 Raises:
446 ValueError: if the Android build branch is invalid.
447 """
Bernie Thompson54650022018-01-12 10:03:20 -0800448 if build_branch == constants.ANDROID_MST_BUILD_BRANCH:
449 return constants.ANDROID_MST_BUILD_TARGETS
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700450 elif build_branch == constants.ANDROID_NYC_BUILD_BRANCH:
Bernie Thompson63ed5612017-08-16 12:27:34 -0700451 return constants.ANDROID_NYC_BUILD_TARGETS
Ben Linb8499402018-03-08 16:54:00 -0800452 elif build_branch == constants.ANDROID_PI_BUILD_BRANCH:
453 return constants.ANDROID_PI_BUILD_TARGETS
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700454 else:
455 raise ValueError('Unknown branch: %s' % build_branch)
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700456
457
David Rileyc0da9d92016-02-01 12:11:01 -0800458def GetAndroidRevisionListLink(build_branch, old_android, new_android):
459 """Returns a link to the list of revisions between two Android versions
460
461 Given two AndroidEBuilds, generate a link to a page that prints the
462 Android changes between those two revisions, inclusive.
463
464 Args:
465 build_branch: branch of Android builds
466 old_android: ebuild for the version to diff from
467 new_android: ebuild for the version to which to diff
468
469 Returns:
470 The desired URL.
471 """
472 return _ANDROID_VERSION_URL % {'branch': build_branch,
Hidehiko Abec9ecf262017-07-05 15:17:41 +0900473 'old': old_android.version_no_rev,
474 'new': new_android.version_no_rev}
David Rileyc0da9d92016-02-01 12:11:01 -0800475
476
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900477def MarkAndroidEBuildAsStable(stable_candidate, unstable_ebuild,
478 android_package, android_version, package_dir,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700479 build_branch, arc_bucket_url, build_targets):
David Rileyc0da9d92016-02-01 12:11:01 -0800480 r"""Uprevs the Android ebuild.
481
482 This is the main function that uprevs from a stable candidate
483 to its new version.
484
485 Args:
486 stable_candidate: ebuild that corresponds to the stable ebuild we are
487 revving from. If None, builds the a new ebuild given the version
488 with revision set to 1.
489 unstable_ebuild: ebuild corresponding to the unstable ebuild for Android.
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900490 android_package: android package name.
David Rileyc0da9d92016-02-01 12:11:01 -0800491 android_version: The \d+ build id of Android.
David Rileyc0da9d92016-02-01 12:11:01 -0800492 package_dir: Path to the android-container package dir.
David Riley73f00d92016-02-16 18:54:20 -0800493 build_branch: branch of Android builds.
494 arc_bucket_url: URL of the target ARC build gs bucket.
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700495 build_targets: build targets for this particular Android branch.
David Rileyc0da9d92016-02-01 12:11:01 -0800496
497 Returns:
498 Full portage version atom (including rc's, etc) that was revved.
499 """
500 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
501 """Returns True if the new ebuild is redundant.
502
503 This is True if there if the current stable ebuild is the exact same copy
504 of the new one.
505 """
506 if not stable_ebuild:
507 return False
508
David Riley676f5402016-02-12 17:24:23 -0800509 if stable_candidate.version_no_rev == new_ebuild.version_no_rev:
David Rileyc0da9d92016-02-01 12:11:01 -0800510 return filecmp.cmp(
511 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False)
512
513 # Case where we have the last stable candidate with same version just rev.
David Riley676f5402016-02-12 17:24:23 -0800514 if stable_candidate and stable_candidate.version_no_rev == android_version:
David Rileyc0da9d92016-02-01 12:11:01 -0800515 new_ebuild_path = '%s-r%d.ebuild' % (
516 stable_candidate.ebuild_path_no_revision,
517 stable_candidate.current_revision + 1)
518 else:
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900519 pf = '%s-%s-r1' % (android_package, android_version)
David Rileyc0da9d92016-02-01 12:11:01 -0800520 new_ebuild_path = os.path.join(package_dir, '%s.ebuild' % pf)
521
David Riley73f00d92016-02-16 18:54:20 -0800522 variables = {'BASE_URL': arc_bucket_url}
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700523 for build, (target, _) in build_targets.iteritems():
David Riley73f00d92016-02-16 18:54:20 -0800524 variables[build + '_TARGET'] = '%s-%s' % (build_branch, target)
David Rileyc0da9d92016-02-01 12:11:01 -0800525
526 portage_util.EBuild.MarkAsStable(
527 unstable_ebuild.ebuild_path, new_ebuild_path,
528 variables, make_stable=True)
529 new_ebuild = portage_util.EBuild(new_ebuild_path)
530
531 # Determine whether this is ebuild is redundant.
532 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
533 msg = 'Previous ebuild with same version found and ebuild is redundant.'
534 logging.info(msg)
535 os.unlink(new_ebuild_path)
536 return None
537
538 if stable_candidate:
539 logging.PrintBuildbotLink('Android revisions',
540 GetAndroidRevisionListLink(build_branch,
541 stable_candidate,
542 new_ebuild))
543
544 git.RunGit(package_dir, ['add', new_ebuild_path])
545 if stable_candidate and not stable_candidate.IsSticky():
546 git.RunGit(package_dir, ['rm', stable_candidate.ebuild_path])
547
548 # Update ebuild manifest and git add it.
549 gen_manifest_cmd = ['ebuild', new_ebuild_path, 'manifest', '--force']
550 cros_build_lib.RunCommand(gen_manifest_cmd,
551 extra_env=None, print_cmd=True)
552 git.RunGit(package_dir, ['add', 'Manifest'])
553
554 portage_util.EBuild.CommitChange(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900555 _GIT_COMMIT_MESSAGE % {'android_package': android_package,
David Rileyc0da9d92016-02-01 12:11:01 -0800556 'android_version': android_version},
557 package_dir)
558
559 return '%s-%s' % (new_ebuild.package, new_ebuild.version)
560
561
562def GetParser():
563 """Creates the argument parser."""
564 parser = commandline.ArgumentParser()
565 parser.add_argument('-b', '--boards')
566 parser.add_argument('--android_bucket_url',
David Riley73f00d92016-02-16 18:54:20 -0800567 default=constants.ANDROID_BUCKET_URL,
568 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800569 parser.add_argument('--android_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900570 required=True,
571 help='Android branch to import from. '
572 'Ex: git_mnc-dr-arc-dev')
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900573 parser.add_argument('--android_gts_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900574 help='Android GTS branch to copy artifacts from. '
575 'Ex: git_mnc-dev')
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900576 parser.add_argument('--android_package',
577 default=constants.ANDROID_PACKAGE_NAME)
David Riley73f00d92016-02-16 18:54:20 -0800578 parser.add_argument('--arc_bucket_url',
579 default=constants.ARC_BUCKET_URL,
580 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800581 parser.add_argument('-f', '--force_version',
582 help='Android build id to use')
583 parser.add_argument('-s', '--srcroot',
584 default=os.path.join(os.environ['HOME'], 'trunk', 'src'),
585 help='Path to the src directory')
586 parser.add_argument('-t', '--tracking_branch', default='cros/master',
587 help='Branch we are tracking changes against')
588 return parser
589
590
591def main(argv):
Hidehiko Abec9ecf262017-07-05 15:17:41 +0900592 logging.EnableBuildbotMarkers()
David Rileyc0da9d92016-02-01 12:11:01 -0800593 parser = GetParser()
594 options = parser.parse_args(argv)
595 options.Freeze()
596
597 overlay_dir = os.path.abspath(_OVERLAY_DIR % {'srcroot': options.srcroot})
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900598 android_package_dir = os.path.join(
599 overlay_dir,
600 portage_util.GetFullAndroidPortagePackageName(options.android_package))
David Rileyc0da9d92016-02-01 12:11:01 -0800601 version_to_uprev = None
David Rileyc0da9d92016-02-01 12:11:01 -0800602
603 (unstable_ebuild, stable_ebuilds) = FindAndroidCandidates(android_package_dir)
David Riley73f00d92016-02-16 18:54:20 -0800604 acls = MakeAclDict(android_package_dir)
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700605 build_targets = MakeBuildTargetDict(options.android_build_branch)
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900606 # Mirror artifacts, i.e., images and some sdk tools (e.g., adb, aapt).
607 version_to_uprev = MirrorArtifacts(options.android_bucket_url,
608 options.android_build_branch,
609 options.arc_bucket_url, acls,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700610 build_targets,
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900611 options.force_version)
612
613 # Mirror GTS.
Hidehiko Abee8cd06c2017-05-12 23:32:19 +0900614 if options.android_gts_build_branch:
615 MirrorArtifacts(options.android_bucket_url,
616 options.android_gts_build_branch,
617 options.arc_bucket_url, acls,
618 constants.ANDROID_GTS_BUILD_TARGETS)
David Riley73f00d92016-02-16 18:54:20 -0800619
David Rileyc0da9d92016-02-01 12:11:01 -0800620 stable_candidate = portage_util.BestEBuild(stable_ebuilds)
621
622 if stable_candidate:
David Riley676f5402016-02-12 17:24:23 -0800623 logging.info('Stable candidate found %s' % stable_candidate.version)
David Rileyc0da9d92016-02-01 12:11:01 -0800624 else:
625 logging.info('No stable candidate found.')
626
627 tracking_branch = 'remotes/m/%s' % os.path.basename(options.tracking_branch)
628 existing_branch = git.GetCurrentBranch(android_package_dir)
629 work_branch = cros_mark_as_stable.GitBranch(constants.STABLE_EBUILD_BRANCH,
630 tracking_branch,
631 android_package_dir)
632 work_branch.CreateBranch()
633
634 # In the case of uprevving overlays that have patches applied to them,
635 # include the patched changes in the stabilizing branch.
636 if existing_branch:
637 git.RunGit(overlay_dir, ['rebase', existing_branch])
638
639 android_version_atom = MarkAndroidEBuildAsStable(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900640 stable_candidate, unstable_ebuild, options.android_package,
David Riley73f00d92016-02-16 18:54:20 -0800641 version_to_uprev, android_package_dir,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700642 options.android_build_branch, options.arc_bucket_url, build_targets)
David Rileyc0da9d92016-02-01 12:11:01 -0800643 if android_version_atom:
644 if options.boards:
645 cros_mark_as_stable.CleanStalePackages(options.srcroot,
646 options.boards.split(':'),
647 [android_version_atom])
648
649 # Explicit print to communicate to caller.
650 print('ANDROID_VERSION_ATOM=%s' % android_version_atom)