Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at fix-function-merge 160 lines 4.5 kB view raw
1#!/usr/bin/env nix-shell 2#!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.beautifulsoup4 ps.lxml ps.packaging ])" 3from itertools import groupby 4import json 5import os 6import pathlib 7import subprocess 8import sys 9import urllib.request 10from dataclasses import dataclass 11from enum import Enum 12 13from bs4 import BeautifulSoup, NavigableString, Tag 14from packaging.version import parse as parse_version, Version 15 16 17HERE = pathlib.Path(__file__).parent 18ROOT = HERE.parent.parent.parent.parent 19VERSIONS_FILE = HERE / "kernels-org.json" 20 21 22class KernelNature(Enum): 23 MAINLINE = 1 24 STABLE = 2 25 LONGTERM = 3 26 27 28@dataclass 29class KernelRelease: 30 nature: KernelNature 31 version: str 32 branch: str 33 date: str 34 link: str 35 eol: bool = False 36 37 38def parse_release(release: Tag) -> KernelRelease | None: 39 columns: list[Tag] = list(release.find_all("td")) 40 try: 41 nature = KernelNature[columns[0].get_text().rstrip(":").upper()] 42 except KeyError: 43 return None 44 45 version = parse_version(columns[1].get_text().rstrip(" [EOL]")) 46 date = columns[2].get_text() 47 link = columns[3].find("a") 48 if link is not None and isinstance(link, Tag): 49 link = link.attrs.get("href") 50 assert link is not None, f"link for kernel {version} is non-existent" 51 eol = bool(release.find(class_="eolkernel")) 52 53 return KernelRelease( 54 nature=nature, 55 branch=get_branch(version), 56 version=version, 57 date=date, 58 link=link, 59 eol=eol, 60 ) 61 62 63def get_branch(version: Version): 64 # This is a testing kernel. 65 if version.is_prerelease: 66 return "testing" 67 else: 68 return f"{version.major}.{version.minor}" 69 70 71def get_hash(kernel: KernelRelease): 72 if kernel.branch == "testing": 73 args = ["--unpack"] 74 else: 75 args = [] 76 77 hash = ( 78 subprocess.check_output(["nix-prefetch-url", kernel.link] + args) 79 .decode() 80 .strip() 81 ) 82 return f"sha256:{hash}" 83 84 85def get_oldest_branch() -> Version: 86 with open(VERSIONS_FILE) as f: 87 return parse_version(sorted(json.load(f).keys())[0]) 88 89 90def predates_oldest_branch(oldest: Version, to_compare: str) -> bool: 91 if to_compare == "testing": 92 return False 93 94 return parse_version(to_compare) < oldest 95 96 97def commit(message): 98 return subprocess.check_call(["git", "commit", "-m", message, VERSIONS_FILE]) 99 100 101def main(): 102 kernel_org = urllib.request.urlopen("https://kernel.org/") 103 soup = BeautifulSoup(kernel_org.read().decode(), "lxml") 104 release_table = soup.find(id="releases") 105 if not release_table or isinstance(release_table, NavigableString): 106 print(release_table, file=sys.stderr) 107 print("Failed to find the release table on https://kernel.org", file=sys.stderr) 108 sys.exit(1) 109 110 releases = release_table.find_all("tr") 111 parsed_releases = filter(None, [parse_release(release) for release in releases]) 112 all_kernels = json.load(VERSIONS_FILE.open()) 113 114 oldest_branch = get_oldest_branch() 115 116 for (branch, kernels) in groupby(parsed_releases, lambda kernel: get_branch(kernel.version)): 117 kernel = max(kernels, key=lambda kernel: kernel.version) 118 nixpkgs_branch = branch.replace(".", "_") 119 120 old_version = parse_version(all_kernels.get(branch, {}).get("version")) 121 if old_version == kernel.version: 122 print(f"linux_{nixpkgs_branch}: {kernel.version} is latest, skipping...") 123 continue 124 125 if predates_oldest_branch(oldest_branch, kernel.branch): 126 print( 127 f"{kernel.branch} is too old and not supported anymore, skipping...", 128 file=sys.stderr 129 ) 130 continue 131 132 if old_version is None: 133 if kernel.eol: 134 print( 135 f"{kernel.branch} is EOL, not adding...", 136 file=sys.stderr 137 ) 138 continue 139 140 message = f"linux_{nixpkgs_branch}: init at {kernel.version}" 141 else: 142 message = f"linux_{nixpkgs_branch}: {old_version} -> {kernel.version}" 143 144 print(message, file=sys.stderr) 145 146 all_kernels[branch] = { 147 "version": str(kernel.version), 148 "hash": get_hash(kernel), 149 } 150 151 with VERSIONS_FILE.open("w") as fd: 152 json.dump(all_kernels, fd, indent=4) 153 fd.write("\n") # makes editorconfig happy 154 155 if os.environ.get("COMMIT") == "1": 156 commit(message) 157 158 159if __name__ == "__main__": 160 main()