Bazel installer: Retry ripunzip step.

Ripunzip is great, but occasionally bugs out due to a parallelism issue.
As we don't want this to fail CI, retry the entire ripunzip/installation step
up to 3 times.
We need to clean up the working directory as ripunzip doesn't support overwriting
files. I've not been able to test this with the original issue (it doesn't seem
to reproduce locally for me), but I injected another error and got 3 retries
of installation.
This commit is contained in:
Cornelius Riemenschneider
2024-07-30 18:20:19 +02:00
parent 31f68d2da8
commit 674a5bb9b4

View File

@@ -13,24 +13,41 @@ 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)")
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`")
@@ -45,13 +62,14 @@ script = runfiles.Rlocation(opts.pkg_install_script)
_WIN_FILE_IN_USE_ERROR_CODE = 32
if destdir.exists() and opts.cleanup:
if platform.system() == 'Windows':
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(destdir)
shutil.rmtree(dir)
break
except OSError as e:
if e.winerror == _WIN_FILE_IN_USE_ERROR_CODE:
@@ -59,21 +77,41 @@ if destdir.exists() and opts.cleanup:
else:
raise
else:
shutil.rmtree(destdir)
shutil.rmtree(dir)
else:
shutil.rmtree(destdir)
shutil.rmtree(dir)
destdir.mkdir(parents=True, exist_ok=True)
subprocess.run([script, "--destdir", destdir], check=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)
subprocess.run([ripunzip, "unzip-file", zip, "-d", dest], check=True)
if destdir.exists() and opts.cleanup:
rmdir(destdir)
class RetryException(Exception):
pass
attempts = 0
success = False
while attempts < 3 and success is False:
destdir.mkdir(parents=True, exist_ok=True)
subprocess.run([script, "--destdir", destdir], check=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...")
attempts += 1
rmdir(destdir)
break
sys.exit(ret.returncode)