blob: dedb6703398b7fe7e354c603b2ece7a98f2d75bf [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
Junichi Uekawa6d61ab02020-04-15 14:52:28 +090048_GIT_COMMIT_MESSAGE = """Marking latest for %(android_package)s ebuild with \
49version %(android_version)s as stable.
50
51BUG=None
52TEST=CQ
53"""
David Rileyc0da9d92016-02-01 12:11:01 -080054
55# URLs that print lists of Android revisions between two build ids.
56_ANDROID_VERSION_URL = ('http://android-build-uber.corp.google.com/repo.html?'
57 'last_bid=%(old)s&bid=%(new)s&branch=%(branch)s')
58
59
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090060def IsBuildIdValid(bucket_url, build_branch, build_id, targets):
David Rileyc0da9d92016-02-01 12:11:01 -080061 """Checks that a specific build_id is valid.
62
63 Looks for that build_id for all builds. Confirms that the subpath can
64 be found and that the zip file is present in that subdirectory.
65
66 Args:
67 bucket_url: URL of Android build gs bucket
68 build_branch: branch of Android builds
69 build_id: A string. The Android build id number to check.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090070 targets: Dict from build key to (targe build suffix, artifact file pattern)
71 pair.
David Rileyc0da9d92016-02-01 12:11:01 -080072
73 Returns:
74 Returns subpaths dictionary if build_id is valid.
75 None if the build_id is not valid.
76 """
77 gs_context = gs.GSContext()
78 subpaths_dict = {}
Mike Frysinger0bdbc102019-06-13 15:27:29 -040079 for build, (target, _) in targets.items():
David Rileyc0da9d92016-02-01 12:11:01 -080080 build_dir = '%s-%s' % (build_branch, target)
81 build_id_path = os.path.join(bucket_url, build_dir, build_id)
82
83 # Find name of subpath.
84 try:
85 subpaths = gs_context.List(build_id_path)
86 except gs.GSNoSuchKey:
87 logging.warn(
88 'Directory [%s] does not contain any subpath, ignoring it.',
89 build_id_path)
90 return None
91 if len(subpaths) > 1:
92 logging.warn(
93 'Directory [%s] contains more than one subpath, ignoring it.',
94 build_id_path)
95 return None
96
97 subpath_dir = subpaths[0].url.rstrip('/')
98 subpath_name = os.path.basename(subpath_dir)
99
100 # Look for a zipfile ending in the build_id number.
101 try:
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900102 gs_context.List(subpath_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800103 except gs.GSNoSuchKey:
104 logging.warn(
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900105 'Did not find a file for build id [%s] in directory [%s].',
David Rileyc0da9d92016-02-01 12:11:01 -0800106 build_id, subpath_dir)
107 return None
108
109 # Record subpath for the build.
110 subpaths_dict[build] = subpath_name
111
112 # If we got here, it means we found an appropriate build for all platforms.
113 return subpaths_dict
114
115
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900116def GetLatestBuild(bucket_url, build_branch, targets):
David Rileyc0da9d92016-02-01 12:11:01 -0800117 """Searches the gs bucket for the latest green build.
118
119 Args:
120 bucket_url: URL of Android build gs bucket
121 build_branch: branch of Android builds
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900122 targets: Dict from build key to (targe build suffix, artifact file pattern)
123 pair.
David Rileyc0da9d92016-02-01 12:11:01 -0800124
125 Returns:
126 Tuple of (latest version string, subpaths dictionary)
127 If no latest build can be found, returns None, None
128 """
129 gs_context = gs.GSContext()
130 common_build_ids = None
131 # Find builds for each target.
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400132 for target, _ in targets.values():
David Rileyc0da9d92016-02-01 12:11:01 -0800133 build_dir = '-'.join((build_branch, target))
134 base_path = os.path.join(bucket_url, build_dir)
135 build_ids = []
136 for gs_result in gs_context.List(base_path):
137 # Remove trailing slashes and get the base name, which is the build_id.
138 build_id = os.path.basename(gs_result.url.rstrip('/'))
139 if not build_id.isdigit():
140 logging.warn('Directory [%s] does not look like a valid build_id.',
141 gs_result.url)
142 continue
143 build_ids.append(build_id)
144
145 # Update current list of builds.
146 if common_build_ids is None:
147 # First run, populate it with the first platform.
148 common_build_ids = set(build_ids)
149 else:
150 # Already populated, find the ones that are common.
151 common_build_ids.intersection_update(build_ids)
152
153 if common_build_ids is None:
154 logging.warn('Did not find a build_id common to all platforms.')
155 return None, None
156
157 # Otherwise, find the most recent one that is valid.
158 for build_id in sorted(common_build_ids, key=int, reverse=True):
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900159 subpaths = IsBuildIdValid(bucket_url, build_branch, build_id, targets)
David Rileyc0da9d92016-02-01 12:11:01 -0800160 if subpaths:
161 return build_id, subpaths
162
163 # If not found, no build_id is valid.
164 logging.warn('Did not find a build_id valid on all platforms.')
165 return None, None
166
167
168def FindAndroidCandidates(package_dir):
169 """Return a tuple of Android's unstable ebuild and stable ebuilds.
170
171 Args:
172 package_dir: The path to where the package ebuild is stored.
173
174 Returns:
175 Tuple [unstable_ebuild, stable_ebuilds].
176
177 Raises:
178 Exception: if no unstable ebuild exists for Android.
179 """
180 stable_ebuilds = []
181 unstable_ebuilds = []
182 for path in glob.glob(os.path.join(package_dir, '*.ebuild')):
183 ebuild = portage_util.EBuild(path)
184 if ebuild.version == '9999':
185 unstable_ebuilds.append(ebuild)
186 else:
187 stable_ebuilds.append(ebuild)
188
189 # Apply some sanity checks.
190 if not unstable_ebuilds:
191 raise Exception('Missing 9999 ebuild for %s' % package_dir)
192 if not stable_ebuilds:
Lann Martinffb95162018-08-28 12:02:54 -0600193 logging.warning('Missing stable ebuild for %s', package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800194
195 return portage_util.BestEBuild(unstable_ebuilds), stable_ebuilds
196
197
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800198def _GetArcBasename(build, basename):
199 """Tweaks filenames between Android bucket and ARC++ bucket.
200
201 Android builders create build artifacts with the same name for -user and
202 -userdebug builds, which breaks the android-container ebuild (b/33072485).
203 When copying the artifacts from the Android bucket to the ARC++ bucket some
204 artifacts will be renamed from the usual pattern
205 *cheets_${ARCH}-target_files-S{VERSION}.zip to
206 cheets_${BUILD_NAME}-target_files-S{VERSION}.zip which will typically look
207 like cheets_(${LABEL})*${ARCH}_userdebug-target_files-S{VERSION}.zip.
208
209 Args:
210 build: the build being mirrored, e.g. 'X86', 'ARM', 'X86_USERDEBUG'.
211 basename: the basename of the artifact to copy.
212
213 Returns:
214 The basename of the destination.
215 """
216 if build not in constants.ARC_BUILDS_NEED_ARTIFACTS_RENAMED:
217 return basename
Yūki Ishiief1ada92018-03-27 15:46:15 +0900218 if basename in constants.ARC_ARTIFACTS_RENAME_NOT_NEEDED:
219 return basename
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800220 to_discard, sep, to_keep = basename.partition('-')
221 if not sep:
222 logging.error(('Build %s: Could not find separator "-" in artifact'
223 ' basename %s'), build, basename)
224 return basename
Bernie Thompson63ed5612017-08-16 12:27:34 -0700225 if 'cheets_' in to_discard:
226 return 'cheets_%s-%s' % (build.lower(), to_keep)
227 elif 'bertha_' in to_discard:
228 return 'bertha_%s-%s' % (build.lower(), to_keep)
229 logging.error('Build %s: Unexpected artifact basename %s',
230 build, basename)
231 return basename
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800232
233
khmel@google.com50c42dd2018-05-11 11:33:35 -0700234def PackSdkTools(build_branch, build_id, targets, arc_bucket_url, acl):
khmel@google.com778a1cd2018-04-13 11:11:58 -0700235 """Creates static SDK tools pack from ARC++ specific bucket.
236
237 Ebuild needs archives to process binaries natively. This collects static SDK
238 tools and packs them to tbz2 archive which can referenced from Android
239 container ebuild file. Pack is placed into the same bucket where SDK tools
240 exist. If pack already exists and up to date then copying is skipped.
241 Otherwise fresh pack is copied.
242
243 Args:
244 build_branch: branch of Android builds
245 build_id: A string. The Android build id number to check.
246 targets: Dict from build key to (targe build suffix, artifact file pattern)
247 pair.
248 arc_bucket_url: URL of the target ARC build gs bucket
khmel@google.com50c42dd2018-05-11 11:33:35 -0700249 acl: ACL file to apply.
khmel@google.com778a1cd2018-04-13 11:11:58 -0700250 """
251
252 if not 'SDK_TOOLS' in targets:
253 return
254
255 gs_context = gs.GSContext()
256 target, pattern = targets['SDK_TOOLS']
257 build_dir = '%s-%s' % (build_branch, target)
258 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
259
260 sdk_tools_dir = tempfile.mkdtemp()
261
262 try:
263 sdk_tools_bin_dir = os.path.join(sdk_tools_dir, 'bin')
264 os.mkdir(sdk_tools_bin_dir)
265
266 for tool in gs_context.List(arc_dir):
267 if re.search(pattern, tool.url):
268 local_tool_path = os.path.join(sdk_tools_bin_dir,
269 os.path.basename(tool.url))
270 gs_context.Copy(tool.url, local_tool_path, version=0)
271 file_time = int(gs_context.Stat(tool.url).creation_time.strftime('%s'))
272 os.utime(local_tool_path, (file_time, file_time))
273
274 # Fix ./ times to make tar file stable.
275 os.utime(sdk_tools_bin_dir, (0, 0))
276
277 sdk_tools_file_name = 'sdk_tools_%s.tbz2' % build_id
278 sdk_tools_local_path = os.path.join(sdk_tools_dir, sdk_tools_file_name)
279 sdk_tools_target_path = os.path.join(arc_dir, sdk_tools_file_name)
280 subprocess.call(['tar', '--group=root:0', '--owner=root:0',
281 '--create', '--bzip2', '--sort=name',
282 '--file=%s' % sdk_tools_local_path,
283 '--directory=%s' % sdk_tools_bin_dir, '.'])
284
285 if gs_context.Exists(sdk_tools_target_path):
286 # Calculate local md5
287 md5 = hashlib.md5()
288 with open(sdk_tools_local_path, 'rb') as f:
289 while True:
290 buf = f.read(4096)
291 if not buf:
292 break
293 md5.update(buf)
294 md5_local = md5.digest()
295 # Get target md5
296 md5_target = base64.decodestring(
297 gs_context.Stat(sdk_tools_target_path).hash_md5)
298 if md5_local == md5_target:
299 logging.info('SDK tools pack %s is up to date', sdk_tools_target_path)
300 return
301 logging.warning('SDK tools pack %s invalid, removing',
302 sdk_tools_target_path)
303 gs_context.Remove(sdk_tools_target_path)
304
305 logging.info('Creating SDK tools pack %s', sdk_tools_target_path)
306 gs_context.Copy(sdk_tools_local_path, sdk_tools_target_path, version=0)
khmel@google.com50c42dd2018-05-11 11:33:35 -0700307 gs_context.ChangeACL(sdk_tools_target_path, acl_args_file=acl)
khmel@google.com778a1cd2018-04-13 11:11:58 -0700308 finally:
309 shutil.rmtree(sdk_tools_dir)
310
311
David Riley73f00d92016-02-16 18:54:20 -0800312def CopyToArcBucket(android_bucket_url, build_branch, build_id, subpaths,
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900313 targets, arc_bucket_url, acls):
David Riley73f00d92016-02-16 18:54:20 -0800314 """Copies from source Android bucket to ARC++ specific bucket.
315
316 Copies each build to the ARC bucket eliminating the subpath.
317 Applies build specific ACLs for each file.
318
319 Args:
320 android_bucket_url: URL of Android build gs bucket
321 build_branch: branch of Android builds
322 build_id: A string. The Android build id number to check.
323 subpaths: Subpath dictionary for each build to copy.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900324 targets: Dict from build key to (targe build suffix, artifact file pattern)
325 pair.
David Riley73f00d92016-02-16 18:54:20 -0800326 arc_bucket_url: URL of the target ARC build gs bucket
327 acls: ACLs dictionary for each build to copy.
328 """
329 gs_context = gs.GSContext()
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400330 for build, subpath in subpaths.items():
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900331 target, pattern = targets[build]
David Riley73f00d92016-02-16 18:54:20 -0800332 build_dir = '%s-%s' % (build_branch, target)
333 android_dir = os.path.join(android_bucket_url, build_dir, build_id, subpath)
334 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
335
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900336 # Copy all target files from android_dir to arc_dir, setting ACLs.
337 for targetfile in gs_context.List(android_dir):
338 if re.search(pattern, targetfile.url):
339 basename = os.path.basename(targetfile.url)
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800340 arc_path = os.path.join(arc_dir, _GetArcBasename(build, basename))
David Riley73f00d92016-02-16 18:54:20 -0800341 acl = acls[build]
342 needs_copy = True
khmel@google.com96c193e2018-05-10 14:00:38 -0700343 retry_count = 2
David Riley73f00d92016-02-16 18:54:20 -0800344
khmel@google.com96c193e2018-05-10 14:00:38 -0700345 # Retry in case race condition when several boards trying to copy the
346 # same resource
347 while True:
348 # Check a pre-existing file with the original source.
349 if gs_context.Exists(arc_path):
350 if (gs_context.Stat(targetfile.url).hash_crc32c !=
351 gs_context.Stat(arc_path).hash_crc32c):
352 logging.warn('Removing incorrect file %s', arc_path)
353 gs_context.Remove(arc_path)
354 else:
355 logging.info('Skipping already copied file %s', arc_path)
356 needs_copy = False
David Riley73f00d92016-02-16 18:54:20 -0800357
khmel@google.com96c193e2018-05-10 14:00:38 -0700358 # Copy if necessary, and set the ACL unconditionally.
359 # The Stat() call above doesn't verify the ACL is correct and
360 # the ChangeACL should be relatively cheap compared to the copy.
361 # This covers the following caes:
362 # - handling an interrupted copy from a previous run.
363 # - rerunning the copy in case one of the googlestorage_acl_X.txt
364 # files changes (e.g. we add a new variant which reuses a build).
365 if needs_copy:
366 logging.info('Copying %s -> %s (acl %s)',
367 targetfile.url, arc_path, acl)
368 try:
369 gs_context.Copy(targetfile.url, arc_path, version=0)
370 except gs.GSContextPreconditionFailed as error:
371 if not retry_count:
372 raise error
373 # Retry one more time after a short delay
374 logging.warning('Will retry copying %s -> %s',
375 targetfile.url, arc_path)
376 time.sleep(5)
377 retry_count = retry_count - 1
378 continue
379 gs_context.ChangeACL(arc_path, acl_args_file=acl)
380 break
David Riley73f00d92016-02-16 18:54:20 -0800381
382
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900383def MirrorArtifacts(android_bucket_url, android_build_branch, arc_bucket_url,
384 acls, targets, version=None):
385 """Mirrors artifacts from Android bucket to ARC bucket.
386
387 First, this function identifies which build version should be copied,
388 if not given. Please see GetLatestBuild() and IsBuildIdValid() for details.
389
390 On build version identified, then copies target artifacts to the ARC bucket,
391 with setting ACLs.
392
393 Args:
394 android_bucket_url: URL of Android build gs bucket
395 android_build_branch: branch of Android builds
396 arc_bucket_url: URL of the target ARC build gs bucket
397 acls: ACLs dictionary for each build to copy.
398 targets: Dict from build key to (targe build suffix, artifact file pattern)
399 pair.
400 version: (optional) A string. The Android build id number to check.
401 If not passed, detect latest good build version.
402
403 Returns:
404 Mirrored version.
405 """
406 if version:
407 subpaths = IsBuildIdValid(
408 android_bucket_url, android_build_branch, version, targets)
409 if not subpaths:
Lann Martinffb95162018-08-28 12:02:54 -0600410 logging.error('Requested build %s is not valid', version)
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900411 else:
412 version, subpaths = GetLatestBuild(
413 android_bucket_url, android_build_branch, targets)
414
415 CopyToArcBucket(android_bucket_url, android_build_branch, version, subpaths,
416 targets, arc_bucket_url, acls)
khmel@google.com50c42dd2018-05-11 11:33:35 -0700417 PackSdkTools(android_build_branch, version, targets, arc_bucket_url,
418 acls['SDK_TOOLS'])
khmel@google.com778a1cd2018-04-13 11:11:58 -0700419
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900420 return version
421
422
David Riley73f00d92016-02-16 18:54:20 -0800423def MakeAclDict(package_dir):
424 """Creates a dictionary of acl files for each build type.
425
426 Args:
427 package_dir: The path to where the package acl files are stored.
428
429 Returns:
430 Returns acls dictionary.
431 """
432 return dict(
433 (k, os.path.join(package_dir, v))
434 for k, v in constants.ARC_BUCKET_ACLS.items()
435 )
436
437
Qijiang Fan6588cc92019-11-20 13:26:04 +0900438def MakeBuildTargetDict(package_name, build_branch):
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700439 """Creates a dictionary of build targets.
440
Bernie Thompson63ed5612017-08-16 12:27:34 -0700441 Not all targets are common between branches, for example
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700442 sdk_google_cheets_x86 only exists on N.
443 This generates a dictionary listing the available build targets for a
444 specific branch.
445
446 Args:
Qijiang Fan6588cc92019-11-20 13:26:04 +0900447 package_name: package name of chromeos arc package.
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700448 build_branch: branch of Android builds.
449
450 Returns:
451 Returns build target dictionary.
452
453 Raises:
454 ValueError: if the Android build branch is invalid.
455 """
Qijiang Fan6588cc92019-11-20 13:26:04 +0900456 if constants.ANDROID_CONTAINER_PACKAGE_KEYWORD in package_name:
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900457 target_list = {
458 constants.ANDROID_MST_BUILD_BRANCH:
459 constants.ANDROID_MST_BUILD_TARGETS,
460 constants.ANDROID_NYC_BUILD_BRANCH:
461 constants.ANDROID_NYC_BUILD_TARGETS,
462 constants.ANDROID_PI_BUILD_BRANCH:
463 constants.ANDROID_PI_BUILD_TARGETS,
464 constants.ANDROID_QT_BUILD_BRANCH:
465 constants.ANDROID_QT_BUILD_TARGETS,
466 constants.ANDROID_RVC_BUILD_BRANCH:
467 constants.ANDROID_RVC_BUILD_TARGETS,
468 }
Qijiang Fan6588cc92019-11-20 13:26:04 +0900469 elif constants.ANDROID_VM_PACKAGE_KEYWORD in package_name:
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900470 target_list = {
471 constants.ANDROID_VMPI_BUILD_BRANCH:
472 constants.ANDROID_VMPI_BUILD_TARGETS,
473 constants.ANDROID_VMMST_BUILD_BRANCH:
474 constants.ANDROID_VMMST_BUILD_TARGETS,
475 constants.ANDROID_VMRVC_BUILD_BRANCH:
476 constants.ANDROID_VMRVC_BUILD_TARGETS,
477 }
478 else:
479 raise ValueError('Unknown package: %s' % package_name)
480 target = target_list.get(build_branch)
481 if not target:
Qijiang Fan6588cc92019-11-20 13:26:04 +0900482 raise ValueError('Unknown branch: %s' % build_branch)
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900483 return target
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700484
485
David Rileyc0da9d92016-02-01 12:11:01 -0800486def GetAndroidRevisionListLink(build_branch, old_android, new_android):
487 """Returns a link to the list of revisions between two Android versions
488
489 Given two AndroidEBuilds, generate a link to a page that prints the
490 Android changes between those two revisions, inclusive.
491
492 Args:
493 build_branch: branch of Android builds
494 old_android: ebuild for the version to diff from
495 new_android: ebuild for the version to which to diff
496
497 Returns:
498 The desired URL.
499 """
500 return _ANDROID_VERSION_URL % {'branch': build_branch,
Hidehiko Abec9ecf262017-07-05 15:17:41 +0900501 'old': old_android.version_no_rev,
502 'new': new_android.version_no_rev}
David Rileyc0da9d92016-02-01 12:11:01 -0800503
504
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900505def MarkAndroidEBuildAsStable(stable_candidate, unstable_ebuild,
506 android_package, android_version, package_dir,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700507 build_branch, arc_bucket_url, build_targets):
David Rileyc0da9d92016-02-01 12:11:01 -0800508 r"""Uprevs the Android ebuild.
509
510 This is the main function that uprevs from a stable candidate
511 to its new version.
512
513 Args:
514 stable_candidate: ebuild that corresponds to the stable ebuild we are
515 revving from. If None, builds the a new ebuild given the version
516 with revision set to 1.
517 unstable_ebuild: ebuild corresponding to the unstable ebuild for Android.
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900518 android_package: android package name.
David Rileyc0da9d92016-02-01 12:11:01 -0800519 android_version: The \d+ build id of Android.
David Rileyc0da9d92016-02-01 12:11:01 -0800520 package_dir: Path to the android-container package dir.
David Riley73f00d92016-02-16 18:54:20 -0800521 build_branch: branch of Android builds.
522 arc_bucket_url: URL of the target ARC build gs bucket.
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700523 build_targets: build targets for this particular Android branch.
David Rileyc0da9d92016-02-01 12:11:01 -0800524
525 Returns:
526 Full portage version atom (including rc's, etc) that was revved.
527 """
528 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
529 """Returns True if the new ebuild is redundant.
530
531 This is True if there if the current stable ebuild is the exact same copy
532 of the new one.
533 """
534 if not stable_ebuild:
535 return False
536
David Riley676f5402016-02-12 17:24:23 -0800537 if stable_candidate.version_no_rev == new_ebuild.version_no_rev:
David Rileyc0da9d92016-02-01 12:11:01 -0800538 return filecmp.cmp(
539 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False)
540
541 # Case where we have the last stable candidate with same version just rev.
David Riley676f5402016-02-12 17:24:23 -0800542 if stable_candidate and stable_candidate.version_no_rev == android_version:
David Rileyc0da9d92016-02-01 12:11:01 -0800543 new_ebuild_path = '%s-r%d.ebuild' % (
544 stable_candidate.ebuild_path_no_revision,
545 stable_candidate.current_revision + 1)
546 else:
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900547 pf = '%s-%s-r1' % (android_package, android_version)
David Rileyc0da9d92016-02-01 12:11:01 -0800548 new_ebuild_path = os.path.join(package_dir, '%s.ebuild' % pf)
549
David Riley73f00d92016-02-16 18:54:20 -0800550 variables = {'BASE_URL': arc_bucket_url}
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400551 for build, (target, _) in build_targets.items():
David Riley73f00d92016-02-16 18:54:20 -0800552 variables[build + '_TARGET'] = '%s-%s' % (build_branch, target)
David Rileyc0da9d92016-02-01 12:11:01 -0800553
554 portage_util.EBuild.MarkAsStable(
555 unstable_ebuild.ebuild_path, new_ebuild_path,
556 variables, make_stable=True)
557 new_ebuild = portage_util.EBuild(new_ebuild_path)
558
559 # Determine whether this is ebuild is redundant.
560 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
561 msg = 'Previous ebuild with same version found and ebuild is redundant.'
562 logging.info(msg)
563 os.unlink(new_ebuild_path)
564 return None
565
566 if stable_candidate:
567 logging.PrintBuildbotLink('Android revisions',
568 GetAndroidRevisionListLink(build_branch,
569 stable_candidate,
570 new_ebuild))
571
572 git.RunGit(package_dir, ['add', new_ebuild_path])
573 if stable_candidate and not stable_candidate.IsSticky():
574 git.RunGit(package_dir, ['rm', stable_candidate.ebuild_path])
575
576 # Update ebuild manifest and git add it.
577 gen_manifest_cmd = ['ebuild', new_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400578 cros_build_lib.run(gen_manifest_cmd, extra_env=None, print_cmd=True)
David Rileyc0da9d92016-02-01 12:11:01 -0800579 git.RunGit(package_dir, ['add', 'Manifest'])
580
581 portage_util.EBuild.CommitChange(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900582 _GIT_COMMIT_MESSAGE % {'android_package': android_package,
David Rileyc0da9d92016-02-01 12:11:01 -0800583 'android_version': android_version},
584 package_dir)
585
586 return '%s-%s' % (new_ebuild.package, new_ebuild.version)
587
588
589def GetParser():
590 """Creates the argument parser."""
591 parser = commandline.ArgumentParser()
592 parser.add_argument('-b', '--boards')
593 parser.add_argument('--android_bucket_url',
David Riley73f00d92016-02-16 18:54:20 -0800594 default=constants.ANDROID_BUCKET_URL,
595 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800596 parser.add_argument('--android_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900597 required=True,
598 help='Android branch to import from. '
599 'Ex: git_mnc-dr-arc-dev')
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900600 parser.add_argument('--android_gts_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900601 help='Android GTS branch to copy artifacts from. '
602 'Ex: git_mnc-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
641 # Mirror GTS.
Hidehiko Abee8cd06c2017-05-12 23:32:19 +0900642 if options.android_gts_build_branch:
643 MirrorArtifacts(options.android_bucket_url,
644 options.android_gts_build_branch,
645 options.arc_bucket_url, acls,
646 constants.ANDROID_GTS_BUILD_TARGETS)
David Riley73f00d92016-02-16 18:54:20 -0800647
David Rileyc0da9d92016-02-01 12:11:01 -0800648 stable_candidate = portage_util.BestEBuild(stable_ebuilds)
649
650 if stable_candidate:
Lann Martinffb95162018-08-28 12:02:54 -0600651 logging.info('Stable candidate found %s', stable_candidate.version)
David Rileyc0da9d92016-02-01 12:11:01 -0800652 else:
653 logging.info('No stable candidate found.')
654
655 tracking_branch = 'remotes/m/%s' % os.path.basename(options.tracking_branch)
656 existing_branch = git.GetCurrentBranch(android_package_dir)
657 work_branch = cros_mark_as_stable.GitBranch(constants.STABLE_EBUILD_BRANCH,
658 tracking_branch,
659 android_package_dir)
660 work_branch.CreateBranch()
661
662 # In the case of uprevving overlays that have patches applied to them,
663 # include the patched changes in the stabilizing branch.
664 if existing_branch:
665 git.RunGit(overlay_dir, ['rebase', existing_branch])
666
667 android_version_atom = MarkAndroidEBuildAsStable(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900668 stable_candidate, unstable_ebuild, options.android_package,
David Riley73f00d92016-02-16 18:54:20 -0800669 version_to_uprev, android_package_dir,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700670 options.android_build_branch, options.arc_bucket_url, build_targets)
David Rileyc0da9d92016-02-01 12:11:01 -0800671 if android_version_atom:
672 if options.boards:
673 cros_mark_as_stable.CleanStalePackages(options.srcroot,
674 options.boards.split(':'),
675 [android_version_atom])
676
677 # Explicit print to communicate to caller.
678 print('ANDROID_VERSION_ATOM=%s' % android_version_atom)