blob: 7bcb266d863bd23be25a8ac13722d12d32346a96 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Aviv Keshetb1238c32013-04-01 11:42:13 -07002# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Mike Frysingerad8c6ca2014-02-03 11:28:45 -05006"""Fast alternative to `emerge-$BOARD autotest-all`
Aviv Keshetb1238c32013-04-01 11:42:13 -07007
Aviv Keshetb1238c32013-04-01 11:42:13 -07008Simple script to be run inside the chroot. Used as a fast approximation of
9emerge-$board autotest-all, by simply rsync'ing changes from trunk to sysroot.
10"""
11
Mike Frysinger383367e2014-09-16 15:06:17 -040012from __future__ import print_function
13
Aviv Keshete7b20192013-04-24 14:05:53 -070014import argparse
Aviv Keshetfe54a8a2013-09-16 15:49:03 -070015import glob
Aviv Keshetb1238c32013-04-01 11:42:13 -070016import os
Aviv Keshet787ffcd2013-04-08 15:14:56 -070017import re
Aviv Keshetb1238c32013-04-01 11:42:13 -070018import sys
Aviv Keshet787ffcd2013-04-08 15:14:56 -070019from collections import namedtuple
20
Alex Klein727e3202020-05-29 11:13:55 -060021from chromite.lib import commandline
Aviv Keshetb7519e12016-10-04 00:50:00 -070022from chromite.lib import constants
Aviv Keshetb1238c32013-04-01 11:42:13 -070023from chromite.lib import cros_build_lib
Ralph Nathan91874ca2015-03-19 13:29:41 -070024from chromite.lib import cros_logging as logging
Aviv Keshetb1238c32013-04-01 11:42:13 -070025from chromite.lib import git
Aviv Keshet557e6882013-04-25 13:26:09 -070026from chromite.lib import osutils
Alex Klein18a60af2020-06-11 12:08:47 -060027from chromite.lib.parser import package_info
Aviv Keshetb1238c32013-04-01 11:42:13 -070028
Aviv Keshet940c17f2013-04-11 18:41:42 -070029if cros_build_lib.IsInsideChroot():
Mike Frysinger27e21b72018-07-12 14:20:21 -040030 # pylint: disable=import-error
Aviv Keshet940c17f2013-04-11 18:41:42 -070031 import portage
32
Mike Frysingere65f3752014-12-08 00:46:39 -050033
Mike Frysinger2c9d0612020-02-19 02:52:41 -050034assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
35
36
Aviv Keshetb1238c32013-04-01 11:42:13 -070037INCLUDE_PATTERNS_FILENAME = 'autotest-quickmerge-includepatterns'
Derek Beckett1f19c9c2020-12-14 12:25:53 -080038AUTOTEST_SYMLINK = 'autotest_lib'
Aviv Keshetb1238c32013-04-01 11:42:13 -070039AUTOTEST_PROJECT_NAME = 'chromiumos/third_party/autotest'
Aviv Keshet5f3cf722013-05-09 17:35:25 -070040AUTOTEST_EBUILD = 'chromeos-base/autotest'
Aviv Keshetfe54a8a2013-09-16 15:49:03 -070041DOWNGRADE_EBUILDS = ['chromeos-base/autotest']
Aviv Keshet787ffcd2013-04-08 15:14:56 -070042
Aviv Keshetc73cfc32013-06-14 16:18:53 -070043IGNORE_SUBDIRS = ['ExternalSource',
44 'logs',
45 'results',
46 'site-packages']
47
Aviv Keshet787ffcd2013-04-08 15:14:56 -070048# Data structure describing a single rsync filesystem change.
49#
50# change_description: An 11 character string, the rsync change description
51# for the particular file.
52# absolute_path: The absolute path of the created or modified file.
53ItemizedChange = namedtuple('ItemizedChange', ['change_description',
54 'absolute_path'])
55
Aviv Keshet787ffcd2013-04-08 15:14:56 -070056# Data structure describing the rsync new/modified files or directories.
57#
58# new_files: A list of ItemizedChange objects for new files.
59# modified_files: A list of ItemizedChange objects for modified files.
60# new_directories: A list of ItemizedChange objects for new directories.
61ItemizedChangeReport = namedtuple('ItemizedChangeReport',
62 ['new_files', 'modified_files',
63 'new_directories'])
64
Mike Frysingere65f3752014-12-08 00:46:39 -050065
Aviv Keshet84bdfc52013-06-04 13:19:38 -070066class PortagePackageAPIError(Exception):
67 """Exception thrown when unable to retrieve a portage package API."""
68
Aviv Keshet787ffcd2013-04-08 15:14:56 -070069
Aviv Keshet75d65962013-04-17 16:15:23 -070070def GetStalePackageNames(change_list, autotest_sysroot):
Aviv Keshete7b20192013-04-24 14:05:53 -070071 """Given a rsync change report, returns the names of stale test packages.
Aviv Keshet75d65962013-04-17 16:15:23 -070072
73 This function pulls out test package names for client-side tests, stored
74 within the client/site_tests directory tree, that had any files added or
75 modified and for whom any existing bzipped test packages may now be stale.
76
Mike Frysinger02e1e072013-11-10 22:11:34 -050077 Args:
Aviv Keshet75d65962013-04-17 16:15:23 -070078 change_list: A list of ItemizedChange objects corresponding to changed
79 or modified files.
80 autotest_sysroot: Absolute path of autotest in the sysroot,
Aviv Keshet474469d2013-07-22 12:54:52 -070081 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -070082
83 Returns:
84 A list of test package names, eg ['factory_Leds', 'login_UserPolicyKeys'].
85 May contain duplicate entries if multiple files within a test directory
86 were modified.
87 """
88 exp = os.path.abspath(autotest_sysroot) + r'/client/site_tests/(.*?)/.*'
89 matches = [re.match(exp, change.absolute_path) for change in change_list]
90 return [match.group(1) for match in matches if match]
91
92
Aviv Keshet787ffcd2013-04-08 15:14:56 -070093def ItemizeChangesFromRsyncOutput(rsync_output, destination_path):
94 """Convert the output of an rsync with `-i` to a ItemizedChangeReport object.
95
Mike Frysinger02e1e072013-11-10 22:11:34 -050096 Args:
Aviv Keshet787ffcd2013-04-08 15:14:56 -070097 rsync_output: String stdout of rsync command that was run with `-i` option.
98 destination_path: String absolute path of the destination directory for the
99 rsync operations. This argument is necessary because
100 rsync's output only gives the relative path of
101 touched/added files.
102
103 Returns:
104 ItemizedChangeReport object giving the absolute paths of files that were
105 created or modified by rsync.
106 """
107 modified_matches = re.findall(r'([.>]f[^+]{9}) (.*)', rsync_output)
108 new_matches = re.findall(r'(>f\+{9}) (.*)', rsync_output)
109 new_symlink_matches = re.findall(r'(cL\+{9}) (.*) -> .*', rsync_output)
110 new_dir_matches = re.findall(r'(cd\+{9}) (.*)', rsync_output)
111
112 absolute_modified = [ItemizedChange(c, os.path.join(destination_path, f))
113 for (c, f) in modified_matches]
114
115 # Note: new symlinks are treated as new files.
116 absolute_new = [ItemizedChange(c, os.path.join(destination_path, f))
117 for (c, f) in new_matches + new_symlink_matches]
118
119 absolute_new_dir = [ItemizedChange(c, os.path.join(destination_path, f))
120 for (c, f) in new_dir_matches]
121
122 return ItemizedChangeReport(new_files=absolute_new,
123 modified_files=absolute_modified,
124 new_directories=absolute_new_dir)
125
126
Aviv Keshete00caeb2013-04-17 14:03:25 -0700127def GetPackageAPI(portage_root, package_cp):
Aviv Keshete7b20192013-04-24 14:05:53 -0700128 """Gets portage API handles for the given package.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700129
Mike Frysinger02e1e072013-11-10 22:11:34 -0500130 Args:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700131 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500132 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700133
134 Returns:
135 Returns (package, vartree) tuple, where
136 package is of type portage.dbapi.vartree.dblink
137 vartree is of type portage.dbapi.vartree.vartree
Aviv Keshet940c17f2013-04-11 18:41:42 -0700138 """
139 if portage_root is None:
Mike Frysingere65f3752014-12-08 00:46:39 -0500140 # pylint: disable=no-member
Aviv Keshete7b20192013-04-24 14:05:53 -0700141 portage_root = portage.root
Aviv Keshet940c17f2013-04-11 18:41:42 -0700142 # Ensure that portage_root ends with trailing slash.
143 portage_root = os.path.join(portage_root, '')
144
Aviv Keshete7b20192013-04-24 14:05:53 -0700145 # Create a vartree object corresponding to portage_root.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700146 trees = portage.create_trees(portage_root, portage_root)
147 vartree = trees[portage_root]['vartree']
148
Aviv Keshete7b20192013-04-24 14:05:53 -0700149 # List the matching installed packages in cpv format.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700150 matching_packages = vartree.dbapi.cp_list(package_cp)
151
152 if not matching_packages:
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700153 raise PortagePackageAPIError('No matching package for %s in portage_root '
154 '%s' % (package_cp, portage_root))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700155
156 if len(matching_packages) > 1:
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700157 raise PortagePackageAPIError('Too many matching packages for %s in '
158 'portage_root %s' % (package_cp,
159 portage_root))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700160
Aviv Keshete7b20192013-04-24 14:05:53 -0700161 # Convert string match to package dblink.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700162 package_cpv = matching_packages[0]
Alex Klein18a60af2020-06-11 12:08:47 -0600163 package_split = package_info.SplitCPV(package_cpv)
Mike Frysingere65f3752014-12-08 00:46:39 -0500164 # pylint: disable=no-member
Aviv Keshete7b20192013-04-24 14:05:53 -0700165 package = portage.dblink(package_split.category,
Aviv Keshet940c17f2013-04-11 18:41:42 -0700166 package_split.pv, settings=vartree.settings,
167 vartree=vartree)
168
Aviv Keshete00caeb2013-04-17 14:03:25 -0700169 return package, vartree
170
171
172def DowngradePackageVersion(portage_root, package_cp,
173 downgrade_to_version='0'):
Aviv Keshete7b20192013-04-24 14:05:53 -0700174 """Downgrade the specified portage package version.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700175
Mike Frysinger02e1e072013-11-10 22:11:34 -0500176 Args:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700177 portage_root: Root directory of portage tree. Eg '/' or '/build/lumpy'
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500178 package_cp: A string similar to 'chromeos-base/autotest-tests'.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700179 downgrade_to_version: String version to downgrade to. Default: '0'
180
181 Returns:
Aviv Keshet557e6882013-04-25 13:26:09 -0700182 True on success. False on failure (nonzero return code from `mv` command).
Aviv Keshete00caeb2013-04-17 14:03:25 -0700183 """
Aviv Keshet84bdfc52013-06-04 13:19:38 -0700184 try:
185 package, _ = GetPackageAPI(portage_root, package_cp)
186 except PortagePackageAPIError:
187 # Unable to fetch a corresponding portage package API for this
188 # package_cp (either no such package, or name ambigious and matches).
189 # So, just fail out.
190 return False
Aviv Keshete00caeb2013-04-17 14:03:25 -0700191
192 source_directory = package.dbdir
193 destination_path = os.path.join(
194 package.dbroot, package_cp + '-' + downgrade_to_version)
195 if os.path.abspath(source_directory) == os.path.abspath(destination_path):
Aviv Keshet557e6882013-04-25 13:26:09 -0700196 return True
Aviv Keshete00caeb2013-04-17 14:03:25 -0700197 command = ['mv', source_directory, destination_path]
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500198 code = cros_build_lib.sudo_run(command, check=False).returncode
Aviv Keshet557e6882013-04-25 13:26:09 -0700199 return code == 0
Aviv Keshete00caeb2013-04-17 14:03:25 -0700200
201
Aviv Keshete7b20192013-04-24 14:05:53 -0700202def UpdatePackageContents(change_report, package_cp, portage_root=None):
203 """Add newly created files/directors to package contents.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700204
205 Given an ItemizedChangeReport, add the newly created files and directories
206 to the CONTENTS of an installed portage package, such that these files are
207 considered owned by that package.
208
Mike Frysinger02e1e072013-11-10 22:11:34 -0500209 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700210 change_report: ItemizedChangeReport object for the changes to be
211 made to the package.
Aviv Keshete00caeb2013-04-17 14:03:25 -0700212 package_cp: A string similar to 'chromeos-base/autotest-tests' giving
213 the package category and name of the package to be altered.
214 portage_root: Portage root path, corresponding to the board that
215 we are working on. Defaults to '/'
216 """
217 package, vartree = GetPackageAPI(portage_root, package_cp)
218
Aviv Keshete7b20192013-04-24 14:05:53 -0700219 # Append new contents to package contents dictionary.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700220 contents = package.getcontents().copy()
221 for _, filename in change_report.new_files:
222 contents.setdefault(filename, (u'obj', '0', '0'))
223 for _, dirname in change_report.new_directories:
Aviv Keshete7b20192013-04-24 14:05:53 -0700224 # Strip trailing slashes if present.
225 contents.setdefault(dirname.rstrip('/'), (u'dir',))
Aviv Keshet940c17f2013-04-11 18:41:42 -0700226
Aviv Keshete7b20192013-04-24 14:05:53 -0700227 # Write new contents dictionary to file.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700228 vartree.dbapi.writeContentsToContentsFile(package, contents)
229
230
Aviv Keshet19276752013-05-16 11:12:23 -0700231def RemoveBzipPackages(autotest_sysroot):
232 """Remove all bzipped test/dep/profiler packages from sysroot autotest.
Aviv Keshet75d65962013-04-17 16:15:23 -0700233
Mike Frysinger02e1e072013-11-10 22:11:34 -0500234 Args:
Aviv Keshet75d65962013-04-17 16:15:23 -0700235 autotest_sysroot: Absolute path of autotest in the sysroot,
Aviv Keshet474469d2013-07-22 12:54:52 -0700236 e.g. '/build/lumpy/usr/local/build/autotest'
Aviv Keshet75d65962013-04-17 16:15:23 -0700237 """
Aviv Keshet19276752013-05-16 11:12:23 -0700238 osutils.RmDir(os.path.join(autotest_sysroot, 'packages'),
Mike Frysingere65f3752014-12-08 00:46:39 -0500239 ignore_missing=True)
Aviv Keshet19276752013-05-16 11:12:23 -0700240 osutils.SafeUnlink(os.path.join(autotest_sysroot, 'packages.checksum'))
Aviv Keshet75d65962013-04-17 16:15:23 -0700241
242
Aviv Keshetb1238c32013-04-01 11:42:13 -0700243def RsyncQuickmerge(source_path, sysroot_autotest_path,
244 include_pattern_file=None, pretend=False,
Aviv Keshet60968ec2013-04-11 18:44:14 -0700245 overwrite=False):
Aviv Keshetb1238c32013-04-01 11:42:13 -0700246 """Run rsync quickmerge command, with specified arguments.
Aviv Keshete7b20192013-04-24 14:05:53 -0700247
Aviv Keshetb1238c32013-04-01 11:42:13 -0700248 Command will take form `rsync -a [options] --exclude=**.pyc
249 --exclude=**.pyo
Don Garrett25f309a2014-03-19 14:02:12 -0700250 [optional --include-from include_pattern_file]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700251 --exclude=* [source_path] [sysroot_autotest_path]`
252
Mike Frysinger02e1e072013-11-10 22:11:34 -0500253 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700254 source_path: Directory to rsync from.
255 sysroot_autotest_path: Directory to rsync too.
256 include_pattern_file: Optional pattern of files to include in rsync.
Mike Frysingerad8c6ca2014-02-03 11:28:45 -0500257 pretend: True to use the '-n' option to rsync, to perform dry run.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700258 overwrite: True to omit '-u' option, overwrite all files in sysroot,
259 not just older files.
Aviv Keshet557e6882013-04-25 13:26:09 -0700260
261 Returns:
262 The cros_build_lib.CommandResult object resulting from the rsync command.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700263 """
264 command = ['rsync', '-a']
265
Prathmesh Prabhu137266a2014-02-11 20:02:18 -0800266 # For existing files, preserve destination permissions. This ensures that
267 # existing files end up with the file permissions set by the ebuilds.
268 # If this script copies over a file that does not exist in the destination
269 # tree, it will set the least restrictive permissions allowed in the
270 # destination tree. This could happen if the file copied is not installed by
271 # *any* ebuild, or if the ebuild that installs the file was never emerged.
272 command += ['--no-p', '--chmod=ugo=rwX']
273
Aviv Keshetb1238c32013-04-01 11:42:13 -0700274 if pretend:
275 command += ['-n']
276
277 if not overwrite:
278 command += ['-u']
279
Aviv Keshet60968ec2013-04-11 18:44:14 -0700280 command += ['-i']
Aviv Keshetb1238c32013-04-01 11:42:13 -0700281
282 command += ['--exclude=**.pyc']
283 command += ['--exclude=**.pyo']
284
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800285 # Always exclude the autotest symlink to avoid a possible recursion hole.
286 # The order here is (unfortunately) extremely important.
287 if AUTOTEST_SYMLINK not in source_path:
288 command += ['--exclude=%s/' % AUTOTEST_SYMLINK]
289
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700290 # Exclude files with a specific substring in their name, because
291 # they create an ambiguous itemized report. (see unit test file for details)
292 command += ['--exclude=** -> *']
293
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800294 # Order seems important here, and this include must come before the possible
295 # exclude below...
Aviv Keshetb1238c32013-04-01 11:42:13 -0700296 if include_pattern_file:
297 command += ['--include-from=%s' % include_pattern_file]
298
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800299 if AUTOTEST_SYMLINK in source_path:
300 command += ['-l']
301 else:
302 command += ['-L', '--exclude=*']
Po-Hsien Wang745ac352018-04-13 12:25:41 -0700303
Aviv Keshetb1238c32013-04-01 11:42:13 -0700304 command += [source_path, sysroot_autotest_path]
305
Mike Frysinger13858562020-02-25 16:07:55 -0500306 return cros_build_lib.sudo_run(command, stdout=True, encoding='utf-8')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700307
308
309def ParseArguments(argv):
310 """Parse command line arguments
311
Mike Frysinger02e1e072013-11-10 22:11:34 -0500312 Returns:
313 parsed arguments.
Aviv Keshetb1238c32013-04-01 11:42:13 -0700314 """
Alex Klein727e3202020-05-29 11:13:55 -0600315 parser = commandline.ArgumentParser(
316 description='Perform a fast approximation to emerge-$board '
317 'autotest-all, by rsyncing source tree to sysroot.')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700318
Aviv Keshet0a366a02013-07-18 10:52:04 -0700319 default_board = cros_build_lib.GetDefaultBoard()
320 parser.add_argument('--board', metavar='BOARD', default=default_board,
321 help='Board to perform quickmerge for. Default: ' +
322 (default_board or 'Not configured.'))
Aviv Keshetb1238c32013-04-01 11:42:13 -0700323 parser.add_argument('--pretend', action='store_true',
324 help='Dry run only, do not modify sysroot autotest.')
325 parser.add_argument('--overwrite', action='store_true',
326 help='Overwrite existing files even if newer.')
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700327 parser.add_argument('--force', action='store_true',
Simran Basi8fc88992015-04-21 17:15:23 -0700328 help=argparse.SUPPRESS)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700329
Aviv Keshet474469d2013-07-22 12:54:52 -0700330 # Used only if test_that is calling autotest_quickmerge and has detected that
331 # the sysroot autotest path is still in usr/local/autotest (ie the build
332 # pre-dates https://chromium-review.googlesource.com/#/c/62880/ )
333 parser.add_argument('--legacy_path', action='store_true',
334 help=argparse.SUPPRESS)
335
Aviv Keshetb1238c32013-04-01 11:42:13 -0700336 return parser.parse_args(argv)
337
338
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800339def _maybe_add_autotest_symlink(src_paths, path, dest_path):
340 """If the symlink folders exists, add them to the src to quickmerge."""
341 autotest_client_symlink = os.path.join(path, 'client', AUTOTEST_SYMLINK)
342 if os.path.exists(autotest_client_symlink):
343 src_paths.append((autotest_client_symlink,
344 os.path.join(dest_path, 'client/')))
345 autotest_main_symlink = os.path.join(path, AUTOTEST_SYMLINK)
346 if os.path.exists(autotest_main_symlink):
347 src_paths.append((autotest_main_symlink, dest_path))
348
349
Aviv Keshetb1238c32013-04-01 11:42:13 -0700350def main(argv):
351 cros_build_lib.AssertInsideChroot()
352
353 args = ParseArguments(argv)
354
Aviv Keshete7b20192013-04-24 14:05:53 -0700355 if os.geteuid() != 0:
Aviv Keshet940c17f2013-04-11 18:41:42 -0700356 try:
Mike Frysinger45602c72019-09-22 02:15:11 -0400357 cros_build_lib.sudo_run([sys.executable] + sys.argv)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700358 except cros_build_lib.RunCommandError:
359 return 1
360 return 0
361
Aviv Keshetb1238c32013-04-01 11:42:13 -0700362 if not args.board:
Mike Frysinger383367e2014-09-16 15:06:17 -0400363 print('No board specified. Aborting.')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700364 return 1
365
366 manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
David Jamese3b06062013-11-09 18:52:02 -0800367 checkout = manifest.FindCheckout(AUTOTEST_PROJECT_NAME)
Simran Basi348fccc2015-04-28 12:39:01 -0700368 brillo_autotest_src_path = os.path.join(checkout.GetPath(absolute=True), '')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700369
370 script_path = os.path.dirname(__file__)
371 include_pattern_file = os.path.join(script_path, INCLUDE_PATTERNS_FILENAME)
372
373 # TODO: Determine the following string programatically.
Aviv Keshet940c17f2013-04-11 18:41:42 -0700374 sysroot_path = os.path.join('/build', args.board, '')
Aviv Keshet474469d2013-07-22 12:54:52 -0700375 sysroot_autotest_path = os.path.join(sysroot_path,
376 constants.AUTOTEST_BUILD_PATH, '')
377 if args.legacy_path:
378 sysroot_autotest_path = os.path.join(sysroot_path, 'usr/local/autotest',
379 '')
Aviv Keshetb1238c32013-04-01 11:42:13 -0700380
Simran Basi348fccc2015-04-28 12:39:01 -0700381 # Generate the list of source paths to copy.
382 src_paths = {os.path.abspath(brillo_autotest_src_path)}
383 for quickmerge_file in glob.glob(os.path.join(sysroot_autotest_path,
384 'quickmerge', '*', '*')):
385 try:
386 path = osutils.ReadFile(quickmerge_file).strip()
387 if path and os.path.exists(path):
388 src_paths.add(os.path.abspath(path))
389 except IOError:
390 logging.error('Could not quickmerge for project: %s',
391 os.path.basename(quickmerge_file))
Aviv Keshetb1238c32013-04-01 11:42:13 -0700392
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800393 # Autotest uses a circular symlink in client that *must* be added after the
394 # other sections of Autotest.
395 src_paths = list(src_paths)
396
397 # All destination paths up to this point are the same, but other sources
398 # added below might have a different one.
399 src_dest_paths = [(src_path + '/', sysroot_autotest_path)
400 for src_path in src_paths]
401
402 _maybe_add_autotest_symlink(src_dest_paths, brillo_autotest_src_path,
403 sysroot_autotest_path)
Simran Basi348fccc2015-04-28 12:39:01 -0700404 num_new_files = 0
405 num_modified_files = 0
Derek Beckett1f19c9c2020-12-14 12:25:53 -0800406 for src_path, dest_path in src_dest_paths:
407 rsync_output = RsyncQuickmerge(src_path, dest_path,
Simran Basi348fccc2015-04-28 12:39:01 -0700408 include_pattern_file, args.pretend,
409 args.overwrite)
Aviv Keshete00caeb2013-04-17 14:03:25 -0700410
Simran Basi348fccc2015-04-28 12:39:01 -0700411 if args.verbose:
412 logging.info(rsync_output.output)
413 change_report = ItemizeChangesFromRsyncOutput(rsync_output.output,
414 sysroot_autotest_path)
415 num_new_files = num_new_files + len(change_report.new_files)
416 num_modified_files = num_modified_files + len(change_report.modified_files)
417 if not args.pretend:
418 logging.info('Updating portage database.')
419 UpdatePackageContents(change_report, AUTOTEST_EBUILD, sysroot_path)
Aviv Keshet60968ec2013-04-11 18:44:14 -0700420
Aviv Keshet940c17f2013-04-11 18:41:42 -0700421 if not args.pretend:
Aviv Keshetfe54a8a2013-09-16 15:49:03 -0700422 for logfile in glob.glob(os.path.join(sysroot_autotest_path, 'packages',
423 '*.log')):
424 try:
425 # Open file in a try-except block, for atomicity, instead of
426 # doing existence check.
427 with open(logfile, 'r') as f:
428 package_cp = f.readline().strip()
429 DOWNGRADE_EBUILDS.append(package_cp)
430 except IOError:
431 pass
432
Aviv Keshet3cc4e9e2013-04-24 10:47:23 -0700433 for ebuild in DOWNGRADE_EBUILDS:
Aviv Keshet557e6882013-04-25 13:26:09 -0700434 if not DowngradePackageVersion(sysroot_path, ebuild):
Aviv Keshet3cc4e9e2013-04-24 10:47:23 -0700435 logging.warning('Unable to downgrade package %s version number.',
Aviv Keshete7b20192013-04-24 14:05:53 -0700436 ebuild)
Aviv Keshet19276752013-05-16 11:12:23 -0700437 RemoveBzipPackages(sysroot_autotest_path)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700438
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700439 sentinel_filename = os.path.join(sysroot_autotest_path,
440 '.quickmerge_sentinel')
Mike Frysinger45602c72019-09-22 02:15:11 -0400441 cros_build_lib.run(['touch', sentinel_filename])
Aviv Keshetc73cfc32013-06-14 16:18:53 -0700442
Aviv Keshet940c17f2013-04-11 18:41:42 -0700443 if args.pretend:
Aviv Keshete00caeb2013-04-17 14:03:25 -0700444 logging.info('The following message is pretend only. No filesystem '
Aviv Keshete7b20192013-04-24 14:05:53 -0700445 'changes made.')
Aviv Keshete00caeb2013-04-17 14:03:25 -0700446 logging.info('Quickmerge complete. Created or modified %s files.',
Simran Basi348fccc2015-04-28 12:39:01 -0700447 num_new_files + num_modified_files)
Aviv Keshete00caeb2013-04-17 14:03:25 -0700448
449 return 0