at 25.11-pre 4.4 kB view raw
1#!/usr/bin/env nix-shell 2#!nix-shell -i python3 -p "python3.withPackages(ps: [ ps.beautifulsoup4 ps.click ps.httpx ps.jinja2 ps.packaging ps.pyyaml ])" nix-update 3import base64 4import binascii 5import json 6import pathlib 7import subprocess 8from urllib.parse import urljoin, urlparse 9 10import bs4 11import click 12import httpx 13import jinja2 14import packaging.version as v 15 16import utils 17 18 19LEAF_TEMPLATE = jinja2.Template(''' 20{ mkKdeDerivation }: 21mkKdeDerivation { 22 pname = "{{ pname }}"; 23} 24'''.strip()) 25 26ROOT_TEMPLATE = jinja2.Template(''' 27{ callPackage }: 28{ 29 {%- for p in packages %} 30 {{ p }} = callPackage ./{{ p }} { }; 31 {%- endfor %} 32} 33'''.strip()) 34 35PROJECTS_WITH_RUST = { 36 "akonadi-search", 37 "angelfish", 38 "kdepim-addons", 39} 40 41def to_sri(hash): 42 raw = binascii.unhexlify(hash) 43 b64 = base64.b64encode(raw).decode() 44 return f"sha256-{b64}" 45 46 47@click.command 48@click.argument( 49 "pkgset", 50 type=click.Choice(["frameworks", "gear", "plasma"]), 51 required=True 52) 53@click.argument( 54 "version", 55 type=str, 56 required=True 57) 58@click.option( 59 "--nixpkgs", 60 type=click.Path( 61 exists=True, 62 file_okay=False, 63 resolve_path=True, 64 writable=True, 65 path_type=pathlib.Path, 66 ), 67 default=pathlib.Path(__file__).parent.parent.parent.parent 68) 69@click.option( 70 "--sources-url", 71 type=str, 72 default=None, 73) 74def main(pkgset: str, version: str, nixpkgs: pathlib.Path, sources_url: str | None): 75 root_dir = nixpkgs / "pkgs/kde" 76 set_dir = root_dir / pkgset 77 generated_dir = root_dir / "generated" 78 metadata = utils.KDERepoMetadata.from_json(generated_dir) 79 80 if sources_url is None: 81 set_url = { 82 "frameworks": f"frameworks/{version}/", 83 "gear": f"release-service/{version}/src/", 84 "plasma": f"plasma/{version}/", 85 }[pkgset] 86 sources_url = f"https://download.kde.org/stable/{set_url}" 87 88 client = httpx.Client() 89 sources = client.get(sources_url) 90 sources.raise_for_status() 91 bs = bs4.BeautifulSoup(sources.text, features="html.parser") 92 93 results = {} 94 projects_to_update_rust = set() 95 for item in bs.select("tr")[3:]: 96 link = item.select_one("td:nth-child(2) a") 97 if not link: 98 continue 99 100 project_name, version_and_ext = link.text.rsplit("-", maxsplit=1) 101 102 if project_name not in metadata.projects_by_name: 103 print(f"Warning: unknown tarball: {project_name}") 104 105 if project_name in PROJECTS_WITH_RUST: 106 projects_to_update_rust.add(project_name) 107 108 if version_and_ext.endswith(".sig"): 109 continue 110 111 version = version_and_ext.removesuffix(".tar.xz") 112 113 url = urljoin(sources_url, link.attrs["href"]) 114 115 hash = client.get(url + ".sha256").text.split(" ", maxsplit=1)[0] 116 assert hash 117 118 if existing := results.get(project_name): 119 old_version = existing["version"] 120 if v.parse(old_version) > v.parse(version): 121 print(f"{project_name} {old_version} is newer than {version}, skipping...") 122 continue 123 124 results[project_name] = { 125 "version": version, 126 "url": "mirror://kde" + urlparse(url).path, 127 "hash": to_sri(hash) 128 } 129 130 pkg_dir = set_dir / project_name 131 pkg_file = pkg_dir / "default.nix" 132 133 if not pkg_file.exists(): 134 print(f"Generated new package: {pkgset}/{project_name}") 135 pkg_dir.mkdir(parents=True, exist_ok=True) 136 with pkg_file.open("w") as fd: 137 fd.write(LEAF_TEMPLATE.render(pname=project_name) + "\n") 138 139 set_dir.mkdir(parents=True, exist_ok=True) 140 with (set_dir / "default.nix").open("w") as fd: 141 fd.write(ROOT_TEMPLATE.render(packages=sorted(results.keys())) + "\n") 142 143 sources_dir = generated_dir / "sources" 144 sources_dir.mkdir(parents=True, exist_ok=True) 145 with (sources_dir / f"{pkgset}.json").open("w") as fd: 146 json.dump(results, fd, indent=2) 147 148 for project_name in projects_to_update_rust: 149 print(f"Updating cargoDeps hash for {pkgset}/{project_name}...") 150 subprocess.run([ 151 "nix-update", 152 f"kdePackages.{project_name}", 153 "--version", 154 "skip", 155 "--override-filename", 156 pkg_file 157 ]) 158 159 160if __name__ == "__main__": 161 main() # type: ignore