blob: 94ad3aa7df2bf1e69f7c2f9f208b80d48c9138eb [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
Chris McDonald59650c32021-07-20 15:29:28 -060012from collections import namedtuple
Aviv Keshetfe54a8a2013-09-16 15:49:03 -070013import glob
Chris McDonald59650c32021-07-20 15:29:28 -060014import 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 -070018
Alex Klein727e3202020-05-29 11:13:55 -060019from chromite.lib import commandline
Aviv Keshetb7519e12016-10-04 00:50:00 -070020from chromite.lib import constants
Aviv Keshetb1238c32013-04-01 11:42:13 -070021from chromite.lib import cros_build_lib
22from 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
Chris McDonald59650c32021-07-20 15:29:28 -060026
Aviv Keshet940c17f2013-04-11 18:41:42 -070027if cros_build_lib.IsInsideChroot():
Mike Frysinger27e21b72018-07-12 14:20:21 -040028 # pylint: disable=import-error
Aviv Keshet940c17f2013-04-11 18:41:42 -070029 import portage
30
Mike Frysingere65f3752014-12-08 00:46:39 -050031
Aviv Keshetb1238c32013-04-01 11:42:13 -070032INCLUDE_PATTERNS_FILENAME = 'autotest-quickmerge-includepatterns'
Derek Beckett1f19c9c2020-12-14 12:25:53 -080033AUTOTEST_SYMLINK = 'autotest_lib'
Aviv Keshetb1238c32013-04-01 11:42:13 -070034AUTOTEST_PROJECT_NAME = 'chromiumos/third_party/autotest'
Aviv Keshet5f3cf722013-05-09 17:35:25 -070035AUTOTEST_EBUILD = 'chromeos-base/autotest'
Aviv Keshetfe54a8a2013-09-16 15:49:03 -070036DOWNGRADE_EBUILDS = ['chromeos-base/autotest']
Aviv Keshet787ffcd2013-04-08 15:14:56 -070037
Aviv Keshetc73cfc32013-06-14 16:18:53 -070038IGNORE_SUBDIRS = ['ExternalSource',
39 'logs',
40 'results',
41 'site-packages']
42
Aviv Keshet787ffcd2013-04-08 15:14:56 -070043# Data structure describing a single rsync filesystem change.
44#
45# change_description: An 11 character string, the rsync change description
46# for the particular file.
47# absolute_path: The absolute path of the created or modified file.
48ItemizedChange = namedtuple('ItemizedChange', ['change_description',
49 'absolute_path'])
50
Aviv Keshet787ffcd2013-04-08 15:14:56 -070051# 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
Mike Frysingere65f3752014-12-08 00:46:39 -050060
Aviv Keshet84bdfc52013-06-04 13:19:38 -070061class PortagePackageAPIError(Exception):
62 """Exception thrown when unable to retrieve a portage package API."""
63
Aviv Keshet787ffcd2013-04-08 15:14:56 -070064
Aviv Keshet75d65962013-04-17 16:15:23 -070065def GetStalePackageNames(change_list, autotest_sysroot):
Aviv Keshete7b20192013-04-24 14:05:53 -070066 """Given a rsync change report, returns the names of stale test packages.
Aviv Keshet75d65962013-04-17 16:15:23 -070067
68 This function pulls out test package names for client-side tests, stored
69 within the client/site_tests directory tree, that had any files added or
70 modified and for whom any existing bzipped test packages may now be stale.
71
Mike Frysinger02e1e072013-11-10 22:11:34 -050072 Args:
Aviv Keshet75d65962013-04-17 16:15:23 -070073 change_list: A list of ItemizedChange objects corresponding to changed
74 or modified files.
75 autotest_sysroot: Absolute path of autotest in the sysroot,
Aviv Keshet474469d2013-07-22 12:54:52 -070076 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -070077
78 Returns:
79 A list of test package names, eg ['factory_Leds', 'login_UserPolicyKeys'].
80 May contain duplicate entries if multiple files within a test directory
81 were modified.
82 """
83 exp = os.path.abspath(autotest_sysroot) + r'/client/site_tests/(.*?)/.*'
84 matches = [re.match(exp, change.absolute_path) for change in change_list]
85 return [match.group(1) for match in matches if match]
86
87
Aviv Keshet787ffcd2013-04-08 15:14:56 -070088def ItemizeChangesFromRsyncOutput(rsync_output, destination_path):
89 """Convert the output of an rsync with `-i` to a ItemizedChangeReport object.
90
Mike Frysinger02e1e072013-11-10 22:11:34 -050091 Args:
Aviv Keshet787ffcd2013-04-08 15:14:56 -070092 rsync_output: String stdout of rsync command that was run with `-i` option.
93 destination_path: String absolute path of the destination directory for the
94 rsync operations. This argument is necessary because
95 rsync's output only gives the relative path of
96 touched/added files.
97
98 Returns:
99 ItemizedChangeReport object giving the absolute paths of files that were
100 created or modified by rsync.
101 """
102 modified_matches = re.findall(r'([.>]f[^+]{9}) (.*)', rsync_output)
103 new_matches = re.findall(r'(>f\+{9}) (.*)', rsync_output)
104 new_symlink_matches = re.findall(r'(cL\+{9}) (.*) -> .*', rsync_output)
105 new_dir_matches = re.findall(r'(cd\+{9}) (.*)', rsync_output)
106
107 absolute_modified = [ItemizedChange(c, os.path.join(destination_path, f))
108 for (c, f) in modified_matches]
109
110 # Note: new symlinks are treated as new files.
111 absolute_new = [ItemizedChange(c, os.path.join(destination_path, f))
112 for (c, f) in new_matches + new_symlink_matches]
113
114 absolute_new_dir = [ItemizedChange(c, os.path.join(destination_path, f))
115 for (c, f) in new_dir_matches]
116
117 return ItemizedChangeReport(new_files=absolute_new,
118 modified_files=absolute_modified,
119 new_directories=absolute_new_dir)
120
121
Aviv Keshete00caeb2013-04-17 14:03:25 -0700122def GetPackageAPI(portage_root, package_cp):
Aviv Keshete7b20192013-04-24 14:05:53 -0700123 """Gets portage API handles for the given package.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700124
Mike Frysinger02e1e072013-11-10 22:11:34 -0500125 Args:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700126 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500127 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700128
129 Returns:
130 Returns (package, vartree) tuple, where
131 package is of type portage.dbapi.vartree.dblink
132 vartree is of type portage.dbapi.vartree.vartree
Aviv Keshet940c17f2013-04-11 18:41:42 -0700133 """
134 if portage_root is None:
Mike Frysingere65f3752014-12-08 00:46:39 -0500135 # pylint: disable=no-member
Aviv Keshete7b20192013-04-24 14:05:53 -0700136 portage_root = portage.root
Aviv Keshet940c17f2013-04-11 18:41:42 -0700137 # Ensure that portage_root ends with trailing slash.
138 portage_root = os.path.join(portage_root, '')
139
Aviv Keshete7b20192013-04-24 14:05:53 -0700140 # Create a vartree object corresponding to portage_root.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700141 trees = portage.create_trees(portage_root, portage_root)
142 vartree = trees[portage_root]['vartree']
143
Aviv Keshete7b20192013-04-24 14:05:53 -0700144 # List the matching installed packages in cpv format.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700145 matching_packages = vartree.dbapi.cp_list(package_cp)
146
147 if not matching_packages:
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700148 raise PortagePackageAPIError('No matching package for %s in portage_root '
149 '%s' % (package_cp, portage_root))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700150
151 if len(matching_packages) > 1:
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700152 raise PortagePackageAPIError('Too many matching packages for %s in '
153 'portage_root %s' % (package_cp,
154 portage_root))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700155
Aviv Keshete7b20192013-04-24 14:05:53 -0700156 # Convert string match to package dblink.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700157 package_cpv = matching_packages[0]
Alex Klein18a60af2020-06-11 12:08:47 -0600158 package_split = package_info.SplitCPV(package_cpv)
Mike Frysingere65f3752014-12-08 00:46:39 -0500159 # pylint: disable=no-member
Aviv Keshete7b20192013-04-24 14:05:53 -0700160 package = portage.dblink(package_split.category,
Aviv Keshet940c17f2013-04-11 18:41:42 -0700161 package_split.pv, settings=vartree.settings,
162 vartree=vartree)
163
Aviv Keshete00caeb2013-04-17 14:03:25 -0700164 return package, vartree
165
166
167def DowngradePackageVersion(portage_root, package_cp,
168 downgrade_to_version='0'):
Aviv Keshete7b20192013-04-24 14:05:53 -0700169 """Downgrade the specified portage package version.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700170
Mike Frysinger02e1e072013-11-10 22:11:34 -0500171 Args:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700172 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500173 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700174 downgrade_to_version: String version to downgrade to. Default: '0'
175
176 Returns:
Aviv Keshet557e6882013-04-25 13:26:09 -0700177 True on success. False on failure (nonzero return code from `mv` command).
Aviv Keshete00caeb2013-04-17 14:03:25 -0700178 """
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700179 try:
180 package, _ = GetPackageAPI(portage_root, package_cp)
181 except PortagePackageAPIError:
182 # Unable to fetch a corresponding portage package API for this
183 # package_cp (either no such package, or name ambigious and matches).
184 # So, just fail out.
185 return False
Aviv Keshete00caeb2013-04-17 14:03:25 -0700186
187 source_directory = package.dbdir
188 destination_path = os.path.join(
189 package.dbroot, package_cp + '-' + downgrade_to_version)
190 if os.path.abspath(source_directory) == os.path.abspath(destination_path):
Aviv Keshet557e6882013-04-25 13:26:09 -0700191 return True
Aviv Keshete00caeb2013-04-17 14:03:25 -0700192 command = ['mv', source_directory, destination_path]
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500193 code = cros_build_lib.sudo_run(command, check=False).returncode
Aviv Keshet557e6882013-04-25 13:26:09 -0700194 return code == 0
Aviv Keshete00caeb2013-04-17 14:03:25 -0700195
196
Aviv Keshete7b20192013-04-24 14:05:53 -0700197def UpdatePackageContents(change_report, package_cp, portage_root=None):
198 """Add newly created files/directors to package contents.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700199
200 Given an ItemizedChangeReport, add the newly created files and directories
201 to the CONTENTS of an installed portage package, such that these files are
202 considered owned by that package.
203
Mike Frysinger02e1e072013-11-10 22:11:34 -0500204 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700205 change_report: ItemizedChangeReport object for the changes to be
206 made to the package.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700207 package_cp: A string similar to 'chromeos-base/autotest-tests' giving
208 the package category and name of the package to be altered.
209 portage_root: Portage root path, corresponding to the board that
210 we are working on. Defaults to '/'
211 """
212 package, vartree = GetPackageAPI(portage_root, package_cp)
213
Aviv Keshete7b20192013-04-24 14:05:53 -0700214 # Append new contents to package contents dictionary.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700215 contents = package.getcontents().copy()
216 for _, filename in change_report.new_files:
217 contents.setdefault(filename, (u'obj', '0', '0'))
218 for _, dirname in change_report.new_directories:
Aviv Keshete7b20192013-04-24 14:05:53 -0700219 # Strip trailing slashes if present.
220 contents.setdefault(dirname.rstrip('/'), (u'dir',))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700221
Aviv Keshete7b20192013-04-24 14:05:53 -0700222 # Write new contents dictionary to file.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700223 vartree.dbapi.writeContentsToContentsFile(package, contents)
224
225
Aviv Keshet19276752013-05-16 11:12:23 -0700226def RemoveBzipPackages(autotest_sysroot):
227 """Remove all bzipped test/dep/profiler packages from sysroot autotest.
Aviv Keshet75d65962013-04-17 16:15:23 -0700228
Mike Frysinger02e1e072013-11-10 22:11:34 -0500229 Args:
Aviv Keshet75d65962013-04-17 16:15:23 -0700230 autotest_sysroot: Absolute path of autotest in the sysroot,
Aviv Keshet474469d2013-07-22 12:54:52 -0700231 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -0700232 """
Aviv Keshet19276752013-05-16 11:12:23 -0700233 osutils.RmDir(os.path.join(autotest_sysroot, 'packages'),
Mike Frysingere65f3752014-12-08 00:46:39 -0500234 ignore_missing=True)
Aviv Keshet19276752013-05-16 11:12:23 -0700235 osutils.SafeUnlink(os.path.join(autotest_sysroot, 'packages.checksum'))
Aviv Keshet75d65962013-04-17 16:15:23 -0700236
237
Aviv Keshetb1238c32013-04-01 11:42:13 -0700238def RsyncQuickmerge(source_path, sysroot_autotest_path,
239 include_pattern_file=None, pretend=False,
Aviv Keshet60968ec2013-04-11 18:44:14 -0700240 overwrite=False):
Aviv Keshetb1238c32013-04-01 11:42:13 -0700241 """Run rsync quickmerge command, with specified arguments.
Aviv Keshete7b20192013-04-24 14:05:53 -0700242
Aviv Keshetb1238c32013-04-01 11:42:13 -0700243 Command will take form `rsync -a [options] --exclude=**.pyc
244 --exclude=**.pyo
Don Garrett25f309a2014-03-19 14:02:12 -0700245 [optional --include-from include_pattern_file]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700246 --exclude=* [source_path] [sysroot_autotest_path]`
247
Mike Frysinger02e1e072013-11-10 22:11:34 -0500248 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700249 source_path: Directory to rsync from.
250 sysroot_autotest_path: Directory to rsync too.
251 include_pattern_file: Optional pattern of files to include in rsync.
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500252 pretend: True to use the '-n' option to rsync, to perform dry run.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700253 overwrite: True to omit '-u' option, overwrite all files in sysroot,
254 not just older files.
Aviv Keshet557e6882013-04-25 13:26:09 -0700255
256 Returns:
257 The cros_build_lib.CommandResult object resulting from the rsync command.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700258 """
259 command = ['rsync', '-a']
260
Prathmesh Prabhu137266a2014-02-11 20:02:18 -0800261 # For existing files, preserve destination permissions. This ensures that
262 # existing files end up with the file permissions set by the ebuilds.
263 # If this script copies over a file that does not exist in the destination
264 # tree, it will set the least restrictive permissions allowed in the
265 # destination tree. This could happen if the file copied is not installed by
266 # *any* ebuild, or if the ebuild that installs the file was never emerged.
267 command += ['--no-p', '--chmod=ugo=rwX']
268
Aviv Keshetb1238c32013-04-01 11:42:13 -0700269 if pretend:
270 command += ['-n']
271
272 if not overwrite:
273 command += ['-u']
274
Aviv Keshet60968ec2013-04-11 18:44:14 -0700275 command += ['-i']
Aviv Keshetb1238c32013-04-01 11:42:13 -0700276
277 command += ['--exclude=**.pyc']
278 command += ['--exclude=**.pyo']
279
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800280 # Always exclude the autotest symlink to avoid a possible recursion hole.
281 # The order here is (unfortunately) extremely important.
282 if AUTOTEST_SYMLINK not in source_path:
283 command += ['--exclude=%s/' % AUTOTEST_SYMLINK]
284
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700285 # Exclude files with a specific substring in their name, because
286 # they create an ambiguous itemized report. (see unit test file for details)
287 command += ['--exclude=** -> *']
288
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800289 # Order seems important here, and this include must come before the possible
290 # exclude below...
Aviv Keshetb1238c32013-04-01 11:42:13 -0700291 if include_pattern_file:
292 command += ['--include-from=%s' % include_pattern_file]
293
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800294 if AUTOTEST_SYMLINK in source_path:
295 command += ['-l']
296 else:
297 command += ['-L', '--exclude=*']
Po-Hsien Wang745ac352018-04-13 12:25:41 -0700298
Aviv Keshetb1238c32013-04-01 11:42:13 -0700299 command += [source_path, sysroot_autotest_path]
300
Mike Frysinger13858562020-02-25 16:07:55 -0500301 return cros_build_lib.sudo_run(command, stdout=True, encoding='utf-8')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700302
303
304def ParseArguments(argv):
305 """Parse command line arguments
306
Mike Frysinger02e1e072013-11-10 22:11:34 -0500307 Returns:
308 parsed arguments.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700309 """
Alex Klein727e3202020-05-29 11:13:55 -0600310 parser = commandline.ArgumentParser(
311 description='Perform a fast approximation to emerge-$board '
312 'autotest-all, by rsyncing source tree to sysroot.')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700313
Aviv Keshet0a366a02013-07-18 10:52:04 -0700314 default_board = cros_build_lib.GetDefaultBoard()
315 parser.add_argument('--board', metavar='BOARD', default=default_board,
316 help='Board to perform quickmerge for. Default: ' +
317 (default_board or 'Not configured.'))
Aviv Keshetb1238c32013-04-01 11:42:13 -0700318 parser.add_argument('--pretend', action='store_true',
319 help='Dry run only, do not modify sysroot autotest.')
320 parser.add_argument('--overwrite', action='store_true',
321 help='Overwrite existing files even if newer.')
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700322 parser.add_argument('--force', action='store_true',
Simran Basi8fc88992015-04-21 17:15:23 -0700323 help=argparse.SUPPRESS)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700324
Aviv Keshet474469d2013-07-22 12:54:52 -0700325 # Used only if test_that is calling autotest_quickmerge and has detected that
326 # the sysroot autotest path is still in usr/local/autotest (ie the build
327 # pre-dates https://chromium-review.googlesource.com/#/c/62880/ )
328 parser.add_argument('--legacy_path', action='store_true',
329 help=argparse.SUPPRESS)
330
Aviv Keshetb1238c32013-04-01 11:42:13 -0700331 return parser.parse_args(argv)
332
333
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800334def _maybe_add_autotest_symlink(src_paths, path, dest_path):
335 """If the symlink folders exists, add them to the src to quickmerge."""
336 autotest_client_symlink = os.path.join(path, 'client', AUTOTEST_SYMLINK)
337 if os.path.exists(autotest_client_symlink):
338 src_paths.append((autotest_client_symlink,
339 os.path.join(dest_path, 'client/')))
340 autotest_main_symlink = os.path.join(path, AUTOTEST_SYMLINK)
341 if os.path.exists(autotest_main_symlink):
342 src_paths.append((autotest_main_symlink, dest_path))
343
344
Aviv Keshetb1238c32013-04-01 11:42:13 -0700345def main(argv):
346 cros_build_lib.AssertInsideChroot()
347
348 args = ParseArguments(argv)
349
Aviv Keshete7b20192013-04-24 14:05:53 -0700350 if os.geteuid() != 0:
Aviv Keshet940c17f2013-04-11 18:41:42 -0700351 try:
Mike Frysinger45602c72019-09-22 02:15:11 -0400352 cros_build_lib.sudo_run([sys.executable] + sys.argv)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700353 except cros_build_lib.RunCommandError:
354 return 1
355 return 0
356
Aviv Keshetb1238c32013-04-01 11:42:13 -0700357 if not args.board:
Mike Frysinger383367e2014-09-16 15:06:17 -0400358 print('No board specified. Aborting.')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700359 return 1
360
361 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
David Jamese3b06062013-11-09 18:52:02 -0800362 checkout = manifest.FindCheckout(AUTOTEST_PROJECT_NAME)
Simran Basi348fccc2015-04-28 12:39:01 -0700363 brillo_autotest_src_path = os.path.join(checkout.GetPath(absolute=True), '')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700364
365 script_path = os.path.dirname(__file__)
366 include_pattern_file = os.path.join(script_path, INCLUDE_PATTERNS_FILENAME)
367
368 # TODO: Determine the following string programatically.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700369 sysroot_path = os.path.join('/build', args.board, '')
Aviv Keshet474469d2013-07-22 12:54:52 -0700370 sysroot_autotest_path = os.path.join(sysroot_path,
371 constants.AUTOTEST_BUILD_PATH, '')
372 if args.legacy_path:
373 sysroot_autotest_path = os.path.join(sysroot_path, 'usr/local/autotest',
374 '')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700375
Simran Basi348fccc2015-04-28 12:39:01 -0700376 # Generate the list of source paths to copy.
377 src_paths = {os.path.abspath(brillo_autotest_src_path)}
378 for quickmerge_file in glob.glob(os.path.join(sysroot_autotest_path,
379 'quickmerge', '*', '*')):
380 try:
381 path = osutils.ReadFile(quickmerge_file).strip()
382 if path and os.path.exists(path):
383 src_paths.add(os.path.abspath(path))
384 except IOError:
385 logging.error('Could not quickmerge for project: %s',
386 os.path.basename(quickmerge_file))
Aviv Keshetb1238c32013-04-01 11:42:13 -0700387
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800388 # Autotest uses a circular symlink in client that *must* be added after the
389 # other sections of Autotest.
390 src_paths = list(src_paths)
391
392 # All destination paths up to this point are the same, but other sources
393 # added below might have a different one.
394 src_dest_paths = [(src_path + '/', sysroot_autotest_path)
395 for src_path in src_paths]
396
397 _maybe_add_autotest_symlink(src_dest_paths, brillo_autotest_src_path,
398 sysroot_autotest_path)
Simran Basi348fccc2015-04-28 12:39:01 -0700399 num_new_files = 0
400 num_modified_files = 0
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800401 for src_path, dest_path in src_dest_paths:
402 rsync_output = RsyncQuickmerge(src_path, dest_path,
Simran Basi348fccc2015-04-28 12:39:01 -0700403 include_pattern_file, args.pretend,
404 args.overwrite)
Aviv Keshete00caeb2013-04-17 14:03:25 -0700405
Simran Basi348fccc2015-04-28 12:39:01 -0700406 if args.verbose:
407 logging.info(rsync_output.output)
408 change_report = ItemizeChangesFromRsyncOutput(rsync_output.output,
409 sysroot_autotest_path)
410 num_new_files = num_new_files + len(change_report.new_files)
411 num_modified_files = num_modified_files + len(change_report.modified_files)
412 if not args.pretend:
413 logging.info('Updating portage database.')
414 UpdatePackageContents(change_report, AUTOTEST_EBUILD, sysroot_path)
Aviv Keshet60968ec2013-04-11 18:44:14 -0700415
Aviv Keshet940c17f2013-04-11 18:41:42 -0700416 if not args.pretend:
Aviv Keshetfe54a8a2013-09-16 15:49:03 -0700417 for logfile in glob.glob(os.path.join(sysroot_autotest_path, 'packages',
418 '*.log')):
419 try:
420 # Open file in a try-except block, for atomicity, instead of
421 # doing existence check.
422 with open(logfile, 'r') as f:
423 package_cp = f.readline().strip()
424 DOWNGRADE_EBUILDS.append(package_cp)
425 except IOError:
426 pass
427
Aviv Keshet3cc4e9e2013-04-24 10:47:23 -0700428 for ebuild in DOWNGRADE_EBUILDS:
Aviv Keshet557e6882013-04-25 13:26:09 -0700429 if not DowngradePackageVersion(sysroot_path, ebuild):
Aviv Keshet3cc4e9e2013-04-24 10:47:23 -0700430 logging.warning('Unable to downgrade package %s version number.',
Aviv Keshete7b20192013-04-24 14:05:53 -0700431 ebuild)
Aviv Keshet19276752013-05-16 11:12:23 -0700432 RemoveBzipPackages(sysroot_autotest_path)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700433
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700434 sentinel_filename = os.path.join(sysroot_autotest_path,
435 '.quickmerge_sentinel')
Mike Frysinger45602c72019-09-22 02:15:11 -0400436 cros_build_lib.run(['touch', sentinel_filename])
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700437
Aviv Keshet940c17f2013-04-11 18:41:42 -0700438 if args.pretend:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700439 logging.info('The following message is pretend only. No filesystem '
Aviv Keshete7b20192013-04-24 14:05:53 -0700440 'changes made.')
Aviv Keshete00caeb2013-04-17 14:03:25 -0700441 logging.info('Quickmerge complete. Created or modified %s files.',
Simran Basi348fccc2015-04-28 12:39:01 -0700442 num_new_files + num_modified_files)
Aviv Keshete00caeb2013-04-17 14:03:25 -0700443
444 return 0