llvm_tools: uprev ebuilds for LLVM roll CLs
Currently update_chromeos_llvm_hash.py uprevs ebuild files by increasing
the -r*.ebuild by 1. This patch renames the ebuild files with the new
SVN reversion and date for LLVM roll CLs.
BUG=chromium:1041590
TEST=local tests.
Change-Id: I209191f7d34594010914afb54d4c346e3f13c6fa
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/2139094
Reviewed-by: Manoj Gupta <manojgupta@chromium.org>
Tested-by: Jian Cai <jiancai@google.com>
diff --git a/llvm_tools/README.md b/llvm_tools/README.md
index 07c1165..d42462a 100644
--- a/llvm_tools/README.md
+++ b/llvm_tools/README.md
@@ -64,11 +64,11 @@
--builders kevin-release-tryjob nocturne-release-tryjob
```
-## `update_chromeos_llvm_next_hash.py`
+## `update_chromeos_llvm_hash.py`
### Usage
-This script is used for updating a package's/packages' `LLVM_NEXT_HASH` and
+This script is used for updating a package's/packages' LLVM hashes and
creating a change list of those changes which will uploaded for review. For
example, some changes that would be included in the change list are
the updated ebuilds, changes made to the patches of the updated packages such
@@ -81,13 +81,14 @@
For example:
```
-$ ./update_chromeos_llvm_next_hash.py \
+$ ./update_chromeos_llvm_hash.py \
--update_packages sys-devel/llvm sys-libs/compiler-rt \
+ --is_llvm_next \
--llvm_version google3 \
--failure_mode disable_patches
```
-The example above would update sys-devel/llvm and sys-libs/compiler-rt
+The example above would update sys-devel/llvm and sys-libs/compiler-rt's
`LLVM_NEXT_HASH` to the latest google3's git hash of LLVM. And the change list
may include patches that were disabled for either sys-devel/llvm or
sys-libs/compiler-rt.
@@ -95,23 +96,24 @@
For help with the command line arguments of the script, run:
```
-$ ./update_chromeos_llvm_next.py --help
+$ ./update_chromeos_llvm_hash.py --help
```
-For example, to update `LLVM_NEXT_HASH` to top of trunk of LLVM:
+For example, to update `LLVM_HASH` to top of trunk of LLVM:
```
-$ ./update_chromeos_llvm_next_hash.py \
+$ ./update_chromeos_llvm_hash.py \
--update_packages sys-devel/llvm sys-libs/compiler-rt \
--llvm_version tot \
--failure_mode disable_patches
```
-For example, to update `LLVM_NEXT_HASH` to the git hash of revision 367622:
+For example, to create a roll CL to the git hash of revision 367622:
```
-$ ./update_chromeos_llvm_next_hash.py \
+$ ./update_chromeos_llvm_hash.py \
--update_packages sys-devel/llvm sys-libs/compiler-rt \
+ sys-libs/libcxx sys-libs/libcxxabi sys-libs/llvm-libunwind \
--llvm_version 367622 \
--failure_mode disable_patches
```
diff --git a/llvm_tools/update_chromeos_llvm_hash.py b/llvm_tools/update_chromeos_llvm_hash.py
index 916eb67..c18e72f 100755
--- a/llvm_tools/update_chromeos_llvm_hash.py
+++ b/llvm_tools/update_chromeos_llvm_hash.py
@@ -14,6 +14,7 @@
from __future__ import print_function
from collections import namedtuple
+from datetime import datetime
from enum import Enum
import argparse
@@ -89,10 +90,8 @@
parser.add_argument(
'--is_llvm_next',
action='store_true',
- help=
- 'which llvm hash to update. Update LLVM_NEXT_HASH specified. ' \
- 'Otherwise, update LLVM_HASH'
- )
+ 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(
@@ -313,15 +312,14 @@
raise ValueError('Failed to update %s' % llvm_variant.value)
-def UprevEbuild(symlink):
- """Uprevs the ebuild's revision number.
+def UprevEbuildSymlink(symlink):
+ """Uprevs the symlink's revision number.
Increases the revision number by 1 and stages the change in
the temporary repo.
Args:
- symlink: The absolute path of the symlink that points to
- the ebuild of the package.
+ symlink: The absolute path of an ebuild symlink.
Raises:
ValueError: Failed to uprev the symlink or failed to stage the changes.
@@ -330,24 +328,84 @@
if not os.path.islink(symlink):
raise ValueError('Invalid symlink provided: %s' % symlink)
- # Find the revision number and increment it by 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.')
+
+ symlink_dirname = os.path.dirname(symlink)
+
+ # rename the symlink
+ cmd = ['git', '-C', symlink_dirname, 'mv', symlink, new_symlink]
+
+ ExecCommandAndCaptureOutput(cmd, verbose=verbose)
+
+
+def UprevEbuildToVersion(symlink, svn_version):
+ """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.
+
+ Raises:
+ ValueError: Failed to uprev the ebuild or failed to stage the changes.
+ """
+
+ if not os.path.islink(symlink):
+ raise ValueError('Invalid symlink provided: %s' % symlink)
+
+ ebuild = os.path.realpath(symlink)
+ # llvm
+ package = os.path.basename(os.path.dirname(symlink))
+ if not package:
+ raise ValueError('Tried to uprev an unknown package')
+ # llvm
+ if package == 'llvm':
+ new_ebuild, is_changed = re.subn(
+ r'pre([0-9]+)_p([0-9]+)',
+ 'pre%s_p%s' % (svn_version, \
+ datetime.today().strftime('%Y%m%d')),
+ ebuild,
+ count=1)
+ # any other package
+ else:
+ new_ebuild, is_changed = re.subn(
+ r'pre([0-9]+)',
+ 'pre%s' % (datetime.today().strftime('%Y%m%d')),
+ ebuild,
+ count=1)
+
if not is_changed: # failed to increment the revision number
raise ValueError('Failed to uprev the ebuild.')
- path_to_symlink_dir = os.path.dirname(symlink)
+ symlink_dirname = os.path.dirname(symlink)
- # Stage the new symlink for commit.
- stage_symlink_cmd = [
- 'git', '-C', path_to_symlink_dir, 'mv', symlink, new_symlink
- ]
+ # Rename the ebuild
+ cmd = ['git', '-C', symlink_dirname, 'mv', ebuild, new_ebuild]
+ ExecCommandAndCaptureOutput(cmd, verbose=verbose)
- ExecCommandAndCaptureOutput(stage_symlink_cmd, verbose=verbose)
+ # Create a symlink of the renamed ebuild
+ new_symlink = new_ebuild[:-len('.ebuild')] + '-r1.ebuild'
+ cmd = ['ln', '-s', new_ebuild, new_symlink]
+ ExecCommandAndCaptureOutput(cmd, verbose=verbose)
+
+ if not os.path.islink(new_symlink):
+ raise ValueError('Invalid symlink name: %s' % new_ebuild[:-len('.ebuild')])
+
+ cmd = ['git', '-C', symlink_dirname, 'add', new_symlink]
+ ExecCommandAndCaptureOutput(cmd, verbose=verbose)
+
+ # Remove the old symlink
+ cmd = ['git', '-C', symlink_dirname, 'rm', symlink]
+ ExecCommandAndCaptureOutput(cmd, verbose=verbose)
def _CreateRepo(path_to_repo_dir, branch):
@@ -636,6 +694,7 @@
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
@@ -685,7 +744,10 @@
UpdateEbuildLLVMHash(ebuild_path, llvm_variant, git_hash, svn_version)
- UprevEbuild(symlink_path)
+ if llvm_variant == LLVMVariant.current:
+ UprevEbuildToVersion(symlink_path, svn_version)
+ 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))
diff --git a/llvm_tools/update_chromeos_llvm_hash_unittest.py b/llvm_tools/update_chromeos_llvm_hash_unittest.py
index b29b078..b6d8c5d 100755
--- a/llvm_tools/update_chromeos_llvm_hash_unittest.py
+++ b/llvm_tools/update_chromeos_llvm_hash_unittest.py
@@ -9,7 +9,9 @@
from __future__ import print_function
from collections import namedtuple
+from datetime import datetime
import os
+import re
import subprocess
import unittest
import unittest.mock as mock
@@ -88,10 +90,7 @@
mock_islink):
symlink_path = '/path/to/chroot/src/package-r1.ebuild'
-
abs_path_to_package = '/abs/path/to/src/package.ebuild'
-
- # Simulate 'os.path.realpath' when a valid path is passed in.
mock_realpath.return_value = abs_path_to_package
expected_resolved_paths = {symlink_path: abs_path_to_package}
@@ -265,61 +264,137 @@
mock_stage_commit_command.assert_called_once()
- # Simulate behavior of 'os.path.islink()' when the argument passed in is not a
- # symbolic link.
@mock.patch.object(os.path, 'islink', return_value=False)
- def testFailedToUprevEbuildForInvalidSymlink(self, mock_islink):
- symlink_to_uprev = '/symlink/to/package.ebuild'
+ def testFailedToUprevEbuildToVersionForInvalidSymlink(self, mock_islink):
+ symlink_path = '/path/to/chroot/package/package.ebuild'
+ svn_version = 1000
- # Verify the exception is raised when a symbolic link is not passed in.
+ # Verify the exception is raised when a invalid symbolic link is passed in.
with self.assertRaises(ValueError) as err:
- update_chromeos_llvm_hash.UprevEbuild(symlink_to_uprev)
+ update_chromeos_llvm_hash.UprevEbuildToVersion(symlink_path, svn_version)
self.assertEqual(
- str(err.exception), 'Invalid symlink provided: %s' % symlink_to_uprev)
+ str(err.exception), 'Invalid symlink provided: %s' % symlink_path)
+
+ mock_islink.assert_called_once()
+
+ @mock.patch.object(os.path, 'islink', return_value=False)
+ def testFailedToUprevEbuildSymlinkForInvalidSymlink(self, mock_islink):
+ symlink_path = '/path/to/chroot/package/package.ebuild'
+
+ # Verify the exception is raised when a invalid symbolic link is passed in.
+ with self.assertRaises(ValueError) as err:
+ update_chromeos_llvm_hash.UprevEbuildSymlink(symlink_path)
+
+ self.assertEqual(
+ str(err.exception), 'Invalid symlink provided: %s' % symlink_path)
mock_islink.assert_called_once()
# Simulate 'os.path.islink' when a symbolic link is passed in.
@mock.patch.object(os.path, 'islink', return_value=True)
- def testFailedToUprevEbuild(self, mock_islink):
- symlink_to_uprev = '/symlink/to/package.ebuild'
+ # Simulate 'os.path.realpath' when a symbolic link is passed in.
+ @mock.patch.object(os.path, 'realpath', return_value=True)
+ def testFailedToUprevEbuildToVersion(self, mock_realpath, mock_islink):
+ symlink_path = '/path/to/chroot/llvm/llvm_pre123_p.ebuild'
+ mock_realpath.return_value = '/abs/path/to/llvm/llvm_pre123_p.ebuild'
+ svn_version = 1000
- # Verify the exception is raised when the symlink does not have a revision
- # number.
+ # Verify the exception is raised when the symlink does not match the
+ # expected pattern
with self.assertRaises(ValueError) as err:
- update_chromeos_llvm_hash.UprevEbuild(symlink_to_uprev)
+ update_chromeos_llvm_hash.UprevEbuildToVersion(symlink_path, svn_version)
self.assertEqual(str(err.exception), 'Failed to uprev the ebuild.')
- mock_islink.assert_called_once_with(symlink_to_uprev)
+ mock_islink.assert_called_once_with(symlink_path)
+
+ # Simulate 'os.path.islink' when a symbolic link is passed in.
+ @mock.patch.object(os.path, 'islink', return_value=True)
+ def testFailedToUprevEbuildSymlink(self, mock_islink):
+ symlink_path = '/path/to/chroot/llvm/llvm_pre123_p.ebuild'
+
+ # Verify the exception is raised when the symlink does not match the
+ # expected pattern
+ with self.assertRaises(ValueError) as err:
+ update_chromeos_llvm_hash.UprevEbuildSymlink(symlink_path)
+
+ self.assertEqual(str(err.exception), 'Failed to uprev the symlink.')
+
+ mock_islink.assert_called_once_with(symlink_path)
# Simulate 'os.path.islink' when a valid symbolic link is passed in.
@mock.patch.object(os.path, 'islink', return_value=True)
- # Simulate 'os.path.dirname' when returning a path to the directory of a
- # valid symbolic link.
- @mock.patch.object(os.path, 'dirname', return_value='/symlink/to')
+ @mock.patch.object(os.path, 'realpath')
# Simulate 'RunCommandWOutput' when successfully added the upreved symlink
# for commit.
@mock.patch.object(
update_chromeos_llvm_hash,
'ExecCommandAndCaptureOutput',
return_value=None)
- def testSuccessfullyUprevEbuild(self, mock_command_output, mock_dirname,
- mock_islink):
+ def testSuccessfullyUprevEbuildToVersion(self, mock_command_output,
+ mock_realpath, mock_islink):
+ symlink = '/symlink/to/llvm/llvm_pre3_p2-r10.ebuild'
+ ebuild = '/abs/path/to/llvm_pre3_p2.ebuild'
+ mock_realpath.return_value = ebuild
+ svn_version = 1000
+ update_chromeos_llvm_hash.UprevEbuildToVersion(symlink, svn_version)
+
+ mock_islink.assert_called()
+
+ mock_realpath.assert_called_once_with(symlink)
+
+ mock_command_output.assert_called()
+
+ # Verify commands
+ symlink_dir = os.path.dirname(symlink)
+ new_ebuild, _is_changed = re.subn(
+ r'pre([0-9]+)_p([0-9]+)',
+ 'pre%s_p%s' % (svn_version, \
+ datetime.today().strftime('%Y%m%d')),
+ ebuild,
+ count=1)
+ new_symlink = new_ebuild[:-len('.ebuild')] + '-r1.ebuild'
+
+ expected_cmd = ['git', '-C', symlink_dir, 'mv', ebuild, new_ebuild]
+ self.assertEqual(mock_command_output.call_args_list[0],
+ mock.call(expected_cmd, verbose=False))
+
+ expected_cmd = ['ln', '-s', new_ebuild, new_symlink]
+ self.assertEqual(mock_command_output.call_args_list[1],
+ mock.call(expected_cmd, verbose=False))
+
+ expected_cmd = ['git', '-C', symlink_dir, 'add', new_symlink]
+ self.assertEqual(mock_command_output.call_args_list[2],
+ mock.call(expected_cmd, verbose=False))
+
+ expected_cmd = ['git', '-C', symlink_dir, 'rm', symlink]
+ self.assertEqual(mock_command_output.call_args_list[3],
+ mock.call(expected_cmd, verbose=False))
+
+ # Simulate 'os.path.islink' when a valid symbolic link is passed in.
+ @mock.patch.object(os.path, 'islink', return_value=True)
+ # Simulate 'RunCommandWOutput' when successfully added the upreved symlink
+ # for commit.
+ @mock.patch.object(
+ update_chromeos_llvm_hash,
+ 'ExecCommandAndCaptureOutput',
+ return_value=None)
+ def testSuccessfullyUprevEbuildSymlink(self, mock_command_output,
+ mock_islink):
symlink_to_uprev = '/symlink/to/package-r1.ebuild'
- update_chromeos_llvm_hash.UprevEbuild(symlink_to_uprev)
+ update_chromeos_llvm_hash.UprevEbuildSymlink(symlink_to_uprev)
mock_islink.assert_called_once_with(symlink_to_uprev)
- mock_dirname.assert_called_once_with(symlink_to_uprev)
-
mock_command_output.assert_called_once()
# Simulate behavior of 'os.path.isdir()' when the path to the repo is not a
+
# directory.
+
@mock.patch.object(os.path, 'isdir', return_value=False)
def testFailedToCreateRepoForInvalidDirectoryPath(self, mock_isdir):
path_to_repo = '/path/to/repo'
@@ -755,12 +830,14 @@
'CreatePathDictionaryFromPackages')
@mock.patch.object(update_chromeos_llvm_hash, '_CreateRepo')
@mock.patch.object(update_chromeos_llvm_hash, 'UpdateEbuildLLVMHash')
- @mock.patch.object(update_chromeos_llvm_hash, 'UprevEbuild')
+ @mock.patch.object(update_chromeos_llvm_hash, 'UprevEbuildSymlink')
@mock.patch.object(update_chromeos_llvm_hash, 'UploadChanges')
@mock.patch.object(update_chromeos_llvm_hash, '_DeleteRepo')
+ @mock.patch.object(os.path, 'realpath')
def testExceptionRaisedWhenUpdatingPackages(
- self, mock_delete_repo, mock_upload_changes, mock_uprev_ebuild,
- mock_update_llvm_next, mock_create_repo, mock_create_path_dict):
+ self, mock_realpath, mock_delete_repo, mock_upload_changes,
+ mock_uprev_symlink, mock_update_llvm_next, mock_create_repo,
+ mock_create_path_dict):
abs_path_to_package = '/some/path/to/chroot/src/path/to/package.ebuild'
@@ -783,9 +860,9 @@
self.assertEqual(svn_version, 1000)
return
- # Test function to simulate 'UprevEbuild' when the symlink to the ebuild
- # does not have a revision number.
- def FailedToUprevEbuild(_symlink_path):
+ # Test function to simulate 'UprevEbuildSymlink' when the symlink to the
+ # ebuild does not have a revision number.
+ def FailedToUprevEbuildSymlink(_symlink_path):
# Raises a 'ValueError' exception because the symlink did not have have a
# revision number.
raise ValueError('Failed to uprev the ebuild.')
@@ -794,7 +871,7 @@
# when an exception is raised.
def ShouldNotExecuteUploadChanges(_repo_path, _git_hash, _commit_messages):
# Test function should not be called (i.e. execution should resume in the
- # 'finally' block) because 'UprevEbuild()' raised an
+ # 'finally' block) because 'UprevEbuildSymlink' raised an
# exception.
assert False, 'Failed to go to "finally" block ' \
'after the exception was raised.'
@@ -810,8 +887,9 @@
# Use test function to simulate behavior.
mock_create_repo.side_effect = SuccessfullyCreateRepoForChanges
mock_update_llvm_next.side_effect = SuccessfullyUpdatedLLVMHash
- mock_uprev_ebuild.side_effect = FailedToUprevEbuild
+ mock_uprev_symlink.side_effect = FailedToUprevEbuildSymlink
mock_upload_changes.side_effect = ShouldNotExecuteUploadChanges
+ mock_realpath.return_value = '/abs/path/to/test-packages/package1.ebuild'
packages_to_update = ['test-packages/package1']
llvm_variant = update_chromeos_llvm_hash.LLVMVariant.next
@@ -824,7 +902,7 @@
extra_commit_msg = None
# Verify exception is raised when an exception is thrown within
- # the 'try' block by UprevEbuild function.
+ # the 'try' block by UprevEbuildSymlink function.
with self.assertRaises(ValueError) as err:
update_chromeos_llvm_hash.UpdatePackages(
packages_to_update, llvm_variant, git_hash, svn_version, chroot_path,
@@ -841,7 +919,7 @@
mock_update_llvm_next.assert_called_once_with(
abs_path_to_package, llvm_variant, git_hash, svn_version)
- mock_uprev_ebuild.assert_called_once_with(symlink_path_to_package)
+ mock_uprev_symlink.assert_called_once_with(symlink_path_to_package)
mock_upload_changes.assert_not_called()
@@ -851,7 +929,7 @@
'CreatePathDictionaryFromPackages')
@mock.patch.object(update_chromeos_llvm_hash, '_CreateRepo')
@mock.patch.object(update_chromeos_llvm_hash, 'UpdateEbuildLLVMHash')
- @mock.patch.object(update_chromeos_llvm_hash, 'UprevEbuild')
+ @mock.patch.object(update_chromeos_llvm_hash, 'UprevEbuildSymlink')
@mock.patch.object(update_chromeos_llvm_hash, 'UploadChanges')
@mock.patch.object(update_chromeos_llvm_hash, '_DeleteRepo')
@mock.patch.object(llvm_patch_management, 'UpdatePackagesPatchMetadataFile')
@@ -859,7 +937,7 @@
'StagePatchMetadataFileForCommit')
def testSuccessfullyUpdatedPackages(
self, mock_stage_patch_file, mock_update_package_metadata_file,
- mock_delete_repo, mock_upload_changes, mock_uprev_ebuild,
+ mock_delete_repo, mock_upload_changes, mock_uprev_symlink,
mock_update_llvm_next, mock_create_repo, mock_create_path_dict):
abs_path_to_package = '/some/path/to/chroot/src/path/to/package.ebuild'
@@ -884,9 +962,9 @@
self.assertEqual(svn_version, 1000)
return
- # Test function to simulate 'UprevEbuild' when successfully incremented
- # the revision number by 1.
- def SuccessfullyUprevedEbuild(symlink_path):
+ # Test function to simulate 'UprevEbuildSymlink' when successfully
+ # incremented the revision number by 1.
+ def SuccessfullyUprevedEbuildSymlink(symlink_path):
self.assertEqual(symlink_path,
'/some/path/to/chroot/src/path/to/package-r1.ebuild')
@@ -943,7 +1021,7 @@
# Use test function to simulate behavior.
mock_create_repo.side_effect = SuccessfullyCreateRepoForChanges
mock_update_llvm_next.side_effect = SuccessfullyUpdatedLLVMHash
- mock_uprev_ebuild.side_effect = SuccessfullyUprevedEbuild
+ mock_uprev_symlink.side_effect = SuccessfullyUprevedEbuildSymlink
mock_update_package_metadata_file.side_effect = RetrievedPatchResults
mock_upload_changes.side_effect = SuccessfullyUploadedChanges
@@ -975,7 +1053,7 @@
mock_update_llvm_next.assert_called_once_with(
abs_path_to_package, llvm_variant, git_hash, svn_version)
- mock_uprev_ebuild.assert_called_once_with(symlink_path_to_package)
+ mock_uprev_symlink.assert_called_once_with(symlink_path_to_package)
expected_commit_messages = [
'llvm-next/tot: upgrade to a123testhash5 (r1000)\n',