|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +import argparse |
| 4 | + |
| 5 | +import json |
| 6 | +import jinja2 |
| 7 | +import re |
| 8 | +import requests |
| 9 | + |
| 10 | +import subprocess as sp |
| 11 | + |
| 12 | +from base64 import b32encode, b32decode, b64encode, b16decode |
| 13 | +from bs4 import BeautifulSoup |
| 14 | + |
| 15 | +env = jinja2.Environment() |
| 16 | + |
| 17 | +all_versions_template = env.from_string("""{ |
| 18 | + buildECTesterStandalone |
| 19 | +}: |
| 20 | +{ {% for version in pkg_versions %} |
| 21 | + {{ version }} {% endfor %} |
| 22 | +}""") |
| 23 | + |
| 24 | +def get_source_hash(url, unpack=False): |
| 25 | + digest_type = "sha256" |
| 26 | + |
| 27 | + cmd = ["nix-prefetch-url"] |
| 28 | + if unpack: |
| 29 | + cmd.append("--unpack") |
| 30 | + cmd.extend(["--type", digest_type, url]) |
| 31 | + |
| 32 | + digest_nixbase32 = sp.check_output(cmd, stderr=sp.DEVNULL).strip() |
| 33 | + digest_sri = sp.check_output(["nix", "hash", "to-sri", "--type", digest_type, digest_nixbase32.decode()], stderr=sp.DEVNULL).strip().decode() |
| 34 | + return digest_sri |
| 35 | + |
| 36 | +def fetch_botan(): |
| 37 | + # NOTE: this way omits the older releases at https://botan.randombit.net/releases/old |
| 38 | + release_list = "https://botan.randombit.net/releases/" |
| 39 | + download_url = "https://botan.randombit.net/releases/{version}" |
| 40 | + resp = requests.get(release_list) |
| 41 | + soup = BeautifulSoup(resp.content, 'html.parser') |
| 42 | + |
| 43 | + single_version_template = env.from_string("""{{ flat_version }} = buildECTesterStandalone { |
| 44 | + {{ pkg }} = { version="{{ version }}"; source_extension="{{ ext }}"; hash="{{ digest }}"; }; |
| 45 | + };""") |
| 46 | + |
| 47 | + renders = [] |
| 48 | + for link in soup.find_all("a"): |
| 49 | + if link.text.startswith("Botan") and not link.text.endswith('.asc'): |
| 50 | + download_link = download_url.format(version=link['href']) |
| 51 | + |
| 52 | + match = re.match(r"Botan-(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\.(?P<ext>.*)", link.text) |
| 53 | + version = f"{match['major']}.{match['minor']}.{match['patch']}" |
| 54 | + ext = f"{match['ext']}" |
| 55 | + |
| 56 | + digest = get_source_hash(download_link) |
| 57 | + # NOTE: use underscore to separate the versions? |
| 58 | + flat_version = f"v{match['major']}{match['minor']}{match['patch']}" |
| 59 | + |
| 60 | + rendered = single_version_template.render(pkg="botan", digest=digest, ext=ext, flat_version=flat_version, version=version).strip() |
| 61 | + renders.append(rendered) |
| 62 | + |
| 63 | + all_versions = all_versions_template.render(pkg_versions=renders).strip() |
| 64 | + with open("./nix/botan_pkg_versions.nix", "w") as handle: |
| 65 | + handle.write(all_versions) |
| 66 | + |
| 67 | +def fetch_cryptopp(): |
| 68 | + owner = "weidai11" |
| 69 | + repo = "cryptopp" |
| 70 | + release_url = f"https://api.github.com/repos/{owner}/{repo}/releases" |
| 71 | + resp = requests.get(release_url) |
| 72 | + |
| 73 | + single_version_template = env.from_string("""{{ flat_version }} = buildECTesterStandalone { |
| 74 | + {{ pkg }} = { version="{{ version }}"; hash="{{ digest }}"; }; |
| 75 | + };""") |
| 76 | + renders = [] |
| 77 | + for release in resp.json(): |
| 78 | + if not release['draft'] and not release['prerelease']: |
| 79 | + _, *version_values = release['tag_name'].split('_') |
| 80 | + underscored_version = '_'.join(version_values) |
| 81 | + flat_version = "v" + "".join(version_values) |
| 82 | + download_url = f"https://github.com/{owner}/{repo}/archive/{release['tag_name']}.tar.gz" |
| 83 | + digest = get_source_hash(download_url, unpack=True) |
| 84 | + |
| 85 | + |
| 86 | + rendered = single_version_template.render(pkg="cryptopp", digest=digest, flat_version=flat_version, version=underscored_version).strip() |
| 87 | + renders.append(rendered) |
| 88 | + |
| 89 | + all_versions = all_versions_template.render(pkg_versions=renders).strip() |
| 90 | + with open("./nix/cryptopp_pkg_versions.nix", "w") as handle: |
| 91 | + handle.write(all_versions) |
| 92 | + |
| 93 | +def fetch_openssl(): |
| 94 | + pkg = "openssl" |
| 95 | + owner = "openssl" |
| 96 | + repo = "openssl" |
| 97 | + release_url = f"https://api.github.com/repos/{owner}/{repo}/releases" |
| 98 | + resp = requests.get(release_url) |
| 99 | + |
| 100 | + single_version_template = env.from_string("""{{ flat_version }} = buildECTesterStandalone { |
| 101 | + {{ pkg }} = { version="{{ version }}"; hash="{{ digest }}"; }; |
| 102 | + };""") |
| 103 | + renders = [] |
| 104 | + for release in resp.json(): |
| 105 | + if not release['draft'] and not release['prerelease']: |
| 106 | + try: |
| 107 | + _, dotted_version = release['tag_name'].split('-') |
| 108 | + except ValueError: |
| 109 | + continue |
| 110 | + flat_version = "v" + "".join(dotted_version.split('.')) |
| 111 | + download_url = f"https://github.com/{owner}/{repo}/archive/{release['tag_name']}.tar.gz" |
| 112 | + digest = get_source_hash(download_url) |
| 113 | + |
| 114 | + |
| 115 | + rendered = single_version_template.render(pkg=pkg, digest=digest, flat_version=flat_version, version=dotted_version).strip() |
| 116 | + renders.append(rendered) |
| 117 | + |
| 118 | + all_versions = all_versions_template.render(pkg_versions=renders).strip() |
| 119 | + with open(f"./nix/{pkg}_pkg_versions.nix", "w") as handle: |
| 120 | + handle.write(all_versions) |
| 121 | + |
| 122 | + |
| 123 | + |
| 124 | + |
| 125 | +def main(): |
| 126 | + parser = argparse.ArgumentParser() |
| 127 | + parser.add_argument("lib") |
| 128 | + args = parser.parse_args() |
| 129 | + |
| 130 | + match args.lib: |
| 131 | + case "botan": |
| 132 | + fetch_botan() |
| 133 | + case "cryptopp": |
| 134 | + fetch_cryptopp() |
| 135 | + case "openssl": |
| 136 | + fetch_openssl() |
| 137 | + |
| 138 | + |
| 139 | +if __name__ == '__main__': |
| 140 | + main() |
0 commit comments