blob: e794189c061a11d8281ac12bda83163178fb7db7 [file] [log] [blame]
Aviv Keshetb1238c32013-04-01 11:42:13 -07001# Copyright (c) 2013 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
Mike Frysingerad8c6ca2014-02-03 11:28:45 -05005"""Fast alternative to `emerge-$BOARD autotest-all`
Aviv Keshetb1238c32013-04-01 11:42:13 -07006
Aviv Keshetb1238c32013-04-01 11:42:13 -07007Simple script to be run inside the chroot. Used as a fast approximation of
8emerge-$board autotest-all, by simply rsync'ing changes from trunk to sysroot.
9"""
10
Mike Frysinger1d4752b2014-11-08 04:00:18 -050011# pylint: disable=bad-continuation
12
Mike Frysinger383367e2014-09-16 15:06:17 -040013from __future__ import print_function
14
Aviv Keshete7b20192013-04-24 14:05:53 -070015import argparse
Aviv Keshetfe54a8a2013-09-16 15:49:03 -070016import glob
Aviv Keshete00caeb2013-04-17 14:03:25 -070017import logging
Aviv Keshetb1238c32013-04-01 11:42:13 -070018import os
Aviv Keshet787ffcd2013-04-08 15:14:56 -070019import re
Aviv Keshetb1238c32013-04-01 11:42:13 -070020import sys
Aviv Keshet787ffcd2013-04-08 15:14:56 -070021from collections import namedtuple
22
Don Garrett88b8d782014-05-13 17:30:55 -070023from chromite.cbuildbot import constants
Aviv Keshetb1238c32013-04-01 11:42:13 -070024from chromite.lib import cros_build_lib
25from chromite.lib import git
Aviv Keshet557e6882013-04-25 13:26:09 -070026from chromite.lib import osutils
Alex Deymo075c2292014-09-04 18:31:50 -070027from chromite.lib import portage_util
Aviv Keshetb1238c32013-04-01 11:42:13 -070028
Aviv Keshetb1238c32013-04-01 11:42:13 -070029
Aviv Keshet940c17f2013-04-11 18:41:42 -070030if cros_build_lib.IsInsideChroot():
Don Garrett25f309a2014-03-19 14:02:12 -070031 # pylint: disable=F0401
Aviv Keshet940c17f2013-04-11 18:41:42 -070032 # Only import portage after we've checked that we're inside the chroot.
33 import portage
34
Aviv Keshetb1238c32013-04-01 11:42:13 -070035INCLUDE_PATTERNS_FILENAME = 'autotest-quickmerge-includepatterns'
36AUTOTEST_PROJECT_NAME = 'chromiumos/third_party/autotest'
Aviv Keshet5f3cf722013-05-09 17:35:25 -070037AUTOTEST_EBUILD = 'chromeos-base/autotest'
Aviv Keshetfe54a8a2013-09-16 15:49:03 -070038DOWNGRADE_EBUILDS = ['chromeos-base/autotest']
Aviv Keshet787ffcd2013-04-08 15:14:56 -070039
Aviv Keshetc73cfc32013-06-14 16:18:53 -070040IGNORE_SUBDIRS = ['ExternalSource',
41 'logs',
42 'results',
43 'site-packages']
44
Aviv Keshet787ffcd2013-04-08 15:14:56 -070045# Data structure describing a single rsync filesystem change.
46#
47# change_description: An 11 character string, the rsync change description
48# for the particular file.
49# absolute_path: The absolute path of the created or modified file.
50ItemizedChange = namedtuple('ItemizedChange', ['change_description',
51 'absolute_path'])
52
53
54# Data structure describing the rsync new/modified files or directories.
55#
56# new_files: A list of ItemizedChange objects for new files.
57# modified_files: A list of ItemizedChange objects for modified files.
58# new_directories: A list of ItemizedChange objects for new directories.
59ItemizedChangeReport = namedtuple('ItemizedChangeReport',
60 ['new_files', 'modified_files',
61 'new_directories'])
62
Aviv Keshet84bdfc52013-06-04 13:19:38 -070063class PortagePackageAPIError(Exception):
64 """Exception thrown when unable to retrieve a portage package API."""
65
Aviv Keshet787ffcd2013-04-08 15:14:56 -070066
Aviv Keshetc73cfc32013-06-14 16:18:53 -070067
68def GetNewestFileTime(path, ignore_subdirs=[]):
Mike Frysinger1132a702014-11-10 21:50:14 -050069 # pylint: disable=W0102
Aviv Keshetc73cfc32013-06-14 16:18:53 -070070 """Recursively determine the newest file modification time.
71
Mike Frysinger02e1e072013-11-10 22:11:34 -050072 Args:
Aviv Keshetc73cfc32013-06-14 16:18:53 -070073 path: The absolute path of the directory to recursively search.
74 ignore_subdirs: list of names of subdirectores of given path, to be
75 ignored by recursive search. Useful as a speed
76 optimization, to ignore directories full of many
77 files.
78
79 Returns:
80 The modification time of the most recently modified file recursively
81 contained within the specified directory. Returned as seconds since
82 Jan. 1, 1970, 00:00 GMT, with fractional part (floating point number).
83 """
84 command = ['find', path]
85 for ignore in ignore_subdirs:
86 command.extend(['-path', os.path.join(path, ignore), '-prune', '-o'])
87 command.extend(['-printf', r'%T@\n'])
88
Yu-Ju Hong3add4432014-01-30 11:46:15 -080089 command_result = cros_build_lib.RunCommand(command, error_code_ok=True,
90 capture_output=True)
Aviv Keshetc73cfc32013-06-14 16:18:53 -070091 float_times = [float(str_time) for str_time in
92 command_result.output.split('\n')
93 if str_time != '']
94
95 return max(float_times)
96
97
Aviv Keshet75d65962013-04-17 16:15:23 -070098def GetStalePackageNames(change_list, autotest_sysroot):
Aviv Keshete7b20192013-04-24 14:05:53 -070099 """Given a rsync change report, returns the names of stale test packages.
Aviv Keshet75d65962013-04-17 16:15:23 -0700100
101 This function pulls out test package names for client-side tests, stored
102 within the client/site_tests directory tree, that had any files added or
103 modified and for whom any existing bzipped test packages may now be stale.
104
Mike Frysinger02e1e072013-11-10 22:11:34 -0500105 Args:
Aviv Keshet75d65962013-04-17 16:15:23 -0700106 change_list: A list of ItemizedChange objects corresponding to changed
107 or modified files.
108 autotest_sysroot: Absolute path of autotest in the sysroot,
Aviv Keshet474469d2013-07-22 12:54:52 -0700109 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -0700110
111 Returns:
112 A list of test package names, eg ['factory_Leds', 'login_UserPolicyKeys'].
113 May contain duplicate entries if multiple files within a test directory
114 were modified.
115 """
116 exp = os.path.abspath(autotest_sysroot) + r'/client/site_tests/(.*?)/.*'
117 matches = [re.match(exp, change.absolute_path) for change in change_list]
118 return [match.group(1) for match in matches if match]
119
120
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700121def ItemizeChangesFromRsyncOutput(rsync_output, destination_path):
122 """Convert the output of an rsync with `-i` to a ItemizedChangeReport object.
123
Mike Frysinger02e1e072013-11-10 22:11:34 -0500124 Args:
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700125 rsync_output: String stdout of rsync command that was run with `-i` option.
126 destination_path: String absolute path of the destination directory for the
127 rsync operations. This argument is necessary because
128 rsync's output only gives the relative path of
129 touched/added files.
130
131 Returns:
132 ItemizedChangeReport object giving the absolute paths of files that were
133 created or modified by rsync.
134 """
135 modified_matches = re.findall(r'([.>]f[^+]{9}) (.*)', rsync_output)
136 new_matches = re.findall(r'(>f\+{9}) (.*)', rsync_output)
137 new_symlink_matches = re.findall(r'(cL\+{9}) (.*) -> .*', rsync_output)
138 new_dir_matches = re.findall(r'(cd\+{9}) (.*)', rsync_output)
139
140 absolute_modified = [ItemizedChange(c, os.path.join(destination_path, f))
141 for (c, f) in modified_matches]
142
143 # Note: new symlinks are treated as new files.
144 absolute_new = [ItemizedChange(c, os.path.join(destination_path, f))
145 for (c, f) in new_matches + new_symlink_matches]
146
147 absolute_new_dir = [ItemizedChange(c, os.path.join(destination_path, f))
148 for (c, f) in new_dir_matches]
149
150 return ItemizedChangeReport(new_files=absolute_new,
151 modified_files=absolute_modified,
152 new_directories=absolute_new_dir)
153
154
Aviv Keshete00caeb2013-04-17 14:03:25 -0700155def GetPackageAPI(portage_root, package_cp):
Aviv Keshete7b20192013-04-24 14:05:53 -0700156 """Gets portage API handles for the given package.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700157
Mike Frysinger02e1e072013-11-10 22:11:34 -0500158 Args:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700159 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500160 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700161
162 Returns:
163 Returns (package, vartree) tuple, where
164 package is of type portage.dbapi.vartree.dblink
165 vartree is of type portage.dbapi.vartree.vartree
Aviv Keshet940c17f2013-04-11 18:41:42 -0700166 """
167 if portage_root is None:
Mike Frysinger1132a702014-11-10 21:50:14 -0500168 # pylint: disable=E1101
Aviv Keshete7b20192013-04-24 14:05:53 -0700169 portage_root = portage.root
Aviv Keshet940c17f2013-04-11 18:41:42 -0700170 # Ensure that portage_root ends with trailing slash.
171 portage_root = os.path.join(portage_root, '')
172
Aviv Keshete7b20192013-04-24 14:05:53 -0700173 # Create a vartree object corresponding to portage_root.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700174 trees = portage.create_trees(portage_root, portage_root)
175 vartree = trees[portage_root]['vartree']
176
Aviv Keshete7b20192013-04-24 14:05:53 -0700177 # List the matching installed packages in cpv format.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700178 matching_packages = vartree.dbapi.cp_list(package_cp)
179
180 if not matching_packages:
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700181 raise PortagePackageAPIError('No matching package for %s in portage_root '
182 '%s' % (package_cp, portage_root))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700183
184 if len(matching_packages) > 1:
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700185 raise PortagePackageAPIError('Too many matching packages for %s in '
186 'portage_root %s' % (package_cp,
187 portage_root))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700188
Aviv Keshete7b20192013-04-24 14:05:53 -0700189 # Convert string match to package dblink.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700190 package_cpv = matching_packages[0]
Alex Deymo075c2292014-09-04 18:31:50 -0700191 package_split = portage_util.SplitCPV(package_cpv)
Mike Frysinger1132a702014-11-10 21:50:14 -0500192 # pylint: disable=E1101
Aviv Keshete7b20192013-04-24 14:05:53 -0700193 package = portage.dblink(package_split.category,
Aviv Keshet940c17f2013-04-11 18:41:42 -0700194 package_split.pv, settings=vartree.settings,
195 vartree=vartree)
196
Aviv Keshete00caeb2013-04-17 14:03:25 -0700197 return package, vartree
198
199
200def DowngradePackageVersion(portage_root, package_cp,
201 downgrade_to_version='0'):
Aviv Keshete7b20192013-04-24 14:05:53 -0700202 """Downgrade the specified portage package version.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700203
Mike Frysinger02e1e072013-11-10 22:11:34 -0500204 Args:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700205 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500206 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700207 downgrade_to_version: String version to downgrade to. Default: '0'
208
209 Returns:
Aviv Keshet557e6882013-04-25 13:26:09 -0700210 True on success. False on failure (nonzero return code from `mv` command).
Aviv Keshete00caeb2013-04-17 14:03:25 -0700211 """
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700212 try:
213 package, _ = GetPackageAPI(portage_root, package_cp)
214 except PortagePackageAPIError:
215 # Unable to fetch a corresponding portage package API for this
216 # package_cp (either no such package, or name ambigious and matches).
217 # So, just fail out.
218 return False
Aviv Keshete00caeb2013-04-17 14:03:25 -0700219
220 source_directory = package.dbdir
221 destination_path = os.path.join(
222 package.dbroot, package_cp + '-' + downgrade_to_version)
223 if os.path.abspath(source_directory) == os.path.abspath(destination_path):
Aviv Keshet557e6882013-04-25 13:26:09 -0700224 return True
Aviv Keshete00caeb2013-04-17 14:03:25 -0700225 command = ['mv', source_directory, destination_path]
Aviv Keshet557e6882013-04-25 13:26:09 -0700226 code = cros_build_lib.SudoRunCommand(command, error_code_ok=True).returncode
227 return code == 0
Aviv Keshete00caeb2013-04-17 14:03:25 -0700228
229
Aviv Keshete7b20192013-04-24 14:05:53 -0700230def UpdatePackageContents(change_report, package_cp, portage_root=None):
231 """Add newly created files/directors to package contents.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700232
233 Given an ItemizedChangeReport, add the newly created files and directories
234 to the CONTENTS of an installed portage package, such that these files are
235 considered owned by that package.
236
Mike Frysinger02e1e072013-11-10 22:11:34 -0500237 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700238 change_report: ItemizedChangeReport object for the changes to be
239 made to the package.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700240 package_cp: A string similar to 'chromeos-base/autotest-tests' giving
241 the package category and name of the package to be altered.
242 portage_root: Portage root path, corresponding to the board that
243 we are working on. Defaults to '/'
244 """
245 package, vartree = GetPackageAPI(portage_root, package_cp)
246
Aviv Keshete7b20192013-04-24 14:05:53 -0700247 # Append new contents to package contents dictionary.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700248 contents = package.getcontents().copy()
249 for _, filename in change_report.new_files:
250 contents.setdefault(filename, (u'obj', '0', '0'))
251 for _, dirname in change_report.new_directories:
Aviv Keshete7b20192013-04-24 14:05:53 -0700252 # Strip trailing slashes if present.
253 contents.setdefault(dirname.rstrip('/'), (u'dir',))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700254
Aviv Keshete7b20192013-04-24 14:05:53 -0700255 # Write new contents dictionary to file.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700256 vartree.dbapi.writeContentsToContentsFile(package, contents)
257
258
Aviv Keshet19276752013-05-16 11:12:23 -0700259def RemoveBzipPackages(autotest_sysroot):
260 """Remove all bzipped test/dep/profiler packages from sysroot autotest.
Aviv Keshet75d65962013-04-17 16:15:23 -0700261
Mike Frysinger02e1e072013-11-10 22:11:34 -0500262 Args:
Aviv Keshet75d65962013-04-17 16:15:23 -0700263 autotest_sysroot: Absolute path of autotest in the sysroot,
Aviv Keshet474469d2013-07-22 12:54:52 -0700264 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -0700265 """
Aviv Keshet19276752013-05-16 11:12:23 -0700266 osutils.RmDir(os.path.join(autotest_sysroot, 'packages'),
267 ignore_missing=True)
268 osutils.SafeUnlink(os.path.join(autotest_sysroot, 'packages.checksum'))
Aviv Keshet75d65962013-04-17 16:15:23 -0700269
270
Aviv Keshetb1238c32013-04-01 11:42:13 -0700271def RsyncQuickmerge(source_path, sysroot_autotest_path,
272 include_pattern_file=None, pretend=False,
Aviv Keshet60968ec2013-04-11 18:44:14 -0700273 overwrite=False):
Aviv Keshetb1238c32013-04-01 11:42:13 -0700274 """Run rsync quickmerge command, with specified arguments.
Aviv Keshete7b20192013-04-24 14:05:53 -0700275
Aviv Keshetb1238c32013-04-01 11:42:13 -0700276 Command will take form `rsync -a [options] --exclude=**.pyc
277 --exclude=**.pyo
Don Garrett25f309a2014-03-19 14:02:12 -0700278 [optional --include-from include_pattern_file]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700279 --exclude=* [source_path] [sysroot_autotest_path]`
280
Mike Frysinger02e1e072013-11-10 22:11:34 -0500281 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700282 source_path: Directory to rsync from.
283 sysroot_autotest_path: Directory to rsync too.
284 include_pattern_file: Optional pattern of files to include in rsync.
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500285 pretend: True to use the '-n' option to rsync, to perform dry run.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700286 overwrite: True to omit '-u' option, overwrite all files in sysroot,
287 not just older files.
Aviv Keshet557e6882013-04-25 13:26:09 -0700288
289 Returns:
290 The cros_build_lib.CommandResult object resulting from the rsync command.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700291 """
292 command = ['rsync', '-a']
293
Prathmesh Prabhu137266a2014-02-11 20:02:18 -0800294 # For existing files, preserve destination permissions. This ensures that
295 # existing files end up with the file permissions set by the ebuilds.
296 # If this script copies over a file that does not exist in the destination
297 # tree, it will set the least restrictive permissions allowed in the
298 # destination tree. This could happen if the file copied is not installed by
299 # *any* ebuild, or if the ebuild that installs the file was never emerged.
300 command += ['--no-p', '--chmod=ugo=rwX']
301
Aviv Keshetb1238c32013-04-01 11:42:13 -0700302 if pretend:
303 command += ['-n']
304
305 if not overwrite:
306 command += ['-u']
307
Aviv Keshet60968ec2013-04-11 18:44:14 -0700308 command += ['-i']
Aviv Keshetb1238c32013-04-01 11:42:13 -0700309
310 command += ['--exclude=**.pyc']
311 command += ['--exclude=**.pyo']
312
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700313 # Exclude files with a specific substring in their name, because
314 # they create an ambiguous itemized report. (see unit test file for details)
315 command += ['--exclude=** -> *']
316
Aviv Keshetb1238c32013-04-01 11:42:13 -0700317 if include_pattern_file:
318 command += ['--include-from=%s' % include_pattern_file]
319
320 command += ['--exclude=*']
321
322 command += [source_path, sysroot_autotest_path]
323
Aviv Keshet60968ec2013-04-11 18:44:14 -0700324 return cros_build_lib.SudoRunCommand(command, redirect_stdout=True)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700325
326
327def ParseArguments(argv):
328 """Parse command line arguments
329
Mike Frysinger02e1e072013-11-10 22:11:34 -0500330 Returns:
331 parsed arguments.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700332 """
333 parser = argparse.ArgumentParser(description='Perform a fast approximation '
334 'to emerge-$board autotest-all, by '
335 'rsyncing source tree to sysroot.')
336
Aviv Keshet0a366a02013-07-18 10:52:04 -0700337
338 default_board = cros_build_lib.GetDefaultBoard()
339 parser.add_argument('--board', metavar='BOARD', default=default_board,
340 help='Board to perform quickmerge for. Default: ' +
341 (default_board or 'Not configured.'))
Aviv Keshetb1238c32013-04-01 11:42:13 -0700342 parser.add_argument('--pretend', action='store_true',
343 help='Dry run only, do not modify sysroot autotest.')
344 parser.add_argument('--overwrite', action='store_true',
345 help='Overwrite existing files even if newer.')
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700346 parser.add_argument('--force', action='store_true',
347 help='Do not check whether destination tree is newer '
348 'than source tree, always perform quickmerge.')
Aviv Keshete00caeb2013-04-17 14:03:25 -0700349 parser.add_argument('--verbose', action='store_true',
350 help='Print detailed change report.')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700351
Aviv Keshet474469d2013-07-22 12:54:52 -0700352 # Used only if test_that is calling autotest_quickmerge and has detected that
353 # the sysroot autotest path is still in usr/local/autotest (ie the build
354 # pre-dates https://chromium-review.googlesource.com/#/c/62880/ )
355 parser.add_argument('--legacy_path', action='store_true',
356 help=argparse.SUPPRESS)
357
Aviv Keshetb1238c32013-04-01 11:42:13 -0700358 return parser.parse_args(argv)
359
360
361def main(argv):
362 cros_build_lib.AssertInsideChroot()
363
364 args = ParseArguments(argv)
365
Aviv Keshete7b20192013-04-24 14:05:53 -0700366 if os.geteuid() != 0:
Aviv Keshet940c17f2013-04-11 18:41:42 -0700367 try:
368 cros_build_lib.SudoRunCommand([sys.executable] + sys.argv)
369 except cros_build_lib.RunCommandError:
370 return 1
371 return 0
372
Aviv Keshetb1238c32013-04-01 11:42:13 -0700373 if not args.board:
Mike Frysinger383367e2014-09-16 15:06:17 -0400374 print('No board specified. Aborting.')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700375 return 1
376
377 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
David Jamese3b06062013-11-09 18:52:02 -0800378 checkout = manifest.FindCheckout(AUTOTEST_PROJECT_NAME)
379 source_path = os.path.join(checkout.GetPath(absolute=True), '')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700380
381 script_path = os.path.dirname(__file__)
382 include_pattern_file = os.path.join(script_path, INCLUDE_PATTERNS_FILENAME)
383
384 # TODO: Determine the following string programatically.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700385 sysroot_path = os.path.join('/build', args.board, '')
Aviv Keshet474469d2013-07-22 12:54:52 -0700386 sysroot_autotest_path = os.path.join(sysroot_path,
387 constants.AUTOTEST_BUILD_PATH, '')
388 if args.legacy_path:
389 sysroot_autotest_path = os.path.join(sysroot_path, 'usr/local/autotest',
390 '')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700391
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700392 if not args.force:
393 newest_dest_time = GetNewestFileTime(sysroot_autotest_path, IGNORE_SUBDIRS)
394 newest_source_time = GetNewestFileTime(source_path, IGNORE_SUBDIRS)
395 if newest_dest_time >= newest_source_time:
396 logging.info('The sysroot appears to be newer than the source tree, '
397 'doing nothing and exiting now.')
398 return 0
399
Aviv Keshet60968ec2013-04-11 18:44:14 -0700400 rsync_output = RsyncQuickmerge(source_path, sysroot_autotest_path,
Aviv Keshete7b20192013-04-24 14:05:53 -0700401 include_pattern_file, args.pretend,
402 args.overwrite)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700403
Aviv Keshete00caeb2013-04-17 14:03:25 -0700404 if args.verbose:
405 logging.info(rsync_output.output)
406
Aviv Keshet60968ec2013-04-11 18:44:14 -0700407 change_report = ItemizeChangesFromRsyncOutput(rsync_output.output,
408 sysroot_autotest_path)
409
Aviv Keshet940c17f2013-04-11 18:41:42 -0700410 if not args.pretend:
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700411 logging.info('Updating portage database.')
Aviv Keshet5f3cf722013-05-09 17:35:25 -0700412 UpdatePackageContents(change_report, AUTOTEST_EBUILD,
Aviv Keshet940c17f2013-04-11 18:41:42 -0700413 sysroot_path)
Aviv Keshetfe54a8a2013-09-16 15:49:03 -0700414 for logfile in glob.glob(os.path.join(sysroot_autotest_path, 'packages',
415 '*.log')):
416 try:
417 # Open file in a try-except block, for atomicity, instead of
418 # doing existence check.
419 with open(logfile, 'r') as f:
420 package_cp = f.readline().strip()
421 DOWNGRADE_EBUILDS.append(package_cp)
422 except IOError:
423 pass
424
Aviv Keshet3cc4e9e2013-04-24 10:47:23 -0700425 for ebuild in DOWNGRADE_EBUILDS:
Aviv Keshet557e6882013-04-25 13:26:09 -0700426 if not DowngradePackageVersion(sysroot_path, ebuild):
Aviv Keshet3cc4e9e2013-04-24 10:47:23 -0700427 logging.warning('Unable to downgrade package %s version number.',
Aviv Keshete7b20192013-04-24 14:05:53 -0700428 ebuild)
Aviv Keshet19276752013-05-16 11:12:23 -0700429 RemoveBzipPackages(sysroot_autotest_path)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700430
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700431 sentinel_filename = os.path.join(sysroot_autotest_path,
432 '.quickmerge_sentinel')
433 cros_build_lib.RunCommand(['touch', sentinel_filename])
434
Aviv Keshetfe54a8a2013-09-16 15:49:03 -0700435
Aviv Keshet940c17f2013-04-11 18:41:42 -0700436 if args.pretend:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700437 logging.info('The following message is pretend only. No filesystem '
Aviv Keshete7b20192013-04-24 14:05:53 -0700438 'changes made.')
Aviv Keshete00caeb2013-04-17 14:03:25 -0700439 logging.info('Quickmerge complete. Created or modified %s files.',
Aviv Keshete7b20192013-04-24 14:05:53 -0700440 len(change_report.new_files) +
441 len(change_report.modified_files))
Aviv Keshete00caeb2013-04-17 14:03:25 -0700442
443 return 0