| #!/usr/bin/env python |
| |
| """ |
| This script updates the version of tool binaries defined in a Bazel rules_multitool lockfile. |
| If the tool has binaries hosted in a public GitHub repo's Release assets, it will update the |
| lockfile's URL and hash to the latest versions, otherwise it will skip it. |
| |
| See: https://github.com/theoremlp/rules_multitool |
| |
| ----------------------------------------------------------------------------------------------------------- |
| usage: update_multitool_binaries.py [-h] [--file LOCKFILE_PATH] |
| |
| options: |
| -h, --help show this help message and exit |
| --file LOCKFILE_PATH path to multitool lockfile (defaults to 'multitool.lock.json' in current directory) |
| ----------------------------------------------------------------------------------------------------------- |
| """ |
| |
| import argparse |
| import json |
| import os |
| import re |
| import urllib.request |
| |
| |
| def run(lockfile_path): |
| with open(lockfile_path) as f: |
| data = json.load(f) |
| |
| for tool in [tool for tool in data if tool != "$schema"]: |
| match = re.search(f"download/(.*?)/{tool}", data[tool]["binaries"][0]["url"]) |
| if match: |
| version = match[1] |
| else: |
| continue |
| match = re.search("github.com/(.*?)/releases", data[tool]["binaries"][0]["url"]) |
| if match: |
| releases_url = f"https://api.github.com/repos/{match[1]}/releases/latest" |
| else: |
| continue |
| try: |
| with urllib.request.urlopen(releases_url) as response: |
| json_resp = json.loads(response.read()) |
| new_version = json_resp["tag_name"] |
| assets = json_resp["assets"] |
| except Exception: |
| continue |
| if new_version != version: |
| print(f"found new version of '{tool}': {new_version}") |
| urls = [asset.get("browser_download_url") for asset in assets] |
| hashes = [asset.get("digest").split(":")[1] for asset in assets] |
| for binary in data[tool]["binaries"]: |
| new_url = binary["url"].replace(version, new_version) |
| new_hash = hashes[urls.index(new_url)] |
| binary["url"] = new_url |
| binary["sha256"] = new_hash |
| |
| with open(lockfile_path, "w") as f: |
| json.dump(data, f, indent=2) |
| |
| print(f"\ngenerated new '{lockfile_path}' with updated urls and hashes") |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "--file", |
| dest="lockfile_path", |
| default=os.path.join(os.getcwd(), "multitool.lock.json"), |
| help="path to multitool lockfile (defaults to 'multitool.lock.json' in current directory)", |
| ) |
| args = parser.parse_args() |
| run(args.lockfile_path) |
| |
| |
| if __name__ == "__main__": |
| main() |