-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathinstall.py
More file actions
116 lines (103 loc) · 3.7 KB
/
install.py
File metadata and controls
116 lines (103 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
"""
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)