blob: e96b99ef0f5257dd26d1cb2be136cc85fd91d084 [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
Mike Frysinger00a02292020-04-19 06:28:03 -040024import base64
David Rileyc0da9d92016-02-01 12:11:01 -080025import filecmp
khmel@google.com778a1cd2018-04-13 11:11:58 -070026import hashlib
David Rileyc0da9d92016-02-01 12:11:01 -080027import glob
28import os
Hidehiko Abe12727dd2016-05-27 23:23:45 +090029import re
khmel@google.com778a1cd2018-04-13 11:11:58 -070030import shutil
31import tempfile
khmel@google.com96c193e2018-05-10 14:00:38 -070032import time
khmel@google.com778a1cd2018-04-13 11:11:58 -070033import subprocess
Mike Frysinger00a02292020-04-19 06:28:03 -040034import sys
David Rileyc0da9d92016-02-01 12:11:01 -080035
Aviv Keshetb7519e12016-10-04 00:50:00 -070036from chromite.lib import constants
David Rileyc0da9d92016-02-01 12:11:01 -080037from chromite.lib import commandline
38from chromite.lib import cros_build_lib
39from chromite.lib import cros_logging as logging
40from chromite.lib import git
41from chromite.lib import gs
42from chromite.lib import portage_util
43from chromite.scripts import cros_mark_as_stable
44
45
Mike Frysinger00a02292020-04-19 06:28:03 -040046assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
47
48
David Rileyc0da9d92016-02-01 12:11:01 -080049# Dir where all the action happens.
50_OVERLAY_DIR = '%(srcroot)s/private-overlays/project-cheets-private/'
51
Junichi Uekawa6d61ab02020-04-15 14:52:28 +090052_GIT_COMMIT_MESSAGE = """Marking latest for %(android_package)s ebuild with \
53version %(android_version)s as stable.
54
55BUG=None
56TEST=CQ
57"""
David Rileyc0da9d92016-02-01 12:11:01 -080058
59# URLs that print lists of Android revisions between two build ids.
60_ANDROID_VERSION_URL = ('http://android-build-uber.corp.google.com/repo.html?'
61 'last_bid=%(old)s&bid=%(new)s&branch=%(branch)s')
62
63
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090064def IsBuildIdValid(bucket_url, build_branch, build_id, targets):
David Rileyc0da9d92016-02-01 12:11:01 -080065 """Checks that a specific build_id is valid.
66
67 Looks for that build_id for all builds. Confirms that the subpath can
68 be found and that the zip file is present in that subdirectory.
69
70 Args:
71 bucket_url: URL of Android build gs bucket
72 build_branch: branch of Android builds
73 build_id: A string. The Android build id number to check.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090074 targets: Dict from build key to (targe build suffix, artifact file pattern)
75 pair.
David Rileyc0da9d92016-02-01 12:11:01 -080076
77 Returns:
78 Returns subpaths dictionary if build_id is valid.
79 None if the build_id is not valid.
80 """
81 gs_context = gs.GSContext()
82 subpaths_dict = {}
Mike Frysinger0bdbc102019-06-13 15:27:29 -040083 for build, (target, _) in targets.items():
David Rileyc0da9d92016-02-01 12:11:01 -080084 build_dir = '%s-%s' % (build_branch, target)
85 build_id_path = os.path.join(bucket_url, build_dir, build_id)
86
87 # Find name of subpath.
88 try:
89 subpaths = gs_context.List(build_id_path)
90 except gs.GSNoSuchKey:
91 logging.warn(
92 'Directory [%s] does not contain any subpath, ignoring it.',
93 build_id_path)
94 return None
95 if len(subpaths) > 1:
96 logging.warn(
97 'Directory [%s] contains more than one subpath, ignoring it.',
98 build_id_path)
99 return None
100
101 subpath_dir = subpaths[0].url.rstrip('/')
102 subpath_name = os.path.basename(subpath_dir)
103
104 # Look for a zipfile ending in the build_id number.
105 try:
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900106 gs_context.List(subpath_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800107 except gs.GSNoSuchKey:
108 logging.warn(
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900109 'Did not find a file for build id [%s] in directory [%s].',
David Rileyc0da9d92016-02-01 12:11:01 -0800110 build_id, subpath_dir)
111 return None
112
113 # Record subpath for the build.
114 subpaths_dict[build] = subpath_name
115
116 # If we got here, it means we found an appropriate build for all platforms.
117 return subpaths_dict
118
119
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900120def GetLatestBuild(bucket_url, build_branch, targets):
David Rileyc0da9d92016-02-01 12:11:01 -0800121 """Searches the gs bucket for the latest green build.
122
123 Args:
124 bucket_url: URL of Android build gs bucket
125 build_branch: branch of Android builds
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900126 targets: Dict from build key to (targe build suffix, artifact file pattern)
127 pair.
David Rileyc0da9d92016-02-01 12:11:01 -0800128
129 Returns:
130 Tuple of (latest version string, subpaths dictionary)
131 If no latest build can be found, returns None, None
132 """
133 gs_context = gs.GSContext()
134 common_build_ids = None
135 # Find builds for each target.
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400136 for target, _ in targets.values():
David Rileyc0da9d92016-02-01 12:11:01 -0800137 build_dir = '-'.join((build_branch, target))
138 base_path = os.path.join(bucket_url, build_dir)
139 build_ids = []
140 for gs_result in gs_context.List(base_path):
141 # Remove trailing slashes and get the base name, which is the build_id.
142 build_id = os.path.basename(gs_result.url.rstrip('/'))
143 if not build_id.isdigit():
144 logging.warn('Directory [%s] does not look like a valid build_id.',
145 gs_result.url)
146 continue
147 build_ids.append(build_id)
148
149 # Update current list of builds.
150 if common_build_ids is None:
151 # First run, populate it with the first platform.
152 common_build_ids = set(build_ids)
153 else:
154 # Already populated, find the ones that are common.
155 common_build_ids.intersection_update(build_ids)
156
157 if common_build_ids is None:
158 logging.warn('Did not find a build_id common to all platforms.')
159 return None, None
160
161 # Otherwise, find the most recent one that is valid.
162 for build_id in sorted(common_build_ids, key=int, reverse=True):
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900163 subpaths = IsBuildIdValid(bucket_url, build_branch, build_id, targets)
David Rileyc0da9d92016-02-01 12:11:01 -0800164 if subpaths:
165 return build_id, subpaths
166
167 # If not found, no build_id is valid.
168 logging.warn('Did not find a build_id valid on all platforms.')
169 return None, None
170
171
172def FindAndroidCandidates(package_dir):
173 """Return a tuple of Android's unstable ebuild and stable ebuilds.
174
175 Args:
176 package_dir: The path to where the package ebuild is stored.
177
178 Returns:
179 Tuple [unstable_ebuild, stable_ebuilds].
180
181 Raises:
182 Exception: if no unstable ebuild exists for Android.
183 """
184 stable_ebuilds = []
185 unstable_ebuilds = []
186 for path in glob.glob(os.path.join(package_dir, '*.ebuild')):
187 ebuild = portage_util.EBuild(path)
188 if ebuild.version == '9999':
189 unstable_ebuilds.append(ebuild)
190 else:
191 stable_ebuilds.append(ebuild)
192
193 # Apply some sanity checks.
194 if not unstable_ebuilds:
195 raise Exception('Missing 9999 ebuild for %s' % package_dir)
196 if not stable_ebuilds:
Lann Martinffb95162018-08-28 12:02:54 -0600197 logging.warning('Missing stable ebuild for %s', package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800198
199 return portage_util.BestEBuild(unstable_ebuilds), stable_ebuilds
200
201
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800202def _GetArcBasename(build, basename):
203 """Tweaks filenames between Android bucket and ARC++ bucket.
204
205 Android builders create build artifacts with the same name for -user and
206 -userdebug builds, which breaks the android-container ebuild (b/33072485).
207 When copying the artifacts from the Android bucket to the ARC++ bucket some
208 artifacts will be renamed from the usual pattern
209 *cheets_${ARCH}-target_files-S{VERSION}.zip to
210 cheets_${BUILD_NAME}-target_files-S{VERSION}.zip which will typically look
211 like cheets_(${LABEL})*${ARCH}_userdebug-target_files-S{VERSION}.zip.
212
213 Args:
214 build: the build being mirrored, e.g. 'X86', 'ARM', 'X86_USERDEBUG'.
215 basename: the basename of the artifact to copy.
216
217 Returns:
218 The basename of the destination.
219 """
220 if build not in constants.ARC_BUILDS_NEED_ARTIFACTS_RENAMED:
221 return basename
Yūki Ishiief1ada92018-03-27 15:46:15 +0900222 if basename in constants.ARC_ARTIFACTS_RENAME_NOT_NEEDED:
223 return basename
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800224 to_discard, sep, to_keep = basename.partition('-')
225 if not sep:
226 logging.error(('Build %s: Could not find separator "-" in artifact'
227 ' basename %s'), build, basename)
228 return basename
Bernie Thompson63ed5612017-08-16 12:27:34 -0700229 if 'cheets_' in to_discard:
230 return 'cheets_%s-%s' % (build.lower(), to_keep)
231 elif 'bertha_' in to_discard:
232 return 'bertha_%s-%s' % (build.lower(), to_keep)
233 logging.error('Build %s: Unexpected artifact basename %s',
234 build, basename)
235 return basename
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800236
237
khmel@google.com50c42dd2018-05-11 11:33:35 -0700238def PackSdkTools(build_branch, build_id, targets, arc_bucket_url, acl):
khmel@google.com778a1cd2018-04-13 11:11:58 -0700239 """Creates static SDK tools pack from ARC++ specific bucket.
240
241 Ebuild needs archives to process binaries natively. This collects static SDK
242 tools and packs them to tbz2 archive which can referenced from Android
243 container ebuild file. Pack is placed into the same bucket where SDK tools
244 exist. If pack already exists and up to date then copying is skipped.
245 Otherwise fresh pack is copied.
246
247 Args:
248 build_branch: branch of Android builds
249 build_id: A string. The Android build id number to check.
250 targets: Dict from build key to (targe build suffix, artifact file pattern)
251 pair.
252 arc_bucket_url: URL of the target ARC build gs bucket
khmel@google.com50c42dd2018-05-11 11:33:35 -0700253 acl: ACL file to apply.
khmel@google.com778a1cd2018-04-13 11:11:58 -0700254 """
255
256 if not 'SDK_TOOLS' in targets:
257 return
258
259 gs_context = gs.GSContext()
260 target, pattern = targets['SDK_TOOLS']
261 build_dir = '%s-%s' % (build_branch, target)
262 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
263
264 sdk_tools_dir = tempfile.mkdtemp()
265
266 try:
267 sdk_tools_bin_dir = os.path.join(sdk_tools_dir, 'bin')
268 os.mkdir(sdk_tools_bin_dir)
269
270 for tool in gs_context.List(arc_dir):
271 if re.search(pattern, tool.url):
272 local_tool_path = os.path.join(sdk_tools_bin_dir,
273 os.path.basename(tool.url))
274 gs_context.Copy(tool.url, local_tool_path, version=0)
275 file_time = int(gs_context.Stat(tool.url).creation_time.strftime('%s'))
276 os.utime(local_tool_path, (file_time, file_time))
277
278 # Fix ./ times to make tar file stable.
279 os.utime(sdk_tools_bin_dir, (0, 0))
280
281 sdk_tools_file_name = 'sdk_tools_%s.tbz2' % build_id
282 sdk_tools_local_path = os.path.join(sdk_tools_dir, sdk_tools_file_name)
283 sdk_tools_target_path = os.path.join(arc_dir, sdk_tools_file_name)
284 subprocess.call(['tar', '--group=root:0', '--owner=root:0',
285 '--create', '--bzip2', '--sort=name',
286 '--file=%s' % sdk_tools_local_path,
287 '--directory=%s' % sdk_tools_bin_dir, '.'])
288
289 if gs_context.Exists(sdk_tools_target_path):
290 # Calculate local md5
291 md5 = hashlib.md5()
292 with open(sdk_tools_local_path, 'rb') as f:
293 while True:
294 buf = f.read(4096)
295 if not buf:
296 break
297 md5.update(buf)
298 md5_local = md5.digest()
299 # Get target md5
300 md5_target = base64.decodestring(
301 gs_context.Stat(sdk_tools_target_path).hash_md5)
302 if md5_local == md5_target:
303 logging.info('SDK tools pack %s is up to date', sdk_tools_target_path)
304 return
305 logging.warning('SDK tools pack %s invalid, removing',
306 sdk_tools_target_path)
307 gs_context.Remove(sdk_tools_target_path)
308
309 logging.info('Creating SDK tools pack %s', sdk_tools_target_path)
310 gs_context.Copy(sdk_tools_local_path, sdk_tools_target_path, version=0)
khmel@google.com50c42dd2018-05-11 11:33:35 -0700311 gs_context.ChangeACL(sdk_tools_target_path, acl_args_file=acl)
khmel@google.com778a1cd2018-04-13 11:11:58 -0700312 finally:
313 shutil.rmtree(sdk_tools_dir)
314
315
David Riley73f00d92016-02-16 18:54:20 -0800316def CopyToArcBucket(android_bucket_url, build_branch, build_id, subpaths,
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900317 targets, arc_bucket_url, acls):
David Riley73f00d92016-02-16 18:54:20 -0800318 """Copies from source Android bucket to ARC++ specific bucket.
319
320 Copies each build to the ARC bucket eliminating the subpath.
321 Applies build specific ACLs for each file.
322
323 Args:
324 android_bucket_url: URL of Android build gs bucket
325 build_branch: branch of Android builds
326 build_id: A string. The Android build id number to check.
327 subpaths: Subpath dictionary for each build to copy.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900328 targets: Dict from build key to (targe build suffix, artifact file pattern)
329 pair.
David Riley73f00d92016-02-16 18:54:20 -0800330 arc_bucket_url: URL of the target ARC build gs bucket
331 acls: ACLs dictionary for each build to copy.
332 """
333 gs_context = gs.GSContext()
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400334 for build, subpath in subpaths.items():
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900335 target, pattern = targets[build]
David Riley73f00d92016-02-16 18:54:20 -0800336 build_dir = '%s-%s' % (build_branch, target)
337 android_dir = os.path.join(android_bucket_url, build_dir, build_id, subpath)
338 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
339
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900340 # Copy all target files from android_dir to arc_dir, setting ACLs.
341 for targetfile in gs_context.List(android_dir):
342 if re.search(pattern, targetfile.url):
343 basename = os.path.basename(targetfile.url)
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800344 arc_path = os.path.join(arc_dir, _GetArcBasename(build, basename))
David Riley73f00d92016-02-16 18:54:20 -0800345 acl = acls[build]
346 needs_copy = True
khmel@google.com96c193e2018-05-10 14:00:38 -0700347 retry_count = 2
David Riley73f00d92016-02-16 18:54:20 -0800348
khmel@google.com96c193e2018-05-10 14:00:38 -0700349 # Retry in case race condition when several boards trying to copy the
350 # same resource
351 while True:
352 # Check a pre-existing file with the original source.
353 if gs_context.Exists(arc_path):
354 if (gs_context.Stat(targetfile.url).hash_crc32c !=
355 gs_context.Stat(arc_path).hash_crc32c):
356 logging.warn('Removing incorrect file %s', arc_path)
357 gs_context.Remove(arc_path)
358 else:
359 logging.info('Skipping already copied file %s', arc_path)
360 needs_copy = False
David Riley73f00d92016-02-16 18:54:20 -0800361
khmel@google.com96c193e2018-05-10 14:00:38 -0700362 # Copy if necessary, and set the ACL unconditionally.
363 # The Stat() call above doesn't verify the ACL is correct and
364 # the ChangeACL should be relatively cheap compared to the copy.
365 # This covers the following caes:
366 # - handling an interrupted copy from a previous run.
367 # - rerunning the copy in case one of the googlestorage_acl_X.txt
368 # files changes (e.g. we add a new variant which reuses a build).
369 if needs_copy:
370 logging.info('Copying %s -> %s (acl %s)',
371 targetfile.url, arc_path, acl)
372 try:
373 gs_context.Copy(targetfile.url, arc_path, version=0)
374 except gs.GSContextPreconditionFailed as error:
375 if not retry_count:
376 raise error
377 # Retry one more time after a short delay
378 logging.warning('Will retry copying %s -> %s',
379 targetfile.url, arc_path)
380 time.sleep(5)
381 retry_count = retry_count - 1
382 continue
383 gs_context.ChangeACL(arc_path, acl_args_file=acl)
384 break
David Riley73f00d92016-02-16 18:54:20 -0800385
386
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900387def MirrorArtifacts(android_bucket_url, android_build_branch, arc_bucket_url,
388 acls, targets, version=None):
389 """Mirrors artifacts from Android bucket to ARC bucket.
390
391 First, this function identifies which build version should be copied,
392 if not given. Please see GetLatestBuild() and IsBuildIdValid() for details.
393
394 On build version identified, then copies target artifacts to the ARC bucket,
395 with setting ACLs.
396
397 Args:
398 android_bucket_url: URL of Android build gs bucket
399 android_build_branch: branch of Android builds
400 arc_bucket_url: URL of the target ARC build gs bucket
401 acls: ACLs dictionary for each build to copy.
402 targets: Dict from build key to (targe build suffix, artifact file pattern)
403 pair.
404 version: (optional) A string. The Android build id number to check.
405 If not passed, detect latest good build version.
406
407 Returns:
408 Mirrored version.
409 """
410 if version:
411 subpaths = IsBuildIdValid(
412 android_bucket_url, android_build_branch, version, targets)
413 if not subpaths:
Lann Martinffb95162018-08-28 12:02:54 -0600414 logging.error('Requested build %s is not valid', version)
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900415 else:
416 version, subpaths = GetLatestBuild(
417 android_bucket_url, android_build_branch, targets)
418
419 CopyToArcBucket(android_bucket_url, android_build_branch, version, subpaths,
420 targets, arc_bucket_url, acls)
khmel@google.com50c42dd2018-05-11 11:33:35 -0700421 PackSdkTools(android_build_branch, version, targets, arc_bucket_url,
422 acls['SDK_TOOLS'])
khmel@google.com778a1cd2018-04-13 11:11:58 -0700423
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900424 return version
425
426
David Riley73f00d92016-02-16 18:54:20 -0800427def MakeAclDict(package_dir):
428 """Creates a dictionary of acl files for each build type.
429
430 Args:
431 package_dir: The path to where the package acl files are stored.
432
433 Returns:
434 Returns acls dictionary.
435 """
436 return dict(
437 (k, os.path.join(package_dir, v))
438 for k, v in constants.ARC_BUCKET_ACLS.items()
439 )
440
441
Qijiang Fan6588cc92019-11-20 13:26:04 +0900442def MakeBuildTargetDict(package_name, build_branch):
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700443 """Creates a dictionary of build targets.
444
Bernie Thompson63ed5612017-08-16 12:27:34 -0700445 Not all targets are common between branches, for example
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700446 sdk_google_cheets_x86 only exists on N.
447 This generates a dictionary listing the available build targets for a
448 specific branch.
449
450 Args:
Qijiang Fan6588cc92019-11-20 13:26:04 +0900451 package_name: package name of chromeos arc package.
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700452 build_branch: branch of Android builds.
453
454 Returns:
455 Returns build target dictionary.
456
457 Raises:
458 ValueError: if the Android build branch is invalid.
459 """
Qijiang Fan6588cc92019-11-20 13:26:04 +0900460 if constants.ANDROID_CONTAINER_PACKAGE_KEYWORD in package_name:
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900461 target_list = {
462 constants.ANDROID_MST_BUILD_BRANCH:
463 constants.ANDROID_MST_BUILD_TARGETS,
464 constants.ANDROID_NYC_BUILD_BRANCH:
465 constants.ANDROID_NYC_BUILD_TARGETS,
466 constants.ANDROID_PI_BUILD_BRANCH:
467 constants.ANDROID_PI_BUILD_TARGETS,
468 constants.ANDROID_QT_BUILD_BRANCH:
469 constants.ANDROID_QT_BUILD_TARGETS,
470 constants.ANDROID_RVC_BUILD_BRANCH:
471 constants.ANDROID_RVC_BUILD_TARGETS,
472 }
Qijiang Fan6588cc92019-11-20 13:26:04 +0900473 elif constants.ANDROID_VM_PACKAGE_KEYWORD in package_name:
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900474 target_list = {
475 constants.ANDROID_VMPI_BUILD_BRANCH:
476 constants.ANDROID_VMPI_BUILD_TARGETS,
477 constants.ANDROID_VMMST_BUILD_BRANCH:
478 constants.ANDROID_VMMST_BUILD_TARGETS,
479 constants.ANDROID_VMRVC_BUILD_BRANCH:
480 constants.ANDROID_VMRVC_BUILD_TARGETS,
481 }
482 else:
483 raise ValueError('Unknown package: %s' % package_name)
484 target = target_list.get(build_branch)
485 if not target:
Qijiang Fan6588cc92019-11-20 13:26:04 +0900486 raise ValueError('Unknown branch: %s' % build_branch)
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900487 return target
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700488
489
David Rileyc0da9d92016-02-01 12:11:01 -0800490def GetAndroidRevisionListLink(build_branch, old_android, new_android):
491 """Returns a link to the list of revisions between two Android versions
492
493 Given two AndroidEBuilds, generate a link to a page that prints the
494 Android changes between those two revisions, inclusive.
495
496 Args:
497 build_branch: branch of Android builds
498 old_android: ebuild for the version to diff from
499 new_android: ebuild for the version to which to diff
500
501 Returns:
502 The desired URL.
503 """
504 return _ANDROID_VERSION_URL % {'branch': build_branch,
Hidehiko Abec9ecf262017-07-05 15:17:41 +0900505 'old': old_android.version_no_rev,
506 'new': new_android.version_no_rev}
David Rileyc0da9d92016-02-01 12:11:01 -0800507
508
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900509def MarkAndroidEBuildAsStable(stable_candidate, unstable_ebuild,
510 android_package, android_version, package_dir,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700511 build_branch, arc_bucket_url, build_targets):
David Rileyc0da9d92016-02-01 12:11:01 -0800512 r"""Uprevs the Android ebuild.
513
514 This is the main function that uprevs from a stable candidate
515 to its new version.
516
517 Args:
518 stable_candidate: ebuild that corresponds to the stable ebuild we are
519 revving from. If None, builds the a new ebuild given the version
520 with revision set to 1.
521 unstable_ebuild: ebuild corresponding to the unstable ebuild for Android.
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900522 android_package: android package name.
David Rileyc0da9d92016-02-01 12:11:01 -0800523 android_version: The \d+ build id of Android.
David Rileyc0da9d92016-02-01 12:11:01 -0800524 package_dir: Path to the android-container package dir.
David Riley73f00d92016-02-16 18:54:20 -0800525 build_branch: branch of Android builds.
526 arc_bucket_url: URL of the target ARC build gs bucket.
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700527 build_targets: build targets for this particular Android branch.
David Rileyc0da9d92016-02-01 12:11:01 -0800528
529 Returns:
530 Full portage version atom (including rc's, etc) that was revved.
531 """
532 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
533 """Returns True if the new ebuild is redundant.
534
535 This is True if there if the current stable ebuild is the exact same copy
536 of the new one.
537 """
538 if not stable_ebuild:
539 return False
540
David Riley676f5402016-02-12 17:24:23 -0800541 if stable_candidate.version_no_rev == new_ebuild.version_no_rev:
David Rileyc0da9d92016-02-01 12:11:01 -0800542 return filecmp.cmp(
543 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False)
544
545 # Case where we have the last stable candidate with same version just rev.
David Riley676f5402016-02-12 17:24:23 -0800546 if stable_candidate and stable_candidate.version_no_rev == android_version:
David Rileyc0da9d92016-02-01 12:11:01 -0800547 new_ebuild_path = '%s-r%d.ebuild' % (
548 stable_candidate.ebuild_path_no_revision,
549 stable_candidate.current_revision + 1)
550 else:
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900551 pf = '%s-%s-r1' % (android_package, android_version)
David Rileyc0da9d92016-02-01 12:11:01 -0800552 new_ebuild_path = os.path.join(package_dir, '%s.ebuild' % pf)
553
David Riley73f00d92016-02-16 18:54:20 -0800554 variables = {'BASE_URL': arc_bucket_url}
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400555 for build, (target, _) in build_targets.items():
David Riley73f00d92016-02-16 18:54:20 -0800556 variables[build + '_TARGET'] = '%s-%s' % (build_branch, target)
David Rileyc0da9d92016-02-01 12:11:01 -0800557
558 portage_util.EBuild.MarkAsStable(
559 unstable_ebuild.ebuild_path, new_ebuild_path,
560 variables, make_stable=True)
561 new_ebuild = portage_util.EBuild(new_ebuild_path)
562
563 # Determine whether this is ebuild is redundant.
564 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
565 msg = 'Previous ebuild with same version found and ebuild is redundant.'
566 logging.info(msg)
567 os.unlink(new_ebuild_path)
568 return None
569
570 if stable_candidate:
571 logging.PrintBuildbotLink('Android revisions',
572 GetAndroidRevisionListLink(build_branch,
573 stable_candidate,
574 new_ebuild))
575
576 git.RunGit(package_dir, ['add', new_ebuild_path])
577 if stable_candidate and not stable_candidate.IsSticky():
578 git.RunGit(package_dir, ['rm', stable_candidate.ebuild_path])
579
580 # Update ebuild manifest and git add it.
581 gen_manifest_cmd = ['ebuild', new_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400582 cros_build_lib.run(gen_manifest_cmd, extra_env=None, print_cmd=True)
David Rileyc0da9d92016-02-01 12:11:01 -0800583 git.RunGit(package_dir, ['add', 'Manifest'])
584
585 portage_util.EBuild.CommitChange(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900586 _GIT_COMMIT_MESSAGE % {'android_package': android_package,
David Rileyc0da9d92016-02-01 12:11:01 -0800587 'android_version': android_version},
588 package_dir)
589
590 return '%s-%s' % (new_ebuild.package, new_ebuild.version)
591
592
593def GetParser():
594 """Creates the argument parser."""
595 parser = commandline.ArgumentParser()
596 parser.add_argument('-b', '--boards')
597 parser.add_argument('--android_bucket_url',
David Riley73f00d92016-02-16 18:54:20 -0800598 default=constants.ANDROID_BUCKET_URL,
599 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800600 parser.add_argument('--android_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900601 required=True,
602 help='Android branch to import from. '
603 'Ex: git_mnc-dr-arc-dev')
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900604 parser.add_argument('--android_gts_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900605 help='Android GTS branch to copy artifacts from. '
606 'Ex: git_mnc-dev')
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900607 parser.add_argument('--android_package',
608 default=constants.ANDROID_PACKAGE_NAME)
David Riley73f00d92016-02-16 18:54:20 -0800609 parser.add_argument('--arc_bucket_url',
610 default=constants.ARC_BUCKET_URL,
611 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800612 parser.add_argument('-f', '--force_version',
613 help='Android build id to use')
614 parser.add_argument('-s', '--srcroot',
615 default=os.path.join(os.environ['HOME'], 'trunk', 'src'),
616 help='Path to the src directory')
617 parser.add_argument('-t', '--tracking_branch', default='cros/master',
618 help='Branch we are tracking changes against')
619 return parser
620
621
622def main(argv):
Hidehiko Abec9ecf262017-07-05 15:17:41 +0900623 logging.EnableBuildbotMarkers()
David Rileyc0da9d92016-02-01 12:11:01 -0800624 parser = GetParser()
625 options = parser.parse_args(argv)
626 options.Freeze()
627
628 overlay_dir = os.path.abspath(_OVERLAY_DIR % {'srcroot': options.srcroot})
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900629 android_package_dir = os.path.join(
630 overlay_dir,
631 portage_util.GetFullAndroidPortagePackageName(options.android_package))
David Rileyc0da9d92016-02-01 12:11:01 -0800632 version_to_uprev = None
David Rileyc0da9d92016-02-01 12:11:01 -0800633
634 (unstable_ebuild, stable_ebuilds) = FindAndroidCandidates(android_package_dir)
David Riley73f00d92016-02-16 18:54:20 -0800635 acls = MakeAclDict(android_package_dir)
Qijiang Fan6588cc92019-11-20 13:26:04 +0900636 build_targets = MakeBuildTargetDict(options.android_package,
637 options.android_build_branch)
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900638 # Mirror artifacts, i.e., images and some sdk tools (e.g., adb, aapt).
639 version_to_uprev = MirrorArtifacts(options.android_bucket_url,
640 options.android_build_branch,
641 options.arc_bucket_url, acls,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700642 build_targets,
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900643 options.force_version)
644
645 # Mirror GTS.
Hidehiko Abee8cd06c2017-05-12 23:32:19 +0900646 if options.android_gts_build_branch:
647 MirrorArtifacts(options.android_bucket_url,
648 options.android_gts_build_branch,
649 options.arc_bucket_url, acls,
650 constants.ANDROID_GTS_BUILD_TARGETS)
David Riley73f00d92016-02-16 18:54:20 -0800651
David Rileyc0da9d92016-02-01 12:11:01 -0800652 stable_candidate = portage_util.BestEBuild(stable_ebuilds)
653
654 if stable_candidate:
Lann Martinffb95162018-08-28 12:02:54 -0600655 logging.info('Stable candidate found %s', stable_candidate.version)
David Rileyc0da9d92016-02-01 12:11:01 -0800656 else:
657 logging.info('No stable candidate found.')
658
659 tracking_branch = 'remotes/m/%s' % os.path.basename(options.tracking_branch)
660 existing_branch = git.GetCurrentBranch(android_package_dir)
661 work_branch = cros_mark_as_stable.GitBranch(constants.STABLE_EBUILD_BRANCH,
662 tracking_branch,
663 android_package_dir)
664 work_branch.CreateBranch()
665
666 # In the case of uprevving overlays that have patches applied to them,
667 # include the patched changes in the stabilizing branch.
668 if existing_branch:
669 git.RunGit(overlay_dir, ['rebase', existing_branch])
670
671 android_version_atom = MarkAndroidEBuildAsStable(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900672 stable_candidate, unstable_ebuild, options.android_package,
David Riley73f00d92016-02-16 18:54:20 -0800673 version_to_uprev, android_package_dir,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700674 options.android_build_branch, options.arc_bucket_url, build_targets)
David Rileyc0da9d92016-02-01 12:11:01 -0800675 if android_version_atom:
676 if options.boards:
677 cros_mark_as_stable.CleanStalePackages(options.srcroot,
678 options.boards.split(':'),
679 [android_version_atom])
680
681 # Explicit print to communicate to caller.
682 print('ANDROID_VERSION_ATOM=%s' % android_version_atom)