blob: 6ea8245de43817ea486056e9ad0fc7cdca43d71b [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 = {}
Mike Frysinger0bdbc102019-06-13 15:27:29 -040075 for build, (target, _) in targets.items():
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.
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400128 for target, _ in targets.values():
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:
Lann Martinffb95162018-08-28 12:02:54 -0600189 logging.warning('Missing stable ebuild for %s', package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800190
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.com50c42dd2018-05-11 11:33:35 -0700230def PackSdkTools(build_branch, build_id, targets, arc_bucket_url, acl):
khmel@google.com778a1cd2018-04-13 11:11:58 -0700231 """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
khmel@google.com50c42dd2018-05-11 11:33:35 -0700245 acl: ACL file to apply.
khmel@google.com778a1cd2018-04-13 11:11:58 -0700246 """
247
248 if not 'SDK_TOOLS' in targets:
249 return
250
251 gs_context = gs.GSContext()
252 target, pattern = targets['SDK_TOOLS']
253 build_dir = '%s-%s' % (build_branch, target)
254 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
255
256 sdk_tools_dir = tempfile.mkdtemp()
257
258 try:
259 sdk_tools_bin_dir = os.path.join(sdk_tools_dir, 'bin')
260 os.mkdir(sdk_tools_bin_dir)
261
262 for tool in gs_context.List(arc_dir):
263 if re.search(pattern, tool.url):
264 local_tool_path = os.path.join(sdk_tools_bin_dir,
265 os.path.basename(tool.url))
266 gs_context.Copy(tool.url, local_tool_path, version=0)
267 file_time = int(gs_context.Stat(tool.url).creation_time.strftime('%s'))
268 os.utime(local_tool_path, (file_time, file_time))
269
270 # Fix ./ times to make tar file stable.
271 os.utime(sdk_tools_bin_dir, (0, 0))
272
273 sdk_tools_file_name = 'sdk_tools_%s.tbz2' % build_id
274 sdk_tools_local_path = os.path.join(sdk_tools_dir, sdk_tools_file_name)
275 sdk_tools_target_path = os.path.join(arc_dir, sdk_tools_file_name)
276 subprocess.call(['tar', '--group=root:0', '--owner=root:0',
277 '--create', '--bzip2', '--sort=name',
278 '--file=%s' % sdk_tools_local_path,
279 '--directory=%s' % sdk_tools_bin_dir, '.'])
280
281 if gs_context.Exists(sdk_tools_target_path):
282 # Calculate local md5
283 md5 = hashlib.md5()
284 with open(sdk_tools_local_path, 'rb') as f:
285 while True:
286 buf = f.read(4096)
287 if not buf:
288 break
289 md5.update(buf)
290 md5_local = md5.digest()
291 # Get target md5
292 md5_target = base64.decodestring(
293 gs_context.Stat(sdk_tools_target_path).hash_md5)
294 if md5_local == md5_target:
295 logging.info('SDK tools pack %s is up to date', sdk_tools_target_path)
296 return
297 logging.warning('SDK tools pack %s invalid, removing',
298 sdk_tools_target_path)
299 gs_context.Remove(sdk_tools_target_path)
300
301 logging.info('Creating SDK tools pack %s', sdk_tools_target_path)
302 gs_context.Copy(sdk_tools_local_path, sdk_tools_target_path, version=0)
khmel@google.com50c42dd2018-05-11 11:33:35 -0700303 gs_context.ChangeACL(sdk_tools_target_path, acl_args_file=acl)
khmel@google.com778a1cd2018-04-13 11:11:58 -0700304 finally:
305 shutil.rmtree(sdk_tools_dir)
306
307
David Riley73f00d92016-02-16 18:54:20 -0800308def CopyToArcBucket(android_bucket_url, build_branch, build_id, subpaths,
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900309 targets, arc_bucket_url, acls):
David Riley73f00d92016-02-16 18:54:20 -0800310 """Copies from source Android bucket to ARC++ specific bucket.
311
312 Copies each build to the ARC bucket eliminating the subpath.
313 Applies build specific ACLs for each file.
314
315 Args:
316 android_bucket_url: URL of Android build gs bucket
317 build_branch: branch of Android builds
318 build_id: A string. The Android build id number to check.
319 subpaths: Subpath dictionary for each build to copy.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900320 targets: Dict from build key to (targe build suffix, artifact file pattern)
321 pair.
David Riley73f00d92016-02-16 18:54:20 -0800322 arc_bucket_url: URL of the target ARC build gs bucket
323 acls: ACLs dictionary for each build to copy.
324 """
325 gs_context = gs.GSContext()
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400326 for build, subpath in subpaths.items():
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900327 target, pattern = targets[build]
David Riley73f00d92016-02-16 18:54:20 -0800328 build_dir = '%s-%s' % (build_branch, target)
329 android_dir = os.path.join(android_bucket_url, build_dir, build_id, subpath)
330 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
331
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900332 # Copy all target files from android_dir to arc_dir, setting ACLs.
333 for targetfile in gs_context.List(android_dir):
334 if re.search(pattern, targetfile.url):
335 basename = os.path.basename(targetfile.url)
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800336 arc_path = os.path.join(arc_dir, _GetArcBasename(build, basename))
David Riley73f00d92016-02-16 18:54:20 -0800337 acl = acls[build]
338 needs_copy = True
khmel@google.com96c193e2018-05-10 14:00:38 -0700339 retry_count = 2
David Riley73f00d92016-02-16 18:54:20 -0800340
khmel@google.com96c193e2018-05-10 14:00:38 -0700341 # Retry in case race condition when several boards trying to copy the
342 # same resource
343 while True:
344 # Check a pre-existing file with the original source.
345 if gs_context.Exists(arc_path):
346 if (gs_context.Stat(targetfile.url).hash_crc32c !=
347 gs_context.Stat(arc_path).hash_crc32c):
348 logging.warn('Removing incorrect file %s', arc_path)
349 gs_context.Remove(arc_path)
350 else:
351 logging.info('Skipping already copied file %s', arc_path)
352 needs_copy = False
David Riley73f00d92016-02-16 18:54:20 -0800353
khmel@google.com96c193e2018-05-10 14:00:38 -0700354 # Copy if necessary, and set the ACL unconditionally.
355 # The Stat() call above doesn't verify the ACL is correct and
356 # the ChangeACL should be relatively cheap compared to the copy.
357 # This covers the following caes:
358 # - handling an interrupted copy from a previous run.
359 # - rerunning the copy in case one of the googlestorage_acl_X.txt
360 # files changes (e.g. we add a new variant which reuses a build).
361 if needs_copy:
362 logging.info('Copying %s -> %s (acl %s)',
363 targetfile.url, arc_path, acl)
364 try:
365 gs_context.Copy(targetfile.url, arc_path, version=0)
366 except gs.GSContextPreconditionFailed as error:
367 if not retry_count:
368 raise error
369 # Retry one more time after a short delay
370 logging.warning('Will retry copying %s -> %s',
371 targetfile.url, arc_path)
372 time.sleep(5)
373 retry_count = retry_count - 1
374 continue
375 gs_context.ChangeACL(arc_path, acl_args_file=acl)
376 break
David Riley73f00d92016-02-16 18:54:20 -0800377
378
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900379def MirrorArtifacts(android_bucket_url, android_build_branch, arc_bucket_url,
380 acls, targets, version=None):
381 """Mirrors artifacts from Android bucket to ARC bucket.
382
383 First, this function identifies which build version should be copied,
384 if not given. Please see GetLatestBuild() and IsBuildIdValid() for details.
385
386 On build version identified, then copies target artifacts to the ARC bucket,
387 with setting ACLs.
388
389 Args:
390 android_bucket_url: URL of Android build gs bucket
391 android_build_branch: branch of Android builds
392 arc_bucket_url: URL of the target ARC build gs bucket
393 acls: ACLs dictionary for each build to copy.
394 targets: Dict from build key to (targe build suffix, artifact file pattern)
395 pair.
396 version: (optional) A string. The Android build id number to check.
397 If not passed, detect latest good build version.
398
399 Returns:
400 Mirrored version.
401 """
402 if version:
403 subpaths = IsBuildIdValid(
404 android_bucket_url, android_build_branch, version, targets)
405 if not subpaths:
Lann Martinffb95162018-08-28 12:02:54 -0600406 logging.error('Requested build %s is not valid', version)
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900407 else:
408 version, subpaths = GetLatestBuild(
409 android_bucket_url, android_build_branch, targets)
410
411 CopyToArcBucket(android_bucket_url, android_build_branch, version, subpaths,
412 targets, arc_bucket_url, acls)
khmel@google.com50c42dd2018-05-11 11:33:35 -0700413 PackSdkTools(android_build_branch, version, targets, arc_bucket_url,
414 acls['SDK_TOOLS'])
khmel@google.com778a1cd2018-04-13 11:11:58 -0700415
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900416 return version
417
418
David Riley73f00d92016-02-16 18:54:20 -0800419def MakeAclDict(package_dir):
420 """Creates a dictionary of acl files for each build type.
421
422 Args:
423 package_dir: The path to where the package acl files are stored.
424
425 Returns:
426 Returns acls dictionary.
427 """
428 return dict(
429 (k, os.path.join(package_dir, v))
430 for k, v in constants.ARC_BUCKET_ACLS.items()
431 )
432
433
Qijiang Fan6588cc92019-11-20 13:26:04 +0900434def MakeBuildTargetDict(package_name, build_branch):
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700435 """Creates a dictionary of build targets.
436
Bernie Thompson63ed5612017-08-16 12:27:34 -0700437 Not all targets are common between branches, for example
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700438 sdk_google_cheets_x86 only exists on N.
439 This generates a dictionary listing the available build targets for a
440 specific branch.
441
442 Args:
Qijiang Fan6588cc92019-11-20 13:26:04 +0900443 package_name: package name of chromeos arc package.
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700444 build_branch: branch of Android builds.
445
446 Returns:
447 Returns build target dictionary.
448
449 Raises:
450 ValueError: if the Android build branch is invalid.
451 """
Qijiang Fan6588cc92019-11-20 13:26:04 +0900452 if constants.ANDROID_CONTAINER_PACKAGE_KEYWORD in package_name:
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900453 target_list = {
454 constants.ANDROID_MST_BUILD_BRANCH:
455 constants.ANDROID_MST_BUILD_TARGETS,
456 constants.ANDROID_NYC_BUILD_BRANCH:
457 constants.ANDROID_NYC_BUILD_TARGETS,
458 constants.ANDROID_PI_BUILD_BRANCH:
459 constants.ANDROID_PI_BUILD_TARGETS,
460 constants.ANDROID_QT_BUILD_BRANCH:
461 constants.ANDROID_QT_BUILD_TARGETS,
462 constants.ANDROID_RVC_BUILD_BRANCH:
463 constants.ANDROID_RVC_BUILD_TARGETS,
464 }
Qijiang Fan6588cc92019-11-20 13:26:04 +0900465 elif constants.ANDROID_VM_PACKAGE_KEYWORD in package_name:
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900466 target_list = {
467 constants.ANDROID_VMPI_BUILD_BRANCH:
468 constants.ANDROID_VMPI_BUILD_TARGETS,
469 constants.ANDROID_VMMST_BUILD_BRANCH:
470 constants.ANDROID_VMMST_BUILD_TARGETS,
471 constants.ANDROID_VMRVC_BUILD_BRANCH:
472 constants.ANDROID_VMRVC_BUILD_TARGETS,
473 }
474 else:
475 raise ValueError('Unknown package: %s' % package_name)
476 target = target_list.get(build_branch)
477 if not target:
Qijiang Fan6588cc92019-11-20 13:26:04 +0900478 raise ValueError('Unknown branch: %s' % build_branch)
Federico 'Morg' Pareschi041ee652020-03-10 15:09:42 +0900479 return target
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700480
481
David Rileyc0da9d92016-02-01 12:11:01 -0800482def GetAndroidRevisionListLink(build_branch, old_android, new_android):
483 """Returns a link to the list of revisions between two Android versions
484
485 Given two AndroidEBuilds, generate a link to a page that prints the
486 Android changes between those two revisions, inclusive.
487
488 Args:
489 build_branch: branch of Android builds
490 old_android: ebuild for the version to diff from
491 new_android: ebuild for the version to which to diff
492
493 Returns:
494 The desired URL.
495 """
496 return _ANDROID_VERSION_URL % {'branch': build_branch,
Hidehiko Abec9ecf262017-07-05 15:17:41 +0900497 'old': old_android.version_no_rev,
498 'new': new_android.version_no_rev}
David Rileyc0da9d92016-02-01 12:11:01 -0800499
500
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900501def MarkAndroidEBuildAsStable(stable_candidate, unstable_ebuild,
502 android_package, android_version, package_dir,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700503 build_branch, arc_bucket_url, build_targets):
David Rileyc0da9d92016-02-01 12:11:01 -0800504 r"""Uprevs the Android ebuild.
505
506 This is the main function that uprevs from a stable candidate
507 to its new version.
508
509 Args:
510 stable_candidate: ebuild that corresponds to the stable ebuild we are
511 revving from. If None, builds the a new ebuild given the version
512 with revision set to 1.
513 unstable_ebuild: ebuild corresponding to the unstable ebuild for Android.
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900514 android_package: android package name.
David Rileyc0da9d92016-02-01 12:11:01 -0800515 android_version: The \d+ build id of Android.
David Rileyc0da9d92016-02-01 12:11:01 -0800516 package_dir: Path to the android-container package dir.
David Riley73f00d92016-02-16 18:54:20 -0800517 build_branch: branch of Android builds.
518 arc_bucket_url: URL of the target ARC build gs bucket.
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700519 build_targets: build targets for this particular Android branch.
David Rileyc0da9d92016-02-01 12:11:01 -0800520
521 Returns:
522 Full portage version atom (including rc's, etc) that was revved.
523 """
524 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
525 """Returns True if the new ebuild is redundant.
526
527 This is True if there if the current stable ebuild is the exact same copy
528 of the new one.
529 """
530 if not stable_ebuild:
531 return False
532
David Riley676f5402016-02-12 17:24:23 -0800533 if stable_candidate.version_no_rev == new_ebuild.version_no_rev:
David Rileyc0da9d92016-02-01 12:11:01 -0800534 return filecmp.cmp(
535 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False)
536
537 # Case where we have the last stable candidate with same version just rev.
David Riley676f5402016-02-12 17:24:23 -0800538 if stable_candidate and stable_candidate.version_no_rev == android_version:
David Rileyc0da9d92016-02-01 12:11:01 -0800539 new_ebuild_path = '%s-r%d.ebuild' % (
540 stable_candidate.ebuild_path_no_revision,
541 stable_candidate.current_revision + 1)
542 else:
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900543 pf = '%s-%s-r1' % (android_package, android_version)
David Rileyc0da9d92016-02-01 12:11:01 -0800544 new_ebuild_path = os.path.join(package_dir, '%s.ebuild' % pf)
545
David Riley73f00d92016-02-16 18:54:20 -0800546 variables = {'BASE_URL': arc_bucket_url}
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400547 for build, (target, _) in build_targets.items():
David Riley73f00d92016-02-16 18:54:20 -0800548 variables[build + '_TARGET'] = '%s-%s' % (build_branch, target)
David Rileyc0da9d92016-02-01 12:11:01 -0800549
550 portage_util.EBuild.MarkAsStable(
551 unstable_ebuild.ebuild_path, new_ebuild_path,
552 variables, make_stable=True)
553 new_ebuild = portage_util.EBuild(new_ebuild_path)
554
555 # Determine whether this is ebuild is redundant.
556 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
557 msg = 'Previous ebuild with same version found and ebuild is redundant.'
558 logging.info(msg)
559 os.unlink(new_ebuild_path)
560 return None
561
562 if stable_candidate:
563 logging.PrintBuildbotLink('Android revisions',
564 GetAndroidRevisionListLink(build_branch,
565 stable_candidate,
566 new_ebuild))
567
568 git.RunGit(package_dir, ['add', new_ebuild_path])
569 if stable_candidate and not stable_candidate.IsSticky():
570 git.RunGit(package_dir, ['rm', stable_candidate.ebuild_path])
571
572 # Update ebuild manifest and git add it.
573 gen_manifest_cmd = ['ebuild', new_ebuild_path, 'manifest', '--force']
Mike Frysinger45602c72019-09-22 02:15:11 -0400574 cros_build_lib.run(gen_manifest_cmd, extra_env=None, print_cmd=True)
David Rileyc0da9d92016-02-01 12:11:01 -0800575 git.RunGit(package_dir, ['add', 'Manifest'])
576
577 portage_util.EBuild.CommitChange(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900578 _GIT_COMMIT_MESSAGE % {'android_package': android_package,
David Rileyc0da9d92016-02-01 12:11:01 -0800579 'android_version': android_version},
580 package_dir)
581
582 return '%s-%s' % (new_ebuild.package, new_ebuild.version)
583
584
585def GetParser():
586 """Creates the argument parser."""
587 parser = commandline.ArgumentParser()
588 parser.add_argument('-b', '--boards')
589 parser.add_argument('--android_bucket_url',
David Riley73f00d92016-02-16 18:54:20 -0800590 default=constants.ANDROID_BUCKET_URL,
591 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800592 parser.add_argument('--android_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900593 required=True,
594 help='Android branch to import from. '
595 'Ex: git_mnc-dr-arc-dev')
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900596 parser.add_argument('--android_gts_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900597 help='Android GTS branch to copy artifacts from. '
598 'Ex: git_mnc-dev')
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900599 parser.add_argument('--android_package',
600 default=constants.ANDROID_PACKAGE_NAME)
David Riley73f00d92016-02-16 18:54:20 -0800601 parser.add_argument('--arc_bucket_url',
602 default=constants.ARC_BUCKET_URL,
603 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800604 parser.add_argument('-f', '--force_version',
605 help='Android build id to use')
606 parser.add_argument('-s', '--srcroot',
607 default=os.path.join(os.environ['HOME'], 'trunk', 'src'),
608 help='Path to the src directory')
609 parser.add_argument('-t', '--tracking_branch', default='cros/master',
610 help='Branch we are tracking changes against')
611 return parser
612
613
614def main(argv):
Hidehiko Abec9ecf262017-07-05 15:17:41 +0900615 logging.EnableBuildbotMarkers()
David Rileyc0da9d92016-02-01 12:11:01 -0800616 parser = GetParser()
617 options = parser.parse_args(argv)
618 options.Freeze()
619
620 overlay_dir = os.path.abspath(_OVERLAY_DIR % {'srcroot': options.srcroot})
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900621 android_package_dir = os.path.join(
622 overlay_dir,
623 portage_util.GetFullAndroidPortagePackageName(options.android_package))
David Rileyc0da9d92016-02-01 12:11:01 -0800624 version_to_uprev = None
David Rileyc0da9d92016-02-01 12:11:01 -0800625
626 (unstable_ebuild, stable_ebuilds) = FindAndroidCandidates(android_package_dir)
David Riley73f00d92016-02-16 18:54:20 -0800627 acls = MakeAclDict(android_package_dir)
Qijiang Fan6588cc92019-11-20 13:26:04 +0900628 build_targets = MakeBuildTargetDict(options.android_package,
629 options.android_build_branch)
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900630 # Mirror artifacts, i.e., images and some sdk tools (e.g., adb, aapt).
631 version_to_uprev = MirrorArtifacts(options.android_bucket_url,
632 options.android_build_branch,
633 options.arc_bucket_url, acls,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700634 build_targets,
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900635 options.force_version)
636
637 # Mirror GTS.
Hidehiko Abee8cd06c2017-05-12 23:32:19 +0900638 if options.android_gts_build_branch:
639 MirrorArtifacts(options.android_bucket_url,
640 options.android_gts_build_branch,
641 options.arc_bucket_url, acls,
642 constants.ANDROID_GTS_BUILD_TARGETS)
David Riley73f00d92016-02-16 18:54:20 -0800643
David Rileyc0da9d92016-02-01 12:11:01 -0800644 stable_candidate = portage_util.BestEBuild(stable_ebuilds)
645
646 if stable_candidate:
Lann Martinffb95162018-08-28 12:02:54 -0600647 logging.info('Stable candidate found %s', stable_candidate.version)
David Rileyc0da9d92016-02-01 12:11:01 -0800648 else:
649 logging.info('No stable candidate found.')
650
651 tracking_branch = 'remotes/m/%s' % os.path.basename(options.tracking_branch)
652 existing_branch = git.GetCurrentBranch(android_package_dir)
653 work_branch = cros_mark_as_stable.GitBranch(constants.STABLE_EBUILD_BRANCH,
654 tracking_branch,
655 android_package_dir)
656 work_branch.CreateBranch()
657
658 # In the case of uprevving overlays that have patches applied to them,
659 # include the patched changes in the stabilizing branch.
660 if existing_branch:
661 git.RunGit(overlay_dir, ['rebase', existing_branch])
662
663 android_version_atom = MarkAndroidEBuildAsStable(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900664 stable_candidate, unstable_ebuild, options.android_package,
David Riley73f00d92016-02-16 18:54:20 -0800665 version_to_uprev, android_package_dir,
Nicolas Norvez4bd854f2017-05-23 10:04:45 -0700666 options.android_build_branch, options.arc_bucket_url, build_targets)
David Rileyc0da9d92016-02-01 12:11:01 -0800667 if android_version_atom:
668 if options.boards:
669 cros_mark_as_stable.CleanStalePackages(options.srcroot,
670 options.boards.split(':'),
671 [android_version_atom])
672
673 # Explicit print to communicate to caller.
674 print('ANDROID_VERSION_ATOM=%s' % android_version_atom)