blob: 2eb4d0948d55f943701b78cd8520e2b9fbe7762d [file] [log] [blame]
David Rileyc0da9d92016-02-01 12:11:01 -08001# Copyright 2016 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This module uprevs Android for cbuildbot.
6
7After calling, it prints outs ANDROID_VERSION_ATOM=(version atom string). A
8caller could then use this atom with emerge to build the newly uprevved version
9of Android e.g.
10
Shuhei Takahashi6d02c192017-04-05 14:01:24 +090011./cros_mark_android_as_stable \
12 --android_package=android-container \
13 --android_build_branch=git_mnc-dr-arc-dev \
14 --android_gts_build_branch=git_mnc-dev
15
David Rileyc0da9d92016-02-01 12:11:01 -080016Returns chromeos-base/android-container-2559197
17
18emerge-veyron_minnie-cheets =chromeos-base/android-container-2559197-r1
19"""
20
21from __future__ import print_function
22
23import filecmp
24import glob
25import os
Hidehiko Abe12727dd2016-05-27 23:23:45 +090026import re
David Rileyc0da9d92016-02-01 12:11:01 -080027
Aviv Keshetb7519e12016-10-04 00:50:00 -070028from chromite.lib import constants
David Rileyc0da9d92016-02-01 12:11:01 -080029from chromite.lib import commandline
30from chromite.lib import cros_build_lib
31from chromite.lib import cros_logging as logging
32from chromite.lib import git
33from chromite.lib import gs
34from chromite.lib import portage_util
35from chromite.scripts import cros_mark_as_stable
36
37
38# Dir where all the action happens.
39_OVERLAY_DIR = '%(srcroot)s/private-overlays/project-cheets-private/'
40
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +090041_GIT_COMMIT_MESSAGE = ('Marking latest for %(android_package)s ebuild '
David Rileyc0da9d92016-02-01 12:11:01 -080042 'with version %(android_version)s as stable.')
43
44# URLs that print lists of Android revisions between two build ids.
45_ANDROID_VERSION_URL = ('http://android-build-uber.corp.google.com/repo.html?'
46 'last_bid=%(old)s&bid=%(new)s&branch=%(branch)s')
47
48
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090049def IsBuildIdValid(bucket_url, build_branch, build_id, targets):
David Rileyc0da9d92016-02-01 12:11:01 -080050 """Checks that a specific build_id is valid.
51
52 Looks for that build_id for all builds. Confirms that the subpath can
53 be found and that the zip file is present in that subdirectory.
54
55 Args:
56 bucket_url: URL of Android build gs bucket
57 build_branch: branch of Android builds
58 build_id: A string. The Android build id number to check.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090059 targets: Dict from build key to (targe build suffix, artifact file pattern)
60 pair.
David Rileyc0da9d92016-02-01 12:11:01 -080061
62 Returns:
63 Returns subpaths dictionary if build_id is valid.
64 None if the build_id is not valid.
65 """
66 gs_context = gs.GSContext()
67 subpaths_dict = {}
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +090068 for build, (target, _) in targets.iteritems():
David Rileyc0da9d92016-02-01 12:11:01 -080069 build_dir = '%s-%s' % (build_branch, target)
70 build_id_path = os.path.join(bucket_url, build_dir, build_id)
71
72 # Find name of subpath.
73 try:
74 subpaths = gs_context.List(build_id_path)
75 except gs.GSNoSuchKey:
76 logging.warn(
77 'Directory [%s] does not contain any subpath, ignoring it.',
78 build_id_path)
79 return None
80 if len(subpaths) > 1:
81 logging.warn(
82 'Directory [%s] contains more than one subpath, ignoring it.',
83 build_id_path)
84 return None
85
86 subpath_dir = subpaths[0].url.rstrip('/')
87 subpath_name = os.path.basename(subpath_dir)
88
89 # Look for a zipfile ending in the build_id number.
90 try:
Hidehiko Abe12727dd2016-05-27 23:23:45 +090091 gs_context.List(subpath_dir)
David Rileyc0da9d92016-02-01 12:11:01 -080092 except gs.GSNoSuchKey:
93 logging.warn(
Hidehiko Abe12727dd2016-05-27 23:23:45 +090094 'Did not find a file for build id [%s] in directory [%s].',
David Rileyc0da9d92016-02-01 12:11:01 -080095 build_id, subpath_dir)
96 return None
97
98 # Record subpath for the build.
99 subpaths_dict[build] = subpath_name
100
101 # If we got here, it means we found an appropriate build for all platforms.
102 return subpaths_dict
103
104
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900105def GetLatestBuild(bucket_url, build_branch, targets):
David Rileyc0da9d92016-02-01 12:11:01 -0800106 """Searches the gs bucket for the latest green build.
107
108 Args:
109 bucket_url: URL of Android build gs bucket
110 build_branch: branch of Android builds
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900111 targets: Dict from build key to (targe build suffix, artifact file pattern)
112 pair.
David Rileyc0da9d92016-02-01 12:11:01 -0800113
114 Returns:
115 Tuple of (latest version string, subpaths dictionary)
116 If no latest build can be found, returns None, None
117 """
118 gs_context = gs.GSContext()
119 common_build_ids = None
120 # Find builds for each target.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900121 for target, _ in targets.itervalues():
David Rileyc0da9d92016-02-01 12:11:01 -0800122 build_dir = '-'.join((build_branch, target))
123 base_path = os.path.join(bucket_url, build_dir)
124 build_ids = []
125 for gs_result in gs_context.List(base_path):
126 # Remove trailing slashes and get the base name, which is the build_id.
127 build_id = os.path.basename(gs_result.url.rstrip('/'))
128 if not build_id.isdigit():
129 logging.warn('Directory [%s] does not look like a valid build_id.',
130 gs_result.url)
131 continue
132 build_ids.append(build_id)
133
134 # Update current list of builds.
135 if common_build_ids is None:
136 # First run, populate it with the first platform.
137 common_build_ids = set(build_ids)
138 else:
139 # Already populated, find the ones that are common.
140 common_build_ids.intersection_update(build_ids)
141
142 if common_build_ids is None:
143 logging.warn('Did not find a build_id common to all platforms.')
144 return None, None
145
146 # Otherwise, find the most recent one that is valid.
147 for build_id in sorted(common_build_ids, key=int, reverse=True):
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900148 subpaths = IsBuildIdValid(bucket_url, build_branch, build_id, targets)
David Rileyc0da9d92016-02-01 12:11:01 -0800149 if subpaths:
150 return build_id, subpaths
151
152 # If not found, no build_id is valid.
153 logging.warn('Did not find a build_id valid on all platforms.')
154 return None, None
155
156
157def FindAndroidCandidates(package_dir):
158 """Return a tuple of Android's unstable ebuild and stable ebuilds.
159
160 Args:
161 package_dir: The path to where the package ebuild is stored.
162
163 Returns:
164 Tuple [unstable_ebuild, stable_ebuilds].
165
166 Raises:
167 Exception: if no unstable ebuild exists for Android.
168 """
169 stable_ebuilds = []
170 unstable_ebuilds = []
171 for path in glob.glob(os.path.join(package_dir, '*.ebuild')):
172 ebuild = portage_util.EBuild(path)
173 if ebuild.version == '9999':
174 unstable_ebuilds.append(ebuild)
175 else:
176 stable_ebuilds.append(ebuild)
177
178 # Apply some sanity checks.
179 if not unstable_ebuilds:
180 raise Exception('Missing 9999 ebuild for %s' % package_dir)
181 if not stable_ebuilds:
182 logging.warning('Missing stable ebuild for %s' % package_dir)
183
184 return portage_util.BestEBuild(unstable_ebuilds), stable_ebuilds
185
186
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800187def _GetArcBasename(build, basename):
188 """Tweaks filenames between Android bucket and ARC++ bucket.
189
190 Android builders create build artifacts with the same name for -user and
191 -userdebug builds, which breaks the android-container ebuild (b/33072485).
192 When copying the artifacts from the Android bucket to the ARC++ bucket some
193 artifacts will be renamed from the usual pattern
194 *cheets_${ARCH}-target_files-S{VERSION}.zip to
195 cheets_${BUILD_NAME}-target_files-S{VERSION}.zip which will typically look
196 like cheets_(${LABEL})*${ARCH}_userdebug-target_files-S{VERSION}.zip.
197
198 Args:
199 build: the build being mirrored, e.g. 'X86', 'ARM', 'X86_USERDEBUG'.
200 basename: the basename of the artifact to copy.
201
202 Returns:
203 The basename of the destination.
204 """
205 if build not in constants.ARC_BUILDS_NEED_ARTIFACTS_RENAMED:
206 return basename
207 to_discard, sep, to_keep = basename.partition('-')
208 if not sep:
209 logging.error(('Build %s: Could not find separator "-" in artifact'
210 ' basename %s'), build, basename)
211 return basename
212 if 'cheets_' not in to_discard:
213 logging.error('Build %s: Unexpected artifact basename %s',
214 build, basename)
215 return basename
216 return 'cheets_%s-%s' % (build.lower(), to_keep)
217
218
David Riley73f00d92016-02-16 18:54:20 -0800219def CopyToArcBucket(android_bucket_url, build_branch, build_id, subpaths,
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900220 targets, arc_bucket_url, acls):
David Riley73f00d92016-02-16 18:54:20 -0800221 """Copies from source Android bucket to ARC++ specific bucket.
222
223 Copies each build to the ARC bucket eliminating the subpath.
224 Applies build specific ACLs for each file.
225
226 Args:
227 android_bucket_url: URL of Android build gs bucket
228 build_branch: branch of Android builds
229 build_id: A string. The Android build id number to check.
230 subpaths: Subpath dictionary for each build to copy.
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900231 targets: Dict from build key to (targe build suffix, artifact file pattern)
232 pair.
David Riley73f00d92016-02-16 18:54:20 -0800233 arc_bucket_url: URL of the target ARC build gs bucket
234 acls: ACLs dictionary for each build to copy.
235 """
236 gs_context = gs.GSContext()
237 for build, subpath in subpaths.iteritems():
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900238 target, pattern = targets[build]
David Riley73f00d92016-02-16 18:54:20 -0800239 build_dir = '%s-%s' % (build_branch, target)
240 android_dir = os.path.join(android_bucket_url, build_dir, build_id, subpath)
241 arc_dir = os.path.join(arc_bucket_url, build_dir, build_id)
242
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900243 # Copy all target files from android_dir to arc_dir, setting ACLs.
244 for targetfile in gs_context.List(android_dir):
245 if re.search(pattern, targetfile.url):
246 basename = os.path.basename(targetfile.url)
Nicolas Norvezb08f54d2016-12-05 17:58:54 -0800247 arc_path = os.path.join(arc_dir, _GetArcBasename(build, basename))
David Riley73f00d92016-02-16 18:54:20 -0800248 acl = acls[build]
249 needs_copy = True
250
251 # Check a pre-existing file with the original source.
252 if gs_context.Exists(arc_path):
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900253 if (gs_context.Stat(targetfile.url).hash_crc32c !=
Elijah Taylorbfc30692016-04-22 14:05:23 -0700254 gs_context.Stat(arc_path).hash_crc32c):
David Riley73f00d92016-02-16 18:54:20 -0800255 logging.warn('Removing incorrect file %s', arc_path)
256 gs_context.Remove(arc_path)
257 else:
258 logging.info('Skipping already copied file %s', arc_path)
259 needs_copy = False
260
261 # Copy if necessary, and set the ACL unconditionally.
262 # The Stat() call above doesn't verify the ACL is correct and
263 # the ChangeACL should be relatively cheap compared to the copy.
264 # This covers the following caes:
265 # - handling an interrupted copy from a previous run.
266 # - rerunning the copy in case one of the googlestorage_acl_X.txt
267 # files changes (e.g. we add a new variant which reuses a build).
268 if needs_copy:
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900269 logging.info('Copying %s -> %s (acl %s)',
270 targetfile.url, arc_path, acl)
271 gs_context.Copy(targetfile.url, arc_path, version=0)
David Riley73f00d92016-02-16 18:54:20 -0800272 gs_context.ChangeACL(arc_path, acl_args_file=acl)
273
274
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900275def MirrorArtifacts(android_bucket_url, android_build_branch, arc_bucket_url,
276 acls, targets, version=None):
277 """Mirrors artifacts from Android bucket to ARC bucket.
278
279 First, this function identifies which build version should be copied,
280 if not given. Please see GetLatestBuild() and IsBuildIdValid() for details.
281
282 On build version identified, then copies target artifacts to the ARC bucket,
283 with setting ACLs.
284
285 Args:
286 android_bucket_url: URL of Android build gs bucket
287 android_build_branch: branch of Android builds
288 arc_bucket_url: URL of the target ARC build gs bucket
289 acls: ACLs dictionary for each build to copy.
290 targets: Dict from build key to (targe build suffix, artifact file pattern)
291 pair.
292 version: (optional) A string. The Android build id number to check.
293 If not passed, detect latest good build version.
294
295 Returns:
296 Mirrored version.
297 """
298 if version:
299 subpaths = IsBuildIdValid(
300 android_bucket_url, android_build_branch, version, targets)
301 if not subpaths:
302 logging.error('Requested build %s is not valid' % version)
303 else:
304 version, subpaths = GetLatestBuild(
305 android_bucket_url, android_build_branch, targets)
306
307 CopyToArcBucket(android_bucket_url, android_build_branch, version, subpaths,
308 targets, arc_bucket_url, acls)
309 return version
310
311
David Riley73f00d92016-02-16 18:54:20 -0800312def MakeAclDict(package_dir):
313 """Creates a dictionary of acl files for each build type.
314
315 Args:
316 package_dir: The path to where the package acl files are stored.
317
318 Returns:
319 Returns acls dictionary.
320 """
321 return dict(
322 (k, os.path.join(package_dir, v))
323 for k, v in constants.ARC_BUCKET_ACLS.items()
324 )
325
326
David Rileyc0da9d92016-02-01 12:11:01 -0800327def GetAndroidRevisionListLink(build_branch, old_android, new_android):
328 """Returns a link to the list of revisions between two Android versions
329
330 Given two AndroidEBuilds, generate a link to a page that prints the
331 Android changes between those two revisions, inclusive.
332
333 Args:
334 build_branch: branch of Android builds
335 old_android: ebuild for the version to diff from
336 new_android: ebuild for the version to which to diff
337
338 Returns:
339 The desired URL.
340 """
341 return _ANDROID_VERSION_URL % {'branch': build_branch,
342 'old': old_android.version,
343 'new': new_android.version}
344
345
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900346def MarkAndroidEBuildAsStable(stable_candidate, unstable_ebuild,
347 android_package, android_version, package_dir,
348 build_branch, arc_bucket_url):
David Rileyc0da9d92016-02-01 12:11:01 -0800349 r"""Uprevs the Android ebuild.
350
351 This is the main function that uprevs from a stable candidate
352 to its new version.
353
354 Args:
355 stable_candidate: ebuild that corresponds to the stable ebuild we are
356 revving from. If None, builds the a new ebuild given the version
357 with revision set to 1.
358 unstable_ebuild: ebuild corresponding to the unstable ebuild for Android.
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900359 android_package: android package name.
David Rileyc0da9d92016-02-01 12:11:01 -0800360 android_version: The \d+ build id of Android.
David Rileyc0da9d92016-02-01 12:11:01 -0800361 package_dir: Path to the android-container package dir.
David Riley73f00d92016-02-16 18:54:20 -0800362 build_branch: branch of Android builds.
363 arc_bucket_url: URL of the target ARC build gs bucket.
David Rileyc0da9d92016-02-01 12:11:01 -0800364
365 Returns:
366 Full portage version atom (including rc's, etc) that was revved.
367 """
368 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
369 """Returns True if the new ebuild is redundant.
370
371 This is True if there if the current stable ebuild is the exact same copy
372 of the new one.
373 """
374 if not stable_ebuild:
375 return False
376
David Riley676f5402016-02-12 17:24:23 -0800377 if stable_candidate.version_no_rev == new_ebuild.version_no_rev:
David Rileyc0da9d92016-02-01 12:11:01 -0800378 return filecmp.cmp(
379 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False)
380
381 # Case where we have the last stable candidate with same version just rev.
David Riley676f5402016-02-12 17:24:23 -0800382 if stable_candidate and stable_candidate.version_no_rev == android_version:
David Rileyc0da9d92016-02-01 12:11:01 -0800383 new_ebuild_path = '%s-r%d.ebuild' % (
384 stable_candidate.ebuild_path_no_revision,
385 stable_candidate.current_revision + 1)
386 else:
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900387 pf = '%s-%s-r1' % (android_package, android_version)
David Rileyc0da9d92016-02-01 12:11:01 -0800388 new_ebuild_path = os.path.join(package_dir, '%s.ebuild' % pf)
389
David Riley73f00d92016-02-16 18:54:20 -0800390 variables = {'BASE_URL': arc_bucket_url}
Hidehiko Abe12727dd2016-05-27 23:23:45 +0900391 for build, (target, _) in constants.ANDROID_BUILD_TARGETS.iteritems():
David Riley73f00d92016-02-16 18:54:20 -0800392 variables[build + '_TARGET'] = '%s-%s' % (build_branch, target)
David Rileyc0da9d92016-02-01 12:11:01 -0800393
394 portage_util.EBuild.MarkAsStable(
395 unstable_ebuild.ebuild_path, new_ebuild_path,
396 variables, make_stable=True)
397 new_ebuild = portage_util.EBuild(new_ebuild_path)
398
399 # Determine whether this is ebuild is redundant.
400 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
401 msg = 'Previous ebuild with same version found and ebuild is redundant.'
402 logging.info(msg)
403 os.unlink(new_ebuild_path)
404 return None
405
406 if stable_candidate:
407 logging.PrintBuildbotLink('Android revisions',
408 GetAndroidRevisionListLink(build_branch,
409 stable_candidate,
410 new_ebuild))
411
412 git.RunGit(package_dir, ['add', new_ebuild_path])
413 if stable_candidate and not stable_candidate.IsSticky():
414 git.RunGit(package_dir, ['rm', stable_candidate.ebuild_path])
415
416 # Update ebuild manifest and git add it.
417 gen_manifest_cmd = ['ebuild', new_ebuild_path, 'manifest', '--force']
418 cros_build_lib.RunCommand(gen_manifest_cmd,
419 extra_env=None, print_cmd=True)
420 git.RunGit(package_dir, ['add', 'Manifest'])
421
422 portage_util.EBuild.CommitChange(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900423 _GIT_COMMIT_MESSAGE % {'android_package': android_package,
David Rileyc0da9d92016-02-01 12:11:01 -0800424 'android_version': android_version},
425 package_dir)
426
427 return '%s-%s' % (new_ebuild.package, new_ebuild.version)
428
429
430def GetParser():
431 """Creates the argument parser."""
432 parser = commandline.ArgumentParser()
433 parser.add_argument('-b', '--boards')
434 parser.add_argument('--android_bucket_url',
David Riley73f00d92016-02-16 18:54:20 -0800435 default=constants.ANDROID_BUCKET_URL,
436 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800437 parser.add_argument('--android_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900438 required=True,
439 help='Android branch to import from. '
440 'Ex: git_mnc-dr-arc-dev')
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900441 parser.add_argument('--android_gts_build_branch',
Shuhei Takahashi6d02c192017-04-05 14:01:24 +0900442 help='Android GTS branch to copy artifacts from. '
443 'Ex: git_mnc-dev')
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900444 parser.add_argument('--android_package',
445 default=constants.ANDROID_PACKAGE_NAME)
David Riley73f00d92016-02-16 18:54:20 -0800446 parser.add_argument('--arc_bucket_url',
447 default=constants.ARC_BUCKET_URL,
448 type='gs_path')
David Rileyc0da9d92016-02-01 12:11:01 -0800449 parser.add_argument('-f', '--force_version',
450 help='Android build id to use')
451 parser.add_argument('-s', '--srcroot',
452 default=os.path.join(os.environ['HOME'], 'trunk', 'src'),
453 help='Path to the src directory')
454 parser.add_argument('-t', '--tracking_branch', default='cros/master',
455 help='Branch we are tracking changes against')
456 return parser
457
458
459def main(argv):
460 parser = GetParser()
461 options = parser.parse_args(argv)
462 options.Freeze()
463
464 overlay_dir = os.path.abspath(_OVERLAY_DIR % {'srcroot': options.srcroot})
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900465 android_package_dir = os.path.join(
466 overlay_dir,
467 portage_util.GetFullAndroidPortagePackageName(options.android_package))
David Rileyc0da9d92016-02-01 12:11:01 -0800468 version_to_uprev = None
David Rileyc0da9d92016-02-01 12:11:01 -0800469
470 (unstable_ebuild, stable_ebuilds) = FindAndroidCandidates(android_package_dir)
David Riley73f00d92016-02-16 18:54:20 -0800471 acls = MakeAclDict(android_package_dir)
Hidehiko Abe1ebc25d2016-07-28 02:24:37 +0900472 # Mirror artifacts, i.e., images and some sdk tools (e.g., adb, aapt).
473 version_to_uprev = MirrorArtifacts(options.android_bucket_url,
474 options.android_build_branch,
475 options.arc_bucket_url, acls,
476 constants.ANDROID_BUILD_TARGETS,
477 options.force_version)
478
479 # Mirror GTS.
Hidehiko Abee8cd06c2017-05-12 23:32:19 +0900480 if options.android_gts_build_branch:
481 MirrorArtifacts(options.android_bucket_url,
482 options.android_gts_build_branch,
483 options.arc_bucket_url, acls,
484 constants.ANDROID_GTS_BUILD_TARGETS)
David Riley73f00d92016-02-16 18:54:20 -0800485
David Rileyc0da9d92016-02-01 12:11:01 -0800486 stable_candidate = portage_util.BestEBuild(stable_ebuilds)
487
488 if stable_candidate:
David Riley676f5402016-02-12 17:24:23 -0800489 logging.info('Stable candidate found %s' % stable_candidate.version)
David Rileyc0da9d92016-02-01 12:11:01 -0800490 else:
491 logging.info('No stable candidate found.')
492
493 tracking_branch = 'remotes/m/%s' % os.path.basename(options.tracking_branch)
494 existing_branch = git.GetCurrentBranch(android_package_dir)
495 work_branch = cros_mark_as_stable.GitBranch(constants.STABLE_EBUILD_BRANCH,
496 tracking_branch,
497 android_package_dir)
498 work_branch.CreateBranch()
499
500 # In the case of uprevving overlays that have patches applied to them,
501 # include the patched changes in the stabilizing branch.
502 if existing_branch:
503 git.RunGit(overlay_dir, ['rebase', existing_branch])
504
505 android_version_atom = MarkAndroidEBuildAsStable(
Hidehiko Abe4fd94ae2017-01-24 18:59:55 +0900506 stable_candidate, unstable_ebuild, options.android_package,
David Riley73f00d92016-02-16 18:54:20 -0800507 version_to_uprev, android_package_dir,
508 options.android_build_branch, options.arc_bucket_url)
David Rileyc0da9d92016-02-01 12:11:01 -0800509 if android_version_atom:
510 if options.boards:
511 cros_mark_as_stable.CleanStalePackages(options.srcroot,
512 options.boards.split(':'),
513 [android_version_atom])
514
515 # Explicit print to communicate to caller.
516 print('ANDROID_VERSION_ATOM=%s' % android_version_atom)