aboutsummaryrefslogtreecommitdiff
path: root/llvm_tools/update_chromeos_llvm_hash.py
diff options
context:
space:
mode:
Diffstat (limited to 'llvm_tools/update_chromeos_llvm_hash.py')
-rwxr-xr-xllvm_tools/update_chromeos_llvm_hash.py1194
1 files changed, 684 insertions, 510 deletions
diff --git a/llvm_tools/update_chromeos_llvm_hash.py b/llvm_tools/update_chromeos_llvm_hash.py
index 4e9b9104..75c6ce6c 100755
--- a/llvm_tools/update_chromeos_llvm_hash.py
+++ b/llvm_tools/update_chromeos_llvm_hash.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Copyright 2019 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -10,37 +10,40 @@ For each package, a temporary repo is created and the changes are uploaded
for review.
"""
-from __future__ import print_function
-
import argparse
import datetime
import enum
import os
+from pathlib import Path
import re
import subprocess
+from typing import Dict, Iterable
import chroot
import failure_modes
import get_llvm_hash
import git
-import llvm_patch_management
+import patch_utils
+import subprocess_helpers
+
DEFAULT_PACKAGES = [
- 'dev-util/lldb-server',
- 'sys-devel/llvm',
- 'sys-libs/compiler-rt',
- 'sys-libs/libcxx',
- 'sys-libs/libcxxabi',
- 'sys-libs/llvm-libunwind',
+ "dev-util/lldb-server",
+ "sys-devel/llvm",
+ "sys-libs/compiler-rt",
+ "sys-libs/libcxx",
+ "sys-libs/llvm-libunwind",
]
+DEFAULT_MANIFEST_PACKAGES = ["sys-devel/llvm"]
+
# Specify which LLVM hash to update
class LLVMVariant(enum.Enum):
- """Represent the LLVM hash in an ebuild file to update."""
+ """Represent the LLVM hash in an ebuild file to update."""
- current = 'LLVM_HASH'
- next = 'LLVM_NEXT_HASH'
+ current = "LLVM_HASH"
+ next = "LLVM_NEXT_HASH"
# If set to `True`, then the contents of `stdout` after executing a command will
@@ -48,582 +51,753 @@ class LLVMVariant(enum.Enum):
verbose = False
-def defaultCrosRoot():
- """Get default location of chroot_path.
+def defaultCrosRoot() -> Path:
+ """Get default location of chroot_path.
- The logic assumes that the cros_root is ~/chromiumos, unless llvm_tools is
- inside of a CrOS checkout, in which case that checkout should be used.
+ The logic assumes that the cros_root is ~/chromiumos, unless llvm_tools is
+ inside of a CrOS checkout, in which case that checkout should be used.
- Returns:
- The best guess location for the cros checkout.
- """
- llvm_tools_path = os.path.realpath(os.path.dirname(__file__))
- if llvm_tools_path.endswith('src/third_party/toolchain-utils/llvm_tools'):
- return os.path.join(llvm_tools_path, '../../../../')
- return '~/chromiumos'
+ Returns:
+ The best guess location for the cros checkout.
+ """
+ llvm_tools_path = os.path.realpath(os.path.dirname(__file__))
+ if llvm_tools_path.endswith("src/third_party/toolchain-utils/llvm_tools"):
+ return Path(llvm_tools_path).parent.parent.parent.parent
+ return Path.home() / "chromiumos"
def GetCommandLineArgs():
- """Parses the command line for the optional command line arguments.
-
- Returns:
- The log level to use when retrieving the LLVM hash or google3 LLVM version,
- the chroot path to use for executing chroot commands,
- a list of a package or packages to update their LLVM next hash,
- and the LLVM version to use when retrieving the LLVM hash.
- """
-
- # Create parser and add optional command-line arguments.
- parser = argparse.ArgumentParser(
- description="Updates the build's hash for llvm-next.")
-
- # Add argument for a specific chroot path.
- parser.add_argument('--chroot_path',
- default=defaultCrosRoot(),
- help='the path to the chroot (default: %(default)s)')
-
- # Add argument for specific builds to uprev and update their llvm-next hash.
- parser.add_argument('--update_packages',
- default=DEFAULT_PACKAGES,
- required=False,
- nargs='+',
- help='the ebuilds to update their hash for llvm-next '
- '(default: %(default)s)')
-
- # Add argument for whether to display command contents to `stdout`.
- parser.add_argument('--verbose',
- action='store_true',
- help='display contents of a command to the terminal '
- '(default: %(default)s)')
-
- # Add argument for the LLVM hash to update
- parser.add_argument(
- '--is_llvm_next',
- action='store_true',
- help='which llvm hash to update. If specified, update LLVM_NEXT_HASH. '
- 'Otherwise, update LLVM_HASH')
-
- # Add argument for the LLVM version to use.
- parser.add_argument(
- '--llvm_version',
- type=get_llvm_hash.IsSvnOption,
- required=True,
- help='which git hash to use. Either a svn revision, or one '
- 'of %s' % sorted(get_llvm_hash.KNOWN_HASH_SOURCES))
-
- # Add argument for the mode of the patch management when handling patches.
- parser.add_argument(
- '--failure_mode',
- default=failure_modes.FailureModes.FAIL.value,
- choices=[
- failure_modes.FailureModes.FAIL.value,
- failure_modes.FailureModes.CONTINUE.value,
- failure_modes.FailureModes.DISABLE_PATCHES.value,
- failure_modes.FailureModes.REMOVE_PATCHES.value
- ],
- help='the mode of the patch manager when handling failed patches '
- '(default: %(default)s)')
-
- # Add argument for the patch metadata file.
- parser.add_argument(
- '--patch_metadata_file',
- default='PATCHES.json',
- help='the .json file that has all the patches and their '
- 'metadata if applicable (default: PATCHES.json inside $FILESDIR)')
-
- # Parse the command line.
- args_output = parser.parse_args()
-
- # FIXME: We shouldn't be using globals here, but until we fix it, make pylint
- # stop complaining about it.
- # pylint: disable=global-statement
- global verbose
-
- verbose = args_output.verbose
-
- return args_output
+ """Parses the command line for the optional command line arguments.
+
+ Returns:
+ The log level to use when retrieving the LLVM hash or google3 LLVM version,
+ the chroot path to use for executing chroot commands,
+ a list of a package or packages to update their LLVM next hash,
+ and the LLVM version to use when retrieving the LLVM hash.
+ """
+
+ # Create parser and add optional command-line arguments.
+ parser = argparse.ArgumentParser(
+ description="Updates the build's hash for llvm-next."
+ )
+
+ # Add argument for a specific chroot path.
+ parser.add_argument(
+ "--chroot_path",
+ type=Path,
+ default=defaultCrosRoot(),
+ help="the path to the chroot (default: %(default)s)",
+ )
+
+ # Add argument for specific builds to uprev and update their llvm-next hash.
+ parser.add_argument(
+ "--update_packages",
+ default=",".join(DEFAULT_PACKAGES),
+ help="Comma-separated ebuilds to update llvm-next hash for "
+ "(default: %(default)s)",
+ )
+
+ parser.add_argument(
+ "--manifest_packages",
+ default="",
+ help="Comma-separated ebuilds to update manifests for "
+ "(default: %(default)s)",
+ )
+
+ # Add argument for whether to display command contents to `stdout`.
+ parser.add_argument(
+ "--verbose",
+ action="store_true",
+ help="display contents of a command to the terminal "
+ "(default: %(default)s)",
+ )
+
+ # Add argument for the LLVM hash to update
+ parser.add_argument(
+ "--is_llvm_next",
+ action="store_true",
+ help="which llvm hash to update. If specified, update LLVM_NEXT_HASH. "
+ "Otherwise, update LLVM_HASH",
+ )
+
+ # Add argument for the LLVM version to use.
+ parser.add_argument(
+ "--llvm_version",
+ type=get_llvm_hash.IsSvnOption,
+ required=True,
+ help="which git hash to use. Either a svn revision, or one "
+ f"of {sorted(get_llvm_hash.KNOWN_HASH_SOURCES)}",
+ )
+
+ # Add argument for the mode of the patch management when handling patches.
+ parser.add_argument(
+ "--failure_mode",
+ default=failure_modes.FailureModes.FAIL.value,
+ choices=[
+ failure_modes.FailureModes.FAIL.value,
+ failure_modes.FailureModes.CONTINUE.value,
+ failure_modes.FailureModes.DISABLE_PATCHES.value,
+ failure_modes.FailureModes.REMOVE_PATCHES.value,
+ ],
+ help="the mode of the patch manager when handling failed patches "
+ "(default: %(default)s)",
+ )
+
+ # Add argument for the patch metadata file.
+ parser.add_argument(
+ "--patch_metadata_file",
+ default="PATCHES.json",
+ help="the .json file that has all the patches and their "
+ "metadata if applicable (default: PATCHES.json inside $FILESDIR)",
+ )
+
+ # Parse the command line.
+ args_output = parser.parse_args()
+
+ # FIXME: We shouldn't be using globals here, but until we fix it, make pylint
+ # stop complaining about it.
+ # pylint: disable=global-statement
+ global verbose
+
+ verbose = args_output.verbose
+
+ return args_output
def GetEbuildPathsFromSymLinkPaths(symlinks):
- """Reads the symlink(s) to get the ebuild path(s) to the package(s).
+ """Reads the symlink(s) to get the ebuild path(s) to the package(s).
- Args:
- symlinks: A list of absolute path symlink/symlinks that point
- to the package's ebuild.
+ Args:
+ symlinks: A list of absolute path symlink/symlinks that point
+ to the package's ebuild.
- Returns:
- A dictionary where the key is the absolute path of the symlink and the value
- is the absolute path to the ebuild that was read from the symlink.
+ Returns:
+ A dictionary where the key is the absolute path of the symlink and the value
+ is the absolute path to the ebuild that was read from the symlink.
- Raises:
- ValueError: Invalid symlink(s) were provided.
- """
+ Raises:
+ ValueError: Invalid symlink(s) were provided.
+ """
- # A dictionary that holds:
- # key: absolute symlink path
- # value: absolute ebuild path
- resolved_paths = {}
+ # A dictionary that holds:
+ # key: absolute symlink path
+ # value: absolute ebuild path
+ resolved_paths = {}
- # Iterate through each symlink.
- #
- # For each symlink, check that it is a valid symlink,
- # and then construct the ebuild path, and
- # then add the ebuild path to the dict.
- for cur_symlink in symlinks:
- if not os.path.islink(cur_symlink):
- raise ValueError('Invalid symlink provided: %s' % cur_symlink)
+ # Iterate through each symlink.
+ #
+ # For each symlink, check that it is a valid symlink,
+ # and then construct the ebuild path, and
+ # then add the ebuild path to the dict.
+ for cur_symlink in symlinks:
+ if not os.path.islink(cur_symlink):
+ raise ValueError(f"Invalid symlink provided: {cur_symlink}")
- # Construct the absolute path to the ebuild.
- ebuild_path = os.path.realpath(cur_symlink)
+ # Construct the absolute path to the ebuild.
+ ebuild_path = os.path.realpath(cur_symlink)
- if cur_symlink not in resolved_paths:
- resolved_paths[cur_symlink] = ebuild_path
+ if cur_symlink not in resolved_paths:
+ resolved_paths[cur_symlink] = ebuild_path
- return resolved_paths
+ return resolved_paths
def UpdateEbuildLLVMHash(ebuild_path, llvm_variant, git_hash, svn_version):
- """Updates the LLVM hash in the ebuild.
+ """Updates the LLVM hash in the ebuild.
- The build changes are staged for commit in the temporary repo.
+ The build changes are staged for commit in the temporary repo.
- Args:
- ebuild_path: The absolute path to the ebuild.
- llvm_variant: Which LLVM hash to update.
- git_hash: The new git hash.
- svn_version: The SVN-style revision number of git_hash.
+ Args:
+ ebuild_path: The absolute path to the ebuild.
+ llvm_variant: Which LLVM hash to update.
+ git_hash: The new git hash.
+ svn_version: The SVN-style revision number of git_hash.
- Raises:
- ValueError: Invalid ebuild path provided or failed to stage the commit
- of the changes or failed to update the LLVM hash.
- """
+ Raises:
+ ValueError: Invalid ebuild path provided or failed to stage the commit
+ of the changes or failed to update the LLVM hash.
+ """
- # Iterate through each ebuild.
- #
- # For each ebuild, read the file in
- # advance and then create a temporary file
- # that gets updated with the new LLVM hash
- # and revision number and then the ebuild file
- # gets updated to the temporary file.
+ # Iterate through each ebuild.
+ #
+ # For each ebuild, read the file in
+ # advance and then create a temporary file
+ # that gets updated with the new LLVM hash
+ # and revision number and then the ebuild file
+ # gets updated to the temporary file.
- if not os.path.isfile(ebuild_path):
- raise ValueError('Invalid ebuild path provided: %s' % ebuild_path)
+ if not os.path.isfile(ebuild_path):
+ raise ValueError(f"Invalid ebuild path provided: {ebuild_path}")
- temp_ebuild_file = '%s.temp' % ebuild_path
+ temp_ebuild_file = f"{ebuild_path}.temp"
- with open(ebuild_path) as ebuild_file:
- # write updates to a temporary file in case of interrupts
- with open(temp_ebuild_file, 'w') as temp_file:
- for cur_line in ReplaceLLVMHash(ebuild_file, llvm_variant, git_hash,
- svn_version):
- temp_file.write(cur_line)
- os.rename(temp_ebuild_file, ebuild_path)
+ with open(ebuild_path) as ebuild_file:
+ # write updates to a temporary file in case of interrupts
+ with open(temp_ebuild_file, "w") as temp_file:
+ for cur_line in ReplaceLLVMHash(
+ ebuild_file, llvm_variant, git_hash, svn_version
+ ):
+ temp_file.write(cur_line)
+ os.rename(temp_ebuild_file, ebuild_path)
- # Get the path to the parent directory.
- parent_dir = os.path.dirname(ebuild_path)
+ # Get the path to the parent directory.
+ parent_dir = os.path.dirname(ebuild_path)
- # Stage the changes.
- subprocess.check_output(['git', '-C', parent_dir, 'add', ebuild_path])
+ # Stage the changes.
+ subprocess.check_output(["git", "-C", parent_dir, "add", ebuild_path])
def ReplaceLLVMHash(ebuild_lines, llvm_variant, git_hash, svn_version):
- """Updates the LLVM git hash.
+ """Updates the LLVM git hash.
- Args:
- ebuild_lines: The contents of the ebuild file.
- llvm_variant: The LLVM hash to update.
- git_hash: The new git hash.
- svn_version: The SVN-style revision number of git_hash.
+ Args:
+ ebuild_lines: The contents of the ebuild file.
+ llvm_variant: The LLVM hash to update.
+ git_hash: The new git hash.
+ svn_version: The SVN-style revision number of git_hash.
- Yields:
- lines of the modified ebuild file
- """
- is_updated = False
- llvm_regex = re.compile('^' + re.escape(llvm_variant.value) +
- '=\"[a-z0-9]+\"')
- for cur_line in ebuild_lines:
- if not is_updated and llvm_regex.search(cur_line):
- # Update the git hash and revision number.
- cur_line = '%s=\"%s\" # r%d\n' % (llvm_variant.value, git_hash,
- svn_version)
+ Yields:
+ lines of the modified ebuild file
+ """
+ is_updated = False
+ llvm_regex = re.compile(
+ "^" + re.escape(llvm_variant.value) + '="[a-z0-9]+"'
+ )
+ for cur_line in ebuild_lines:
+ if not is_updated and llvm_regex.search(cur_line):
+ # Update the git hash and revision number.
+ cur_line = f'{llvm_variant.value}="{git_hash}" # r{svn_version}\n'
- is_updated = True
+ is_updated = True
- yield cur_line
+ yield cur_line
- if not is_updated:
- raise ValueError('Failed to update %s' % llvm_variant.value)
+ if not is_updated:
+ raise ValueError(f"Failed to update {llvm_variant.value}")
def UprevEbuildSymlink(symlink):
- """Uprevs the symlink's revision number.
+ """Uprevs the symlink's revision number.
- Increases the revision number by 1 and stages the change in
- the temporary repo.
+ Increases the revision number by 1 and stages the change in
+ the temporary repo.
- Args:
- symlink: The absolute path of an ebuild symlink.
+ Args:
+ symlink: The absolute path of an ebuild symlink.
- Raises:
- ValueError: Failed to uprev the symlink or failed to stage the changes.
- """
+ Raises:
+ ValueError: Failed to uprev the symlink or failed to stage the changes.
+ """
- if not os.path.islink(symlink):
- raise ValueError('Invalid symlink provided: %s' % symlink)
+ if not os.path.islink(symlink):
+ raise ValueError(f"Invalid symlink provided: {symlink}")
- new_symlink, is_changed = re.subn(
- r'r([0-9]+).ebuild',
- lambda match: 'r%s.ebuild' % str(int(match.group(1)) + 1),
- symlink,
- count=1)
+ new_symlink, is_changed = re.subn(
+ r"r([0-9]+).ebuild",
+ lambda match: "r%s.ebuild" % str(int(match.group(1)) + 1),
+ symlink,
+ count=1,
+ )
- if not is_changed:
- raise ValueError('Failed to uprev the symlink.')
+ if not is_changed:
+ raise ValueError("Failed to uprev the symlink.")
- # rename the symlink
- subprocess.check_output(
- ['git', '-C',
- os.path.dirname(symlink), 'mv', symlink, new_symlink])
+ # rename the symlink
+ subprocess.check_output(
+ ["git", "-C", os.path.dirname(symlink), "mv", symlink, new_symlink]
+ )
def UprevEbuildToVersion(symlink, svn_version, git_hash):
- """Uprevs the ebuild's revision number.
-
- Increases the revision number by 1 and stages the change in
- the temporary repo.
-
- Args:
- symlink: The absolute path of an ebuild symlink.
- svn_version: The SVN-style revision number of git_hash.
- git_hash: The new git hash.
-
- Raises:
- ValueError: Failed to uprev the ebuild or failed to stage the changes.
- AssertionError: No llvm version provided for an LLVM uprev
- """
-
- if not os.path.islink(symlink):
- raise ValueError('Invalid symlink provided: %s' % symlink)
-
- ebuild = os.path.realpath(symlink)
- llvm_major_version = get_llvm_hash.GetLLVMMajorVersion(git_hash)
- # llvm
- package = os.path.basename(os.path.dirname(symlink))
- if not package:
- raise ValueError('Tried to uprev an unknown package')
- if package == 'llvm':
- new_ebuild, is_changed = re.subn(
- r'(\d+)\.(\d+)_pre([0-9]+)_p([0-9]+)',
- '%s.\\2_pre%s_p%s' % (llvm_major_version, svn_version,
- datetime.datetime.today().strftime('%Y%m%d')),
- ebuild,
- count=1)
- # any other package
- else:
- new_ebuild, is_changed = re.subn(r'(\d+)\.(\d+)_pre([0-9]+)',
- '%s.\\2_pre%s' %
- (llvm_major_version, svn_version),
- ebuild,
- count=1)
-
- if not is_changed: # failed to increment the revision number
- raise ValueError('Failed to uprev the ebuild.')
-
- symlink_dir = os.path.dirname(symlink)
-
- # Rename the ebuild
- subprocess.check_output(['git', '-C', symlink_dir, 'mv', ebuild, new_ebuild])
-
- # Create a symlink of the renamed ebuild
- new_symlink = new_ebuild[:-len('.ebuild')] + '-r1.ebuild'
- subprocess.check_output(['ln', '-s', '-r', new_ebuild, new_symlink])
-
- if not os.path.islink(new_symlink):
- raise ValueError('Invalid symlink name: %s' % new_ebuild[:-len('.ebuild')])
-
- subprocess.check_output(['git', '-C', symlink_dir, 'add', new_symlink])
-
- # Remove the old symlink
- subprocess.check_output(['git', '-C', symlink_dir, 'rm', symlink])
-
-
-def CreatePathDictionaryFromPackages(chroot_path, update_packages):
- """Creates a symlink and ebuild path pair dictionary from the packages.
-
- Args:
- chroot_path: The absolute path to the chroot.
- update_packages: The filtered packages to be updated.
-
- Returns:
- A dictionary where the key is the absolute path to the symlink
- of the package and the value is the absolute path to the ebuild of
- the package.
- """
-
- # Construct a list containing the chroot file paths of the package(s).
- chroot_file_paths = chroot.GetChrootEbuildPaths(chroot_path, update_packages)
-
- # Construct a list containing the symlink(s) of the package(s).
- symlink_file_paths = chroot.ConvertChrootPathsToAbsolutePaths(
- chroot_path, chroot_file_paths)
-
- # Create a dictionary where the key is the absolute path of the symlink to
- # the package and the value is the absolute path to the ebuild of the package.
- return GetEbuildPathsFromSymLinkPaths(symlink_file_paths)
-
-
-def RemovePatchesFromFilesDir(patches):
- """Removes the patches from $FILESDIR of a package.
+ """Uprevs the ebuild's revision number.
+
+ Increases the revision number by 1 and stages the change in
+ the temporary repo.
+
+ Args:
+ symlink: The absolute path of an ebuild symlink.
+ svn_version: The SVN-style revision number of git_hash.
+ git_hash: The new git hash.
+
+ Raises:
+ ValueError: Failed to uprev the ebuild or failed to stage the changes.
+ AssertionError: No llvm version provided for an LLVM uprev
+ """
+
+ if not os.path.islink(symlink):
+ raise ValueError(f"Invalid symlink provided: {symlink}")
+
+ ebuild = os.path.realpath(symlink)
+ llvm_major_version = get_llvm_hash.GetLLVMMajorVersion(git_hash)
+ # llvm
+ package = os.path.basename(os.path.dirname(symlink))
+ if not package:
+ raise ValueError("Tried to uprev an unknown package")
+ if package == "llvm":
+ new_ebuild, is_changed = re.subn(
+ r"(\d+)\.(\d+)_pre([0-9]+)_p([0-9]+)",
+ "%s.\\2_pre%s_p%s"
+ % (
+ llvm_major_version,
+ svn_version,
+ datetime.datetime.today().strftime("%Y%m%d"),
+ ),
+ ebuild,
+ count=1,
+ )
+ # any other package
+ else:
+ new_ebuild, is_changed = re.subn(
+ r"(\d+)\.(\d+)_pre([0-9]+)",
+ "%s.\\2_pre%s" % (llvm_major_version, svn_version),
+ ebuild,
+ count=1,
+ )
- Args:
- patches: A list of absolute pathes of patches to remove
+ if not is_changed: # failed to increment the revision number
+ raise ValueError("Failed to uprev the ebuild.")
- Raises:
- ValueError: Failed to remove a patch in $FILESDIR.
- """
+ symlink_dir = os.path.dirname(symlink)
- for patch in patches:
+ # Rename the ebuild
subprocess.check_output(
- ['git', '-C', os.path.dirname(patch), 'rm', '-f', patch])
-
-
-def StagePatchMetadataFileForCommit(patch_metadata_file_path):
- """Stages the updated patch metadata file for commit.
+ ["git", "-C", symlink_dir, "mv", ebuild, new_ebuild]
+ )
- Args:
- patch_metadata_file_path: The absolute path to the patch metadata file.
+ # Create a symlink of the renamed ebuild
+ new_symlink = new_ebuild[: -len(".ebuild")] + "-r1.ebuild"
+ subprocess.check_output(["ln", "-s", "-r", new_ebuild, new_symlink])
- Raises:
- ValueError: Failed to stage the patch metadata file for commit or invalid
- patch metadata file.
- """
+ if not os.path.islink(new_symlink):
+ raise ValueError(
+ f'Invalid symlink name: {new_ebuild[:-len(".ebuild")]}'
+ )
- if not os.path.isfile(patch_metadata_file_path):
- raise ValueError('Invalid patch metadata file provided: %s' %
- patch_metadata_file_path)
+ subprocess.check_output(["git", "-C", symlink_dir, "add", new_symlink])
- # Cmd to stage the patch metadata file for commit.
- subprocess.check_output([
- 'git', '-C',
- os.path.dirname(patch_metadata_file_path), 'add',
- patch_metadata_file_path
- ])
+ # Remove the old symlink
+ subprocess.check_output(["git", "-C", symlink_dir, "rm", symlink])
-def StagePackagesPatchResultsForCommit(package_info_dict, commit_messages):
- """Stages the patch results of the packages to the commit message.
-
- Args:
- package_info_dict: A dictionary where the key is the package name and the
- value is a dictionary that contains information about the patches of the
- package (key).
- commit_messages: The commit message that has the updated ebuilds and
- upreving information.
-
- Returns:
- commit_messages with new additions
- """
-
- # For each package, check if any patches for that package have
- # changed, if so, add which patches have changed to the commit
- # message.
- for package_name, patch_info_dict in package_info_dict.items():
- if (patch_info_dict['disabled_patches']
- or patch_info_dict['removed_patches']
- or patch_info_dict['modified_metadata']):
- cur_package_header = '\nFor the package %s:' % package_name
- commit_messages.append(cur_package_header)
-
- # Add to the commit message that the patch metadata file was modified.
- if patch_info_dict['modified_metadata']:
- patch_metadata_path = patch_info_dict['modified_metadata']
- commit_messages.append('The patch metadata file %s was modified' %
- os.path.basename(patch_metadata_path))
-
- StagePatchMetadataFileForCommit(patch_metadata_path)
-
- # Add each disabled patch to the commit message.
- if patch_info_dict['disabled_patches']:
- commit_messages.append('The following patches were disabled:')
-
- for patch_path in patch_info_dict['disabled_patches']:
- commit_messages.append(os.path.basename(patch_path))
-
- # Add each removed patch to the commit message.
- if patch_info_dict['removed_patches']:
- commit_messages.append('The following patches were removed:')
-
- for patch_path in patch_info_dict['removed_patches']:
- commit_messages.append(os.path.basename(patch_path))
-
- RemovePatchesFromFilesDir(patch_info_dict['removed_patches'])
-
- return commit_messages
-
-
-def UpdatePackages(packages, llvm_variant, git_hash, svn_version, chroot_path,
- patch_metadata_file, mode, git_hash_source,
- extra_commit_msg):
- """Updates an LLVM hash and uprevs the ebuild of the packages.
-
- A temporary repo is created for the changes. The changes are
- then uploaded for review.
-
- Args:
- packages: A list of all the packages that are going to be updated.
- llvm_variant: The LLVM hash to update.
- git_hash: The new git hash.
- svn_version: The SVN-style revision number of git_hash.
- chroot_path: The absolute path to the chroot.
- patch_metadata_file: The name of the .json file in '$FILESDIR/' that has
- the patches and its metadata.
- mode: The mode of the patch manager when handling an applicable patch
- that failed to apply.
- Ex. 'FailureModes.FAIL'
- git_hash_source: The source of which git hash to use based off of.
- Ex. 'google3', 'tot', or <version> such as 365123
- extra_commit_msg: extra test to append to the commit message.
-
- Returns:
- A nametuple that has two (key, value) pairs, where the first pair is the
- Gerrit commit URL and the second pair is the change list number.
- """
-
- # Determines whether to print the result of each executed command.
- llvm_patch_management.verbose = verbose
-
- # Construct a dictionary where the key is the absolute path of the symlink to
- # the package and the value is the absolute path to the ebuild of the package.
- paths_dict = CreatePathDictionaryFromPackages(chroot_path, packages)
-
- repo_path = os.path.dirname(next(iter(paths_dict.values())))
-
- branch = 'update-' + llvm_variant.value + '-' + git_hash
-
- git.CreateBranch(repo_path, branch)
-
- try:
- commit_message_header = 'llvm'
- if llvm_variant == LLVMVariant.next:
- commit_message_header = 'llvm-next'
- if git_hash_source in get_llvm_hash.KNOWN_HASH_SOURCES:
- commit_message_header += ('/%s: upgrade to %s (r%d)' %
- (git_hash_source, git_hash, svn_version))
- else:
- commit_message_header += (': upgrade to %s (r%d)' %
- (git_hash, svn_version))
-
- commit_messages = [
- commit_message_header + '\n',
- 'The following packages have been updated:',
- ]
+def CreatePathDictionaryFromPackages(chroot_path, update_packages):
+ """Creates a symlink and ebuild path pair dictionary from the packages.
- # Holds the list of packages that are updating.
- packages = []
+ Args:
+ chroot_path: The absolute path to the chroot.
+ update_packages: The filtered packages to be updated.
- # Iterate through the dictionary.
- #
- # For each iteration:
- # 1) Update the ebuild's LLVM hash.
- # 2) Uprev the ebuild (symlink).
- # 3) Add the modified package to the commit message.
- for symlink_path, ebuild_path in paths_dict.items():
- path_to_ebuild_dir = os.path.dirname(ebuild_path)
+ Returns:
+ A dictionary where the key is the absolute path to the symlink
+ of the package and the value is the absolute path to the ebuild of
+ the package.
+ """
- UpdateEbuildLLVMHash(ebuild_path, llvm_variant, git_hash, svn_version)
+ # Construct a list containing the chroot file paths of the package(s).
+ chroot_file_paths = chroot.GetChrootEbuildPaths(
+ chroot_path, update_packages
+ )
- if llvm_variant == LLVMVariant.current:
- UprevEbuildToVersion(symlink_path, svn_version, git_hash)
- else:
- UprevEbuildSymlink(symlink_path)
+ # Construct a list containing the symlink(s) of the package(s).
+ symlink_file_paths = chroot.ConvertChrootPathsToAbsolutePaths(
+ chroot_path, chroot_file_paths
+ )
- cur_dir_name = os.path.basename(path_to_ebuild_dir)
- parent_dir_name = os.path.basename(os.path.dirname(path_to_ebuild_dir))
+ # Create a dictionary where the key is the absolute path of the symlink to
+ # the package and the value is the absolute path to the ebuild of the package.
+ return GetEbuildPathsFromSymLinkPaths(symlink_file_paths)
- packages.append('%s/%s' % (parent_dir_name, cur_dir_name))
- commit_messages.append('%s/%s' % (parent_dir_name, cur_dir_name))
- EnsurePackageMaskContains(chroot_path, git_hash)
+def RemovePatchesFromFilesDir(patches):
+ """Removes the patches from $FILESDIR of a package.
- # Handle the patches for each package.
- package_info_dict = llvm_patch_management.UpdatePackagesPatchMetadataFile(
- chroot_path, svn_version, patch_metadata_file, packages, mode)
+ Args:
+ patches: A list of absolute paths of patches to remove
- # Update the commit message if changes were made to a package's patches.
- commit_messages = StagePackagesPatchResultsForCommit(
- package_info_dict, commit_messages)
+ Raises:
+ ValueError: Failed to remove a patch in $FILESDIR.
+ """
- if extra_commit_msg:
- commit_messages.append(extra_commit_msg)
+ for patch in patches:
+ subprocess.check_output(
+ ["git", "-C", os.path.dirname(patch), "rm", "-f", patch]
+ )
- change_list = git.UploadChanges(repo_path, branch, commit_messages)
- finally:
- git.DeleteBranch(repo_path, branch)
+def StagePatchMetadataFileForCommit(patch_metadata_file_path):
+ """Stages the updated patch metadata file for commit.
- return change_list
+ Args:
+ patch_metadata_file_path: The absolute path to the patch metadata file.
+ Raises:
+ ValueError: Failed to stage the patch metadata file for commit or invalid
+ patch metadata file.
+ """
-def EnsurePackageMaskContains(chroot_path, git_hash):
- """Adds the major version of llvm to package.mask if it's not already present.
+ if not os.path.isfile(patch_metadata_file_path):
+ raise ValueError(
+ f"Invalid patch metadata file provided: {patch_metadata_file_path}"
+ )
- Args:
- chroot_path: The absolute path to the chroot.
- git_hash: The new git hash.
+ # Cmd to stage the patch metadata file for commit.
+ subprocess.check_output(
+ [
+ "git",
+ "-C",
+ os.path.dirname(patch_metadata_file_path),
+ "add",
+ patch_metadata_file_path,
+ ]
+ )
- Raises:
- FileExistsError: package.mask not found in ../../chromiumos-overlay
- """
- llvm_major_version = get_llvm_hash.GetLLVMMajorVersion(git_hash)
+def StagePackagesPatchResultsForCommit(package_info_dict, commit_messages):
+ """Stages the patch results of the packages to the commit message.
+
+ Args:
+ package_info_dict: A dictionary where the key is the package name and the
+ value is a dictionary that contains information about the patches of the
+ package (key).
+ commit_messages: The commit message that has the updated ebuilds and
+ upreving information.
+
+ Returns:
+ commit_messages with new additions
+ """
+
+ # For each package, check if any patches for that package have
+ # changed, if so, add which patches have changed to the commit
+ # message.
+ for package_name, patch_info_dict in package_info_dict.items():
+ if (
+ patch_info_dict["disabled_patches"]
+ or patch_info_dict["removed_patches"]
+ or patch_info_dict["modified_metadata"]
+ ):
+ cur_package_header = f"\nFor the package {package_name}:"
+ commit_messages.append(cur_package_header)
+
+ # Add to the commit message that the patch metadata file was modified.
+ if patch_info_dict["modified_metadata"]:
+ patch_metadata_path = patch_info_dict["modified_metadata"]
+ metadata_file_name = os.path.basename(patch_metadata_path)
+ commit_messages.append(
+ f"The patch metadata file {metadata_file_name} was modified"
+ )
+
+ StagePatchMetadataFileForCommit(patch_metadata_path)
+
+ # Add each disabled patch to the commit message.
+ if patch_info_dict["disabled_patches"]:
+ commit_messages.append("The following patches were disabled:")
+
+ for patch_path in patch_info_dict["disabled_patches"]:
+ commit_messages.append(os.path.basename(patch_path))
+
+ # Add each removed patch to the commit message.
+ if patch_info_dict["removed_patches"]:
+ commit_messages.append("The following patches were removed:")
+
+ for patch_path in patch_info_dict["removed_patches"]:
+ commit_messages.append(os.path.basename(patch_path))
+
+ RemovePatchesFromFilesDir(patch_info_dict["removed_patches"])
+
+ return commit_messages
+
+
+def UpdateManifests(packages: Iterable[str], chroot_path: Path):
+ """Updates manifest files for packages.
+
+ Args:
+ packages: A list of packages to update manifests for.
+ chroot_path: The absolute path to the chroot.
+
+ Raises:
+ CalledProcessError: ebuild failed to update manifest.
+ """
+ manifest_ebuilds = chroot.GetChrootEbuildPaths(chroot_path, packages)
+ for ebuild_path in manifest_ebuilds:
+ subprocess_helpers.ChrootRunCommand(
+ chroot_path, ["ebuild", ebuild_path, "manifest"]
+ )
+
+
+def UpdatePackages(
+ packages: Iterable[str],
+ manifest_packages: Iterable[str],
+ llvm_variant,
+ git_hash,
+ svn_version,
+ chroot_path: Path,
+ mode,
+ git_hash_source,
+ extra_commit_msg,
+):
+ """Updates an LLVM hash and uprevs the ebuild of the packages.
+
+ A temporary repo is created for the changes. The changes are
+ then uploaded for review.
+
+ Args:
+ packages: A list of all the packages that are going to be updated.
+ manifest_packages: A list of packages to update manifests for.
+ llvm_variant: The LLVM hash to update.
+ git_hash: The new git hash.
+ svn_version: The SVN-style revision number of git_hash.
+ chroot_path: The absolute path to the chroot.
+ mode: The mode of the patch manager when handling an applicable patch
+ that failed to apply.
+ Ex. 'FailureModes.FAIL'
+ git_hash_source: The source of which git hash to use based off of.
+ Ex. 'google3', 'tot', or <version> such as 365123
+ extra_commit_msg: extra test to append to the commit message.
+
+ Returns:
+ A nametuple that has two (key, value) pairs, where the first pair is the
+ Gerrit commit URL and the second pair is the change list number.
+ """
+
+ # Construct a dictionary where the key is the absolute path of the symlink to
+ # the package and the value is the absolute path to the ebuild of the package.
+ paths_dict = CreatePathDictionaryFromPackages(chroot_path, packages)
+
+ repo_path = os.path.dirname(next(iter(paths_dict.values())))
+
+ branch = "update-" + llvm_variant.value + "-" + git_hash
+
+ git.CreateBranch(repo_path, branch)
+
+ try:
+ commit_message_header = "llvm"
+ if llvm_variant == LLVMVariant.next:
+ commit_message_header = "llvm-next"
+ if git_hash_source in get_llvm_hash.KNOWN_HASH_SOURCES:
+ commit_message_header += (
+ f"/{git_hash_source}: upgrade to {git_hash} (r{svn_version})"
+ )
+ else:
+ commit_message_header += f": upgrade to {git_hash} (r{svn_version})"
+
+ commit_lines = [
+ commit_message_header + "\n",
+ "The following packages have been updated:",
+ ]
+
+ # Holds the list of packages that are updating.
+ packages = []
+
+ # Iterate through the dictionary.
+ #
+ # For each iteration:
+ # 1) Update the ebuild's LLVM hash.
+ # 2) Uprev the ebuild (symlink).
+ # 3) Add the modified package to the commit message.
+ for symlink_path, ebuild_path in paths_dict.items():
+ path_to_ebuild_dir = os.path.dirname(ebuild_path)
+
+ UpdateEbuildLLVMHash(
+ ebuild_path, llvm_variant, git_hash, svn_version
+ )
+
+ if llvm_variant == LLVMVariant.current:
+ UprevEbuildToVersion(symlink_path, svn_version, git_hash)
+ else:
+ UprevEbuildSymlink(symlink_path)
+
+ cur_dir_name = os.path.basename(path_to_ebuild_dir)
+ parent_dir_name = os.path.basename(
+ os.path.dirname(path_to_ebuild_dir)
+ )
+
+ packages.append(f"{parent_dir_name}/{cur_dir_name}")
+ commit_lines.append(f"{parent_dir_name}/{cur_dir_name}")
+
+ if manifest_packages:
+ UpdateManifests(manifest_packages, chroot_path)
+ commit_lines.append("Updated manifest for:")
+ commit_lines.extend(manifest_packages)
+
+ EnsurePackageMaskContains(chroot_path, git_hash)
+
+ # Handle the patches for each package.
+ package_info_dict = UpdatePackagesPatchMetadataFile(
+ chroot_path, svn_version, packages, mode
+ )
+
+ # Update the commit message if changes were made to a package's patches.
+ commit_lines = StagePackagesPatchResultsForCommit(
+ package_info_dict, commit_lines
+ )
+
+ if extra_commit_msg:
+ commit_lines.append(extra_commit_msg)
+
+ change_list = git.UploadChanges(repo_path, branch, commit_lines)
+
+ finally:
+ git.DeleteBranch(repo_path, branch)
+
+ return change_list
- overlay_dir = os.path.join(chroot_path, 'src/third_party/chromiumos-overlay')
- mask_path = os.path.join(overlay_dir,
- 'profiles/targets/chromeos/package.mask')
- with open(mask_path, 'r+') as mask_file:
- mask_contents = mask_file.read()
- expected_line = '=sys-devel/llvm-%s.0_pre*\n' % llvm_major_version
- if expected_line not in mask_contents:
- mask_file.write(expected_line)
- subprocess.check_output(['git', '-C', overlay_dir, 'add', mask_path])
+def EnsurePackageMaskContains(chroot_path, git_hash):
+ """Adds the major version of llvm to package.mask if it's not already present.
+
+ Args:
+ chroot_path: The absolute path to the chroot.
+ git_hash: The new git hash.
+
+ Raises:
+ FileExistsError: package.mask not found in ../../chromiumos-overlay
+ """
+
+ llvm_major_version = get_llvm_hash.GetLLVMMajorVersion(git_hash)
+
+ overlay_dir = os.path.join(
+ chroot_path, "src/third_party/chromiumos-overlay"
+ )
+ mask_path = os.path.join(
+ overlay_dir, "profiles/targets/chromeos/package.mask"
+ )
+ with open(mask_path, "r+") as mask_file:
+ mask_contents = mask_file.read()
+ expected_line = f"=sys-devel/llvm-{llvm_major_version}.0_pre*\n"
+ if expected_line not in mask_contents:
+ mask_file.write(expected_line)
+
+ subprocess.check_output(["git", "-C", overlay_dir, "add", mask_path])
+
+
+def UpdatePackagesPatchMetadataFile(
+ chroot_path: Path,
+ svn_version: int,
+ packages: Iterable[str],
+ mode: failure_modes.FailureModes,
+) -> Dict[str, patch_utils.PatchInfo]:
+ """Updates the packages metadata file.
+
+ Args:
+ chroot_path: The absolute path to the chroot.
+ svn_version: The version to use for patch management.
+ packages: All the packages to update their patch metadata file.
+ mode: The mode for the patch manager to use when an applicable patch
+ fails to apply.
+ Ex: 'FailureModes.FAIL'
+
+ Returns:
+ A dictionary where the key is the package name and the value is a dictionary
+ that has information on the patches.
+ """
+
+ # A dictionary where the key is the package name and the value is a dictionary
+ # that has information on the patches.
+ package_info = {}
+
+ llvm_hash = get_llvm_hash.LLVMHash()
+
+ with llvm_hash.CreateTempDirectory() as temp_dir:
+ with get_llvm_hash.CreateTempLLVMRepo(temp_dir) as dirname:
+ # Ensure that 'svn_version' exists in the chromiumum mirror of LLVM by
+ # finding its corresponding git hash.
+ git_hash = get_llvm_hash.GetGitHashFrom(dirname, svn_version)
+ move_head_cmd = ["git", "-C", dirname, "checkout", git_hash, "-q"]
+ subprocess.run(move_head_cmd, stdout=subprocess.DEVNULL, check=True)
+
+ for cur_package in packages:
+ # Get the absolute path to $FILESDIR of the package.
+ chroot_ebuild_str = subprocess_helpers.ChrootRunCommand(
+ chroot_path, ["equery", "w", cur_package]
+ ).strip()
+ if not chroot_ebuild_str:
+ raise RuntimeError(
+ f"could not find ebuild for {cur_package}"
+ )
+ chroot_ebuild_path = Path(
+ chroot.ConvertChrootPathsToAbsolutePaths(
+ chroot_path, [chroot_ebuild_str]
+ )[0]
+ )
+ patches_json_fp = (
+ chroot_ebuild_path.parent / "files" / "PATCHES.json"
+ )
+ if not patches_json_fp.is_file():
+ raise RuntimeError(
+ f"patches file {patches_json_fp} is not a file"
+ )
+
+ src_path = Path(dirname)
+ with patch_utils.git_clean_context(src_path):
+ if (
+ mode == failure_modes.FailureModes.FAIL
+ or mode == failure_modes.FailureModes.CONTINUE
+ ):
+ patches_info = patch_utils.apply_all_from_json(
+ svn_version=svn_version,
+ llvm_src_dir=src_path,
+ patches_json_fp=patches_json_fp,
+ continue_on_failure=mode
+ == failure_modes.FailureModes.CONTINUE,
+ )
+ elif mode == failure_modes.FailureModes.REMOVE_PATCHES:
+ patches_info = patch_utils.remove_old_patches(
+ svn_version, src_path, patches_json_fp
+ )
+ elif mode == failure_modes.FailureModes.DISABLE_PATCHES:
+ patches_info = patch_utils.update_version_ranges(
+ svn_version, src_path, patches_json_fp
+ )
+
+ package_info[cur_package] = patches_info._asdict()
+
+ return package_info
def main():
- """Updates the LLVM next hash for each package.
-
- Raises:
- AssertionError: The script was run inside the chroot.
- """
-
- chroot.VerifyOutsideChroot()
-
- args_output = GetCommandLineArgs()
-
- llvm_variant = LLVMVariant.current
- if args_output.is_llvm_next:
- llvm_variant = LLVMVariant.next
-
- git_hash_source = args_output.llvm_version
-
- git_hash, svn_version = get_llvm_hash.GetLLVMHashAndVersionFromSVNOption(
- git_hash_source)
-
- change_list = UpdatePackages(args_output.update_packages,
- llvm_variant,
- git_hash,
- svn_version,
- args_output.chroot_path,
- args_output.patch_metadata_file,
- failure_modes.FailureModes(
- args_output.failure_mode),
- git_hash_source,
- extra_commit_msg=None)
-
- print('Successfully updated packages to %s (%d)' % (git_hash, svn_version))
- print('Gerrit URL: %s' % change_list.url)
- print('Change list number: %d' % change_list.cl_number)
-
-
-if __name__ == '__main__':
- main()
+ """Updates the LLVM next hash for each package.
+
+ Raises:
+ AssertionError: The script was run inside the chroot.
+ """
+
+ chroot.VerifyOutsideChroot()
+
+ args_output = GetCommandLineArgs()
+
+ llvm_variant = LLVMVariant.current
+ if args_output.is_llvm_next:
+ llvm_variant = LLVMVariant.next
+
+ git_hash_source = args_output.llvm_version
+
+ git_hash, svn_version = get_llvm_hash.GetLLVMHashAndVersionFromSVNOption(
+ git_hash_source
+ )
+
+ # Filter out empty strings. For example "".split{",") returns [""].
+ packages = set(p for p in args_output.update_packages.split(",") if p)
+ manifest_packages = set(
+ p for p in args_output.manifest_packages.split(",") if p
+ )
+ if not manifest_packages and not args_output.is_llvm_next:
+ # Set default manifest packages only for the current llvm.
+ manifest_packages = set(DEFAULT_MANIFEST_PACKAGES)
+ change_list = UpdatePackages(
+ packages=packages,
+ manifest_packages=manifest_packages,
+ llvm_variant=llvm_variant,
+ git_hash=git_hash,
+ svn_version=svn_version,
+ chroot_path=args_output.chroot_path,
+ mode=failure_modes.FailureModes(args_output.failure_mode),
+ git_hash_source=git_hash_source,
+ extra_commit_msg=None,
+ )
+
+ print(f"Successfully updated packages to {git_hash} ({svn_version})")
+ print(f"Gerrit URL: {change_list.url}")
+ print(f"Change list number: {change_list.cl_number}")
+
+
+if __name__ == "__main__":
+ main()