aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Burgess IV <gbiv@google.com>2024-04-16 08:46:20 -0600
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2024-04-17 15:40:14 +0000
commit9e2e613c5ac8d748ee2e64afa5780691ca3dac4a (patch)
tree577ebd06b18737aaaa52d18254b76aa20f413f48
parentd581fd07d429da6ff84cd793722e07df46fcb0ff (diff)
downloadtoolchain-utils-9e2e613c5ac8d748ee2e64afa5780691ca3dac4a.tar.gz
llvm_tools: add upload_llvm_testing_helper_cl.py
This script provides a simple way to upload isolated, 'all-in-one' CLs that make LLVM easier to test. BUG=b:333462347 TEST=Ran the script: crrev.com/c/5457603 Change-Id: I2a107798ab4b2171b98b57634df6081de9dba485 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/5458715 Reviewed-by: Ryan Beltran <ryanbeltran@chromium.org> Commit-Queue: George Burgess <gbiv@chromium.org> Tested-by: George Burgess <gbiv@chromium.org>
-rwxr-xr-xllvm_tools/upload_llvm_testing_helper_cl.py186
-rwxr-xr-xllvm_tools/upload_llvm_testing_helper_cl_test.py69
2 files changed, 255 insertions, 0 deletions
diff --git a/llvm_tools/upload_llvm_testing_helper_cl.py b/llvm_tools/upload_llvm_testing_helper_cl.py
new file mode 100755
index 00000000..d0587044
--- /dev/null
+++ b/llvm_tools/upload_llvm_testing_helper_cl.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+# Copyright 2024 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Uploads an LLVM 'testing helper' CL.
+
+These CLs make the validation of LLVM easier, and do things like:
+- allowing patches to be disabled if they no longer apply
+- disabling warnings
+"""
+
+import argparse
+import logging
+from pathlib import Path
+import subprocess
+import sys
+from typing import List
+
+import chroot
+from cros_utils import git_utils
+
+
+# Text to add to the bottom of ebuild hooks.
+DISABLE_WARNINGS_BLOCK = r"""
+
+# Disable -Werror where possible, so more serious issues (e.g., compiler
+# crashes) can be more easily surfaced.
+cros_pre_src_configure_disable_werror() {
+ # Add the special env var to toolchain/fatal_clang_warnings. There's logic
+ # in Chromite to search for & upload these directories on all builds,
+ # including failing ones.
+ local d="${CROS_ARTIFACTS_TMP_DIR}/toolchain/fatal_clang_warnings"
+ export CFLAGS+=" -D_CROSTC_FORCE_DISABLE_WERROR=${d} "
+ export CXXFLAGS+=" -D_CROSTC_FORCE_DISABLE_WERROR=${d} "
+ # Set these for ec ebuilds, since those ignore CFLAGS/CXXFLAGS
+ [[ -n "${_ECLASS_CROS_EC:-}" ]] && export EXTRA_CFLAGS+=" -D_CROSTC_FORCE_DISABLE_WERROR=${d} "
+
+ # Also export an env var, since some build systems will ignore our CFLAGS
+ # but not filter the environment.
+ export FORCE_DISABLE_WERROR=1
+}
+"""
+
+# Text to add to the bottom of `profiles/base/use.force`.
+USE_FORCE_BLOCK = r"""
+
+# Force patch disabling, rather than failing to build LLVM and its subpackages.
+# Without this, we'll lose signal on builders where any patch fails to apply.
+continue-on-patch-failure
+"""
+
+COMMIT_MESSAGE = """\
+DO NOT COMMIT: llvm-testing helper CL
+
+This CL was automatically generated to facilitate LLVM testing.
+The script that generated this is located at
+src/third_party/toolchain-utils/llvm_tools/upload_llvm_testing_helper_cl.py.
+
+BUG=None
+TEST=None
+"""
+
+
+def add_force_rebuild_marker(chromiumos_overlay: Path):
+ """Adds a marker to force this change to appear as a toolchain change."""
+ # `touch`ing anything in `sys-devel/llvm/files` causes an LLVM revbump, and
+ # causes all packages to be rebuilt.
+ force_rebuild_file = (
+ chromiumos_overlay / "sys-devel" / "llvm" / "files" / "force_rebuild"
+ )
+ force_rebuild_file.touch()
+
+
+def add_use_force_block(chromiumos_overlay: Path):
+ use_force = chromiumos_overlay / "profiles" / "base" / "use.force"
+ # If this doesn't exist, that _can_ be worked with, but it's a smoke signal
+ # (since e.g., maybe the file no longer takes effect). Have someone
+ # investigate.
+ if not use_force.exists():
+ raise ValueError(f"No file found at {use_force}; refusing to patch")
+ with use_force.open("a", encoding="utf-8") as f:
+ f.write(USE_FORCE_BLOCK)
+
+
+def add_disable_warnings_block(chromiumos_overlay: Path):
+ ebuild_hooks = chromiumos_overlay / "profiles" / "base" / "profile.bashrc"
+ # If this doesn't exist, that _can_ be worked with, but it's a smoke signal
+ # (since e.g., maybe the file no longer takes effect). Have someone
+ # investigate.
+ if not ebuild_hooks.exists():
+ raise ValueError(f"No file found at {ebuild_hooks}; refusing to patch")
+ with ebuild_hooks.open("a", encoding="utf-8") as f:
+ f.write(DISABLE_WARNINGS_BLOCK)
+
+
+def commit_all_changes(git_dir: Path, message: str) -> str:
+ """Commits all changes in `git_dir`, with the given commit message."""
+ # Explicitly add using `git add -A`, since that stages all unstaged changes
+ # & adds any files that aren't tracked. `git commit -a` skips adding
+ # untracked files.
+ subprocess.run(
+ ["git", "add", "-A"],
+ check=True,
+ cwd=git_dir,
+ stdin=subprocess.DEVNULL,
+ )
+ subprocess.run(
+ ["git", "commit", "-m", message],
+ check=True,
+ cwd=git_dir,
+ stdin=subprocess.DEVNULL,
+ )
+ return subprocess.run(
+ ["git", "rev-parse", "HEAD"],
+ check=True,
+ cwd=git_dir,
+ stdin=subprocess.DEVNULL,
+ stdout=subprocess.PIPE,
+ encoding="utf-8",
+ ).stdout.strip()
+
+
+def create_helper_cl_commit_in_worktree_of(chromiumos_overlay: Path) -> str:
+ """Creates a commit containing the helper CL diff. Returns the SHA.commit"""
+ with git_utils.create_worktree(chromiumos_overlay) as worktree:
+ logging.info("Adding helper changes to CL in %s...", worktree)
+ add_force_rebuild_marker(worktree)
+ add_use_force_block(worktree)
+ add_disable_warnings_block(worktree)
+ return commit_all_changes(worktree, COMMIT_MESSAGE)
+
+
+def main(argv: List[str]) -> None:
+ logging.basicConfig(
+ format=">> %(asctime)s: %(levelname)s: %(filename)s:%(lineno)d: "
+ "%(message)s",
+ level=logging.INFO,
+ )
+
+ my_dir = Path(__file__).parent.resolve()
+ parser = argparse.ArgumentParser(
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ )
+ parser.add_argument(
+ "--chromeos-tree",
+ type=Path,
+ help="""
+ The ChromeOS tree to update in. The `llvm-project` directory of this
+ may also be consulted. Will try to autodetect if none is specified.
+ """,
+ )
+ parser.add_argument(
+ "--dry-run",
+ action="store_true",
+ help="Commit changes, but don't actually upload them.",
+ )
+ opts = parser.parse_args(argv)
+
+ chromeos_tree = opts.chromeos_tree
+ if not chromeos_tree:
+ chromeos_tree = chroot.FindChromeOSRootAbove(my_dir)
+
+ chromiumos_overlay = (
+ chromeos_tree / "src" / "third_party" / "chromiumos-overlay"
+ )
+ helper_sha = create_helper_cl_commit_in_worktree_of(chromiumos_overlay)
+ if opts.dry_run:
+ logging.info(
+ "--dry-run specified; not uploading new commit (%s).",
+ helper_sha,
+ )
+ return
+
+ # This logs the CL information, so no need to print anything after this.
+ git_utils.upload_to_gerrit(
+ git_repo=chromiumos_overlay,
+ remote="cros",
+ branch="main",
+ ref=helper_sha,
+ )
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/llvm_tools/upload_llvm_testing_helper_cl_test.py b/llvm_tools/upload_llvm_testing_helper_cl_test.py
new file mode 100755
index 00000000..63951a59
--- /dev/null
+++ b/llvm_tools/upload_llvm_testing_helper_cl_test.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+# Copyright 2024 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for upload_llvm_testing_helper_cl"""
+
+from pathlib import Path
+import shutil
+import tempfile
+import unittest
+
+import upload_llvm_testing_helper_cl
+
+
+class Test(unittest.TestCase):
+ """Tests for upload_llvm_testing_helper_cl"""
+
+ def make_tempdir(self) -> Path:
+ tempdir = tempfile.mkdtemp(
+ os.path.basename("upload_llvm_testing_helper_cl_test")
+ )
+ self.addCleanup(shutil.rmtree, tempdir)
+ return Path(tempdir)
+
+ def test_force_rebuild_marker_addition(self):
+ chromiumos_overlay = self.make_tempdir()
+ filesdir = chromiumos_overlay / "sys-devel" / "llvm" / "files"
+ filesdir.mkdir(parents=True)
+ upload_llvm_testing_helper_cl.add_force_rebuild_marker(
+ chromiumos_overlay
+ )
+ self.assertTrue((filesdir / "force_rebuild").exists())
+
+ def test_use_force_block_addition(self):
+ chromiumos_overlay = self.make_tempdir()
+ use_force_file = chromiumos_overlay / "profiles" / "base" / "use.force"
+ use_force_file.parent.mkdir(parents=True)
+ use_force_file.write_text("# Whee", encoding="utf-8")
+
+ upload_llvm_testing_helper_cl.add_use_force_block(chromiumos_overlay)
+ new_contents = use_force_file.read_text(encoding="utf-8")
+
+ self.assertIn("# Whee\n", new_contents)
+ self.assertIn(
+ upload_llvm_testing_helper_cl.USE_FORCE_BLOCK, new_contents
+ )
+
+ def test_warning_disable_block_addition(self):
+ chromiumos_overlay = self.make_tempdir()
+ profile_bashrc = (
+ chromiumos_overlay / "profiles" / "base" / "profile.bashrc"
+ )
+ profile_bashrc.parent.mkdir(parents=True)
+ profile_bashrc.write_text("# Whee", encoding="utf-8")
+
+ upload_llvm_testing_helper_cl.add_disable_warnings_block(
+ chromiumos_overlay
+ )
+ new_contents = profile_bashrc.read_text(encoding="utf-8")
+
+ self.assertIn("# Whee\n", new_contents)
+ self.assertIn(
+ upload_llvm_testing_helper_cl.DISABLE_WARNINGS_BLOCK, new_contents
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()