blob: d3cdaf41e8a2929a13d3f227fa7ce05e18ec7188 [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():
Alex Klein1699fab2022-09-08 08:46:06 -060028 # pylint: disable=import-error
29 import portage
Aviv Keshet940c17f2013-04-11 18:41:42 -070030
Mike Frysingere65f3752014-12-08 00:46:39 -050031
Alex Klein1699fab2022-09-08 08:46:06 -060032INCLUDE_PATTERNS_FILENAME = "autotest-quickmerge-includepatterns"
33AUTOTEST_SYMLINK = "autotest_lib"
34AUTOTEST_PROJECT_NAME = "chromiumos/third_party/autotest"
35AUTOTEST_EBUILD = "chromeos-base/autotest"
36DOWNGRADE_EBUILDS = ["chromeos-base/autotest"]
Aviv Keshet787ffcd2013-04-08 15:14:56 -070037
Alex Klein1699fab2022-09-08 08:46:06 -060038IGNORE_SUBDIRS = ["ExternalSource", "logs", "results", "site-packages"]
Aviv Keshetc73cfc32013-06-14 16:18:53 -070039
Aviv Keshet787ffcd2013-04-08 15:14:56 -070040# Data structure describing a single rsync filesystem change.
41#
42# change_description: An 11 character string, the rsync change description
43# for the particular file.
44# absolute_path: The absolute path of the created or modified file.
Alex Klein1699fab2022-09-08 08:46:06 -060045ItemizedChange = namedtuple(
46 "ItemizedChange", ["change_description", "absolute_path"]
47)
Aviv Keshet787ffcd2013-04-08 15:14:56 -070048
Aviv Keshet787ffcd2013-04-08 15:14:56 -070049# Data structure describing the rsync new/modified files or directories.
50#
51# new_files: A list of ItemizedChange objects for new files.
52# modified_files: A list of ItemizedChange objects for modified files.
53# new_directories: A list of ItemizedChange objects for new directories.
Alex Klein1699fab2022-09-08 08:46:06 -060054ItemizedChangeReport = namedtuple(
55 "ItemizedChangeReport", ["new_files", "modified_files", "new_directories"]
56)
Aviv Keshet787ffcd2013-04-08 15:14:56 -070057
Mike Frysingere65f3752014-12-08 00:46:39 -050058
Aviv Keshet84bdfc52013-06-04 13:19:38 -070059class PortagePackageAPIError(Exception):
Alex Klein1699fab2022-09-08 08:46:06 -060060 """Exception thrown when unable to retrieve a portage package API."""
Aviv Keshet84bdfc52013-06-04 13:19:38 -070061
Aviv Keshet787ffcd2013-04-08 15:14:56 -070062
Aviv Keshet75d65962013-04-17 16:15:23 -070063def GetStalePackageNames(change_list, autotest_sysroot):
Alex Klein1699fab2022-09-08 08:46:06 -060064 """Given a rsync change report, returns the names of stale test packages.
Aviv Keshet75d65962013-04-17 16:15:23 -070065
Alex Klein1699fab2022-09-08 08:46:06 -060066 This function pulls out test package names for client-side tests, stored
67 within the client/site_tests directory tree, that had any files added or
68 modified and for whom any existing bzipped test packages may now be stale.
Aviv Keshet75d65962013-04-17 16:15:23 -070069
Alex Klein1699fab2022-09-08 08:46:06 -060070 Args:
71 change_list: A list of ItemizedChange objects corresponding to changed
72 or modified files.
73 autotest_sysroot: Absolute path of autotest in the sysroot,
74 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -070075
Alex Klein1699fab2022-09-08 08:46:06 -060076 Returns:
77 A list of test package names, eg ['factory_Leds', 'login_UserPolicyKeys'].
78 May contain duplicate entries if multiple files within a test directory
79 were modified.
80 """
81 exp = os.path.abspath(autotest_sysroot) + r"/client/site_tests/(.*?)/.*"
82 matches = [re.match(exp, change.absolute_path) for change in change_list]
83 return [match.group(1) for match in matches if match]
Aviv Keshet75d65962013-04-17 16:15:23 -070084
85
Aviv Keshet787ffcd2013-04-08 15:14:56 -070086def ItemizeChangesFromRsyncOutput(rsync_output, destination_path):
Alex Klein1699fab2022-09-08 08:46:06 -060087 """Convert the output of an rsync with `-i` to a ItemizedChangeReport object.
Aviv Keshet787ffcd2013-04-08 15:14:56 -070088
Alex Klein1699fab2022-09-08 08:46:06 -060089 Args:
90 rsync_output: String stdout of rsync command that was run with `-i` option.
91 destination_path: String absolute path of the destination directory for the
92 rsync operations. This argument is necessary because
93 rsync's output only gives the relative path of
94 touched/added files.
Aviv Keshet787ffcd2013-04-08 15:14:56 -070095
Alex Klein1699fab2022-09-08 08:46:06 -060096 Returns:
97 ItemizedChangeReport object giving the absolute paths of files that were
98 created or modified by rsync.
99 """
100 modified_matches = re.findall(r"([.>]f[^+]{9}) (.*)", rsync_output)
101 new_matches = re.findall(r"(>f\+{9}) (.*)", rsync_output)
102 new_symlink_matches = re.findall(r"(cL\+{9}) (.*) -> .*", rsync_output)
103 new_dir_matches = re.findall(r"(cd\+{9}) (.*)", rsync_output)
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700104
Alex Klein1699fab2022-09-08 08:46:06 -0600105 absolute_modified = [
106 ItemizedChange(c, os.path.join(destination_path, f))
107 for (c, f) in modified_matches
108 ]
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700109
Alex Klein1699fab2022-09-08 08:46:06 -0600110 # Note: new symlinks are treated as new files.
111 absolute_new = [
112 ItemizedChange(c, os.path.join(destination_path, f))
113 for (c, f) in new_matches + new_symlink_matches
114 ]
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700115
Alex Klein1699fab2022-09-08 08:46:06 -0600116 absolute_new_dir = [
117 ItemizedChange(c, os.path.join(destination_path, f))
118 for (c, f) in new_dir_matches
119 ]
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700120
Alex Klein1699fab2022-09-08 08:46:06 -0600121 return ItemizedChangeReport(
122 new_files=absolute_new,
123 modified_files=absolute_modified,
124 new_directories=absolute_new_dir,
125 )
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700126
127
Aviv Keshete00caeb2013-04-17 14:03:25 -0700128def GetPackageAPI(portage_root, package_cp):
Alex Klein1699fab2022-09-08 08:46:06 -0600129 """Gets portage API handles for the given package.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700130
Alex Klein1699fab2022-09-08 08:46:06 -0600131 Args:
132 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
133 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700134
Alex Klein1699fab2022-09-08 08:46:06 -0600135 Returns:
136 Returns (package, vartree) tuple, where
137 package is of type portage.dbapi.vartree.dblink
138 vartree is of type portage.dbapi.vartree.vartree
139 """
140 if portage_root is None:
141 # pylint: disable=no-member
142 portage_root = portage.root
143 # Ensure that portage_root ends with trailing slash.
144 portage_root = os.path.join(portage_root, "")
145
146 # Create a vartree object corresponding to portage_root.
147 trees = portage.create_trees(portage_root, portage_root)
148 vartree = trees[portage_root]["vartree"]
149
150 # List the matching installed packages in cpv format.
151 matching_packages = vartree.dbapi.cp_list(package_cp)
152
153 if not matching_packages:
154 raise PortagePackageAPIError(
155 "No matching package for %s in portage_root "
156 "%s" % (package_cp, portage_root)
157 )
158
159 if len(matching_packages) > 1:
160 raise PortagePackageAPIError(
161 "Too many matching packages for %s in "
162 "portage_root %s" % (package_cp, portage_root)
163 )
164
165 # Convert string match to package dblink.
166 package_cpv = matching_packages[0]
167 package_split = package_info.SplitCPV(package_cpv)
Mike Frysingere65f3752014-12-08 00:46:39 -0500168 # pylint: disable=no-member
Alex Klein1699fab2022-09-08 08:46:06 -0600169 package = portage.dblink(
170 package_split.category,
171 package_split.pv,
172 settings=vartree.settings,
173 vartree=vartree,
174 )
Aviv Keshet940c17f2013-04-11 18:41:42 -0700175
Alex Klein1699fab2022-09-08 08:46:06 -0600176 return package, vartree
Aviv Keshete00caeb2013-04-17 14:03:25 -0700177
178
Alex Klein1699fab2022-09-08 08:46:06 -0600179def DowngradePackageVersion(portage_root, package_cp, downgrade_to_version="0"):
180 """Downgrade the specified portage package version.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700181
Alex Klein1699fab2022-09-08 08:46:06 -0600182 Args:
183 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
184 package_cp: A string similar to 'chromeos-base/autotest-tests'.
185 downgrade_to_version: String version to downgrade to. Default: '0'
Aviv Keshete00caeb2013-04-17 14:03:25 -0700186
Alex Klein1699fab2022-09-08 08:46:06 -0600187 Returns:
188 True on success. False on failure (nonzero return code from `mv` command).
189 """
190 try:
191 package, _ = GetPackageAPI(portage_root, package_cp)
192 except PortagePackageAPIError:
193 # Unable to fetch a corresponding portage package API for this
194 # package_cp (either no such package, or name ambigious and matches).
195 # So, just fail out.
196 return False
Aviv Keshete00caeb2013-04-17 14:03:25 -0700197
Alex Klein1699fab2022-09-08 08:46:06 -0600198 source_directory = package.dbdir
199 destination_path = os.path.join(
200 package.dbroot, package_cp + "-" + downgrade_to_version
201 )
202 if os.path.abspath(source_directory) == os.path.abspath(destination_path):
203 return True
204 command = ["mv", source_directory, destination_path]
205 code = cros_build_lib.sudo_run(command, check=False).returncode
206 return code == 0
Aviv Keshete00caeb2013-04-17 14:03:25 -0700207
208
Aviv Keshete7b20192013-04-24 14:05:53 -0700209def UpdatePackageContents(change_report, package_cp, portage_root=None):
Alex Klein1699fab2022-09-08 08:46:06 -0600210 """Add newly created files/directors to package contents.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700211
Alex Klein1699fab2022-09-08 08:46:06 -0600212 Given an ItemizedChangeReport, add the newly created files and directories
213 to the CONTENTS of an installed portage package, such that these files are
214 considered owned by that package.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700215
Alex Klein1699fab2022-09-08 08:46:06 -0600216 Args:
217 change_report: ItemizedChangeReport object for the changes to be
218 made to the package.
219 package_cp: A string similar to 'chromeos-base/autotest-tests' giving
220 the package category and name of the package to be altered.
221 portage_root: Portage root path, corresponding to the board that
222 we are working on. Defaults to '/'
223 """
224 package, vartree = GetPackageAPI(portage_root, package_cp)
Aviv Keshete00caeb2013-04-17 14:03:25 -0700225
Alex Klein1699fab2022-09-08 08:46:06 -0600226 # Append new contents to package contents dictionary.
227 contents = package.getcontents().copy()
228 for _, filename in change_report.new_files:
229 contents.setdefault(filename, ("obj", "0", "0"))
230 for _, dirname in change_report.new_directories:
231 # Strip trailing slashes if present.
232 contents.setdefault(dirname.rstrip("/"), ("dir",))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700233
Alex Klein1699fab2022-09-08 08:46:06 -0600234 # Write new contents dictionary to file.
235 vartree.dbapi.writeContentsToContentsFile(package, contents)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700236
237
Aviv Keshet19276752013-05-16 11:12:23 -0700238def RemoveBzipPackages(autotest_sysroot):
Alex Klein1699fab2022-09-08 08:46:06 -0600239 """Remove all bzipped test/dep/profiler packages from sysroot autotest.
Aviv Keshet75d65962013-04-17 16:15:23 -0700240
Alex Klein1699fab2022-09-08 08:46:06 -0600241 Args:
242 autotest_sysroot: Absolute path of autotest in the sysroot,
243 e.g. '/build/lumpy/usr/local/build/autotest'
244 """
245 osutils.RmDir(
246 os.path.join(autotest_sysroot, "packages"), ignore_missing=True
247 )
248 osutils.SafeUnlink(os.path.join(autotest_sysroot, "packages.checksum"))
Aviv Keshet75d65962013-04-17 16:15:23 -0700249
250
Alex Klein1699fab2022-09-08 08:46:06 -0600251def RsyncQuickmerge(
252 source_path,
253 sysroot_autotest_path,
254 include_pattern_file=None,
255 pretend=False,
256 overwrite=False,
257):
258 """Run rsync quickmerge command, with specified arguments.
Aviv Keshete7b20192013-04-24 14:05:53 -0700259
Alex Klein1699fab2022-09-08 08:46:06 -0600260 Command will take form `rsync -a [options] --exclude=**.pyc
261 --exclude=**.pyo
262 [optional --include-from include_pattern_file]
263 --exclude=* [source_path] [sysroot_autotest_path]`
Aviv Keshetb1238c32013-04-01 11:42:13 -0700264
Alex Klein1699fab2022-09-08 08:46:06 -0600265 Args:
266 source_path: Directory to rsync from.
267 sysroot_autotest_path: Directory to rsync too.
268 include_pattern_file: Optional pattern of files to include in rsync.
269 pretend: True to use the '-n' option to rsync, to perform dry run.
270 overwrite: True to omit '-u' option, overwrite all files in sysroot,
271 not just older files.
Aviv Keshet557e6882013-04-25 13:26:09 -0700272
Alex Klein1699fab2022-09-08 08:46:06 -0600273 Returns:
274 The cros_build_lib.CompletedProcess object resulting from the rsync command.
275 """
276 command = ["rsync", "-a"]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700277
Alex Klein1699fab2022-09-08 08:46:06 -0600278 # For existing files, preserve destination permissions. This ensures that
279 # existing files end up with the file permissions set by the ebuilds.
280 # If this script copies over a file that does not exist in the destination
281 # tree, it will set the least restrictive permissions allowed in the
282 # destination tree. This could happen if the file copied is not installed by
283 # *any* ebuild, or if the ebuild that installs the file was never emerged.
284 command += ["--no-p", "--chmod=ugo=rwX"]
Prathmesh Prabhu137266a2014-02-11 20:02:18 -0800285
Alex Klein1699fab2022-09-08 08:46:06 -0600286 if pretend:
287 command += ["-n"]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700288
Alex Klein1699fab2022-09-08 08:46:06 -0600289 if not overwrite:
290 command += ["-u"]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700291
Alex Klein1699fab2022-09-08 08:46:06 -0600292 command += ["-i"]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700293
Alex Klein1699fab2022-09-08 08:46:06 -0600294 command += ["--exclude=**.pyc"]
295 command += ["--exclude=**.pyo"]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700296
Alex Klein1699fab2022-09-08 08:46:06 -0600297 # Always exclude the autotest symlink to avoid a possible recursion hole.
298 # The order here is (unfortunately) extremely important.
299 if AUTOTEST_SYMLINK not in source_path:
300 command += ["--exclude=%s/" % AUTOTEST_SYMLINK]
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800301
Alex Klein1699fab2022-09-08 08:46:06 -0600302 # Exclude files with a specific substring in their name, because
303 # they create an ambiguous itemized report. (see unit test file for details)
304 command += ["--exclude=** -> *"]
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700305
Alex Klein1699fab2022-09-08 08:46:06 -0600306 # Order seems important here, and this include must come before the possible
307 # exclude below...
308 if include_pattern_file:
309 command += ["--include-from=%s" % include_pattern_file]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700310
Alex Klein1699fab2022-09-08 08:46:06 -0600311 if AUTOTEST_SYMLINK in source_path:
312 command += ["-l"]
313 else:
314 command += ["-L", "--exclude=*"]
Po-Hsien Wang745ac352018-04-13 12:25:41 -0700315
Alex Klein1699fab2022-09-08 08:46:06 -0600316 command += [source_path, sysroot_autotest_path]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700317
Alex Klein1699fab2022-09-08 08:46:06 -0600318 return cros_build_lib.sudo_run(command, stdout=True, encoding="utf-8")
Aviv Keshetb1238c32013-04-01 11:42:13 -0700319
320
321def ParseArguments(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600322 """Parse command line arguments
Aviv Keshetb1238c32013-04-01 11:42:13 -0700323
Alex Klein1699fab2022-09-08 08:46:06 -0600324 Returns:
325 parsed arguments.
326 """
327 parser = commandline.ArgumentParser(
328 description="Perform a fast approximation to emerge-$board "
329 "autotest-all, by rsyncing source tree to sysroot."
330 )
Aviv Keshetb1238c32013-04-01 11:42:13 -0700331
Alex Klein1699fab2022-09-08 08:46:06 -0600332 default_board = cros_build_lib.GetDefaultBoard()
333 parser.add_argument(
334 "--board",
335 metavar="BOARD",
336 default=default_board,
337 help="Board to perform quickmerge for. Default: "
338 + (default_board or "Not configured."),
339 )
340 parser.add_argument(
341 "--pretend",
342 action="store_true",
343 help="Dry run only, do not modify sysroot autotest.",
344 )
345 parser.add_argument(
346 "--overwrite",
347 action="store_true",
348 help="Overwrite existing files even if newer.",
349 )
350 parser.add_argument("--force", action="store_true", help=argparse.SUPPRESS)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700351
Alex Klein1699fab2022-09-08 08:46:06 -0600352 # 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(
356 "--legacy_path", action="store_true", help=argparse.SUPPRESS
357 )
Aviv Keshet474469d2013-07-22 12:54:52 -0700358
Alex Klein1699fab2022-09-08 08:46:06 -0600359 return parser.parse_args(argv)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700360
361
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800362def _maybe_add_autotest_symlink(src_paths, path, dest_path):
Alex Klein1699fab2022-09-08 08:46:06 -0600363 """If the symlink folders exists, add them to the src to quickmerge."""
364 autotest_client_symlink = os.path.join(path, "client", AUTOTEST_SYMLINK)
365 if os.path.exists(autotest_client_symlink):
366 src_paths.append(
367 (autotest_client_symlink, os.path.join(dest_path, "client/"))
368 )
369 autotest_main_symlink = os.path.join(path, AUTOTEST_SYMLINK)
370 if os.path.exists(autotest_main_symlink):
371 src_paths.append((autotest_main_symlink, dest_path))
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800372
373
Aviv Keshetb1238c32013-04-01 11:42:13 -0700374def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600375 cros_build_lib.AssertInsideChroot()
Aviv Keshetb1238c32013-04-01 11:42:13 -0700376
Alex Klein1699fab2022-09-08 08:46:06 -0600377 args = ParseArguments(argv)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700378
Alex Klein1699fab2022-09-08 08:46:06 -0600379 if osutils.IsNonRootUser():
380 try:
381 cros_build_lib.sudo_run([sys.executable] + sys.argv)
382 except cros_build_lib.RunCommandError:
383 return 1
384 return 0
Aviv Keshet940c17f2013-04-11 18:41:42 -0700385
Alex Klein1699fab2022-09-08 08:46:06 -0600386 if not args.board:
387 print("No board specified. Aborting.")
388 return 1
Aviv Keshetb1238c32013-04-01 11:42:13 -0700389
Alex Klein1699fab2022-09-08 08:46:06 -0600390 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
391 checkout = manifest.FindCheckout(AUTOTEST_PROJECT_NAME)
392 brillo_autotest_src_path = os.path.join(checkout.GetPath(absolute=True), "")
Aviv Keshetb1238c32013-04-01 11:42:13 -0700393
Alex Klein1699fab2022-09-08 08:46:06 -0600394 script_path = os.path.dirname(__file__)
395 include_pattern_file = os.path.join(script_path, INCLUDE_PATTERNS_FILENAME)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700396
Alex Klein1699fab2022-09-08 08:46:06 -0600397 # TODO: Determine the following string programatically.
398 sysroot_path = os.path.join("/build", args.board, "")
399 sysroot_autotest_path = os.path.join(
400 sysroot_path, constants.AUTOTEST_BUILD_PATH, ""
401 )
402 if args.legacy_path:
403 sysroot_autotest_path = os.path.join(
404 sysroot_path, "usr/local/autotest", ""
405 )
Aviv Keshetb1238c32013-04-01 11:42:13 -0700406
Alex Klein1699fab2022-09-08 08:46:06 -0600407 # Generate the list of source paths to copy.
408 src_paths = {os.path.abspath(brillo_autotest_src_path)}
409 for quickmerge_file in glob.glob(
410 os.path.join(sysroot_autotest_path, "quickmerge", "*", "*")
411 ):
412 try:
413 path = osutils.ReadFile(quickmerge_file).strip()
414 if path and os.path.exists(path):
415 src_paths.add(os.path.abspath(path))
416 except IOError:
417 logging.error(
418 "Could not quickmerge for project: %s",
419 os.path.basename(quickmerge_file),
420 )
Aviv Keshetb1238c32013-04-01 11:42:13 -0700421
Alex Klein1699fab2022-09-08 08:46:06 -0600422 # Autotest uses a circular symlink in client that *must* be added after the
423 # other sections of Autotest.
424 src_paths = list(src_paths)
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800425
Alex Klein1699fab2022-09-08 08:46:06 -0600426 # All destination paths up to this point are the same, but other sources
427 # added below might have a different one.
428 src_dest_paths = [
429 (src_path + "/", sysroot_autotest_path) for src_path in src_paths
430 ]
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800431
Alex Klein1699fab2022-09-08 08:46:06 -0600432 _maybe_add_autotest_symlink(
433 src_dest_paths, brillo_autotest_src_path, sysroot_autotest_path
434 )
435 num_new_files = 0
436 num_modified_files = 0
437 for src_path, dest_path in src_dest_paths:
438 rsync_output = RsyncQuickmerge(
439 src_path,
440 dest_path,
441 include_pattern_file,
442 args.pretend,
443 args.overwrite,
444 )
Aviv Keshete00caeb2013-04-17 14:03:25 -0700445
Alex Klein1699fab2022-09-08 08:46:06 -0600446 if args.verbose:
447 logging.info(rsync_output.stdout)
448 change_report = ItemizeChangesFromRsyncOutput(
449 rsync_output.stdout, sysroot_autotest_path
450 )
451 num_new_files = num_new_files + len(change_report.new_files)
452 num_modified_files = num_modified_files + len(
453 change_report.modified_files
454 )
455 if not args.pretend:
456 logging.info("Updating portage database.")
457 UpdatePackageContents(change_report, AUTOTEST_EBUILD, sysroot_path)
458
Simran Basi348fccc2015-04-28 12:39:01 -0700459 if not args.pretend:
Alex Klein1699fab2022-09-08 08:46:06 -0600460 for logfile in glob.glob(
461 os.path.join(sysroot_autotest_path, "packages", "*.log")
462 ):
463 try:
464 # Open file in a try-except block, for atomicity, instead of
465 # doing existence check.
466 with open(logfile, "r") as f:
467 package_cp = f.readline().strip()
468 DOWNGRADE_EBUILDS.append(package_cp)
469 except IOError:
470 pass
Aviv Keshet60968ec2013-04-11 18:44:14 -0700471
Alex Klein1699fab2022-09-08 08:46:06 -0600472 for ebuild in DOWNGRADE_EBUILDS:
473 if not DowngradePackageVersion(sysroot_path, ebuild):
474 logging.warning(
475 "Unable to downgrade package %s version number.", ebuild
476 )
477 RemoveBzipPackages(sysroot_autotest_path)
Aviv Keshetfe54a8a2013-09-16 15:49:03 -0700478
Alex Klein1699fab2022-09-08 08:46:06 -0600479 sentinel_filename = os.path.join(
480 sysroot_autotest_path, ".quickmerge_sentinel"
481 )
482 cros_build_lib.run(["touch", sentinel_filename])
Aviv Keshetb1238c32013-04-01 11:42:13 -0700483
Alex Klein1699fab2022-09-08 08:46:06 -0600484 if args.pretend:
485 logging.info(
486 "The following message is pretend only. No filesystem "
487 "changes made."
488 )
489 logging.info(
490 "Quickmerge complete. Created or modified %s files.",
491 num_new_files + num_modified_files,
492 )
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700493
Alex Klein1699fab2022-09-08 08:46:06 -0600494 return 0