mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
117 lines
3.7 KiB
Python
117 lines
3.7 KiB
Python
"""
|
|
Helper script for installing `codeql_pack` targets.
|
|
|
|
This mainly wraps around a `pkg_install` script from `rules_pkg` adding:
|
|
* resolving destination directory with respect to a provided `--build-file`
|
|
* clean-up of target destination directory before a reinstall
|
|
* installing imported zip files using a provided `--ripunzip`
|
|
"""
|
|
|
|
import argparse
|
|
import pathlib
|
|
import shutil
|
|
import subprocess
|
|
import platform
|
|
import time
|
|
import sys
|
|
from python.runfiles import runfiles
|
|
|
|
runfiles = runfiles.Create()
|
|
assert runfiles, "Installer should be run with `bazel run`"
|
|
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument(
|
|
"--destdir",
|
|
type=pathlib.Path,
|
|
required=True,
|
|
help="Desination directory, relative to `--build-file`",
|
|
)
|
|
parser.add_argument(
|
|
"--pkg-install-script",
|
|
required=True,
|
|
help="The wrapped `pkg_install` installation script rlocation",
|
|
)
|
|
parser.add_argument(
|
|
"--build-file",
|
|
help="BUILD.bazel rlocation relative to which the installation should take place",
|
|
)
|
|
parser.add_argument(
|
|
"--ripunzip", help="ripunzip executable rlocation. Must be provided if `--zip-manifest` is."
|
|
)
|
|
parser.add_argument(
|
|
"--zip-manifest",
|
|
help="The rlocation of a file containing newline-separated `prefix:zip_file` entries",
|
|
)
|
|
parser.add_argument(
|
|
"--cleanup",
|
|
action=argparse.BooleanOptionalAction,
|
|
default=True,
|
|
help="Whether to wipe the destination directory before installing (true by default)",
|
|
)
|
|
opts = parser.parse_args()
|
|
if opts.zip_manifest and not opts.ripunzip:
|
|
parser.error("Provide `--ripunzip` when specifying `--zip-manifest`")
|
|
|
|
if opts.build_file:
|
|
build_file = runfiles.Rlocation(opts.build_file)
|
|
destdir = pathlib.Path(build_file).resolve().parent / opts.destdir
|
|
else:
|
|
destdir = pathlib.Path(opts.destdir)
|
|
assert destdir.is_absolute(), "Provide `--build-file` to resolve destination directory"
|
|
script = runfiles.Rlocation(opts.pkg_install_script)
|
|
|
|
_WIN_FILE_IN_USE_ERROR_CODE = 32
|
|
|
|
|
|
def rmdir(dir: pathlib.Path):
|
|
if platform.system() == "Windows":
|
|
# On Windows we might have virus scanner still looking at the path so
|
|
# attempt removal a couple of times sleeping between each attempt.
|
|
for retry_delay in [1, 2, 2]:
|
|
try:
|
|
shutil.rmtree(dir)
|
|
break
|
|
except OSError as e:
|
|
if e.winerror == _WIN_FILE_IN_USE_ERROR_CODE:
|
|
time.sleep(retry_delay)
|
|
else:
|
|
raise
|
|
else:
|
|
shutil.rmtree(dir)
|
|
else:
|
|
shutil.rmtree(dir)
|
|
|
|
|
|
if destdir.exists() and opts.cleanup:
|
|
rmdir(destdir)
|
|
|
|
|
|
attempts = 0
|
|
success = False
|
|
while attempts < 3 and not success:
|
|
attempts += 1
|
|
destdir.mkdir(parents=True, exist_ok=True)
|
|
subprocess.run([script, "--destdir", destdir], check=True)
|
|
success = True
|
|
|
|
if opts.zip_manifest:
|
|
ripunzip = runfiles.Rlocation(opts.ripunzip)
|
|
zip_manifest = runfiles.Rlocation(opts.zip_manifest)
|
|
with open(zip_manifest) as manifest:
|
|
for line in manifest:
|
|
prefix, _, zip = line.partition(":")
|
|
assert zip, f"missing prefix for {prefix}, you should use prefix:zip format"
|
|
zip = zip.strip()
|
|
dest = destdir / prefix
|
|
dest.mkdir(parents=True, exist_ok=True)
|
|
command = [ripunzip, "unzip-file", zip, "-d", dest]
|
|
print(f"Running ", *command)
|
|
ret = subprocess.run(command)
|
|
success = ret.returncode == 0
|
|
if not success:
|
|
print(f"Failed to unzip {zip} to {dest}, retrying installation...")
|
|
rmdir(destdir)
|
|
break
|
|
if not success:
|
|
sys.exit(1)
|