blob: eba34c9cbfabc0f56245bcdb0f1bcd541870a924 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2013 The ChromiumOS Authors
Aviv Keshetb1238c32013-04-01 11:42:13 -07002# 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:
Alex Klein9e7b29e2023-04-11 16:10:31 -060071 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:
Alex Klein9e7b29e2023-04-11 16:10:31 -060077 A list of test package names, e.g. ['factory_Leds',
78 'login_UserPolicyKeys']. May contain duplicate entries if multiple files
79 within a test directory were modified.
Alex Klein1699fab2022-09-08 08:46:06 -060080 """
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 Klein9e7b29e2023-04-11 16:10:31 -060087 """Convert 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:
Alex Klein9e7b29e2023-04-11 16:10:31 -060090 rsync_output: String stdout of rsync command that was run with `-i`
91 option.
92 destination_path: String absolute path of the destination directory for
93 the rsync operations. This argument is necessary because rsync's
94 output only gives the relative path of touched/added files.
Aviv Keshet787ffcd2013-04-08 15:14:56 -070095
Alex Klein1699fab2022-09-08 08:46:06 -060096 Returns:
Alex Klein9e7b29e2023-04-11 16:10:31 -060097 ItemizedChangeReport object giving the absolute paths of files that were
98 created or modified by rsync.
Alex Klein1699fab2022-09-08 08:46:06 -060099 """
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:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600132 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:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600136 Returns (package, vartree) tuple, where
Alex Klein1699fab2022-09-08 08:46:06 -0600137 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:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600183 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:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600188 bool: True on success. False on failure (nonzero return code from `mv`
189 command).
Alex Klein1699fab2022-09-08 08:46:06 -0600190 """
191 try:
192 package, _ = GetPackageAPI(portage_root, package_cp)
193 except PortagePackageAPIError:
194 # Unable to fetch a corresponding portage package API for this
Alex Klein9e7b29e2023-04-11 16:10:31 -0600195 # package_cp (either no such package, or name ambiguous and matches).
Alex Klein1699fab2022-09-08 08:46:06 -0600196 # So, just fail out.
197 return False
Aviv Keshete00caeb2013-04-17 14:03:25 -0700198
Alex Klein1699fab2022-09-08 08:46:06 -0600199 source_directory = package.dbdir
200 destination_path = os.path.join(
201 package.dbroot, package_cp + "-" + downgrade_to_version
202 )
203 if os.path.abspath(source_directory) == os.path.abspath(destination_path):
204 return True
205 command = ["mv", source_directory, destination_path]
206 code = cros_build_lib.sudo_run(command, check=False).returncode
207 return code == 0
Aviv Keshete00caeb2013-04-17 14:03:25 -0700208
209
Aviv Keshete7b20192013-04-24 14:05:53 -0700210def UpdatePackageContents(change_report, package_cp, portage_root=None):
Alex Klein1699fab2022-09-08 08:46:06 -0600211 """Add newly created files/directors to package contents.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700212
Alex Klein1699fab2022-09-08 08:46:06 -0600213 Given an ItemizedChangeReport, add the newly created files and directories
214 to the CONTENTS of an installed portage package, such that these files are
215 considered owned by that package.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700216
Alex Klein1699fab2022-09-08 08:46:06 -0600217 Args:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600218 change_report: ItemizedChangeReport object for the changes to be
219 made to the package.
220 package_cp: A string similar to 'chromeos-base/autotest-tests' giving
221 the package category and name of the package to be altered.
222 portage_root: Portage root path, corresponding to the board that
223 we are working on. Defaults to '/'.
Alex Klein1699fab2022-09-08 08:46:06 -0600224 """
225 package, vartree = GetPackageAPI(portage_root, package_cp)
Aviv Keshete00caeb2013-04-17 14:03:25 -0700226
Alex Klein1699fab2022-09-08 08:46:06 -0600227 # Append new contents to package contents dictionary.
228 contents = package.getcontents().copy()
229 for _, filename in change_report.new_files:
230 contents.setdefault(filename, ("obj", "0", "0"))
231 for _, dirname in change_report.new_directories:
232 # Strip trailing slashes if present.
233 contents.setdefault(dirname.rstrip("/"), ("dir",))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700234
Alex Klein1699fab2022-09-08 08:46:06 -0600235 # Write new contents dictionary to file.
236 vartree.dbapi.writeContentsToContentsFile(package, contents)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700237
238
Aviv Keshet19276752013-05-16 11:12:23 -0700239def RemoveBzipPackages(autotest_sysroot):
Alex Klein1699fab2022-09-08 08:46:06 -0600240 """Remove all bzipped test/dep/profiler packages from sysroot autotest.
Aviv Keshet75d65962013-04-17 16:15:23 -0700241
Alex Klein1699fab2022-09-08 08:46:06 -0600242 Args:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600243 autotest_sysroot: Absolute path of autotest in the sysroot,
244 e.g. '/build/lumpy/usr/local/build/autotest'
Alex Klein1699fab2022-09-08 08:46:06 -0600245 """
246 osutils.RmDir(
247 os.path.join(autotest_sysroot, "packages"), ignore_missing=True
248 )
249 osutils.SafeUnlink(os.path.join(autotest_sysroot, "packages.checksum"))
Aviv Keshet75d65962013-04-17 16:15:23 -0700250
251
Alex Klein1699fab2022-09-08 08:46:06 -0600252def RsyncQuickmerge(
253 source_path,
254 sysroot_autotest_path,
255 include_pattern_file=None,
256 pretend=False,
257 overwrite=False,
258):
259 """Run rsync quickmerge command, with specified arguments.
Aviv Keshete7b20192013-04-24 14:05:53 -0700260
Alex Klein9e7b29e2023-04-11 16:10:31 -0600261 Command will take form:
262 `rsync -a [options] --exclude=**.pyc --exclude=**.pyo
263 [optional --include-from include_pattern_file]
264 --exclude=* [source_path] [sysroot_autotest_path]`
Aviv Keshetb1238c32013-04-01 11:42:13 -0700265
Alex Klein1699fab2022-09-08 08:46:06 -0600266 Args:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600267 source_path: Directory to rsync from.
268 sysroot_autotest_path: Directory to rsync too.
269 include_pattern_file: Optional pattern of files to include in rsync.
270 pretend: True to use the '-n' option to rsync, to perform dry run.
271 overwrite: True to omit '-u' option, overwrite all files in sysroot,
272 not just older files.
Aviv Keshet557e6882013-04-25 13:26:09 -0700273
Alex Klein1699fab2022-09-08 08:46:06 -0600274 Returns:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600275 The cros_build_lib.CompletedProcess object resulting from the rsync
276 command.
Alex Klein1699fab2022-09-08 08:46:06 -0600277 """
278 command = ["rsync", "-a"]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700279
Alex Klein1699fab2022-09-08 08:46:06 -0600280 # For existing files, preserve destination permissions. This ensures that
281 # existing files end up with the file permissions set by the ebuilds.
282 # If this script copies over a file that does not exist in the destination
283 # tree, it will set the least restrictive permissions allowed in the
284 # destination tree. This could happen if the file copied is not installed by
285 # *any* ebuild, or if the ebuild that installs the file was never emerged.
286 command += ["--no-p", "--chmod=ugo=rwX"]
Prathmesh Prabhu137266a2014-02-11 20:02:18 -0800287
Alex Klein1699fab2022-09-08 08:46:06 -0600288 if pretend:
289 command += ["-n"]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700290
Alex Klein1699fab2022-09-08 08:46:06 -0600291 if not overwrite:
292 command += ["-u"]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700293
Alex Klein1699fab2022-09-08 08:46:06 -0600294 command += ["-i"]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700295
Alex Klein1699fab2022-09-08 08:46:06 -0600296 command += ["--exclude=**.pyc"]
297 command += ["--exclude=**.pyo"]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700298
Alex Klein1699fab2022-09-08 08:46:06 -0600299 # Always exclude the autotest symlink to avoid a possible recursion hole.
300 # The order here is (unfortunately) extremely important.
301 if AUTOTEST_SYMLINK not in source_path:
302 command += ["--exclude=%s/" % AUTOTEST_SYMLINK]
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800303
Alex Klein1699fab2022-09-08 08:46:06 -0600304 # Exclude files with a specific substring in their name, because
305 # they create an ambiguous itemized report. (see unit test file for details)
306 command += ["--exclude=** -> *"]
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700307
Alex Klein1699fab2022-09-08 08:46:06 -0600308 # Order seems important here, and this include must come before the possible
309 # exclude below...
310 if include_pattern_file:
311 command += ["--include-from=%s" % include_pattern_file]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700312
Alex Klein1699fab2022-09-08 08:46:06 -0600313 if AUTOTEST_SYMLINK in source_path:
314 command += ["-l"]
315 else:
316 command += ["-L", "--exclude=*"]
Po-Hsien Wang745ac352018-04-13 12:25:41 -0700317
Alex Klein1699fab2022-09-08 08:46:06 -0600318 command += [source_path, sysroot_autotest_path]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700319
Alex Klein1699fab2022-09-08 08:46:06 -0600320 return cros_build_lib.sudo_run(command, stdout=True, encoding="utf-8")
Aviv Keshetb1238c32013-04-01 11:42:13 -0700321
322
323def ParseArguments(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600324 """Parse command line arguments
Aviv Keshetb1238c32013-04-01 11:42:13 -0700325
Alex Klein1699fab2022-09-08 08:46:06 -0600326 Returns:
Alex Klein9e7b29e2023-04-11 16:10:31 -0600327 parsed arguments.
Alex Klein1699fab2022-09-08 08:46:06 -0600328 """
329 parser = commandline.ArgumentParser(
330 description="Perform a fast approximation to emerge-$board "
331 "autotest-all, by rsyncing source tree to sysroot."
332 )
Aviv Keshetb1238c32013-04-01 11:42:13 -0700333
Alex Klein1699fab2022-09-08 08:46:06 -0600334 default_board = cros_build_lib.GetDefaultBoard()
335 parser.add_argument(
336 "--board",
337 metavar="BOARD",
338 default=default_board,
339 help="Board to perform quickmerge for. Default: "
340 + (default_board or "Not configured."),
341 )
342 parser.add_argument(
343 "--pretend",
344 action="store_true",
345 help="Dry run only, do not modify sysroot autotest.",
346 )
347 parser.add_argument(
348 "--overwrite",
349 action="store_true",
350 help="Overwrite existing files even if newer.",
351 )
352 parser.add_argument("--force", action="store_true", help=argparse.SUPPRESS)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700353
Alex Klein9e7b29e2023-04-11 16:10:31 -0600354 # Used only if test_that is calling autotest_quickmerge and has detected
355 # that the sysroot autotest path is still in usr/local/autotest (ie the
356 # build pre-dates https://chromium-review.googlesource.com/#/c/62880/ )
Alex Klein1699fab2022-09-08 08:46:06 -0600357 parser.add_argument(
358 "--legacy_path", action="store_true", help=argparse.SUPPRESS
359 )
Aviv Keshet474469d2013-07-22 12:54:52 -0700360
Alex Klein1699fab2022-09-08 08:46:06 -0600361 return parser.parse_args(argv)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700362
363
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800364def _maybe_add_autotest_symlink(src_paths, path, dest_path):
Alex Klein1699fab2022-09-08 08:46:06 -0600365 """If the symlink folders exists, add them to the src to quickmerge."""
366 autotest_client_symlink = os.path.join(path, "client", AUTOTEST_SYMLINK)
367 if os.path.exists(autotest_client_symlink):
368 src_paths.append(
369 (autotest_client_symlink, os.path.join(dest_path, "client/"))
370 )
371 autotest_main_symlink = os.path.join(path, AUTOTEST_SYMLINK)
372 if os.path.exists(autotest_main_symlink):
373 src_paths.append((autotest_main_symlink, dest_path))
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800374
375
Aviv Keshetb1238c32013-04-01 11:42:13 -0700376def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600377 cros_build_lib.AssertInsideChroot()
Aviv Keshetb1238c32013-04-01 11:42:13 -0700378
Alex Klein1699fab2022-09-08 08:46:06 -0600379 args = ParseArguments(argv)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700380
Alex Klein1699fab2022-09-08 08:46:06 -0600381 if osutils.IsNonRootUser():
382 try:
383 cros_build_lib.sudo_run([sys.executable] + sys.argv)
384 except cros_build_lib.RunCommandError:
385 return 1
386 return 0
Aviv Keshet940c17f2013-04-11 18:41:42 -0700387
Alex Klein1699fab2022-09-08 08:46:06 -0600388 if not args.board:
389 print("No board specified. Aborting.")
390 return 1
Aviv Keshetb1238c32013-04-01 11:42:13 -0700391
Alex Klein1699fab2022-09-08 08:46:06 -0600392 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
393 checkout = manifest.FindCheckout(AUTOTEST_PROJECT_NAME)
394 brillo_autotest_src_path = os.path.join(checkout.GetPath(absolute=True), "")
Aviv Keshetb1238c32013-04-01 11:42:13 -0700395
Alex Klein1699fab2022-09-08 08:46:06 -0600396 script_path = os.path.dirname(__file__)
397 include_pattern_file = os.path.join(script_path, INCLUDE_PATTERNS_FILENAME)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700398
Alex Klein1699fab2022-09-08 08:46:06 -0600399 # TODO: Determine the following string programatically.
400 sysroot_path = os.path.join("/build", args.board, "")
401 sysroot_autotest_path = os.path.join(
402 sysroot_path, constants.AUTOTEST_BUILD_PATH, ""
403 )
404 if args.legacy_path:
405 sysroot_autotest_path = os.path.join(
406 sysroot_path, "usr/local/autotest", ""
407 )
Aviv Keshetb1238c32013-04-01 11:42:13 -0700408
Alex Klein1699fab2022-09-08 08:46:06 -0600409 # Generate the list of source paths to copy.
410 src_paths = {os.path.abspath(brillo_autotest_src_path)}
411 for quickmerge_file in glob.glob(
412 os.path.join(sysroot_autotest_path, "quickmerge", "*", "*")
413 ):
414 try:
415 path = osutils.ReadFile(quickmerge_file).strip()
416 if path and os.path.exists(path):
417 src_paths.add(os.path.abspath(path))
418 except IOError:
419 logging.error(
420 "Could not quickmerge for project: %s",
421 os.path.basename(quickmerge_file),
422 )
Aviv Keshetb1238c32013-04-01 11:42:13 -0700423
Alex Klein1699fab2022-09-08 08:46:06 -0600424 # Autotest uses a circular symlink in client that *must* be added after the
425 # other sections of Autotest.
426 src_paths = list(src_paths)
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800427
Alex Klein1699fab2022-09-08 08:46:06 -0600428 # All destination paths up to this point are the same, but other sources
429 # added below might have a different one.
430 src_dest_paths = [
431 (src_path + "/", sysroot_autotest_path) for src_path in src_paths
432 ]
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800433
Alex Klein1699fab2022-09-08 08:46:06 -0600434 _maybe_add_autotest_symlink(
435 src_dest_paths, brillo_autotest_src_path, sysroot_autotest_path
436 )
437 num_new_files = 0
438 num_modified_files = 0
439 for src_path, dest_path in src_dest_paths:
440 rsync_output = RsyncQuickmerge(
441 src_path,
442 dest_path,
443 include_pattern_file,
444 args.pretend,
445 args.overwrite,
446 )
Aviv Keshete00caeb2013-04-17 14:03:25 -0700447
Alex Klein1699fab2022-09-08 08:46:06 -0600448 if args.verbose:
449 logging.info(rsync_output.stdout)
450 change_report = ItemizeChangesFromRsyncOutput(
451 rsync_output.stdout, sysroot_autotest_path
452 )
453 num_new_files = num_new_files + len(change_report.new_files)
454 num_modified_files = num_modified_files + len(
455 change_report.modified_files
456 )
457 if not args.pretend:
458 logging.info("Updating portage database.")
459 UpdatePackageContents(change_report, AUTOTEST_EBUILD, sysroot_path)
460
Simran Basi348fccc2015-04-28 12:39:01 -0700461 if not args.pretend:
Alex Klein1699fab2022-09-08 08:46:06 -0600462 for logfile in glob.glob(
463 os.path.join(sysroot_autotest_path, "packages", "*.log")
464 ):
465 try:
466 # Open file in a try-except block, for atomicity, instead of
467 # doing existence check.
Mike Frysinger31fdddd2023-02-24 15:50:55 -0500468 with open(logfile, "r", encoding="utf-8") as f:
Alex Klein1699fab2022-09-08 08:46:06 -0600469 package_cp = f.readline().strip()
470 DOWNGRADE_EBUILDS.append(package_cp)
471 except IOError:
472 pass
Aviv Keshet60968ec2013-04-11 18:44:14 -0700473
Alex Klein1699fab2022-09-08 08:46:06 -0600474 for ebuild in DOWNGRADE_EBUILDS:
475 if not DowngradePackageVersion(sysroot_path, ebuild):
476 logging.warning(
477 "Unable to downgrade package %s version number.", ebuild
478 )
479 RemoveBzipPackages(sysroot_autotest_path)
Aviv Keshetfe54a8a2013-09-16 15:49:03 -0700480
Alex Klein1699fab2022-09-08 08:46:06 -0600481 sentinel_filename = os.path.join(
482 sysroot_autotest_path, ".quickmerge_sentinel"
483 )
484 cros_build_lib.run(["touch", sentinel_filename])
Aviv Keshetb1238c32013-04-01 11:42:13 -0700485
Alex Klein1699fab2022-09-08 08:46:06 -0600486 if args.pretend:
487 logging.info(
488 "The following message is pretend only. No filesystem "
489 "changes made."
490 )
491 logging.info(
492 "Quickmerge complete. Created or modified %s files.",
493 num_new_files + num_modified_files,
494 )
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700495
Alex Klein1699fab2022-09-08 08:46:06 -0600496 return 0