diff options
Diffstat (limited to 'pkgs/by-name/so/sonarr/update.py')
-rw-r--r-- | pkgs/by-name/so/sonarr/update.py | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/pkgs/by-name/so/sonarr/update.py b/pkgs/by-name/so/sonarr/update.py new file mode 100644 index 0000000000000..195a2d5d05ac0 --- /dev/null +++ b/pkgs/by-name/so/sonarr/update.py @@ -0,0 +1,160 @@ +import json +import os +import pathlib +import requests +import shutil +import subprocess +import sys +import tempfile + + +def replace_in_file(file_path, replacements): + file_contents = pathlib.Path(file_path).read_text() + for old, new in replacements.items(): + if old == new: + continue + updated_file_contents = file_contents.replace(old, new) + # A dumb way to check that we’ve actually replaced the string. + if file_contents == updated_file_contents: + print(f"no string to replace: {old} → {new}", file=sys.stderr) + sys.exit(1) + file_contents = updated_file_contents + with tempfile.NamedTemporaryFile(mode="w") as t: + t.write(file_contents) + t.flush() + shutil.copyfile(t.name, file_path) + + +def nix_hash_to_sri(hash): + return subprocess.run( + [ + "nix", + "--extra-experimental-features", "nix-command", + "hash", + "to-sri", + "--type", "sha256", + "--", + hash, + ], + stdout=subprocess.PIPE, + text=True, + check=True, + ).stdout.rstrip() + + +nixpkgs_path = "." +attr_path = os.getenv("UPDATE_NIX_ATTR_PATH", "sonarr") + +package_attrs = json.loads(subprocess.run( + [ + "nix", + "--extra-experimental-features", "nix-command", + "eval", + "--json", + "--file", nixpkgs_path, + "--apply", """p: { + dir = builtins.dirOf p.meta.position; + version = p.version; + sourceHash = p.src.outputHash; + yarnHash = p.yarnOfflineCache.outputHash; + }""", + "--", + attr_path, + ], + stdout=subprocess.PIPE, + text=True, + check=True, +).stdout) + +old_version = package_attrs["version"] +new_version = old_version + +# Note that we use Sonarr API instead of GitHub to fetch latest stable release. +# This corresponds to the Updates tab in the web UI. See also +# https://github.com/Sonarr/Sonarr/blob/070919a7e6a96ca7e26524996417c6f8d1b5fcaa/src/NzbDrone.Core/Update/UpdatePackageProvider.cs +version_update = requests.get( + f"https://services.sonarr.tv/v1/update/main?version={old_version}", +).json() +if version_update["available"]: + new_version = version_update["updatePackage"]["version"] + +if new_version == old_version: + sys.exit() + +source_nix_hash, source_store_path = subprocess.run( + [ + "nix-prefetch-url", + "--name", "source", + "--unpack", + "--print-path", + f"https://github.com/Sonarr/Sonarr/archive/v{new_version}.tar.gz", + ], + stdout=subprocess.PIPE, + text=True, + check=True, +).stdout.rstrip().split("\n") + +old_source_hash = package_attrs["sourceHash"] +new_source_hash = nix_hash_to_sri(source_nix_hash) + +old_yarn_hash = package_attrs["yarnHash"] +new_yarn_hash = nix_hash_to_sri(subprocess.run( + [ + "prefetch-yarn-deps", + # does not support "--" separator :( + # Also --verbose writes to stdout, yikes. + os.path.join(source_store_path, "yarn.lock"), + ], + stdout=subprocess.PIPE, + text=True, + check=True, +).stdout.rstrip()) + +package_dir = package_attrs["dir"] +package_file_name = "package.nix" +deps_file_name = "deps.nix" + +# To update deps.nix, we copy the package to a temporary directory and run +# passthru.fetch-deps script there. +with tempfile.TemporaryDirectory() as work_dir: + package_file = os.path.join(work_dir, package_file_name) + deps_file = os.path.join(work_dir, deps_file_name) + + shutil.copytree(package_dir, work_dir, dirs_exist_ok=True) + + replace_in_file(package_file, { + # NB unlike hashes, versions are likely to be used in code or comments. + # Try to be more specific to avoid false positive matches. + f"version = \"{old_version}\"": f"version = \"{new_version}\"", + old_source_hash: new_source_hash, + old_yarn_hash: new_yarn_hash, + }) + + # Generate nuget-to-nix dependency lock file. + fetch_deps = os.path.join(work_dir, "fetch-deps") + subprocess.run( + [ + "nix", + "--extra-experimental-features", "nix-command", + "build", + "--impure", + "--nix-path", "", + "--include", f"nixpkgs={nixpkgs_path}", + "--include", f"package={package_file}", + "--expr", "(import <nixpkgs> { }).callPackage <package> { }", + "--out-link", fetch_deps, + "passthru.fetch-deps", + ], + check=True, + ) + subprocess.run( + [ + fetch_deps, + deps_file, + ], + stdout=subprocess.DEVNULL, + check=True, + ) + + shutil.copy(deps_file, os.path.join(package_dir, deps_file_name)) + shutil.copy(package_file, os.path.join(package_dir, package_file_name)) |