diff --git a/packages/arm-trusted-firmware/default.nix b/packages/arm-trusted-firmware/default.nix index ce08f6a..3725b31 100644 --- a/packages/arm-trusted-firmware/default.nix +++ b/packages/arm-trusted-firmware/default.nix @@ -6,16 +6,19 @@ DEBUG ? "0", TFA_FLAGS ? "", }: - +let + inherit (lib.trivial) importJSON; + versions = importJSON ./versions.json; +in stdenv.mkDerivation rec { pname = "arm-trusted-firmware"; - version = "2.14"; + version = versions.fw.rev; src = fetchFromGitHub { owner = "ARM-software"; repo = "arm-trusted-firmware"; tag = "v${version}"; - hash = "sha256-7imeQocGMSyGXTEhNs4s0bcDxZpbLSSkOyI7c5UxqVs="; + hash = versions.fw.hash; }; # Add required host tools if needed: diff --git a/packages/arm-trusted-firmware/versions.json b/packages/arm-trusted-firmware/versions.json new file mode 100644 index 0000000..046a5c9 --- /dev/null +++ b/packages/arm-trusted-firmware/versions.json @@ -0,0 +1,9 @@ +{ + "fw": { + "hash": "sha256-eh0b4q6od9ZWAFBQ+wRjpLQEEf8kox2L3l1iHwQtju8=", + "location": "github", + "owner": "ARM-software", + "repo": "arm-trusted-firmware", + "rev": "8fd4c786594239de20669f062e416fe1a37ca59e" + } +} diff --git a/packages/bolt-launcher/default.nix b/packages/bolt-launcher/default.nix index 7b4739c..c5328a8 100644 --- a/packages/bolt-launcher/default.nix +++ b/packages/bolt-launcher/default.nix @@ -41,14 +41,17 @@ jdk17 # for RuneLite/HDOS , # for RS3 }: - +let + inherit (lib.trivial) importJSON; + versions = importJSON ./versions.json; +in stdenv.mkDerivation rec { pname = "bolt-launcher"; - version = "0.20.6"; + version = versions.bolt.version; src = fetchzip { url = "https://codeberg.org/Adamcake/Bolt/releases/download/${version}/Bolt-Linux.zip"; - sha256 = "sha256-kQwQixUwcbyC53q5lyNdcVbMh40Ay5vmWOj4ZVEVznY="; + sha256 = versions.bolt.hash; stripRoot = false; }; diff --git a/packages/bolt-launcher/versions.json b/packages/bolt-launcher/versions.json new file mode 100644 index 0000000..8afa86e --- /dev/null +++ b/packages/bolt-launcher/versions.json @@ -0,0 +1,9 @@ +{ + "bolt": { + "hash": "sha256-s0hC822fXuYiHPRE3xcLNOsZs43xhLJ+vM1cuMc9zZQ=", + "location": "codeberg", + "owner": "Adamcake", + "repo": "Bolt", + "tag": "0.20.6" + } +} diff --git a/packages/edk2/default.nix b/packages/edk2/default.nix index e536c7d..8bb1bfa 100644 --- a/packages/edk2/default.nix +++ b/packages/edk2/default.nix @@ -17,67 +17,37 @@ namespace, }: let + inherit (lib.trivial) importJSON; + pname = "edk2"; version = "stable202511"; + versions = importJSON ./versions.json; - edk2Src = ( - if MODEL == "5" then - fetchFromGitHub rec { - owner = "mjallen18"; - repo = "edk2"; - name = repo; - rev = "9765be56f1f816ef737153f5588b3294fcc69a63"; - hash = "sha256-oqfJbNeOj2BVJqWE+snD6ri3lUO1aNcmPg+eJpjyr5E="; - fetchSubmodules = true; - } - else - fetchFromGitHub rec { - owner = "tianocore"; - repo = "edk2"; - name = repo; - tag = "edk2-${version}"; - hash = "sha256-R/rgz8dWcDYVoiM67K2UGuq0xXbjjJYBPtJ1FmfGIaU="; - fetchSubmodules = true; - } - ); + repoOwner = (if MODEL == "5" then "-mjallen" else ""); - edk2NonOsiSrc = ( - if MODEL == "5" then - fetchFromGitHub rec { - owner = "mjallen18"; - repo = "edk2-non-osi"; - name = repo; - rev = "09ee44f07ded544d976be8a03dec3715719f638e"; - hash = "sha256-k7nUb3WaRUIr9IlXdam2WGKPOzKjLNVFLfuD5h4veMc="; - } - else - fetchFromGitHub rec { - owner = "tianocore"; - repo = "edk2-non-osi"; - name = repo; - rev = "94d048981116e2e3eda52dad1a89958ee404098d"; - hash = "sha256-6yuvVvmGn4yaEksbbvGDX1ZcKpdWBKnwaNjLGvgAWyk="; - } - ); + edk2Src = fetchFromGitHub rec { + owner = versions."edk2${repoOwner}".owner; + repo = "edk2"; + name = repo; + rev = versions."edk2${repoOwner}".rev; + hash = versions."edk2${repoOwner}".hash; + }; - edk2PlatformsSrc = ( - if MODEL == "5" then - fetchFromGitHub rec { - owner = "mjallen18"; - repo = "edk2-platforms"; - name = repo; - rev = "fdf5a10cc60d1f01030e3ded3c6e69179819cd20"; - hash = "sha256-kc5kMEZNLxWFUN8n5+NxXNphkXAtVyjvSAuFyljb8Cs="; - } - else - fetchFromGitHub rec { - owner = "tianocore"; - repo = "edk2-platforms"; - name = repo; - rev = "0991a0b643509d900e5d023a0116789827a696e5"; - hash = "sha256-IdACr0NStqEpC0TFoKKgDwKT2mqyJwVXW/B7hlRXccI="; - } - ); + edk2NonOsiSrc = fetchFromGitHub rec { + owner = versions."edk2-non-osi${repoOwner}".owner; + repo = "edk2-non-osi"; + name = repo; + rev = versions."edk2-non-osi${repoOwner}".rev; + hash = versions."edk2-non-osi${repoOwner}".hash; + }; + + edk2PlatformsSrc = fetchFromGitHub rec { + owner = versions."edk2-platforms${repoOwner}".owner; + repo = "edk2-platforms"; + name = repo; + rev = versions."edk2-platforms${repoOwner}".rev; + hash = versions."edk2-platforms${repoOwner}".hash; + }; baseTools = pkgs.${namespace}.edk2-basetools.override { version = "stable202511"; diff --git a/packages/edk2/versions.json b/packages/edk2/versions.json new file mode 100644 index 0000000..3e4950f --- /dev/null +++ b/packages/edk2/versions.json @@ -0,0 +1,44 @@ +{ + "edk2": { + "hash": "sha256-CS/jWY6B+/PIKDh6cL6n9pwAPhPcjZBZc75SnOJbHf8=", + "location": "github", + "owner": "tianocore", + "repo": "edk2", + "tag": "edk2-stable202511" + }, + "edk2-non-osi": { + "hash": "sha256-6yuvVvmGn4yaEksbbvGDX1ZcKpdWBKnwaNjLGvgAWyk=", + "location": "github", + "owner": "tianocore", + "repo": "edk2-non-osi", + "rev": "94d048981116e2e3eda52dad1a89958ee404098d" + }, + "edk2-platforms": { + "hash": "sha256-IdACr0NStqEpC0TFoKKgDwKT2mqyJwVXW/B7hlRXccI=", + "location": "github", + "owner": "tianocore", + "repo": "edk2-platforms", + "rev": "0991a0b643509d900e5d023a0116789827a696e5" + }, + "edk2-mjallen": { + "hash": "sha256-oqfJbNeOj2BVJqWE+snD6ri3lUO1aNcmPg+eJpjyr5E=", + "location": "github", + "owner": "mjallen18", + "repo": "edk2", + "rev": "9765be56f1f816ef737153f5588b3294fcc69a63" + }, + "edk2-non-osi-mjallen": { + "hash": "sha256-k7nUb3WaRUIr9IlXdam2WGKPOzKjLNVFLfuD5h4veMc=", + "location": "github", + "owner": "mjallen18", + "repo": "edk2-non-osi", + "rev": "09ee44f07ded544d976be8a03dec3715719f638e" + }, + "edk2-platforms-mjallen": { + "hash": "sha256-kc5kMEZNLxWFUN8n5+NxXNphkXAtVyjvSAuFyljb8Cs=", + "location": "github", + "owner": "mjallen18", + "repo": "edk2-platforms", + "rev": "fdf5a10cc60d1f01030e3ded3c6e69179819cd20" + } +} diff --git a/packages/librepods-beta/default.nix b/packages/librepods-beta/default.nix index 81190d4..f1a561e 100644 --- a/packages/librepods-beta/default.nix +++ b/packages/librepods-beta/default.nix @@ -15,7 +15,10 @@ fontconfig, freetype, }: - +let + inherit (lib.trivial) importJSON; + versions = importJSON ./versions.json; +in rustPlatform.buildRustPackage rec { pname = "librepods"; version = "0.1.0"; @@ -23,8 +26,8 @@ rustPlatform.buildRustPackage rec { src = fetchFromGitHub { owner = "kavishdevar"; repo = "librepods"; - rev = "c852b726deb5344ea3637332722a7c93f3858d60"; - hash = "sha256-RoOkINI+ahepAbgwdkcl1iI9XGI/gYXWiH0J9Eb90pg="; + rev = versions.rev; + hash = versions.hash; }; sourceRoot = "${src.name}/linux-rust"; diff --git a/packages/librepods-beta/versions.json b/packages/librepods-beta/versions.json new file mode 100644 index 0000000..c535196 --- /dev/null +++ b/packages/librepods-beta/versions.json @@ -0,0 +1,5 @@ +{ + "repo": "https://github.com/kavishdevar/librepods", + "rev": "c852b726deb5344ea3637332722a7c93f3858d60", + "hash": "sha256-RoOkINI+ahepAbgwdkcl1iI9XGI/gYXWiH0J9Eb90pg=" +} diff --git a/packages/librepods/default.nix b/packages/librepods/default.nix index b248dab..26eaf93 100644 --- a/packages/librepods/default.nix +++ b/packages/librepods/default.nix @@ -9,7 +9,10 @@ libpulseaudio, fetchFromGitHub, }: - +let + inherit (lib.trivial) importJSON; + versions = importJSON ./versions.json; +in stdenv.mkDerivation { pname = "librepods"; version = "unstable"; @@ -17,8 +20,8 @@ stdenv.mkDerivation { src = fetchFromGitHub { owner = "kavishdevar"; repo = "librepods"; - rev = "287163e116d092485d561ad571dae03a2f43cf2f"; - hash = "sha256-PD5U87RVBRCLWwnN54x3AEey6wqoOeZlBvzyIESH1v8="; + rev = versions.rev; + hash = versions.hash; }; sourceRoot = "source/linux"; diff --git a/packages/librepods/versions.json b/packages/librepods/versions.json new file mode 100644 index 0000000..7ec40bd --- /dev/null +++ b/packages/librepods/versions.json @@ -0,0 +1,6 @@ +{ + "repo": "https://github.com/kavishdevar/librepods", + "rev": "287163e116d092485d561ad571dae03a2f43cf2f", + "hash": "sha256-PD5U87RVBRCLWwnN54x3AEey6wqoOeZlBvzyIESH1v8=" + } + \ No newline at end of file diff --git a/packages/omnissa/default.nix b/packages/omnissa/default.nix deleted file mode 100644 index 980febc..0000000 --- a/packages/omnissa/default.nix +++ /dev/null @@ -1,232 +0,0 @@ -{ - stdenv, - lib, - buildFHSEnv, - copyDesktopItems, - fetchurl, - gsettings-desktop-schemas, - makeDesktopItem, - makeWrapper, - opensc, - writeTextDir, - writeShellScript, - # New dependencies for aarch64 support - fex, - muvm, - configText ? "", - # Allow users to choose emulation method - useMusvm ? true, # Use muvm + FEX (better isolation) vs just FEX -}: -let - version = "2506"; - - isAarch64 = stdenv.hostPlatform.system == "aarch64-linux"; - - # Always extract x64 binaries (we'll emulate on aarch64) - sysArch = "x64"; - - # For USB support, ensure that /var/run/omnissa/ - # exists and is owned by you. Then run omnissa-usbarbitrator as root. - - mainProgram = "horizon-client"; - - # This forces the default GTK theme (Adwaita) because Horizon is prone to - # UI usability issues when using non-default themes, such as Adwaita-dark. - wrapBinCommands = path: name: '' - makeWrapper "$out/${path}/${name}" "$out/bin/${name}_wrapper" \ - --set GTK_THEME Adwaita \ - --suffix XDG_DATA_DIRS : "${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}" \ - --suffix LD_LIBRARY_PATH : "$out/lib/omnissa/horizon/crtbora:$out/lib/omnissa" - ''; - - omnissaHorizonClientFiles = stdenv.mkDerivation { - pname = "omnissa-horizon-files"; - inherit version; - src = fetchurl { - url = "https://download3.omnissa.com/software/CART26FQ2_LIN_2506_TARBALL/Omnissa-Horizon-Client-Linux-2506-8.16.0-16536624989.tar.gz"; - sha256 = "5515e79188e2605ced5a95c3a3829865b567be5d7a8de00a57455f7b5b2ae392"; - }; - nativeBuildInputs = [ makeWrapper ]; - installPhase = '' - mkdir ext - find ${sysArch} -type f -print0 | xargs -0n1 tar -Cext --strip-components=1 -xf - - chmod -R u+w ext/usr/lib - mv ext/usr $out - cp -r ext/${sysArch}/include $out/ - cp -r ext/${sysArch}/lib $out/ - - # Horizon includes a copy of libstdc++ which is loaded via $LD_LIBRARY_PATH - # when it cannot detect a new enough version already present on the system. - # The checks are distribution-specific and do not function correctly on NixOS. - # Deleting the bundled library is the simplest way to force it to use our version. - rm "$out/lib/omnissa/gcc/libstdc++.so.6" - - # This opensc library is required to support smartcard authentication during the - # initial connection to Horizon. - mkdir $out/lib/omnissa/horizon/pkcs11 - ln -s ${opensc}/lib/pkcs11/opensc-pkcs11.so $out/lib/omnissa/horizon/pkcs11/libopenscpkcs11.so - - ${wrapBinCommands "bin" "horizon-client"} - ${wrapBinCommands "lib/omnissa/horizon/usb" "horizon-eucusbarbitrator"} - ''; - }; - - # x86_64 FHS environment for native or emulated execution - omnissaFHSUserEnv = - pname: - buildFHSEnv { - inherit pname version; - - # On aarch64, we need to invoke via FEX or muvm - runScript = "${omnissaHorizonClientFiles}/bin/${pname}_wrapper"; - - targetPkgs = - pkgs: with pkgs; [ - at-spi2-atk - atk - cairo - dbus - file - fontconfig - freetype - gdk-pixbuf - glib - gtk2 - gtk3-x11 - harfbuzz - liberation_ttf - libjpeg - libpng - libpulseaudio - libtiff - libudev0-shim - libuuid - libv4l - pango - pcsclite - pixman - udev - omnissaHorizonClientFiles - xorg.libX11 - xorg.libXau - xorg.libXcursor - xorg.libXext - xorg.libXi - xorg.libXinerama - xorg.libxkbfile - xorg.libXrandr - xorg.libXrender - xorg.libXScrnSaver - xorg.libXtst - zlib - libxml2_13 - - (writeTextDir "etc/omnissa/config" configText) - ]; - }; - - # Create wrapper scripts for aarch64 that use FEX or muvm - # Option 1: Direct FEX execution (simpler, less isolation) - fexWrapper = - pname: - writeShellScript "${pname}-fex-wrapper" '' - export FEXINTERPRETER="${fex}/bin/FEXInterpreter" - export FEX_ROOTFS="${fex}/share/fex-emu/RootFS" - - # Set up FEX environment - export FEX_TSOENABLED=1 - - exec ${fex}/bin/FEXBash -c '${omnissaFHSUserEnv pname}/bin/${pname} "$@"' -- "$@" - ''; - - # Option 2: muvm + FEX (better isolation, handles kernel differences) - muvmWrapper = - pname: - writeShellScript "${pname}-muvm-wrapper" '' - # muvm creates a lightweight VM with x86_64 emulation via FEX - # This provides better isolation and compatibility - - exec ${muvm}/bin/muvm \ - --fex \ - --share-display \ - --share-sound \ - -- ${omnissaFHSUserEnv pname}/bin/${pname} "$@" - ''; - - # Select the appropriate wrapper based on configuration - aarch64Wrapper = pname: if useMusvm then muvmWrapper pname else fexWrapper pname; - - # Final wrapper that handles both architectures - - desktopItem = makeDesktopItem { - name = "horizon-client"; - desktopName = "Omnissa Horizon Client"; - icon = "${omnissaHorizonClientFiles}/share/icons/horizon-client.png"; - exec = "${ - if isAarch64 then - aarch64Wrapper mainProgram - else - "${omnissaFHSUserEnv mainProgram}/bin/${mainProgram}" - } %u"; - mimeTypes = [ - "x-scheme-handler/horizon-client" - "x-scheme-handler/vmware-view" - ]; - }; - -in -stdenv.mkDerivation { - pname = "omnissa-horizon-client"; - inherit version; - - dontUnpack = true; - - nativeBuildInputs = [ copyDesktopItems ]; - - desktopItems = [ desktopItem ]; - - installPhase = '' - runHook preInstall - mkdir -p $out/bin - - ${ - if isAarch64 then - '' - # On aarch64, create wrapper scripts that use FEX/muvm - cp ${aarch64Wrapper "horizon-client"} $out/bin/horizon-client - chmod +x $out/bin/horizon-client - cp ${aarch64Wrapper "omnissa-usbarbitrator"} $out/bin/omnissa-usbarbitrator - chmod +x $out/bin/omnissa-usbarbitrator - '' - else - '' - # On x86_64, use native FHS environment directly - ln -s ${omnissaFHSUserEnv "horizon-client"}/bin/horizon-client $out/bin/ - ln -s ${omnissaFHSUserEnv "omnissa-usbarbitrator"}/bin/omnissa-usbarbitrator $out/bin/ - '' - } - - runHook postInstall - ''; - - unwrapped = omnissaHorizonClientFiles; - - passthru = { - updateScript = ./update.sh; - # Expose FHS env for debugging - fhsEnv = omnissaFHSUserEnv mainProgram; - }; - - meta = with lib; { - inherit mainProgram; - description = "Allows you to connect to your Omnissa Horizon virtual desktop"; - homepage = "https://www.omnissa.com/products/horizon-8/"; - license = licenses.unfree; - platforms = [ - "x86_64-linux" - "aarch64-linux" - ]; - maintainers = with maintainers; [ mhutter ]; - }; -} diff --git a/packages/steamdeck-bios-manager/default.nix b/packages/steamdeck-bios-manager/default.nix deleted file mode 100644 index 000fee2..0000000 --- a/packages/steamdeck-bios-manager/default.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ - lib, - stdenv, - fetchFromGitHub, - pciutils, - bash, -}: - -stdenv.mkDerivation { - pname = "steamdeck-bios-manager"; - version = "12b0139e3aabb21e559ab0a0c62a432523080bb9"; - - src = fetchFromGitHub { - owner = "ryanrudolfoba"; - repo = "SteamDeck-BIOS-Manager"; - rev = "12b0139e3aabb21e559ab0a0c62a432523080bb9"; - sha256 = "sha256-Dw1r1UnmSVyrCMNRS79F99x8Vgb6KASN2gBegPbXnpk="; - }; - - # shell scripts — no compilation - dontBuild = true; - - installPhase = '' - mkdir -p $out/bin - cp steamdeck-bios-manager.sh $out/bin/steamdeck-bios-manager - chmod +x $out/bin/steamdeck-bios-manager - ''; - - # runtime deps - nativeBuildInputs = [ - pciutils - bash - ]; - - meta = with lib; { - description = "Manage BIOS for the Steam Deck (unlock, flash, backup, block updates)"; - homepage = "https://github.com/ryanrudolfoba/SteamDeck-BIOS-Manager"; - license = licenses.agpl3Only; - platforms = platforms.linux; - maintainers = [ ]; - sourceProvenance = with sourceTypes; [ ]; - }; -} diff --git a/packages/superposition/default.nix b/packages/superposition/default.nix deleted file mode 100644 index 87107f5..0000000 --- a/packages/superposition/default.nix +++ /dev/null @@ -1,149 +0,0 @@ -{ - lib, - glib, - stdenv, - dbus, - freetype, - fontconfig, - zlib, - libsForQt5, - libxinerama, - libxcb, - libsm, - libxi, - libglvnd, - libxext, - libxrandr, - mailspring, - libx11, - libice, - libxrender, - autoPatchelfHook, - makeWrapper, - xkeyboard_config, - fetchurl, - buildFHSEnv, - openal, - makeDesktopItem, -}: - -let - pname = "unigine-superposition"; - version = "1.1"; - - superposition = stdenv.mkDerivation rec { - inherit pname version; - - src = fetchurl { - url = "https://assets.unigine.com/d/Unigine_Superposition-${version}.run"; - sha256 = "sha256-dJThxzv1nvIWFRPV1cudm/+9hHmSnUl2rFO2lV3lgPg="; - }; - - nativeBuildInputs = [ - autoPatchelfHook - makeWrapper - ]; - - buildInputs = [ - glib - stdenv.cc.cc - dbus - freetype - fontconfig - zlib - libsForQt5.qt5.qtquickcontrols2 - libxinerama - libxcb - libsm - libxi - libglvnd - libxext - libxrandr - mailspring - libx11 - libice - libxrender - ]; - - installPhase = '' - bash $src --target $name --noexec - mkdir -p $out/bin $out/lib/unigine/superposition/ - cp -r $name/* $out/lib/unigine/superposition/ - echo "exec $out/lib/unigine/superposition/Superposition" >> $out/bin/superposition - chmod +x $out/bin/superposition - wrapProgram $out/lib/unigine/superposition/Superposition \ - --set QT_XKB_CONFIG_ROOT ${xkeyboard_config} \ - --run "cd $out/lib/unigine/superposition/" - ''; - - dontUnpack = true; - dontWrapQtApps = true; - - postPatchMkspecs = '' - cp -f $name/bin/superposition $out/lib/unigine/superposition/bin/superposition - ''; - }; - - desktopItem = makeDesktopItem { - name = "Superposition"; - exec = "unigine-superposition"; - genericName = "A GPU Stress test tool from the UNIGINE"; - icon = "Superposition"; - desktopName = "Superposition Benchmark"; - }; - -in - -# We can patch the "/bin/superposition", but "/bin/launcher" checks it for changes. -# For that we need use a buildFHSEnv. - -buildFHSEnv { - inherit pname version; - - targetPkgs = _pkgs: [ - superposition - glib - stdenv.cc.cc - dbus - freetype - fontconfig - zlib - libsForQt5.qt5.qtquickcontrols2 - libxinerama - libxcb - libsm - libxi - libglvnd - libxext - libxrandr - mailspring - libx11 - libice - libxrender - openal - ]; - runScript = "superposition"; - - extraInstallCommands = '' - # create directories - mkdir -p $out/share/icons/hicolor $out/share/applications - # create .desktop file - ln -s ${desktopItem}/share/applications/* $out/share/applications - # install Superposition.desktop and icon - cp ${superposition}/lib/unigine/superposition/Superposition.png $out/share/icons/ - for RES in 16 24 32 48 64 128 256; do - mkdir -p $out/share/icons/hicolor/"$RES"x"$RES"/apps - cp ${superposition}/lib/unigine/superposition/icons/superposition_icon_$RES.png $out/share/icons/hicolor/"$RES"x"$RES"/apps/Superposition.png - done - ''; - - meta = { - description = "Unigine Superposition GPU benchmarking tool"; - homepage = "https://benchmark.unigine.com/superposition"; - sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ]; - license = lib.licenses.unfree; - maintainers = [ ]; - platforms = [ "x86_64-linux" ]; - mainProgram = "unigine-superposition"; - }; -} diff --git a/packages/uboot/versions.json b/packages/uboot/versions.json new file mode 100644 index 0000000..575dede --- /dev/null +++ b/packages/uboot/versions.json @@ -0,0 +1,5 @@ +{ + "repo": "https://ftp.denx.de/pub/u-boot/u-boot-${defaultVersion}.tar.bz2", + "tag": "2025.07", + "hash": "sha256-D5M/bFpCaJW/MG6T5qxTxghw5LVM2lbZUhG+yZ5jvsc=" +} diff --git a/update.py b/update.py new file mode 100755 index 0000000..6619d52 --- /dev/null +++ b/update.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +import json +import re +import subprocess +import sys +from pathlib import Path +from urllib.request import Request, urlopen +from urllib.error import HTTPError + +GITHUB_API = "https://api.github.com" +CODEBERG_API = "https://codeberg.org/api/v1" + +def run(cmd): + p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + if p.returncode != 0: + raise RuntimeError(f"Command failed: {' '.join(cmd)}\n{p.stderr.strip()}") + return p.stdout.strip() + +def http_get_json(url, token=None): + headers = {"Accept": "application/json"} + if token: + headers["Authorization"] = f"token {token}" + req = Request(url, headers=headers) + with urlopen(req) as resp: + return json.load(resp) + +def github_latest_release(owner, repo, token=None): + url = f"{GITHUB_API}/repos/{owner}/{repo}/releases/latest" + return http_get_json(url, token=token) + +def github_latest_commit(owner, repo, token=None): + url = f"{GITHUB_API}/repos/{owner}/{repo}/commits?per_page=1" + data = http_get_json(url, token=token) + return data[0]["sha"] + +def codeberg_latest_release(owner, repo, token=None): + url = f"{CODEBERG_API}/repos/{owner}/{repo}/releases/latest" + return http_get_json(url, token=token) + +def codeberg_latest_commit(owner, repo, token=None): + url = f"{CODEBERG_API}/repos/{owner}/{repo}/commits?limit=1" + data = http_get_json(url, token=token) + return data[0]["sha"] + +def nix_hash_to_sri(hash_str): + # Convert nix-base32 to SRI + return run(["nix", "hash", "to-sri", "--type", "sha256", hash_str]) + +def prefetch_git(url, rev): + out = run(["nix-prefetch-git", "--url", url, "--rev", rev, "--fetch-submodules"]) + data = json.loads(out) + return nix_hash_to_sri(data["sha256"]) + +def prefetch_url(url, unpack=False): + cmd = ["nix-prefetch-url", url] + if unpack: + cmd.insert(1, "--unpack") + hash_str = run(cmd) + return nix_hash_to_sri(hash_str) + +def is_archive_url(url): + return bool(re.search(r"\.(tar\.gz|tar\.xz|tar\.bz2|zip)$", url)) + +def build_repo_url(location, owner, repo): + if location == "github": + return f"https://github.com/{owner}/{repo}.git" + if location == "codeberg": + return f"https://codeberg.org/{owner}/{repo}.git" + raise ValueError(f"Unknown repo location: {location}") + +def build_release_tarball_url(location, owner, repo, tag): + if location == "github": + return f"https://github.com/{owner}/{repo}/archive/refs/tags/{tag}.tar.gz" + if location == "codeberg": + return f"https://codeberg.org/{owner}/{repo}/archive/{tag}.tar.gz" + raise ValueError(f"Unknown repo location: {location}") + +def update_entry(name, entry, gh_token=None, cb_token=None): + location = entry.get("location") + owner = entry.get("owner") + repo = entry.get("repo") + url = entry.get("url") + + if url and (location == "url" or location == "archive"): + # Direct URL source + unpack = is_archive_url(url) + new_hash = prefetch_url(url, unpack=unpack) + entry["hash"] = new_hash + return True + + if location in ("github", "codeberg"): + if entry.get("tag"): + # Use latest release tag + if location == "github": + rel = github_latest_release(owner, repo, token=gh_token) + tag = rel["tag_name"] + else: + rel = codeberg_latest_release(owner, repo, token=cb_token) + tag = rel["tag_name"] + if tag != entry["tag"]: + entry["tag"] = tag + tar_url = build_release_tarball_url(location, owner, repo, tag) + entry["hash"] = prefetch_url(tar_url, unpack=True) + return True + + if entry.get("rev"): + # Use latest commit + if location == "github": + sha = github_latest_commit(owner, repo, token=gh_token) + else: + sha = codeberg_latest_commit(owner, repo, token=cb_token) + if sha != entry["rev"]: + entry["rev"] = sha + repo_url = build_repo_url(location, owner, repo) + entry["hash"] = prefetch_git(repo_url, sha) + return True + + return False + +def process_file(path, gh_token=None, cb_token=None): + data = json.loads(path.read_text()) + changed = False + for name, entry in data.items(): + try: + changed = update_entry(name, entry, gh_token=gh_token, cb_token=cb_token) + except HTTPError as e: + print(f"[WARN] {path}: {name}: HTTP error {e.code}", file=sys.stderr) + except Exception as e: + print(f"[WARN] {path}: {name}: {e}", file=sys.stderr) + if changed: + path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n") + return changed + +def main(root): + gh_token = None + cb_token = None + # Optional tokens from environment + # import os + # gh_token = os.environ.get("GITHUB_TOKEN") + # cb_token = os.environ.get("CODEBERG_TOKEN") + + root = Path(root) + files = list(root.rglob("version*.json")) + if not files: + print("No version*.json files found") + return 1 + + updated = 0 + for f in files: + if process_file(f, gh_token=gh_token, cb_token=cb_token): + print(f"Updated: {f}") + updated += 1 + + print(f"Done. Updated {updated} file(s).") + return 0 + +if __name__ == "__main__": + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(2) + sys.exit(main(sys.argv[1])) \ No newline at end of file