Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at devShellTools-shell 155 lines 4.4 kB view raw
1#! /usr/bin/env nix-shell 2#! nix-shell -i python3 -p python3 python3.pkgs.semver nix-prefetch-github 3from urllib.request import Request, urlopen 4import dataclasses 5import subprocess 6import os.path 7import semver 8from typing import ( 9 Optional, 10 Dict, 11 List, 12) 13import json 14import os 15 16 17SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) 18NIXPKGS = os.path.abspath(os.path.join(SCRIPT_DIR, "../../../../")) 19 20 21OWNER = "LemmyNet" 22UI_REPO = "lemmy-ui" 23SERVER_REPO = "lemmy" 24 25 26@dataclasses.dataclass 27class Pin: 28 serverVersion: str 29 uiVersion: str 30 serverHash: str = "" 31 serverCargoHash: str = "" 32 uiHash: str = "" 33 uiPNPMDepsHash: str = "" 34 35 filename: Optional[str] = None 36 37 def write(self) -> None: 38 if not self.filename: 39 raise ValueError("No filename set") 40 41 with open(self.filename, "w") as fd: 42 pin = dataclasses.asdict(self) 43 del pin["filename"] 44 json.dump(pin, fd, indent=2) 45 fd.write("\n") 46 47 48def github_get(path: str) -> Dict: 49 """Send a GET request to GitHub, optionally adding GITHUB_TOKEN auth header""" 50 url = f"https://api.github.com/{path.lstrip('/')}" 51 print(f"Retrieving {url}") 52 53 req = Request(url) 54 55 if "GITHUB_TOKEN" in os.environ: 56 req.add_header("authorization", f"Bearer {os.environ['GITHUB_TOKEN']}") 57 58 with urlopen(req) as resp: 59 return json.loads(resp.read()) 60 61 62def get_latest_release(owner: str, repo: str) -> str: 63 return github_get(f"/repos/{owner}/{repo}/releases/latest")["tag_name"] 64 65 66def prefetch_github(owner: str, repo: str, rev: str) -> str: 67 """Prefetch GitHub rev and return SRI hash""" 68 print(f"Prefetching {owner}/{repo}({rev})") 69 70 proc = subprocess.run( 71 ["nix-prefetch-github", owner, repo, "--rev", rev, "--fetch-submodules"], 72 check=True, 73 stdout=subprocess.PIPE, 74 ) 75 76 return json.loads(proc.stdout)["hash"] 77 78 79def get_latest_tag(owner: str, repo: str, prerelease: bool = False) -> str: 80 """Get the latest tag from a GitHub Repo""" 81 tags: List[str] = [] 82 83 # As the GitHub API doesn't have any notion of "latest" for tags we need to 84 # collect all of them and sort so we can figure out the latest one. 85 i = 0 86 while i <= 100: # Prevent infinite looping 87 i += 1 88 resp = github_get(f"/repos/{owner}/{repo}/tags?page={i}") 89 if not resp: 90 break 91 92 # Filter out unparseable tags 93 for tag in resp: 94 try: 95 parsed = semver.Version.parse(tag["name"]) 96 if ( 97 semver.Version.parse(tag["name"]) 98 and not prerelease 99 and parsed.prerelease 100 ): # Filter out release candidates 101 continue 102 except ValueError: 103 continue 104 else: 105 tags.append(tag["name"]) 106 107 # Sort and return latest 108 return sorted(tags, key=lambda name: semver.Version.parse(name))[-1] 109 110 111def get_fod_hash(attr: str) -> str: 112 """ 113 Get fixed output hash for attribute. 114 This depends on a fixed output derivation with an empty hash. 115 """ 116 117 print(f"Getting fixed output hash for {attr}") 118 119 proc = subprocess.run(["nix-build", NIXPKGS, "-A", attr], stderr=subprocess.PIPE) 120 if proc.returncode != 1: 121 raise ValueError("Expected nix-build to fail") 122 123 # Iterate list in reverse order so we get the "got:" line early 124 for line in proc.stderr.decode().split("\n")[::-1]: 125 cols = line.split() 126 if cols and cols[0] == "got:": 127 return cols[1] 128 129 raise ValueError("No fixed output hash found") 130 131 132def make_server_pin(pin: Pin, attr: str) -> None: 133 pin.serverHash = prefetch_github(OWNER, SERVER_REPO, pin.serverVersion) 134 pin.write() 135 pin.serverCargoHash = get_fod_hash(attr) 136 pin.write() 137 138 139def make_ui_pin(pin: Pin, attr: str) -> None: 140 pin.uiHash = prefetch_github(OWNER, UI_REPO, pin.uiVersion) 141 pin.write() 142 pin.uiPNPMDepsHash = get_fod_hash(attr) 143 pin.write() 144 145 146if __name__ == "__main__": 147 # Get server version 148 server_version = get_latest_tag(OWNER, SERVER_REPO) 149 150 # Get UI version (not always the same as lemmy-server) 151 ui_version = get_latest_tag(OWNER, UI_REPO) 152 153 pin = Pin(server_version, ui_version, filename=os.path.join(SCRIPT_DIR, "pin.json")) 154 make_server_pin(pin, "lemmy-server") 155 make_ui_pin(pin, "lemmy-ui")