diff --git a/pkgs/by-name/im/immich-cli/package.nix b/pkgs/by-name/im/immich-cli/package.nix index d41dc764f26d..092f2a9fe1ad 100644 --- a/pkgs/by-name/im/immich-cli/package.nix +++ b/pkgs/by-name/im/immich-cli/package.nix @@ -1,26 +1,52 @@ { lib, immich, - buildNpmPackage, + jq, nodejs, makeWrapper, + stdenv, }: -buildNpmPackage { + +let + inherit (immich) pnpm; +in +stdenv.mkDerivation rec { pname = "immich-cli"; - src = "${immich.src}/cli"; - inherit (immich.sources.components.cli) version npmDepsHash; + version = "2.2.86"; + inherit (immich) src pnpmDeps; - nativeBuildInputs = [ makeWrapper ]; + postPatch = '' + local -r cli_version="$(jq -r .version cli/package.json)" + test "$cli_version" = ${version} \ + || (echo "error: update immich-cli version to $cli_version" && exit 1) + ''; - inherit (immich.web) preBuild; + nativeBuildInputs = [ + jq + makeWrapper + nodejs + pnpm + pnpm.configHook + ]; + + buildPhase = '' + runHook preBuild + + pnpm --filter @immich/sdk build + pnpm --filter @immich/cli build + + runHook postBuild + ''; installPhase = '' runHook preInstall - mkdir -p $out - mv package.json package-lock.json node_modules dist $out/ + local -r packageOut="$out/lib/node_modules/@immich/cli" - makeWrapper ${lib.getExe nodejs} $out/bin/immich --add-flags $out/dist/index.js + pnpm --filter @immich/cli deploy --prod --no-optional "$packageOut" + + makeWrapper '${lib.getExe nodejs}' "$out/bin/immich" \ + --add-flags "$packageOut/dist/index.js" runHook postInstall ''; diff --git a/pkgs/by-name/im/immich/package.nix b/pkgs/by-name/im/immich/package.nix index d6889a2a0412..5fd4926b2caa 100644 --- a/pkgs/by-name/im/immich/package.nix +++ b/pkgs/by-name/im/immich/package.nix @@ -1,8 +1,8 @@ { lib, stdenv, - buildNpmPackage, fetchFromGitHub, + pnpm_10, python3, nodejs, node-gyp, @@ -10,7 +10,6 @@ nixosTests, immich-machine-learning, # build-time deps - glib, pkg-config, makeWrapper, curl, @@ -32,12 +31,10 @@ pixman, vips, buildPackages, - sourcesJSON ? ./sources.json, }: let - buildNpmPackage' = buildNpmPackage.override { inherit nodejs; }; - sources = lib.importJSON sourcesJSON; - inherit (sources) version; + pnpm = pnpm_10; + version = "1.140.1"; esbuild' = buildPackages.esbuild.override { buildGoModule = @@ -77,14 +74,14 @@ let # The geodata website is not versioned, so we use the internet archive geodata = let - inherit (sources.components.geonames) timestamp; + timestamp = "20250818205425"; date = "${lib.substring 0 4 timestamp}-${lib.substring 4 2 timestamp}-${lib.substring 6 2 timestamp}T" + "${lib.substring 8 2 timestamp}:${lib.substring 10 2 timestamp}:${lib.substring 12 2 timestamp}Z"; in runCommand "immich-geodata" { - outputHash = sources.components.geonames.hash; + outputHash = "sha256-zZHAomW1C4qReFbhme5dkVnTiLw+jmhZhzuYvoBVBCY="; outputHashMode = "recursive"; nativeBuildInputs = [ cacert @@ -111,69 +108,39 @@ let owner = "immich-app"; repo = "immich"; tag = "v${version}"; - inherit (sources) hash; + hash = "sha256-Bo9wFP0u39aoaNjc8K4Im3HRGZR/TLrDB7+UDAhV1xA="; }; - openapi = buildNpmPackage' { - pname = "immich-openapi-sdk"; - inherit version; - src = "${src}/open-api/typescript-sdk"; - inherit (sources.components."open-api/typescript-sdk") npmDepsHash; - - installPhase = '' - runHook preInstall - - npm config delete cache - npm prune --omit=dev --omit=optional - - mkdir -p $out - mv package.json package-lock.json node_modules build $out/ - - runHook postInstall - ''; - }; - - web = buildNpmPackage' { - pname = "immich-web"; + pnpmDeps = pnpm.fetchDeps { + pname = "immich"; inherit version src; - sourceRoot = "${src.name}/web"; - inherit (sources.components.web) npmDepsHash; + fetcherVersion = 2; + hash = "sha256-DIcUKuU+ToRh/kSLcs4ZEHy7zhFir2nlbRx+/kMagrA="; + }; - # prePatch is needed because npmConfigHook is a postPatch - prePatch = '' - # some part of the build wants to use un-prefixed binaries. let them. - mkdir -p $TMP/bin - ln -s "$(type -p ${stdenv.cc.targetPrefix}pkg-config)" $TMP/bin/pkg-config || true - ln -s "$(type -p ${stdenv.cc.targetPrefix}c++filt)" $TMP/bin/c++filt || true - ln -s "$(type -p ${stdenv.cc.targetPrefix}readelf)" $TMP/bin/readelf || true - export PATH="$TMP/bin:$PATH" - ''; - - preBuild = '' - rm node_modules/@immich/sdk - ln -s ${openapi} node_modules/@immich/sdk - ''; - - env.npm_config_build_from_source = "true"; + web = stdenv.mkDerivation { + pname = "immich-web"; + inherit version src pnpmDeps; nativeBuildInputs = [ - pkg-config + nodejs + pnpm + pnpm.configHook ]; - buildInputs = [ - # https://github.com/Automattic/node-canvas/blob/master/Readme.md#compiling - cairo - giflib - libjpeg - libpng - librsvg - pango - pixman - ]; + buildPhase = '' + runHook preBuild + + pnpm --filter @immich/sdk build + pnpm --filter immich-web build + + runHook postBuild + ''; installPhase = '' runHook preInstall + cd web cp -r build $out runHook postInstall @@ -184,32 +151,24 @@ let mesonFlags = prev.mesonFlags ++ [ "-Dtiff=disabled" ]; }); in -buildNpmPackage' { +stdenv.mkDerivation { pname = "immich"; - inherit version; - src = "${src}/server"; - inherit (sources.components.server) npmDepsHash; + inherit version src pnpmDeps; - # prePatch is needed because npmConfigHook is a postPatch - prePatch = '' + postPatch = '' # pg_dumpall fails without database root access # see https://github.com/immich-app/immich/issues/13971 - substituteInPlace src/services/backup.service.ts \ + substituteInPlace server/src/services/backup.service.ts \ --replace-fail '`/usr/lib/postgresql/''${databaseMajorVersion}/bin/pg_dumpall`' '`pg_dump`' - - # some part of the build wants to use un-prefixed binaries. let them. - mkdir -p $TMP/bin - ln -s "$(type -p ${stdenv.cc.targetPrefix}pkg-config)" $TMP/bin/pkg-config || true - ln -s "$(type -p ${stdenv.cc.targetPrefix}c++filt)" $TMP/bin/c++filt || true - ln -s "$(type -p ${stdenv.cc.targetPrefix}readelf)" $TMP/bin/readelf || true - export PATH="$TMP/bin:$PATH" ''; nativeBuildInputs = [ + nodejs pkg-config + pnpm_10 + pnpm_10.configHook python3 makeWrapper - glib node-gyp # for building node_modules/sharp from source ]; @@ -230,43 +189,60 @@ buildNpmPackage' { vips' ]; - # Required because vips tries to write to the cache dir - makeCacheWritable = true; - env.SHARP_FORCE_GLOBAL_LIBVIPS = 1; env.ESBUILD_BINARY_PATH = lib.getExe esbuild'; + # fix for node-gyp, see https://github.com/nodejs/node-gyp/issues/1191#issuecomment-301243919 + env.npm_config_nodedir = nodejs; + + buildPhase = '' + runHook preBuild - preBuild = '' # If exiftool-vendored.pl isn't found, exiftool is searched for on the PATH - rm -r node_modules/exiftool-vendored.* + rm node_modules/.pnpm/node_modules/exiftool-vendored.pl + + pnpm --filter immich build + + runHook postBuild ''; installPhase = '' runHook preInstall - npm config delete cache - npm prune --omit=dev + local -r packageOut="$out/lib/node_modules/immich" + + # install node_modules and built files in $out + # upstream uses pnpm deploy to build their docker images + pnpm --filter immich deploy --prod --no-optional "$packageOut" # remove build artifacts that bloat the closure - rm -r node_modules/**/{*.target.mk,binding.Makefile,config.gypi,Makefile,Release/.deps} + find "$packageOut/node_modules" \( \ + -name config.gypi \ + -o -name .deps \ + -o -name '*Makefile' \ + -o -name '*.target.mk' \ + \) -exec rm -r {} + - mkdir -p $out/build - mv package.json package-lock.json node_modules dist resources $out/ - ln -s ${web} $out/build/www - ln -s ${geodata} $out/build/geodata + mkdir -p "$packageOut/build" + ln -s '${web}' "$packageOut/build/www" + ln -s '${geodata}' "$packageOut/build/geodata" - echo '${builtins.toJSON buildLock}' > $out/build/build-lock.json + echo '${builtins.toJSON buildLock}' > "$packageOut/build/build-lock.json" - makeWrapper ${lib.getExe nodejs} $out/bin/admin-cli --add-flags $out/dist/main --add-flags cli - makeWrapper ${lib.getExe nodejs} $out/bin/server --add-flags $out/dist/main --chdir $out \ - --set IMMICH_BUILD_DATA $out/build --set NODE_ENV production \ - --suffix PATH : "${ + makeWrapper '${lib.getExe nodejs}' "$out/bin/admin-cli" \ + --add-flags "$packageOut/dist/main" \ + --add-flags cli + makeWrapper '${lib.getExe nodejs}' "$out/bin/server" \ + --add-flags "$packageOut/dist/main" \ + --chdir "$packageOut" \ + --set IMMICH_BUILD_DATA "$packageOut/build" \ + --set NODE_ENV production \ + --suffix PATH : '${ lib.makeBinPath [ exiftool jellyfin-ffmpeg perl # exiftool-vendored checks for Perl even if exiftool comes from $PATH ] - }" + }' runHook postInstall ''; @@ -280,11 +256,10 @@ buildNpmPackage' { inherit src - sources web geodata + pnpm ; - updateScript = ./update.sh; }; meta = { diff --git a/pkgs/by-name/im/immich/sources.json b/pkgs/by-name/im/immich/sources.json deleted file mode 100644 index 70e02e44a510..000000000000 --- a/pkgs/by-name/im/immich/sources.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "version": "1.138.1", - "hash": "sha256-oaZN0kF82mS25bDSTXRjYnWG9RAMSbCUhXn9t0am96U=", - "components": { - "cli": { - "npmDepsHash": "sha256-6k83QOdKh+FlVnYvA9j60115oohUMDc2YvGaj/GMukE=", - "version": "2.2.79" - }, - "server": { - "npmDepsHash": "sha256-4sqWIIGQ8ZW7TvJoNjNNliriuV6Su0askAN6pAq9VFc=", - "version": "1.138.1" - }, - "web": { - "npmDepsHash": "sha256-+W8cDgy3qe6RDen8SEdHPNADkKb4zZH8C/Am/bdU42c=", - "version": "1.138.1" - }, - "open-api/typescript-sdk": { - "npmDepsHash": "sha256-GfmFPsnFu7l4EsnPDv4nj5KLkOz8nEJvMT1BE7zIQ3k=", - "version": "1.138.1" - }, - "geonames": { - "timestamp": "20250818205425", - "hash": "sha256-zZHAomW1C4qReFbhme5dkVnTiLw+jmhZhzuYvoBVBCY=" - } - } -} diff --git a/pkgs/by-name/im/immich/update.sh b/pkgs/by-name/im/immich/update.sh deleted file mode 100755 index 1e11085e3adf..000000000000 --- a/pkgs/by-name/im/immich/update.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env nix-shell -#!nix-shell -i bash -p curl jq prefetch-npm-deps nix-prefetch-github coreutils ripgrep - -set -euo pipefail -cd "$(dirname "${BASH_SOURCE[0]}")" - -old_version=$(jq -r ".version" sources.json || echo -n "0.0.1") -version=$(curl -s "https://api.github.com/repos/immich-app/immich/releases/latest" | jq -r ".tag_name") -version="${version#v}" - -echo "Updating to $version" - -if [[ "$old_version" == "$version" ]]; then - echo "Already up to date!" - exit 0 -fi - -echo "Fetching src" -src_hash=$(nix-prefetch-github immich-app immich --rev "v${version}" | jq -r .hash) -upstream_src="https://raw.githubusercontent.com/immich-app/immich/v$version" - -sources_tmp="$(mktemp)" -cat < "$sources_tmp" -{ - "version": "$version", - "hash": "$src_hash", - "components": {} -} -EOF - -lock=$(mktemp) -for npm_component in cli server web "open-api/typescript-sdk"; do - echo "fetching $npm_component" - curl -s -o "$lock" "$upstream_src/$npm_component/package-lock.json" - hash=$(prefetch-npm-deps "$lock") - echo "$(jq --arg npm_component "$npm_component" \ - --arg hash "$hash" \ - --arg version "$(jq -r '.version' <"$lock")" \ - '.components += {($npm_component): {npmDepsHash: $hash, version: $version}}' \ - "$sources_tmp")" > "$sources_tmp" -done -rm "$lock" - -url="http://download.geonames.org/export/dump" -curl -s "http://web.archive.org/save/$url/cities500.zip" -curl -s "http://web.archive.org/save/$url/admin1CodesASCII.txt" -curl -s "http://web.archive.org/save/$url/admin1Codes.txt" -timestamp=$(curl -s \ - "http://archive.org/wayback/available?url=$url/cities500.zip" \ - | jq -r ".archived_snapshots.closest.timestamp") -echo "$(jq --arg timestamp "$timestamp" --arg hash "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" \ - '.components += {geonames: {timestamp: $timestamp, hash: $hash}}' \ - "$sources_tmp")" > "$sources_tmp" - -cp "$sources_tmp" sources.json -set +o pipefail -output="$(nix-build ../../../.. -A immich.geodata 2>&1 || true)" -set -o pipefail -hash=$(echo "$output" | rg 'got:\s+(sha256-.*)$' -or '$1') -echo "$(jq --arg hash "$hash" '.components.geonames.hash = $hash' "$sources_tmp")" > "$sources_tmp" - -mv "$sources_tmp" sources.json