blob: 09542d7e84878241f39ffd0da077f48ec789cbea [file] [log] [blame]
Aviv Keshetb1238c32013-04-01 11:42:13 -07001#!/usr/bin/python
Aviv Keshetb1238c32013-04-01 11:42:13 -07002# Copyright (c) 2013 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
Mike Frysingerad8c6ca2014-02-03 11:28:45 -05006"""Fast alternative to `emerge-$BOARD autotest-all`
Aviv Keshetb1238c32013-04-01 11:42:13 -07007
Aviv Keshetb1238c32013-04-01 11:42:13 -07008Simple script to be run inside the chroot. Used as a fast approximation of
9emerge-$board autotest-all, by simply rsync'ing changes from trunk to sysroot.
10"""
11
Aviv Keshete7b20192013-04-24 14:05:53 -070012import argparse
Aviv Keshetfe54a8a2013-09-16 15:49:03 -070013import glob
Aviv Keshete00caeb2013-04-17 14:03:25 -070014import logging
Aviv Keshetb1238c32013-04-01 11:42:13 -070015import os
Aviv Keshet787ffcd2013-04-08 15:14:56 -070016import re
Aviv Keshetb1238c32013-04-01 11:42:13 -070017import sys
Aviv Keshet787ffcd2013-04-08 15:14:56 -070018from collections import namedtuple
19
Aviv Keshetb1238c32013-04-01 11:42:13 -070020from chromite.buildbot import constants
Aviv Keshet940c17f2013-04-11 18:41:42 -070021from chromite.buildbot import portage_utilities
Aviv Keshetb1238c32013-04-01 11:42:13 -070022from chromite.lib import cros_build_lib
23from chromite.lib import git
Aviv Keshet557e6882013-04-25 13:26:09 -070024from chromite.lib import osutils
Aviv Keshetb1238c32013-04-01 11:42:13 -070025
Aviv Keshetb1238c32013-04-01 11:42:13 -070026
Aviv Keshet940c17f2013-04-11 18:41:42 -070027if cros_build_lib.IsInsideChroot():
Don Garrett25f309a2014-03-19 14:02:12 -070028 # pylint: disable=F0401
Aviv Keshet940c17f2013-04-11 18:41:42 -070029 # Only import portage after we've checked that we're inside the chroot.
30 import portage
31
Aviv Keshetb1238c32013-04-01 11:42:13 -070032INCLUDE_PATTERNS_FILENAME = 'autotest-quickmerge-includepatterns'
33AUTOTEST_PROJECT_NAME = 'chromiumos/third_party/autotest'
Aviv Keshet5f3cf722013-05-09 17:35:25 -070034AUTOTEST_EBUILD = 'chromeos-base/autotest'
Aviv Keshetfe54a8a2013-09-16 15:49:03 -070035DOWNGRADE_EBUILDS = ['chromeos-base/autotest']
Aviv Keshet787ffcd2013-04-08 15:14:56 -070036
Aviv Keshetc73cfc32013-06-14 16:18:53 -070037IGNORE_SUBDIRS = ['ExternalSource',
38 'logs',
39 'results',
40 'site-packages']
41
Aviv Keshet787ffcd2013-04-08 15:14:56 -070042# Data structure describing a single rsync filesystem change.
43#
44# change_description: An 11 character string, the rsync change description
45# for the particular file.
46# absolute_path: The absolute path of the created or modified file.
47ItemizedChange = namedtuple('ItemizedChange', ['change_description',
48 'absolute_path'])
49
50
51# Data structure describing the rsync new/modified files or directories.
52#
53# new_files: A list of ItemizedChange objects for new files.
54# modified_files: A list of ItemizedChange objects for modified files.
55# new_directories: A list of ItemizedChange objects for new directories.
56ItemizedChangeReport = namedtuple('ItemizedChangeReport',
57 ['new_files', 'modified_files',
58 'new_directories'])
59
Aviv Keshet84bdfc52013-06-04 13:19:38 -070060class PortagePackageAPIError(Exception):
61 """Exception thrown when unable to retrieve a portage package API."""
62
Aviv Keshet787ffcd2013-04-08 15:14:56 -070063
Aviv Keshetc73cfc32013-06-14 16:18:53 -070064
65def GetNewestFileTime(path, ignore_subdirs=[]):
66 #pylint: disable-msg=W0102
67 """Recursively determine the newest file modification time.
68
Mike Frysinger02e1e072013-11-10 22:11:34 -050069 Args:
Aviv Keshetc73cfc32013-06-14 16:18:53 -070070 path: The absolute path of the directory to recursively search.
71 ignore_subdirs: list of names of subdirectores of given path, to be
72 ignored by recursive search. Useful as a speed
73 optimization, to ignore directories full of many
74 files.
75
76 Returns:
77 The modification time of the most recently modified file recursively
78 contained within the specified directory. Returned as seconds since
79 Jan. 1, 1970, 00:00 GMT, with fractional part (floating point number).
80 """
81 command = ['find', path]
82 for ignore in ignore_subdirs:
83 command.extend(['-path', os.path.join(path, ignore), '-prune', '-o'])
84 command.extend(['-printf', r'%T@\n'])
85
Yu-Ju Hong3add4432014-01-30 11:46:15 -080086 command_result = cros_build_lib.RunCommand(command, error_code_ok=True,
87 capture_output=True)
Aviv Keshetc73cfc32013-06-14 16:18:53 -070088 float_times = [float(str_time) for str_time in
89 command_result.output.split('\n')
90 if str_time != '']
91
92 return max(float_times)
93
94
Aviv Keshet75d65962013-04-17 16:15:23 -070095def GetStalePackageNames(change_list, autotest_sysroot):
Aviv Keshete7b20192013-04-24 14:05:53 -070096 """Given a rsync change report, returns the names of stale test packages.
Aviv Keshet75d65962013-04-17 16:15:23 -070097
98 This function pulls out test package names for client-side tests, stored
99 within the client/site_tests directory tree, that had any files added or
100 modified and for whom any existing bzipped test packages may now be stale.
101
Mike Frysinger02e1e072013-11-10 22:11:34 -0500102 Args:
Aviv Keshet75d65962013-04-17 16:15:23 -0700103 change_list: A list of ItemizedChange objects corresponding to changed
104 or modified files.
105 autotest_sysroot: Absolute path of autotest in the sysroot,
Aviv Keshet474469d2013-07-22 12:54:52 -0700106 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -0700107
108 Returns:
109 A list of test package names, eg ['factory_Leds', 'login_UserPolicyKeys'].
110 May contain duplicate entries if multiple files within a test directory
111 were modified.
112 """
113 exp = os.path.abspath(autotest_sysroot) + r'/client/site_tests/(.*?)/.*'
114 matches = [re.match(exp, change.absolute_path) for change in change_list]
115 return [match.group(1) for match in matches if match]
116
117
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700118def ItemizeChangesFromRsyncOutput(rsync_output, destination_path):
119 """Convert the output of an rsync with `-i` to a ItemizedChangeReport object.
120
Mike Frysinger02e1e072013-11-10 22:11:34 -0500121 Args:
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700122 rsync_output: String stdout of rsync command that was run with `-i` option.
123 destination_path: String absolute path of the destination directory for the
124 rsync operations. This argument is necessary because
125 rsync's output only gives the relative path of
126 touched/added files.
127
128 Returns:
129 ItemizedChangeReport object giving the absolute paths of files that were
130 created or modified by rsync.
131 """
132 modified_matches = re.findall(r'([.>]f[^+]{9}) (.*)', rsync_output)
133 new_matches = re.findall(r'(>f\+{9}) (.*)', rsync_output)
134 new_symlink_matches = re.findall(r'(cL\+{9}) (.*) -> .*', rsync_output)
135 new_dir_matches = re.findall(r'(cd\+{9}) (.*)', rsync_output)
136
137 absolute_modified = [ItemizedChange(c, os.path.join(destination_path, f))
138 for (c, f) in modified_matches]
139
140 # Note: new symlinks are treated as new files.
141 absolute_new = [ItemizedChange(c, os.path.join(destination_path, f))
142 for (c, f) in new_matches + new_symlink_matches]
143
144 absolute_new_dir = [ItemizedChange(c, os.path.join(destination_path, f))
145 for (c, f) in new_dir_matches]
146
147 return ItemizedChangeReport(new_files=absolute_new,
148 modified_files=absolute_modified,
149 new_directories=absolute_new_dir)
150
151
Aviv Keshete00caeb2013-04-17 14:03:25 -0700152def GetPackageAPI(portage_root, package_cp):
Aviv Keshete7b20192013-04-24 14:05:53 -0700153 """Gets portage API handles for the given package.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700154
Mike Frysinger02e1e072013-11-10 22:11:34 -0500155 Args:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700156 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500157 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700158
159 Returns:
160 Returns (package, vartree) tuple, where
161 package is of type portage.dbapi.vartree.dblink
162 vartree is of type portage.dbapi.vartree.vartree
Aviv Keshet940c17f2013-04-11 18:41:42 -0700163 """
164 if portage_root is None:
Aviv Keshete7b20192013-04-24 14:05:53 -0700165 # pylint: disable-msg=E1101
166 portage_root = portage.root
Aviv Keshet940c17f2013-04-11 18:41:42 -0700167 # Ensure that portage_root ends with trailing slash.
168 portage_root = os.path.join(portage_root, '')
169
Aviv Keshete7b20192013-04-24 14:05:53 -0700170 # Create a vartree object corresponding to portage_root.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700171 trees = portage.create_trees(portage_root, portage_root)
172 vartree = trees[portage_root]['vartree']
173
Aviv Keshete7b20192013-04-24 14:05:53 -0700174 # List the matching installed packages in cpv format.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700175 matching_packages = vartree.dbapi.cp_list(package_cp)
176
177 if not matching_packages:
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700178 raise PortagePackageAPIError('No matching package for %s in portage_root '
179 '%s' % (package_cp, portage_root))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700180
181 if len(matching_packages) > 1:
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700182 raise PortagePackageAPIError('Too many matching packages for %s in '
183 'portage_root %s' % (package_cp,
184 portage_root))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700185
Aviv Keshete7b20192013-04-24 14:05:53 -0700186 # Convert string match to package dblink.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700187 package_cpv = matching_packages[0]
188 package_split = portage_utilities.SplitCPV(package_cpv)
Aviv Keshete7b20192013-04-24 14:05:53 -0700189 # pylint: disable-msg=E1101
190 package = portage.dblink(package_split.category,
Aviv Keshet940c17f2013-04-11 18:41:42 -0700191 package_split.pv, settings=vartree.settings,
192 vartree=vartree)
193
Aviv Keshete00caeb2013-04-17 14:03:25 -0700194 return package, vartree
195
196
197def DowngradePackageVersion(portage_root, package_cp,
198 downgrade_to_version='0'):
Aviv Keshete7b20192013-04-24 14:05:53 -0700199 """Downgrade the specified portage package version.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700200
Mike Frysinger02e1e072013-11-10 22:11:34 -0500201 Args:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700202 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500203 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700204 downgrade_to_version: String version to downgrade to. Default: '0'
205
206 Returns:
Aviv Keshet557e6882013-04-25 13:26:09 -0700207 True on success. False on failure (nonzero return code from `mv` command).
Aviv Keshete00caeb2013-04-17 14:03:25 -0700208 """
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700209 try:
210 package, _ = GetPackageAPI(portage_root, package_cp)
211 except PortagePackageAPIError:
212 # Unable to fetch a corresponding portage package API for this
213 # package_cp (either no such package, or name ambigious and matches).
214 # So, just fail out.
215 return False
Aviv Keshete00caeb2013-04-17 14:03:25 -0700216
217 source_directory = package.dbdir
218 destination_path = os.path.join(
219 package.dbroot, package_cp + '-' + downgrade_to_version)
220 if os.path.abspath(source_directory) == os.path.abspath(destination_path):
Aviv Keshet557e6882013-04-25 13:26:09 -0700221 return True
Aviv Keshete00caeb2013-04-17 14:03:25 -0700222 command = ['mv', source_directory, destination_path]
Aviv Keshet557e6882013-04-25 13:26:09 -0700223 code = cros_build_lib.SudoRunCommand(command, error_code_ok=True).returncode
224 return code == 0
Aviv Keshete00caeb2013-04-17 14:03:25 -0700225
226
Aviv Keshete7b20192013-04-24 14:05:53 -0700227def UpdatePackageContents(change_report, package_cp, portage_root=None):
228 """Add newly created files/directors to package contents.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700229
230 Given an ItemizedChangeReport, add the newly created files and directories
231 to the CONTENTS of an installed portage package, such that these files are
232 considered owned by that package.
233
Mike Frysinger02e1e072013-11-10 22:11:34 -0500234 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700235 change_report: ItemizedChangeReport object for the changes to be
236 made to the package.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700237 package_cp: A string similar to 'chromeos-base/autotest-tests' giving
238 the package category and name of the package to be altered.
239 portage_root: Portage root path, corresponding to the board that
240 we are working on. Defaults to '/'
241 """
242 package, vartree = GetPackageAPI(portage_root, package_cp)
243
Aviv Keshete7b20192013-04-24 14:05:53 -0700244 # Append new contents to package contents dictionary.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700245 contents = package.getcontents().copy()
246 for _, filename in change_report.new_files:
247 contents.setdefault(filename, (u'obj', '0', '0'))
248 for _, dirname in change_report.new_directories:
Aviv Keshete7b20192013-04-24 14:05:53 -0700249 # Strip trailing slashes if present.
250 contents.setdefault(dirname.rstrip('/'), (u'dir',))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700251
Aviv Keshete7b20192013-04-24 14:05:53 -0700252 # Write new contents dictionary to file.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700253 vartree.dbapi.writeContentsToContentsFile(package, contents)
254
255
Aviv Keshet19276752013-05-16 11:12:23 -0700256def RemoveBzipPackages(autotest_sysroot):
257 """Remove all bzipped test/dep/profiler packages from sysroot autotest.
Aviv Keshet75d65962013-04-17 16:15:23 -0700258
Mike Frysinger02e1e072013-11-10 22:11:34 -0500259 Args:
Aviv Keshet75d65962013-04-17 16:15:23 -0700260 autotest_sysroot: Absolute path of autotest in the sysroot,
Aviv Keshet474469d2013-07-22 12:54:52 -0700261 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -0700262 """
Aviv Keshet19276752013-05-16 11:12:23 -0700263 osutils.RmDir(os.path.join(autotest_sysroot, 'packages'),
264 ignore_missing=True)
265 osutils.SafeUnlink(os.path.join(autotest_sysroot, 'packages.checksum'))
Aviv Keshet75d65962013-04-17 16:15:23 -0700266
267
Aviv Keshetb1238c32013-04-01 11:42:13 -0700268def RsyncQuickmerge(source_path, sysroot_autotest_path,
269 include_pattern_file=None, pretend=False,
Aviv Keshet60968ec2013-04-11 18:44:14 -0700270 overwrite=False):
Aviv Keshetb1238c32013-04-01 11:42:13 -0700271 """Run rsync quickmerge command, with specified arguments.
Aviv Keshete7b20192013-04-24 14:05:53 -0700272
Aviv Keshetb1238c32013-04-01 11:42:13 -0700273 Command will take form `rsync -a [options] --exclude=**.pyc
274 --exclude=**.pyo
Don Garrett25f309a2014-03-19 14:02:12 -0700275 [optional --include-from include_pattern_file]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700276 --exclude=* [source_path] [sysroot_autotest_path]`
277
Mike Frysinger02e1e072013-11-10 22:11:34 -0500278 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700279 source_path: Directory to rsync from.
280 sysroot_autotest_path: Directory to rsync too.
281 include_pattern_file: Optional pattern of files to include in rsync.
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500282 pretend: True to use the '-n' option to rsync, to perform dry run.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700283 overwrite: True to omit '-u' option, overwrite all files in sysroot,
284 not just older files.
Aviv Keshet557e6882013-04-25 13:26:09 -0700285
286 Returns:
287 The cros_build_lib.CommandResult object resulting from the rsync command.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700288 """
289 command = ['rsync', '-a']
290
Prathmesh Prabhu137266a2014-02-11 20:02:18 -0800291 # For existing files, preserve destination permissions. This ensures that
292 # existing files end up with the file permissions set by the ebuilds.
293 # If this script copies over a file that does not exist in the destination
294 # tree, it will set the least restrictive permissions allowed in the
295 # destination tree. This could happen if the file copied is not installed by
296 # *any* ebuild, or if the ebuild that installs the file was never emerged.
297 command += ['--no-p', '--chmod=ugo=rwX']
298
Aviv Keshetb1238c32013-04-01 11:42:13 -0700299 if pretend:
300 command += ['-n']
301
302 if not overwrite:
303 command += ['-u']
304
Aviv Keshet60968ec2013-04-11 18:44:14 -0700305 command += ['-i']
Aviv Keshetb1238c32013-04-01 11:42:13 -0700306
307 command += ['--exclude=**.pyc']
308 command += ['--exclude=**.pyo']
309
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700310 # Exclude files with a specific substring in their name, because
311 # they create an ambiguous itemized report. (see unit test file for details)
312 command += ['--exclude=** -> *']
313
Aviv Keshetb1238c32013-04-01 11:42:13 -0700314 if include_pattern_file:
315 command += ['--include-from=%s' % include_pattern_file]
316
317 command += ['--exclude=*']
318
319 command += [source_path, sysroot_autotest_path]
320
Aviv Keshet60968ec2013-04-11 18:44:14 -0700321 return cros_build_lib.SudoRunCommand(command, redirect_stdout=True)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700322
323
324def ParseArguments(argv):
325 """Parse command line arguments
326
Mike Frysinger02e1e072013-11-10 22:11:34 -0500327 Returns:
328 parsed arguments.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700329 """
330 parser = argparse.ArgumentParser(description='Perform a fast approximation '
331 'to emerge-$board autotest-all, by '
332 'rsyncing source tree to sysroot.')
333
Aviv Keshet0a366a02013-07-18 10:52:04 -0700334
335 default_board = cros_build_lib.GetDefaultBoard()
336 parser.add_argument('--board', metavar='BOARD', default=default_board,
337 help='Board to perform quickmerge for. Default: ' +
338 (default_board or 'Not configured.'))
Aviv Keshetb1238c32013-04-01 11:42:13 -0700339 parser.add_argument('--pretend', action='store_true',
340 help='Dry run only, do not modify sysroot autotest.')
341 parser.add_argument('--overwrite', action='store_true',
342 help='Overwrite existing files even if newer.')
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700343 parser.add_argument('--force', action='store_true',
344 help='Do not check whether destination tree is newer '
345 'than source tree, always perform quickmerge.')
Aviv Keshete00caeb2013-04-17 14:03:25 -0700346 parser.add_argument('--verbose', action='store_true',
347 help='Print detailed change report.')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700348
Aviv Keshet474469d2013-07-22 12:54:52 -0700349 # Used only if test_that is calling autotest_quickmerge and has detected that
350 # the sysroot autotest path is still in usr/local/autotest (ie the build
351 # pre-dates https://chromium-review.googlesource.com/#/c/62880/ )
352 parser.add_argument('--legacy_path', action='store_true',
353 help=argparse.SUPPRESS)
354
Aviv Keshetb1238c32013-04-01 11:42:13 -0700355 return parser.parse_args(argv)
356
357
358def main(argv):
359 cros_build_lib.AssertInsideChroot()
360
361 args = ParseArguments(argv)
362
Aviv Keshete7b20192013-04-24 14:05:53 -0700363 if os.geteuid() != 0:
Aviv Keshet940c17f2013-04-11 18:41:42 -0700364 try:
365 cros_build_lib.SudoRunCommand([sys.executable] + sys.argv)
366 except cros_build_lib.RunCommandError:
367 return 1
368 return 0
369
Aviv Keshetb1238c32013-04-01 11:42:13 -0700370 if not args.board:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700371 print 'No board specified. Aborting.'
Aviv Keshetb1238c32013-04-01 11:42:13 -0700372 return 1
373
374 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
David Jamese3b06062013-11-09 18:52:02 -0800375 checkout = manifest.FindCheckout(AUTOTEST_PROJECT_NAME)
376 source_path = os.path.join(checkout.GetPath(absolute=True), '')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700377
378 script_path = os.path.dirname(__file__)
379 include_pattern_file = os.path.join(script_path, INCLUDE_PATTERNS_FILENAME)
380
381 # TODO: Determine the following string programatically.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700382 sysroot_path = os.path.join('/build', args.board, '')
Aviv Keshet474469d2013-07-22 12:54:52 -0700383 sysroot_autotest_path = os.path.join(sysroot_path,
384 constants.AUTOTEST_BUILD_PATH, '')
385 if args.legacy_path:
386 sysroot_autotest_path = os.path.join(sysroot_path, 'usr/local/autotest',
387 '')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700388
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700389 if not args.force:
390 newest_dest_time = GetNewestFileTime(sysroot_autotest_path, IGNORE_SUBDIRS)
391 newest_source_time = GetNewestFileTime(source_path, IGNORE_SUBDIRS)
392 if newest_dest_time >= newest_source_time:
393 logging.info('The sysroot appears to be newer than the source tree, '
394 'doing nothing and exiting now.')
395 return 0
396
Aviv Keshet60968ec2013-04-11 18:44:14 -0700397 rsync_output = RsyncQuickmerge(source_path, sysroot_autotest_path,
Aviv Keshete7b20192013-04-24 14:05:53 -0700398 include_pattern_file, args.pretend,
399 args.overwrite)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700400
Aviv Keshete00caeb2013-04-17 14:03:25 -0700401 if args.verbose:
402 logging.info(rsync_output.output)
403
Aviv Keshet60968ec2013-04-11 18:44:14 -0700404 change_report = ItemizeChangesFromRsyncOutput(rsync_output.output,
405 sysroot_autotest_path)
406
Aviv Keshet940c17f2013-04-11 18:41:42 -0700407 if not args.pretend:
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700408 logging.info('Updating portage database.')
Aviv Keshet5f3cf722013-05-09 17:35:25 -0700409 UpdatePackageContents(change_report, AUTOTEST_EBUILD,
Aviv Keshet940c17f2013-04-11 18:41:42 -0700410 sysroot_path)
Aviv Keshetfe54a8a2013-09-16 15:49:03 -0700411 for logfile in glob.glob(os.path.join(sysroot_autotest_path, 'packages',
412 '*.log')):
413 try:
414 # Open file in a try-except block, for atomicity, instead of
415 # doing existence check.
416 with open(logfile, 'r') as f:
417 package_cp = f.readline().strip()
418 DOWNGRADE_EBUILDS.append(package_cp)
419 except IOError:
420 pass
421
Aviv Keshet3cc4e9e2013-04-24 10:47:23 -0700422 for ebuild in DOWNGRADE_EBUILDS:
Aviv Keshet557e6882013-04-25 13:26:09 -0700423 if not DowngradePackageVersion(sysroot_path, ebuild):
Aviv Keshet3cc4e9e2013-04-24 10:47:23 -0700424 logging.warning('Unable to downgrade package %s version number.',
Aviv Keshete7b20192013-04-24 14:05:53 -0700425 ebuild)
Aviv Keshet19276752013-05-16 11:12:23 -0700426 RemoveBzipPackages(sysroot_autotest_path)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700427
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700428 sentinel_filename = os.path.join(sysroot_autotest_path,
429 '.quickmerge_sentinel')
430 cros_build_lib.RunCommand(['touch', sentinel_filename])
431
Aviv Keshetfe54a8a2013-09-16 15:49:03 -0700432
Aviv Keshet940c17f2013-04-11 18:41:42 -0700433 if args.pretend:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700434 logging.info('The following message is pretend only. No filesystem '
Aviv Keshete7b20192013-04-24 14:05:53 -0700435 'changes made.')
Aviv Keshete00caeb2013-04-17 14:03:25 -0700436 logging.info('Quickmerge complete. Created or modified %s files.',
Aviv Keshete7b20192013-04-24 14:05:53 -0700437 len(change_report.new_files) +
438 len(change_report.modified_files))
Aviv Keshete00caeb2013-04-17 14:03:25 -0700439
440 return 0