xref: /llvm-project/bolt/utils/nfc-check-setup.py (revision 3837e3e6cecb8edbe3fdb2c73fb6cea6a8dc1a28)
1#!/usr/bin/env python3
2import argparse
3import os
4import re
5import shlex
6import subprocess
7import sys
8import textwrap
9
10
11def get_git_ref_or_rev(dir: str) -> str:
12    # Run 'git symbolic-ref -q --short HEAD || git rev-parse --short HEAD'
13    cmd_ref = "git symbolic-ref -q --short HEAD"
14    ref = subprocess.run(
15        shlex.split(cmd_ref), cwd=dir, text=True, stdout=subprocess.PIPE
16    )
17    if not ref.returncode:
18        return ref.stdout.strip()
19    cmd_rev = "git rev-parse --short HEAD"
20    return subprocess.check_output(shlex.split(cmd_rev), cwd=dir, text=True).strip()
21
22
23def main():
24    parser = argparse.ArgumentParser(
25        description=textwrap.dedent(
26            """
27            This script builds two versions of BOLT (with the current and
28            previous revision) and sets up symlink for llvm-bolt-wrapper.
29            Passes the options through to llvm-bolt-wrapper.
30            """
31        )
32    )
33    parser.add_argument(
34        "build_dir",
35        nargs="?",
36        default=os.getcwd(),
37        help="Path to BOLT build directory, default is current " "directory",
38    )
39    parser.add_argument(
40        "--switch-back",
41        default=False,
42        action="store_true",
43        help="Checkout back to the starting revision",
44    )
45    parser.add_argument(
46        "--cmp-rev",
47        default="HEAD^",
48        help="Revision to checkout to compare vs HEAD",
49    )
50    args, wrapper_args = parser.parse_known_args()
51    bolt_path = f"{args.build_dir}/bin/llvm-bolt"
52
53    source_dir = None
54    # find the repo directory
55    with open(f"{args.build_dir}/CMakeCache.txt") as f:
56        for line in f:
57            m = re.match(r"LLVM_SOURCE_DIR:STATIC=(.*)", line)
58            if m:
59                source_dir = m.groups()[0]
60    if not source_dir:
61        sys.exit("Source directory is not found")
62
63    script_dir = os.path.dirname(os.path.abspath(__file__))
64    wrapper_path = f"{script_dir}/llvm-bolt-wrapper.py"
65    # build the current commit
66    subprocess.run(
67        shlex.split("cmake --build . --target llvm-bolt"), cwd=args.build_dir
68    )
69    # rename llvm-bolt
70    os.replace(bolt_path, f"{bolt_path}.new")
71    # memorize the old hash for logging
72    old_ref = get_git_ref_or_rev(source_dir)
73
74    # determine whether a stash is needed
75    stash = subprocess.run(
76        shlex.split("git status --porcelain"),
77        cwd=source_dir,
78        stdout=subprocess.PIPE,
79        stderr=subprocess.STDOUT,
80        text=True,
81    ).stdout
82    if stash:
83        # save local changes before checkout
84        subprocess.run(shlex.split("git stash push -u"), cwd=source_dir)
85    # check out the previous/cmp commit
86    subprocess.run(shlex.split(f"git checkout -f {args.cmp_rev}"), cwd=source_dir)
87    # get the parent commit hash for logging
88    new_ref = get_git_ref_or_rev(source_dir)
89    # build the previous commit
90    subprocess.run(
91        shlex.split("cmake --build . --target llvm-bolt"), cwd=args.build_dir
92    )
93    # rename llvm-bolt
94    os.replace(bolt_path, f"{bolt_path}.old")
95    # set up llvm-bolt-wrapper.ini
96    ini = subprocess.check_output(
97        shlex.split(f"{wrapper_path} {bolt_path}.old {bolt_path}.new") + wrapper_args,
98        text=True,
99    )
100    with open(f"{args.build_dir}/bin/llvm-bolt-wrapper.ini", "w") as f:
101        f.write(ini)
102    # symlink llvm-bolt-wrapper
103    os.symlink(wrapper_path, bolt_path)
104    if args.switch_back:
105        if stash:
106            subprocess.run(shlex.split("git stash pop"), cwd=source_dir)
107        subprocess.run(shlex.split(f"git checkout {old_ref}"), cwd=source_dir)
108    else:
109        print(
110            f"The repository {source_dir} has been switched from {old_ref} "
111            f"to {new_ref}. Local changes were stashed. Switch back using\n\t"
112            f"git checkout {old_ref}\n"
113        )
114    print(
115        f"Build directory {args.build_dir} is ready to run BOLT tests, e.g.\n"
116        "\tbin/llvm-lit -sv tools/bolt/test\nor\n"
117        "\tbin/llvm-lit -sv tools/bolttests"
118    )
119
120
121if __name__ == "__main__":
122    main()
123