mirror of https://github.com/mongodb/mongo
214 lines
7.9 KiB
Python
Executable File
214 lines
7.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import hashlib
|
|
import os
|
|
import platform
|
|
import shutil
|
|
import stat
|
|
import sys
|
|
import time
|
|
import urllib.request
|
|
|
|
_S3_HASH_MAPPING = {
|
|
"https://mdb-build-public.s3.amazonaws.com/bazelisk-binaries/v1.19.0/bazelisk-darwin-amd64": "f2ba5f721a995b54bab68c6b76a340719888aa740310e634771086b6d1528ecd",
|
|
"https://mdb-build-public.s3.amazonaws.com/bazelisk-binaries/v1.19.0/bazelisk-darwin-arm64": "69fa21cd2ccffc2f0970c21aa3615484ba89e3553ecce1233a9d8ad9570d170e",
|
|
"https://mdb-build-public.s3.amazonaws.com/bazelisk-binaries/v1.19.0/bazelisk-linux-amd64": "d28b588ac0916abd6bf02defb5433f6eddf7cba35ffa808eabb65a44aab226f7",
|
|
"https://mdb-build-public.s3.amazonaws.com/bazelisk-binaries/v1.19.0/bazelisk-linux-arm64": "861a16ba9979613e70bd3d2f9d9ab5e3b59fe79471c5753acdc9c431ab6c9d94",
|
|
"https://mdb-build-public.s3.amazonaws.com/bazelisk-binaries/v1.19.0/bazelisk-windows-amd64.exe": "d04555245a99dfb628e33da24e2b9198beb8f46d7e7661c313eb045f6a59f5e4",
|
|
}
|
|
|
|
BUILDOZER_RELEASE_URL = "https://github.com/bazelbuild/buildtools/releases/download/v7.3.1/"
|
|
|
|
|
|
def determine_platform():
|
|
syst = platform.system()
|
|
pltf = None
|
|
if syst == "Darwin":
|
|
pltf = "darwin"
|
|
elif syst == "Windows":
|
|
pltf = "windows"
|
|
elif syst == "Linux":
|
|
pltf = "linux"
|
|
else:
|
|
return None
|
|
return pltf
|
|
|
|
|
|
def determine_architecture():
|
|
arch = None
|
|
machine = platform.machine()
|
|
if machine in ("AMD64", "x86_64"):
|
|
arch = "amd64"
|
|
elif machine in ("arm", "arm64", "aarch64"):
|
|
arch = "arm64"
|
|
else:
|
|
return None
|
|
|
|
return arch
|
|
|
|
|
|
def _download_path_with_retry(*args, **kwargs):
|
|
for i in range(5):
|
|
try:
|
|
return urllib.request.urlretrieve(*args, **kwargs)
|
|
except Exception as e:
|
|
print(f"Download failed: {e}")
|
|
if i == 4:
|
|
raise
|
|
print("Retrying download...")
|
|
time.sleep(3)
|
|
continue
|
|
|
|
|
|
def _sha256_file(filename: str) -> str:
|
|
sha256_hash = hashlib.sha256()
|
|
with open(filename, "rb") as f:
|
|
for block in iter(lambda: f.read(4096), b""):
|
|
sha256_hash.update(block)
|
|
return sha256_hash.hexdigest()
|
|
|
|
|
|
def _verify_s3_hash(s3_path: str, local_path: str) -> None:
|
|
hash_string = _sha256_file(local_path)
|
|
if hash_string != _S3_HASH_MAPPING[s3_path]:
|
|
raise Exception(
|
|
f"Hash mismatch for {s3_path}, expected {_S3_HASH_MAPPING[s3_path]} but got {hash_string}"
|
|
)
|
|
|
|
|
|
def install_buildozer(download_location: str = "./"):
|
|
operating_system = determine_platform()
|
|
architechture = determine_architecture()
|
|
if operating_system is None or architechture is None:
|
|
print("Unsupported OS for buildozer, not installing.")
|
|
return None
|
|
|
|
if operating_system == "windows" and architechture == "arm64":
|
|
print("There are no published arm windows releases for buildifier.")
|
|
return None
|
|
|
|
extension = ".exe" if operating_system == "windows" else ""
|
|
binary_name = f"buildozer-{operating_system}-{architechture}{extension}"
|
|
url = f"{BUILDOZER_RELEASE_URL}{binary_name}"
|
|
|
|
file_location = os.path.join(download_location, f"buildozer{extension}")
|
|
_download_path_with_retry(url, file_location)
|
|
os.chmod(file_location, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
|
return file_location
|
|
|
|
|
|
def install_bazel(binary_directory: str) -> str:
|
|
install_buildozer(binary_directory)
|
|
normalized_arch = (
|
|
platform.machine().lower().replace("aarch64", "arm64").replace("x86_64", "amd64")
|
|
)
|
|
normalized_os = sys.platform.replace("win32", "windows").replace("darwin", "macos")
|
|
is_bazelisk_supported = normalized_arch not in ["ppc64le", "s390x"]
|
|
binary_filename = "bazelisk"
|
|
binary_path = os.path.join(binary_directory, binary_filename)
|
|
if os.path.exists(binary_path):
|
|
print(f"{binary_filename} already exists ({binary_path}), skipping download")
|
|
_set_bazel_permissions(binary_path)
|
|
return binary_path
|
|
|
|
if is_bazelisk_supported:
|
|
print(f"Downloading {binary_filename}...")
|
|
ext = ".exe" if normalized_os == "windows" else ""
|
|
os_str = normalized_os.replace("macos", "darwin")
|
|
s3_path = f"https://mdb-build-public.s3.amazonaws.com/bazelisk-binaries/v1.19.0/bazelisk-{os_str}-{normalized_arch}{ext}"
|
|
_download_path_with_retry(s3_path, binary_path)
|
|
_verify_s3_hash(s3_path, binary_path)
|
|
print(f"Downloaded {binary_filename} to {binary_path}")
|
|
|
|
else:
|
|
print("Using bazel/bazelisk.py on unsupported platform.")
|
|
repo_dir = os.path.dirname(os.path.dirname(__file__))
|
|
bazelisk_py = os.path.join(repo_dir, "bazel", "bazelisk.py")
|
|
shutil.copyfile(bazelisk_py, binary_path)
|
|
|
|
_set_bazel_permissions(binary_path)
|
|
return binary_path
|
|
|
|
|
|
def _set_bazel_permissions(binary_path: str) -> None:
|
|
# Bazel is a self-extracting zip launcher and needs read perms on the executable to read the zip from itself.
|
|
perms = (
|
|
stat.S_IXUSR
|
|
| stat.S_IXGRP
|
|
| stat.S_IXOTH
|
|
| stat.S_IRUSR
|
|
| stat.S_IRGRP
|
|
| stat.S_IROTH
|
|
| stat.S_IWUSR
|
|
| stat.S_IWGRP
|
|
)
|
|
os.chmod(binary_path, perms)
|
|
|
|
|
|
def create_bazel_to_bazelisk_symlink(binary_directory: str) -> str:
|
|
bazel_symlink = os.path.join(
|
|
binary_directory, "bazel.exe" if sys.platform == "win32" else "bazel"
|
|
)
|
|
if os.path.exists(bazel_symlink):
|
|
print(f"Symlink {bazel_symlink} already exists, skipping symlink creation")
|
|
return bazel_symlink
|
|
|
|
os.symlink(os.path.join(binary_directory, "bazelisk"), bazel_symlink)
|
|
print(f"Symlinked bazel to {bazel_symlink}")
|
|
return bazel_symlink
|
|
|
|
|
|
def main():
|
|
arg_parser = argparse.ArgumentParser()
|
|
arg_parser.add_argument("--add-bazel-symlink", type=bool, default=True)
|
|
args = arg_parser.parse_args()
|
|
|
|
binary_directory = os.path.expanduser("~/.local/bin")
|
|
if not os.path.exists(binary_directory):
|
|
os.makedirs(binary_directory)
|
|
|
|
install_bazel(binary_directory)
|
|
|
|
if args.add_bazel_symlink:
|
|
symlink_path = create_bazel_to_bazelisk_symlink(binary_directory)
|
|
|
|
path_misconfigured = False
|
|
evaluated_path = shutil.which(os.path.basename(symlink_path))
|
|
if evaluated_path is None:
|
|
print(
|
|
"Warning: bazel is not in the PATH. Please add ~/.local/bin to your PATH or call it with the absolute path."
|
|
)
|
|
path_misconfigured = True
|
|
elif os.path.abspath(evaluated_path) != os.path.abspath(symlink_path):
|
|
print(
|
|
f"Warning: the bazel installed ({evaluated_path}) doesn't match the bazel in your path"
|
|
)
|
|
path_misconfigured = True
|
|
|
|
if path_misconfigured:
|
|
abs_binary_directory = os.path.abspath(binary_directory)
|
|
if sys.platform == "win32":
|
|
print("To add it to your PATH, run: \n")
|
|
print(
|
|
f'[Environment]::SetEnvironmentVariable("Path", "{abs_binary_directory};" + $env:Path, "Machine")'
|
|
)
|
|
print("refreshenv")
|
|
else:
|
|
print("To add it to your PATH, run: \n")
|
|
if os.path.exists(os.path.expanduser("~/.bashrc")):
|
|
print(f'echo "export PATH=\\{abs_binary_directory}:$PATH" >> ~/.bashrc')
|
|
print("source ~/.bashrc")
|
|
elif os.path.exists(os.path.expanduser("~/.bash_profile")):
|
|
print(f'echo "export PATH=\\{abs_binary_directory}:$PATH" >> ~/.bash_profile')
|
|
print("source ~/.bash_profile")
|
|
elif os.path.exists(os.path.expanduser("~/.zshrc")):
|
|
print(f'echo "export PATH=\\{abs_binary_directory}:$PATH" >> ~/.zshrc')
|
|
print("source ~/.zshrc")
|
|
else:
|
|
print(f"export PATH={abs_binary_directory}:$PATH")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|