blob: f444ed3c1c6d38b407983e575d8b45bbbf2e485a [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 \
Shao-Chuan Lee9c39e0c2020-04-24 11:40:34 +090013 --android_build_branch=git_pi-arc \
14 --android_package=android-container-pi
Shuhei Takahashi6d02c192017-04-05 14:01:24 +090015
Shao-Chuan Lee9c39e0c2020-04-24 11:40:34 +090016Returns chromeos-base/android-container-pi-6417892-r1
David Rileyc0da9d92016-02-01 12:11:01 -080017
Shao-Chuan Lee9c39e0c2020-04-24 11:40:34 +090018emerge-eve =chromeos-base/android-container-pi-6417892-r1
David Rileyc0da9d92016-02-01 12:11:01 -080019"""
20
21from __future__ import print_function
22
Mike Frysinger00a02292020-04-19 06:28:03 -040023import base64
David Rileyc0da9d92016-02-01 12:11:01 -080024import 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
Mike Frysinger00a02292020-04-19 06:28:03 -040033import sys
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
Mike Frysinger00a02292020-04-19 06:28:03 -040045assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
46
47
David Rileyc0da9d92016-02-01 12:11:01 -080048# Dir where all the action happens.
49_OVERLAY_DIR = '%(srcroot)s/private-overlays/project-cheets-private/'
50
Junichi Uekawa6d61ab02020-04-15 14:52:28 +090051_GIT_COMMIT_MESSAGE = """Marking latest for %(android_package)s ebuild with \
52version %(android_version)s as stable.
53
54BUG=None
55TEST=CQ
56"""
David Rileyc0da9d92016-02-01 12:11:01 -080057
58# URLs that print lists of Android revisions between two build ids.
59_ANDROID_VERSION_URL = ('http://android-build-uber.corp.google.com/repo.html?'
60 'last_bid=%(old)s&bid=%(new)s&branch=%(branch)s')
61
62
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090063def IsBuildIdValid(bucket_url, build_branch, build_id, targets):
David Rileyc0da9d92016-02-01 12:11:01 -080064 """Checks that a specific build_id is valid.
65
66 Looks for that build_id for all builds. Confirms that the subpath can
67 be found and that the zip file is present in that subdirectory.
68
69 Args:
70 bucket_url: URL of Android build gs bucket
71 build_branch: branch of Android builds
72 build_id: A string. The Android build id number to check.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090073 targets: Dict from build key to (targe build suffix, artifact file pattern)
74 pair.
David Rileyc0da9d92016-02-01 12:11:01 -080075
76 Returns:
77 Returns subpaths dictionary if build_id is valid.
78 None if the build_id is not valid.
79 """
80 gs_context = gs.GSContext()
81 subpaths_dict = {}
Mike Frysinger0bdbc102019-06-13 15:27:29 -040082 for build, (target, _) in targets.items():
David Rileyc0da9d92016-02-01 12:11:01 -080083 build_dir = '%s-%s' % (build_branch, target)
84 build_id_path = os.path.join(bucket_url, build_dir, build_id)
85
86 # Find name of subpath.
87 try:
88 subpaths = gs_context.List(build_id_path)
89 except gs.GSNoSuchKey:
90 logging.warn(
91 'Directory [%s] does not contain any subpath, ignoring it.',
92 build_id_path)
93 return None
94 if len(subpaths) > 1:
95 logging.warn(
96 'Directory [%s] contains more than one subpath, ignoring it.',
97 build_id_path)
98 return None
99
100 subpath_dir = subpaths[0].url.rstrip('/')
101 subpath_name = os.path.basename(subpath_dir)
102
103 # Look for a zipfile ending in the build_id number.
104 try:
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900105 gs_context.List(subpath_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800106 except gs.GSNoSuchKey:
107 logging.warn(
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900108 'Did not find a file for build id [%s] in directory [%s].',
David Rileyc0da9d92016-02-01 12:11:01 -0800109 build_id, subpath_dir)
110 return None
111
112 # Record subpath for the build.
113 subpaths_dict[build] = subpath_name
114
115 # If we got here, it means we found an appropriate build for all platforms.
116 return subpaths_dict
117
118
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900119def GetLatestBuild(bucket_url, build_branch, targets):
David Rileyc0da9d92016-02-01 12:11:01 -0800120 """Searches the gs bucket for the latest green build.
121
122 Args:
123 bucket_url: URL of Android build gs bucket
124 build_branch: branch of Android builds
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900125 targets: Dict from build key to (targe build suffix, artifact file pattern)
126 pair.
David Rileyc0da9d92016-02-01 12:11:01 -0800127
128 Returns:
129 Tuple of (latest version string, subpaths dictionary)
130 If no latest build can be found, returns None, None
131 """
132 gs_context = gs.GSContext()
133 common_build_ids = None
134 # Find builds for each target.
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400135 for target, _ in targets.values():
David Rileyc0da9d92016-02-01 12:11:01 -0800136 build_dir = '-'.join((build_branch, target))
137 base_path = os.path.join(bucket_url, build_dir)
138 build_ids = []
139 for gs_result in gs_context.List(base_path):
140 # Remove trailing slashes and get the base name, which is the build_id.
141 build_id = os.path.basename(gs_result.url.rstrip('/'))
142 if not build_id.isdigit():
143 logging.warn('Directory [%s] does not look like a valid build_id.',
144 gs_result.url)
145 continue
146 build_ids.append(build_id)
147
148 # Update current list of builds.
149 if common_build_ids is None:
150 # First run, populate it with the first platform.
151 common_build_ids = set(build_ids)
152 else:
153 # Already populated, find the ones that are common.
154 common_build_ids.intersection_update(build_ids)
155
156 if common_build_ids is None:
157 logging.warn('Did not find a build_id common to all platforms.')
158 return None, None
159
160 # Otherwise, find the most recent one that is valid.
161 for build_id in sorted(common_build_ids, key=int, reverse=True):
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900162 subpaths = IsBuildIdValid(bucket_url, build_branch, build_id, targets)
David Rileyc0da9d92016-02-01 12:11:01 -0800163 if subpaths:
164 return build_id, subpaths
165
166 # If not found, no build_id is valid.
167 logging.warn('Did not find a build_id valid on all platforms.')
168 return None, None
169
170
171def FindAndroidCandidates(package_dir):
172 """Return a tuple of Android's unstable ebuild and stable ebuilds.
173
174 Args:
175 package_dir: The path to where the package ebuild is stored.
176
177 Returns:
178 Tuple [unstable_ebuild, stable_ebuilds].
179
180 Raises:
181 Exception: if no unstable ebuild exists for Android.
182 """
183 stable_ebuilds = []
184 unstable_ebuilds = []
185 for path in glob.glob(os.path.join(package_dir, '*.ebuild')):
186 ebuild = portage_util.EBuild(path)
187 if ebuild.version == '9999':
188 unstable_ebuilds.append(ebuild)
189 else:
190 stable_ebuilds.append(ebuild)
191
192 # Apply some sanity checks.
193 if not unstable_ebuilds:
194 raise Exception('Missing 9999 ebuild for %s' % package_dir)
195 if not stable_ebuilds:
Lann Martinffb95162018-08-28 12:02:54 -0600196 logging.warning('Missing stable ebuild for %s', package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800197
198 return portage_util.BestEBuild(unstable_ebuilds), stable_ebuilds
199
200
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800201def _GetArcBasename(build, basename):
202 """Tweaks filenames between Android bucket and ARC++ bucket.
203
204 Android builders create build artifacts with the same name for -user and
205 -userdebug builds, which breaks the android-container ebuild (b/33072485).
206 When copying the artifacts from the Android bucket to the ARC++ bucket some
207 artifacts will be renamed from the usual pattern
208 *cheets_${ARCH}-target_files-S{VERSION}.zip to
209 cheets_${BUILD_NAME}-target_files-S{VERSION}.zip which will typically look
210 like cheets_(${LABEL})*${ARCH}_userdebug-target_files-S{VERSION}.zip.
211
212 Args:
213 build: the build being mirrored, e.g. 'X86', 'ARM', 'X86_USERDEBUG'.
214 basename: the basename of the artifact to copy.
215
216 Returns:
217 The basename of the destination.
218 """
219 if build not in constants.ARC_BUILDS_NEED_ARTIFACTS_RENAMED:
220 return basename
Yūki Ishiief1ada92018-03-27 15:46:15 +0900221 if basename in constants.ARC_ARTIFACTS_RENAME_NOT_NEEDED:
222 return basename
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800223 to_discard, sep, to_keep = basename.partition('-')
224 if not sep:
225 logging.error(('Build %s: Could not find separator "-" in artifact'
226 ' basename %s'), build, basename)
227 return basename
Bernie Thompson63ed5612017-08-16 12:27:34 -0700228 if 'cheets_' in to_discard:
229 return 'cheets_%s-%s' % (build.lower(), to_keep)
230 elif 'bertha_' in to_discard:
231 return 'bertha_%s-%s' % (build.lower(), to_keep)
232 logging.error('Build %s: Unexpected artifact basename %s',
233 build, basename)
234 return basename
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800235
236
khmel@google.com50c42dd2018-05-11 11:33:35 -0700237def PackSdkTools(build_branch, build_id, targets, arc_bucket_url, acl):
khmel@google.com778a1cd2018-04-13 11:11:58 -0700238 """Creates static SDK tools pack from ARC++ specific bucket.
239
240 Ebuild needs archives to process binaries natively. This collects static SDK
241 tools and packs them to tbz2 archive which can referenced from Android
242 container ebuild file. Pack is placed into the same bucket where SDK tools
243 exist. If pack already exists and up to date then copying is skipped.
244 Otherwise fresh pack is copied.
245
246 Args:
247 build_branch: branch of Android builds
248 build_id: A string. The Android build id number to check.
249 targets: Dict from build key to (targe build suffix, artifact file pattern)
250 pair.
251 arc_bucket_url: URL of the target ARC build gs bucket
khmel@google.com50c42dd2018-05-11 11:33:35 -0700252 acl: ACL file to apply.
khmel@google.com778a1cd2018-04-13 11:11:58 -0700253 """
254
255 if not 'SDK_TOOLS' in targets:
256 return
257
258 gs_context = gs.GSContext()
259 target, pattern = targets['SDK_TOOLS']
260 build_dir = '%s-%s' % (build_branch, target)
261 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
262
263 sdk_tools_dir = tempfile.mkdtemp()
264
265 try:
266 sdk_tools_bin_dir = os.path.join(sdk_tools_dir, 'bin')
267 os.mkdir(sdk_tools_bin_dir)
268
269 for tool in gs_context.List(arc_dir):
270 if re.search(pattern, tool.url):
271 local_tool_path = os.path.join(sdk_tools_bin_dir,
272 os.path.basename(tool.url))
273 gs_context.Copy(tool.url, local_tool_path, version=0)
274 file_time = int(gs_context.Stat(tool.url).creation_time.strftime('%s'))
275 os.utime(local_tool_path, (file_time, file_time))
276
277 # Fix ./ times to make tar file stable.
278 os.utime(sdk_tools_bin_dir, (0, 0))
279
280 sdk_tools_file_name = 'sdk_tools_%s.tbz2' % build_id
281 sdk_tools_local_path = os.path.join(sdk_tools_dir, sdk_tools_file_name)
282 sdk_tools_target_path = os.path.join(arc_dir, sdk_tools_file_name)
283 subprocess.call(['tar', '--group=root:0', '--owner=root:0',
284 '--create', '--bzip2', '--sort=name',
285 '--file=%s' % sdk_tools_local_path,
286 '--directory=%s' % sdk_tools_bin_dir, '.'])
287
288 if gs_context.Exists(sdk_tools_target_path):
289 # Calculate local md5
290 md5 = hashlib.md5()
291 with open(sdk_tools_local_path, 'rb') as f:
292 while True:
293 buf = f.read(4096)
294 if not buf:
295 break
296 md5.update(buf)
297 md5_local = md5.digest()
298 # Get target md5
299 md5_target = base64.decodestring(
300 gs_context.Stat(sdk_tools_target_path).hash_md5)
301 if md5_local == md5_target:
302 logging.info('SDK tools pack %s is up to date', sdk_tools_target_path)
303 return
304 logging.warning('SDK tools pack %s invalid, removing',
305 sdk_tools_target_path)
306 gs_context.Remove(sdk_tools_target_path)
307
308 logging.info('Creating SDK tools pack %s', sdk_tools_target_path)
309 gs_context.Copy(sdk_tools_local_path, sdk_tools_target_path, version=0)
khmel@google.com50c42dd2018-05-11 11:33:35 -0700310 gs_context.ChangeACL(sdk_tools_target_path, acl_args_file=acl)
khmel@google.com778a1cd2018-04-13 11:11:58 -0700311 finally:
312 shutil.rmtree(sdk_tools_dir)
313
314
David Riley73f00d92016-02-16 18:54:20 -0800315def CopyToArcBucket(android_bucket_url, build_branch, build_id, subpaths,
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900316 targets, arc_bucket_url, acls):
David Riley73f00d92016-02-16 18:54:20 -0800317 """Copies from source Android bucket to ARC++ specific bucket.
318
319 Copies each build to the ARC bucket eliminating the subpath.
320 Applies build specific ACLs for each file.
321
322 Args:
323 android_bucket_url: URL of Android build gs bucket
324 build_branch: branch of Android builds
325 build_id: A string. The Android build id number to check.
326 subpaths: Subpath dictionary for each build to copy.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900327 targets: Dict from build key to (targe build suffix, artifact file pattern)
328 pair.
David Riley73f00d92016-02-16 18:54:20 -0800329 arc_bucket_url: URL of the target ARC build gs bucket
330 acls: ACLs dictionary for each build to copy.
331 """
332 gs_context = gs.GSContext()
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400333 for build, subpath in subpaths.items():
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900334 target, pattern = targets[build]
David Riley73f00d92016-02-16 18:54:20 -0800335 build_dir = '%s-%s' % (build_branch, target)
336 android_dir = os.path.join(android_bucket_url, build_dir, build_id, subpath)
337 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
338
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900339 # Copy all target files from android_dir to arc_dir, setting ACLs.
340 for targetfile in gs_context.List(android_dir):
341 if re.search(pattern, targetfile.url):
342 basename = os.path.basename(targetfile.url)
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800343 arc_path = os.path.join(arc_dir, _GetArcBasename(build, basename))
David Riley73f00d92016-02-16 18:54:20 -0800344 acl = acls[build]
345 needs_copy = True
khmel@google.com96c193e2018-05-10 14:00:38 -0700346 retry_count = 2
David Riley73f00d92016-02-16 18:54:20 -0800347
khmel@google.com96c193e2018-05-10 14:00:38 -0700348 # Retry in case race condition when several boards trying to copy the
349 # same resource
350 while True:
351 # Check a pre-existing file with the original source.
352 if gs_context.Exists(arc_path):
353 if (gs_context.Stat(targetfile.url).hash_crc32c !=
354 gs_context.Stat(arc_path).hash_crc32c):
355 logging.warn('Removing incorrect file %s', arc_path)
356 gs_context.Remove(arc_path)
357 else:
358 logging.info('Skipping already copied file %s', arc_path)
359 needs_copy = False
David Riley73f00d92016-02-16 18:54:20 -0800360
khmel@google.com96c193e2018-05-10 14:00:38 -0700361 # Copy if necessary, and set the ACL unconditionally.
362 # The Stat() call above doesn't verify the ACL is correct and
363 # the ChangeACL should be relatively cheap compared to the copy.
364 # This covers the following caes:
365 # - handling an interrupted copy from a previous run.
366 # - rerunning the copy in case one of the googlestorage_acl_X.txt
367 # files changes (e.g. we add a new variant which reuses a build).
368 if needs_copy:
369 logging.info('Copying %s -> %s (acl %s)',
370 targetfile.url, arc_path, acl)
371 try:
372 gs_context.Copy(targetfile.url, arc_path, version=0)
373 except gs.GSContextPreconditionFailed as error:
374 if not retry_count:
375 raise error
376 # Retry one more time after a short delay
377 logging.warning('Will retry copying %s -> %s',
378 targetfile.url, arc_path)
379 time.sleep(5)
380 retry_count = retry_count - 1
381 continue
382 gs_context.ChangeACL(arc_path, acl_args_file=acl)
383 break
David Riley73f00d92016-02-16 18:54:20 -0800384
385
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900386def MirrorArtifacts(android_bucket_url, android_build_branch, arc_bucket_url,
387 acls, targets, version=None):
388 """Mirrors artifacts from Android bucket to ARC bucket.
389
390 First, this function identifies which build version should be copied,
391 if not given. Please see GetLatestBuild() and IsBuildIdValid() for details.
392
393 On build version identified, then copies target artifacts to the ARC bucket,
394 with setting ACLs.
395
396 Args:
397 android_bucket_url: URL of Android build gs bucket
398 android_build_branch: branch of Android builds
399 arc_bucket_url: URL of the target ARC build gs bucket
400 acls: ACLs dictionary for each build to copy.
401 targets: Dict from build key to (targe build suffix, artifact file pattern)
402 pair.
403 version: (optional) A string. The Android build id number to check.
404 If not passed, detect latest good build version.
405
406 Returns:
407 Mirrored version.
408 """
409 if version:
410 subpaths = IsBuildIdValid(
411 android_bucket_url, android_build_branch, version, targets)
412 if not subpaths:
Lann Martinffb95162018-08-28 12:02:54 -0600413 logging.error('Requested build %s is not valid', version)
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900414 else:
415 version, subpaths = GetLatestBuild(
416 android_bucket_url, android_build_branch, targets)
417
418 CopyToArcBucket(android_bucket_url, android_build_branch, version, subpaths,
419 targets, arc_bucket_url, acls)
khmel@google.com50c42dd2018-05-11 11:33:35 -0700420 PackSdkTools(android_build_branch, version, targets, arc_bucket_url,
421 acls['SDK_TOOLS'])
khmel@google.com778a1cd2018-04-13 11:11:58 -0700422
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900423 return version
424
425
David Riley73f00d92016-02-16 18:54:20 -0800426def MakeAclDict(package_dir):
427 """Creates a dictionary of acl files for each build type.
428
429 Args:
430 package_dir: The path to where the package acl files are stored.
431
432 Returns:
433 Returns acls dictionary.
434 """
435 return dict(
436 (k, os.path.join(package_dir, v))
437 for k, v in constants.ARC_BUCKET_ACLS.items()
438 )
439
440
Qijiang Fan6588cc92019-11-20 13:26:04 +0900441def MakeBuildTargetDict(package_name, build_branch):
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700442 """Creates a dictionary of build targets.
443
Bernie Thompson63ed5612017-08-16 12:27:34 -0700444 Not all targets are common between branches, for example
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700445 sdk_google_cheets_x86 only exists on N.
446 This generates a dictionary listing the available build targets for a
447 specific branch.
448
449 Args:
Qijiang Fan6588cc92019-11-20 13:26:04 +0900450 package_name: package name of chromeos arc package.
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700451 build_branch: branch of Android builds.
452
453 Returns:
454 Returns build target dictionary.
455
456 Raises:
457 ValueError: if the Android build branch is invalid.
458 """
Qijiang Fan6588cc92019-11-20 13:26:04 +0900459 if constants.ANDROID_CONTAINER_PACKAGE_KEYWORD in package_name:
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900460 target_list = {
461 constants.ANDROID_MST_BUILD_BRANCH:
462 constants.ANDROID_MST_BUILD_TARGETS,
463 constants.ANDROID_NYC_BUILD_BRANCH:
464 constants.ANDROID_NYC_BUILD_TARGETS,
465 constants.ANDROID_PI_BUILD_BRANCH:
466 constants.ANDROID_PI_BUILD_TARGETS,
467 constants.ANDROID_QT_BUILD_BRANCH:
468 constants.ANDROID_QT_BUILD_TARGETS,
469 constants.ANDROID_RVC_BUILD_BRANCH:
470 constants.ANDROID_RVC_BUILD_TARGETS,
471 }
Qijiang Fan6588cc92019-11-20 13:26:04 +0900472 elif constants.ANDROID_VM_PACKAGE_KEYWORD in package_name:
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900473 target_list = {
474 constants.ANDROID_VMPI_BUILD_BRANCH:
475 constants.ANDROID_VMPI_BUILD_TARGETS,
476 constants.ANDROID_VMMST_BUILD_BRANCH:
477 constants.ANDROID_VMMST_BUILD_TARGETS,
478 constants.ANDROID_VMRVC_BUILD_BRANCH:
479 constants.ANDROID_VMRVC_BUILD_TARGETS,
480 }
481 else:
482 raise ValueError('Unknown package: %s' % package_name)
483 target = target_list.get(build_branch)
484 if not target:
Qijiang Fan6588cc92019-11-20 13:26:04 +0900485 raise ValueError('Unknown branch: %s' % build_branch)
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900486 return target
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700487
488
David Rileyc0da9d92016-02-01 12:11:01 -0800489def GetAndroidRevisionListLink(build_branch, old_android, new_android):
490 """Returns a link to the list of revisions between two Android versions
491
492 Given two AndroidEBuilds, generate a link to a page that prints the
493 Android changes between those two revisions, inclusive.
494
495 Args:
496 build_branch: branch of Android builds
497 old_android: ebuild for the version to diff from
498 new_android: ebuild for the version to which to diff
499
500 Returns:
501 The desired URL.
502 """
503 return _ANDROID_VERSION_URL % {'branch': build_branch,
Hidehiko Abec9ecf262017-07-05 15:17:41 +0900504 'old': old_android.version_no_rev,
505 'new': new_android.version_no_rev}
David Rileyc0da9d92016-02-01 12:11:01 -0800506
507
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900508def MarkAndroidEBuildAsStable(stable_candidate, unstable_ebuild,
509 android_package, android_version, package_dir,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700510 build_branch, arc_bucket_url, build_targets):
David Rileyc0da9d92016-02-01 12:11:01 -0800511 r"""Uprevs the Android ebuild.
512
513 This is the main function that uprevs from a stable candidate
514 to its new version.
515
516 Args:
517 stable_candidate: ebuild that corresponds to the stable ebuild we are
518 revving from. If None, builds the a new ebuild given the version
519 with revision set to 1.
520 unstable_ebuild: ebuild corresponding to the unstable ebuild for Android.
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900521 android_package: android package name.
David Rileyc0da9d92016-02-01 12:11:01 -0800522 android_version: The \d+ build id of Android.
David Rileyc0da9d92016-02-01 12:11:01 -0800523 package_dir: Path to the android-container package dir.
David Riley73f00d92016-02-16 18:54:20 -0800524 build_branch: branch of Android builds.
525 arc_bucket_url: URL of the target ARC build gs bucket.
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700526 build_targets: build targets for this particular Android branch.
David Rileyc0da9d92016-02-01 12:11:01 -0800527
528 Returns:
529 Full portage version atom (including rc's, etc) that was revved.
530 """
531 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
532 """Returns True if the new ebuild is redundant.
533
534 This is True if there if the current stable ebuild is the exact same copy
535 of the new one.
536 """
537 if not stable_ebuild:
538 return False
539
David Riley676f5402016-02-12 17:24:23 -0800540 if stable_candidate.version_no_rev == new_ebuild.version_no_rev:
David Rileyc0da9d92016-02-01 12:11:01 -0800541 return filecmp.cmp(
542 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False)
543
544 # Case where we have the last stable candidate with same version just rev.
David Riley676f5402016-02-12 17:24:23 -0800545 if stable_candidate and stable_candidate.version_no_rev == android_version:
David Rileyc0da9d92016-02-01 12:11:01 -0800546 new_ebuild_path = '%s-r%d.ebuild' % (
547 stable_candidate.ebuild_path_no_revision,
548 stable_candidate.current_revision + 1)
549 else:
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900550 pf = '%s-%s-r1' % (android_package, android_version)
David Rileyc0da9d92016-02-01 12:11:01 -0800551 new_ebuild_path = os.path.join(package_dir, '%s.ebuild' % pf)
552
David Riley73f00d92016-02-16 18:54:20 -0800553 variables = {'BASE_URL': arc_bucket_url}
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400554 for build, (target, _) in build_targets.items():
David Riley73f00d92016-02-16 18:54:20 -0800555 variables[build + '_TARGET'] = '%s-%s' % (build_branch, target)
David Rileyc0da9d92016-02-01 12:11:01 -0800556
557 portage_util.EBuild.MarkAsStable(
558 unstable_ebuild.ebuild_path, new_ebuild_path,
559 variables, make_stable=True)
560 new_ebuild = portage_util.EBuild(new_ebuild_path)
561
562 # Determine whether this is ebuild is redundant.
563 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
564 msg = 'Previous ebuild with same version found and ebuild is redundant.'
565 logging.info(msg)
566 os.unlink(new_ebuild_path)
567 return None
568
569 if stable_candidate:
570 logging.PrintBuildbotLink('Android revisions',
571 GetAndroidRevisionListLink(build_branch,
572 stable_candidate,
573 new_ebuild))
574
575 git.RunGit(package_dir, ['add', new_ebuild_path])
576 if stable_candidate and not stable_candidate.IsSticky():
577 git.RunGit(package_dir, ['rm', stable_candidate.ebuild_path])
578
579 # Update ebuild manifest and git add it.
580 gen_manifest_cmd = ['ebuild', new_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400581 cros_build_lib.run(gen_manifest_cmd, extra_env=None, print_cmd=True)
David Rileyc0da9d92016-02-01 12:11:01 -0800582 git.RunGit(package_dir, ['add', 'Manifest'])
583
584 portage_util.EBuild.CommitChange(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900585 _GIT_COMMIT_MESSAGE % {'android_package': android_package,
David Rileyc0da9d92016-02-01 12:11:01 -0800586 'android_version': android_version},
587 package_dir)
588
589 return '%s-%s' % (new_ebuild.package, new_ebuild.version)
590
591
592def GetParser():
593 """Creates the argument parser."""
594 parser = commandline.ArgumentParser()
595 parser.add_argument('-b', '--boards')
596 parser.add_argument('--android_bucket_url',
David Riley73f00d92016-02-16 18:54:20 -0800597 default=constants.ANDROID_BUCKET_URL,
598 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800599 parser.add_argument('--android_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900600 required=True,
601 help='Android branch to import from. '
602 'Ex: git_mnc-dr-arc-dev')
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900603 parser.add_argument('--android_package',
604 default=constants.ANDROID_PACKAGE_NAME)
David Riley73f00d92016-02-16 18:54:20 -0800605 parser.add_argument('--arc_bucket_url',
606 default=constants.ARC_BUCKET_URL,
607 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800608 parser.add_argument('-f', '--force_version',
609 help='Android build id to use')
610 parser.add_argument('-s', '--srcroot',
611 default=os.path.join(os.environ['HOME'], 'trunk', 'src'),
612 help='Path to the src directory')
613 parser.add_argument('-t', '--tracking_branch', default='cros/master',
614 help='Branch we are tracking changes against')
615 return parser
616
617
618def main(argv):
Hidehiko Abec9ecf262017-07-05 15:17:41 +0900619 logging.EnableBuildbotMarkers()
David Rileyc0da9d92016-02-01 12:11:01 -0800620 parser = GetParser()
621 options = parser.parse_args(argv)
622 options.Freeze()
623
624 overlay_dir = os.path.abspath(_OVERLAY_DIR % {'srcroot': options.srcroot})
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900625 android_package_dir = os.path.join(
626 overlay_dir,
627 portage_util.GetFullAndroidPortagePackageName(options.android_package))
David Rileyc0da9d92016-02-01 12:11:01 -0800628 version_to_uprev = None
David Rileyc0da9d92016-02-01 12:11:01 -0800629
630 (unstable_ebuild, stable_ebuilds) = FindAndroidCandidates(android_package_dir)
David Riley73f00d92016-02-16 18:54:20 -0800631 acls = MakeAclDict(android_package_dir)
Qijiang Fan6588cc92019-11-20 13:26:04 +0900632 build_targets = MakeBuildTargetDict(options.android_package,
633 options.android_build_branch)
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900634 # Mirror artifacts, i.e., images and some sdk tools (e.g., adb, aapt).
635 version_to_uprev = MirrorArtifacts(options.android_bucket_url,
636 options.android_build_branch,
637 options.arc_bucket_url, acls,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700638 build_targets,
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900639 options.force_version)
640
David Rileyc0da9d92016-02-01 12:11:01 -0800641 stable_candidate = portage_util.BestEBuild(stable_ebuilds)
642
643 if stable_candidate:
Lann Martinffb95162018-08-28 12:02:54 -0600644 logging.info('Stable candidate found %s', stable_candidate.version)
David Rileyc0da9d92016-02-01 12:11:01 -0800645 else:
646 logging.info('No stable candidate found.')
647
648 tracking_branch = 'remotes/m/%s' % os.path.basename(options.tracking_branch)
649 existing_branch = git.GetCurrentBranch(android_package_dir)
650 work_branch = cros_mark_as_stable.GitBranch(constants.STABLE_EBUILD_BRANCH,
651 tracking_branch,
652 android_package_dir)
653 work_branch.CreateBranch()
654
655 # In the case of uprevving overlays that have patches applied to them,
656 # include the patched changes in the stabilizing branch.
657 if existing_branch:
658 git.RunGit(overlay_dir, ['rebase', existing_branch])
659
660 android_version_atom = MarkAndroidEBuildAsStable(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900661 stable_candidate, unstable_ebuild, options.android_package,
David Riley73f00d92016-02-16 18:54:20 -0800662 version_to_uprev, android_package_dir,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700663 options.android_build_branch, options.arc_bucket_url, build_targets)
David Rileyc0da9d92016-02-01 12:11:01 -0800664 if android_version_atom:
665 if options.boards:
666 cros_mark_as_stable.CleanStalePackages(options.srcroot,
667 options.boards.split(':'),
668 [android_version_atom])
669
670 # Explicit print to communicate to caller.
671 print('ANDROID_VERSION_ATOM=%s' % android_version_atom)