blob: b5a712e32e8a249a791ca23b22937f05a983167c [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
Aviv Keshete7b20192013-04-24 14:05:53 -070011import argparse
Aviv Keshetfe54a8a2013-09-16 15:49:03 -070012import glob
Aviv Keshetb1238c32013-04-01 11:42:13 -070013import os
Aviv Keshet787ffcd2013-04-08 15:14:56 -070014import re
Aviv Keshetb1238c32013-04-01 11:42:13 -070015import sys
Aviv Keshet787ffcd2013-04-08 15:14:56 -070016from collections import namedtuple
17
Alex Klein727e3202020-05-29 11:13:55 -060018from chromite.lib import commandline
Aviv Keshetb7519e12016-10-04 00:50:00 -070019from chromite.lib import constants
Aviv Keshetb1238c32013-04-01 11:42:13 -070020from chromite.lib import cros_build_lib
Ralph Nathan91874ca2015-03-19 13:29:41 -070021from chromite.lib import cros_logging as logging
Aviv Keshetb1238c32013-04-01 11:42:13 -070022from chromite.lib import git
Aviv Keshet557e6882013-04-25 13:26:09 -070023from chromite.lib import osutils
Alex Klein18a60af2020-06-11 12:08:47 -060024from chromite.lib.parser import package_info
Aviv Keshetb1238c32013-04-01 11:42:13 -070025
Aviv Keshet940c17f2013-04-11 18:41:42 -070026if cros_build_lib.IsInsideChroot():
Mike Frysinger27e21b72018-07-12 14:20:21 -040027 # pylint: disable=import-error
Aviv Keshet940c17f2013-04-11 18:41:42 -070028 import portage
29
Mike Frysingere65f3752014-12-08 00:46:39 -050030
Aviv Keshetb1238c32013-04-01 11:42:13 -070031INCLUDE_PATTERNS_FILENAME = 'autotest-quickmerge-includepatterns'
Derek Beckett1f19c9c2020-12-14 12:25:53 -080032AUTOTEST_SYMLINK = 'autotest_lib'
Aviv Keshetb1238c32013-04-01 11:42:13 -070033AUTOTEST_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
Aviv Keshet787ffcd2013-04-08 15:14:56 -070050# Data structure describing the rsync new/modified files or directories.
51#
52# new_files: A list of ItemizedChange objects for new files.
53# modified_files: A list of ItemizedChange objects for modified files.
54# new_directories: A list of ItemizedChange objects for new directories.
55ItemizedChangeReport = namedtuple('ItemizedChangeReport',
56 ['new_files', 'modified_files',
57 'new_directories'])
58
Mike Frysingere65f3752014-12-08 00:46:39 -050059
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 Keshet75d65962013-04-17 16:15:23 -070064def GetStalePackageNames(change_list, autotest_sysroot):
Aviv Keshete7b20192013-04-24 14:05:53 -070065 """Given a rsync change report, returns the names of stale test packages.
Aviv Keshet75d65962013-04-17 16:15:23 -070066
67 This function pulls out test package names for client-side tests, stored
68 within the client/site_tests directory tree, that had any files added or
69 modified and for whom any existing bzipped test packages may now be stale.
70
Mike Frysinger02e1e072013-11-10 22:11:34 -050071 Args:
Aviv Keshet75d65962013-04-17 16:15:23 -070072 change_list: A list of ItemizedChange objects corresponding to changed
73 or modified files.
74 autotest_sysroot: Absolute path of autotest in the sysroot,
Aviv Keshet474469d2013-07-22 12:54:52 -070075 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -070076
77 Returns:
78 A list of test package names, eg ['factory_Leds', 'login_UserPolicyKeys'].
79 May contain duplicate entries if multiple files within a test directory
80 were modified.
81 """
82 exp = os.path.abspath(autotest_sysroot) + r'/client/site_tests/(.*?)/.*'
83 matches = [re.match(exp, change.absolute_path) for change in change_list]
84 return [match.group(1) for match in matches if match]
85
86
Aviv Keshet787ffcd2013-04-08 15:14:56 -070087def ItemizeChangesFromRsyncOutput(rsync_output, destination_path):
88 """Convert the output of an rsync with `-i` to a ItemizedChangeReport object.
89
Mike Frysinger02e1e072013-11-10 22:11:34 -050090 Args:
Aviv Keshet787ffcd2013-04-08 15:14:56 -070091 rsync_output: String stdout of rsync command that was run with `-i` option.
92 destination_path: String absolute path of the destination directory for the
93 rsync operations. This argument is necessary because
94 rsync's output only gives the relative path of
95 touched/added files.
96
97 Returns:
98 ItemizedChangeReport object giving the absolute paths of files that were
99 created or modified by rsync.
100 """
101 modified_matches = re.findall(r'([.>]f[^+]{9}) (.*)', rsync_output)
102 new_matches = re.findall(r'(>f\+{9}) (.*)', rsync_output)
103 new_symlink_matches = re.findall(r'(cL\+{9}) (.*) -> .*', rsync_output)
104 new_dir_matches = re.findall(r'(cd\+{9}) (.*)', rsync_output)
105
106 absolute_modified = [ItemizedChange(c, os.path.join(destination_path, f))
107 for (c, f) in modified_matches]
108
109 # Note: new symlinks are treated as new files.
110 absolute_new = [ItemizedChange(c, os.path.join(destination_path, f))
111 for (c, f) in new_matches + new_symlink_matches]
112
113 absolute_new_dir = [ItemizedChange(c, os.path.join(destination_path, f))
114 for (c, f) in new_dir_matches]
115
116 return ItemizedChangeReport(new_files=absolute_new,
117 modified_files=absolute_modified,
118 new_directories=absolute_new_dir)
119
120
Aviv Keshete00caeb2013-04-17 14:03:25 -0700121def GetPackageAPI(portage_root, package_cp):
Aviv Keshete7b20192013-04-24 14:05:53 -0700122 """Gets portage API handles for the given package.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700123
Mike Frysinger02e1e072013-11-10 22:11:34 -0500124 Args:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700125 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500126 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700127
128 Returns:
129 Returns (package, vartree) tuple, where
130 package is of type portage.dbapi.vartree.dblink
131 vartree is of type portage.dbapi.vartree.vartree
Aviv Keshet940c17f2013-04-11 18:41:42 -0700132 """
133 if portage_root is None:
Mike Frysingere65f3752014-12-08 00:46:39 -0500134 # pylint: disable=no-member
Aviv Keshete7b20192013-04-24 14:05:53 -0700135 portage_root = portage.root
Aviv Keshet940c17f2013-04-11 18:41:42 -0700136 # Ensure that portage_root ends with trailing slash.
137 portage_root = os.path.join(portage_root, '')
138
Aviv Keshete7b20192013-04-24 14:05:53 -0700139 # Create a vartree object corresponding to portage_root.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700140 trees = portage.create_trees(portage_root, portage_root)
141 vartree = trees[portage_root]['vartree']
142
Aviv Keshete7b20192013-04-24 14:05:53 -0700143 # List the matching installed packages in cpv format.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700144 matching_packages = vartree.dbapi.cp_list(package_cp)
145
146 if not matching_packages:
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700147 raise PortagePackageAPIError('No matching package for %s in portage_root '
148 '%s' % (package_cp, portage_root))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700149
150 if len(matching_packages) > 1:
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700151 raise PortagePackageAPIError('Too many matching packages for %s in '
152 'portage_root %s' % (package_cp,
153 portage_root))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700154
Aviv Keshete7b20192013-04-24 14:05:53 -0700155 # Convert string match to package dblink.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700156 package_cpv = matching_packages[0]
Alex Klein18a60af2020-06-11 12:08:47 -0600157 package_split = package_info.SplitCPV(package_cpv)
Mike Frysingere65f3752014-12-08 00:46:39 -0500158 # pylint: disable=no-member
Aviv Keshete7b20192013-04-24 14:05:53 -0700159 package = portage.dblink(package_split.category,
Aviv Keshet940c17f2013-04-11 18:41:42 -0700160 package_split.pv, settings=vartree.settings,
161 vartree=vartree)
162
Aviv Keshete00caeb2013-04-17 14:03:25 -0700163 return package, vartree
164
165
166def DowngradePackageVersion(portage_root, package_cp,
167 downgrade_to_version='0'):
Aviv Keshete7b20192013-04-24 14:05:53 -0700168 """Downgrade the specified portage package version.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700169
Mike Frysinger02e1e072013-11-10 22:11:34 -0500170 Args:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700171 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500172 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700173 downgrade_to_version: String version to downgrade to. Default: '0'
174
175 Returns:
Aviv Keshet557e6882013-04-25 13:26:09 -0700176 True on success. False on failure (nonzero return code from `mv` command).
Aviv Keshete00caeb2013-04-17 14:03:25 -0700177 """
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700178 try:
179 package, _ = GetPackageAPI(portage_root, package_cp)
180 except PortagePackageAPIError:
181 # Unable to fetch a corresponding portage package API for this
182 # package_cp (either no such package, or name ambigious and matches).
183 # So, just fail out.
184 return False
Aviv Keshete00caeb2013-04-17 14:03:25 -0700185
186 source_directory = package.dbdir
187 destination_path = os.path.join(
188 package.dbroot, package_cp + '-' + downgrade_to_version)
189 if os.path.abspath(source_directory) == os.path.abspath(destination_path):
Aviv Keshet557e6882013-04-25 13:26:09 -0700190 return True
Aviv Keshete00caeb2013-04-17 14:03:25 -0700191 command = ['mv', source_directory, destination_path]
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500192 code = cros_build_lib.sudo_run(command, check=False).returncode
Aviv Keshet557e6882013-04-25 13:26:09 -0700193 return code == 0
Aviv Keshete00caeb2013-04-17 14:03:25 -0700194
195
Aviv Keshete7b20192013-04-24 14:05:53 -0700196def UpdatePackageContents(change_report, package_cp, portage_root=None):
197 """Add newly created files/directors to package contents.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700198
199 Given an ItemizedChangeReport, add the newly created files and directories
200 to the CONTENTS of an installed portage package, such that these files are
201 considered owned by that package.
202
Mike Frysinger02e1e072013-11-10 22:11:34 -0500203 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700204 change_report: ItemizedChangeReport object for the changes to be
205 made to the package.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700206 package_cp: A string similar to 'chromeos-base/autotest-tests' giving
207 the package category and name of the package to be altered.
208 portage_root: Portage root path, corresponding to the board that
209 we are working on. Defaults to '/'
210 """
211 package, vartree = GetPackageAPI(portage_root, package_cp)
212
Aviv Keshete7b20192013-04-24 14:05:53 -0700213 # Append new contents to package contents dictionary.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700214 contents = package.getcontents().copy()
215 for _, filename in change_report.new_files:
216 contents.setdefault(filename, (u'obj', '0', '0'))
217 for _, dirname in change_report.new_directories:
Aviv Keshete7b20192013-04-24 14:05:53 -0700218 # Strip trailing slashes if present.
219 contents.setdefault(dirname.rstrip('/'), (u'dir',))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700220
Aviv Keshete7b20192013-04-24 14:05:53 -0700221 # Write new contents dictionary to file.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700222 vartree.dbapi.writeContentsToContentsFile(package, contents)
223
224
Aviv Keshet19276752013-05-16 11:12:23 -0700225def RemoveBzipPackages(autotest_sysroot):
226 """Remove all bzipped test/dep/profiler packages from sysroot autotest.
Aviv Keshet75d65962013-04-17 16:15:23 -0700227
Mike Frysinger02e1e072013-11-10 22:11:34 -0500228 Args:
Aviv Keshet75d65962013-04-17 16:15:23 -0700229 autotest_sysroot: Absolute path of autotest in the sysroot,
Aviv Keshet474469d2013-07-22 12:54:52 -0700230 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -0700231 """
Aviv Keshet19276752013-05-16 11:12:23 -0700232 osutils.RmDir(os.path.join(autotest_sysroot, 'packages'),
Mike Frysingere65f3752014-12-08 00:46:39 -0500233 ignore_missing=True)
Aviv Keshet19276752013-05-16 11:12:23 -0700234 osutils.SafeUnlink(os.path.join(autotest_sysroot, 'packages.checksum'))
Aviv Keshet75d65962013-04-17 16:15:23 -0700235
236
Aviv Keshetb1238c32013-04-01 11:42:13 -0700237def RsyncQuickmerge(source_path, sysroot_autotest_path,
238 include_pattern_file=None, pretend=False,
Aviv Keshet60968ec2013-04-11 18:44:14 -0700239 overwrite=False):
Aviv Keshetb1238c32013-04-01 11:42:13 -0700240 """Run rsync quickmerge command, with specified arguments.
Aviv Keshete7b20192013-04-24 14:05:53 -0700241
Aviv Keshetb1238c32013-04-01 11:42:13 -0700242 Command will take form `rsync -a [options] --exclude=**.pyc
243 --exclude=**.pyo
Don Garrett25f309a2014-03-19 14:02:12 -0700244 [optional --include-from include_pattern_file]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700245 --exclude=* [source_path] [sysroot_autotest_path]`
246
Mike Frysinger02e1e072013-11-10 22:11:34 -0500247 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700248 source_path: Directory to rsync from.
249 sysroot_autotest_path: Directory to rsync too.
250 include_pattern_file: Optional pattern of files to include in rsync.
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500251 pretend: True to use the '-n' option to rsync, to perform dry run.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700252 overwrite: True to omit '-u' option, overwrite all files in sysroot,
253 not just older files.
Aviv Keshet557e6882013-04-25 13:26:09 -0700254
255 Returns:
256 The cros_build_lib.CommandResult object resulting from the rsync command.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700257 """
258 command = ['rsync', '-a']
259
Prathmesh Prabhu137266a2014-02-11 20:02:18 -0800260 # For existing files, preserve destination permissions. This ensures that
261 # existing files end up with the file permissions set by the ebuilds.
262 # If this script copies over a file that does not exist in the destination
263 # tree, it will set the least restrictive permissions allowed in the
264 # destination tree. This could happen if the file copied is not installed by
265 # *any* ebuild, or if the ebuild that installs the file was never emerged.
266 command += ['--no-p', '--chmod=ugo=rwX']
267
Aviv Keshetb1238c32013-04-01 11:42:13 -0700268 if pretend:
269 command += ['-n']
270
271 if not overwrite:
272 command += ['-u']
273
Aviv Keshet60968ec2013-04-11 18:44:14 -0700274 command += ['-i']
Aviv Keshetb1238c32013-04-01 11:42:13 -0700275
276 command += ['--exclude=**.pyc']
277 command += ['--exclude=**.pyo']
278
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800279 # Always exclude the autotest symlink to avoid a possible recursion hole.
280 # The order here is (unfortunately) extremely important.
281 if AUTOTEST_SYMLINK not in source_path:
282 command += ['--exclude=%s/' % AUTOTEST_SYMLINK]
283
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700284 # Exclude files with a specific substring in their name, because
285 # they create an ambiguous itemized report. (see unit test file for details)
286 command += ['--exclude=** -> *']
287
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800288 # Order seems important here, and this include must come before the possible
289 # exclude below...
Aviv Keshetb1238c32013-04-01 11:42:13 -0700290 if include_pattern_file:
291 command += ['--include-from=%s' % include_pattern_file]
292
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800293 if AUTOTEST_SYMLINK in source_path:
294 command += ['-l']
295 else:
296 command += ['-L', '--exclude=*']
Po-Hsien Wang745ac352018-04-13 12:25:41 -0700297
Aviv Keshetb1238c32013-04-01 11:42:13 -0700298 command += [source_path, sysroot_autotest_path]
299
Mike Frysinger13858562020-02-25 16:07:55 -0500300 return cros_build_lib.sudo_run(command, stdout=True, encoding='utf-8')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700301
302
303def ParseArguments(argv):
304 """Parse command line arguments
305
Mike Frysinger02e1e072013-11-10 22:11:34 -0500306 Returns:
307 parsed arguments.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700308 """
Alex Klein727e3202020-05-29 11:13:55 -0600309 parser = commandline.ArgumentParser(
310 description='Perform a fast approximation to emerge-$board '
311 'autotest-all, by rsyncing source tree to sysroot.')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700312
Aviv Keshet0a366a02013-07-18 10:52:04 -0700313 default_board = cros_build_lib.GetDefaultBoard()
314 parser.add_argument('--board', metavar='BOARD', default=default_board,
315 help='Board to perform quickmerge for. Default: ' +
316 (default_board or 'Not configured.'))
Aviv Keshetb1238c32013-04-01 11:42:13 -0700317 parser.add_argument('--pretend', action='store_true',
318 help='Dry run only, do not modify sysroot autotest.')
319 parser.add_argument('--overwrite', action='store_true',
320 help='Overwrite existing files even if newer.')
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700321 parser.add_argument('--force', action='store_true',
Simran Basi8fc88992015-04-21 17:15:23 -0700322 help=argparse.SUPPRESS)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700323
Aviv Keshet474469d2013-07-22 12:54:52 -0700324 # Used only if test_that is calling autotest_quickmerge and has detected that
325 # the sysroot autotest path is still in usr/local/autotest (ie the build
326 # pre-dates https://chromium-review.googlesource.com/#/c/62880/ )
327 parser.add_argument('--legacy_path', action='store_true',
328 help=argparse.SUPPRESS)
329
Aviv Keshetb1238c32013-04-01 11:42:13 -0700330 return parser.parse_args(argv)
331
332
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800333def _maybe_add_autotest_symlink(src_paths, path, dest_path):
334 """If the symlink folders exists, add them to the src to quickmerge."""
335 autotest_client_symlink = os.path.join(path, 'client', AUTOTEST_SYMLINK)
336 if os.path.exists(autotest_client_symlink):
337 src_paths.append((autotest_client_symlink,
338 os.path.join(dest_path, 'client/')))
339 autotest_main_symlink = os.path.join(path, AUTOTEST_SYMLINK)
340 if os.path.exists(autotest_main_symlink):
341 src_paths.append((autotest_main_symlink, dest_path))
342
343
Aviv Keshetb1238c32013-04-01 11:42:13 -0700344def main(argv):
345 cros_build_lib.AssertInsideChroot()
346
347 args = ParseArguments(argv)
348
Aviv Keshete7b20192013-04-24 14:05:53 -0700349 if os.geteuid() != 0:
Aviv Keshet940c17f2013-04-11 18:41:42 -0700350 try:
Mike Frysinger45602c72019-09-22 02:15:11 -0400351 cros_build_lib.sudo_run([sys.executable] + sys.argv)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700352 except cros_build_lib.RunCommandError:
353 return 1
354 return 0
355
Aviv Keshetb1238c32013-04-01 11:42:13 -0700356 if not args.board:
Mike Frysinger383367e2014-09-16 15:06:17 -0400357 print('No board specified. Aborting.')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700358 return 1
359
360 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
David Jamese3b06062013-11-09 18:52:02 -0800361 checkout = manifest.FindCheckout(AUTOTEST_PROJECT_NAME)
Simran Basi348fccc2015-04-28 12:39:01 -0700362 brillo_autotest_src_path = os.path.join(checkout.GetPath(absolute=True), '')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700363
364 script_path = os.path.dirname(__file__)
365 include_pattern_file = os.path.join(script_path, INCLUDE_PATTERNS_FILENAME)
366
367 # TODO: Determine the following string programatically.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700368 sysroot_path = os.path.join('/build', args.board, '')
Aviv Keshet474469d2013-07-22 12:54:52 -0700369 sysroot_autotest_path = os.path.join(sysroot_path,
370 constants.AUTOTEST_BUILD_PATH, '')
371 if args.legacy_path:
372 sysroot_autotest_path = os.path.join(sysroot_path, 'usr/local/autotest',
373 '')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700374
Simran Basi348fccc2015-04-28 12:39:01 -0700375 # Generate the list of source paths to copy.
376 src_paths = {os.path.abspath(brillo_autotest_src_path)}
377 for quickmerge_file in glob.glob(os.path.join(sysroot_autotest_path,
378 'quickmerge', '*', '*')):
379 try:
380 path = osutils.ReadFile(quickmerge_file).strip()
381 if path and os.path.exists(path):
382 src_paths.add(os.path.abspath(path))
383 except IOError:
384 logging.error('Could not quickmerge for project: %s',
385 os.path.basename(quickmerge_file))
Aviv Keshetb1238c32013-04-01 11:42:13 -0700386
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800387 # Autotest uses a circular symlink in client that *must* be added after the
388 # other sections of Autotest.
389 src_paths = list(src_paths)
390
391 # All destination paths up to this point are the same, but other sources
392 # added below might have a different one.
393 src_dest_paths = [(src_path + '/', sysroot_autotest_path)
394 for src_path in src_paths]
395
396 _maybe_add_autotest_symlink(src_dest_paths, brillo_autotest_src_path,
397 sysroot_autotest_path)
Simran Basi348fccc2015-04-28 12:39:01 -0700398 num_new_files = 0
399 num_modified_files = 0
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800400 for src_path, dest_path in src_dest_paths:
401 rsync_output = RsyncQuickmerge(src_path, dest_path,
Simran Basi348fccc2015-04-28 12:39:01 -0700402 include_pattern_file, args.pretend,
403 args.overwrite)
Aviv Keshete00caeb2013-04-17 14:03:25 -0700404
Simran Basi348fccc2015-04-28 12:39:01 -0700405 if args.verbose:
406 logging.info(rsync_output.output)
407 change_report = ItemizeChangesFromRsyncOutput(rsync_output.output,
408 sysroot_autotest_path)
409 num_new_files = num_new_files + len(change_report.new_files)
410 num_modified_files = num_modified_files + len(change_report.modified_files)
411 if not args.pretend:
412 logging.info('Updating portage database.')
413 UpdatePackageContents(change_report, AUTOTEST_EBUILD, sysroot_path)
Aviv Keshet60968ec2013-04-11 18:44:14 -0700414
Aviv Keshet940c17f2013-04-11 18:41:42 -0700415 if not args.pretend:
Aviv Keshetfe54a8a2013-09-16 15:49:03 -0700416 for logfile in glob.glob(os.path.join(sysroot_autotest_path, 'packages',
417 '*.log')):
418 try:
419 # Open file in a try-except block, for atomicity, instead of
420 # doing existence check.
421 with open(logfile, 'r') as f:
422 package_cp = f.readline().strip()
423 DOWNGRADE_EBUILDS.append(package_cp)
424 except IOError:
425 pass
426
Aviv Keshet3cc4e9e2013-04-24 10:47:23 -0700427 for ebuild in DOWNGRADE_EBUILDS:
Aviv Keshet557e6882013-04-25 13:26:09 -0700428 if not DowngradePackageVersion(sysroot_path, ebuild):
Aviv Keshet3cc4e9e2013-04-24 10:47:23 -0700429 logging.warning('Unable to downgrade package %s version number.',
Aviv Keshete7b20192013-04-24 14:05:53 -0700430 ebuild)
Aviv Keshet19276752013-05-16 11:12:23 -0700431 RemoveBzipPackages(sysroot_autotest_path)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700432
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700433 sentinel_filename = os.path.join(sysroot_autotest_path,
434 '.quickmerge_sentinel')
Mike Frysinger45602c72019-09-22 02:15:11 -0400435 cros_build_lib.run(['touch', sentinel_filename])
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700436
Aviv Keshet940c17f2013-04-11 18:41:42 -0700437 if args.pretend:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700438 logging.info('The following message is pretend only. No filesystem '
Aviv Keshete7b20192013-04-24 14:05:53 -0700439 'changes made.')
Aviv Keshete00caeb2013-04-17 14:03:25 -0700440 logging.info('Quickmerge complete. Created or modified %s files.',
Simran Basi348fccc2015-04-28 12:39:01 -0700441 num_new_files + num_modified_files)
Aviv Keshete00caeb2013-04-17 14:03:25 -0700442
443 return 0