Commit 7c2387c3 authored by Ratchanan Srirattanamet's avatar Ratchanan Srirattanamet
Browse files

actual-server: 25.3.1 -> 25.4.0

Release note available at [1].

This release now requires that the web UI is locally built rather than
fetched from NPM. Thus, the following changes are made:

- `offlineCache` is made to install all dependencies of the workspace.
  The resulting "temporary" `node_modules/` is not suitable for final
  install, but can be used for web UI building.
- Web UI is built into a separated derivation, using `node_modules/`
  built in the previous step.
- In the final derivation, web UI is copied in, then the final
  `node_modules/` is created using `offlineCache`.

The 2-tier node_modules also allow us to avoid downloading architecture-
dependent binaries during the generation of `offlineCache`, allowing us
to eliminate per-architecture hash which allow easier upgrade.

[1]: https://actualbudget.org/docs/releases#2540
parent dc271c12
Loading
Loading
Loading
Loading
+116 −30
Original line number Diff line number Diff line
@@ -7,33 +7,32 @@
  cacert,
  gitMinimal,
  nodejs_20,
  python3,
  yarn,
  nixosTests,
  nix-update-script,
}:
let
  version = "25.3.1";
  version = "25.4.0";
  src = fetchFromGitHub {
    name = "actualbudget-actual-source";
    owner = "actualbudget";
    repo = "actual";
    tag = "v${version}";
    hash = "sha256-UZ2Z1tkMbGJwka//cIC0aG1KCcTSxUPLzctEaOhnKQA=";
    hash = "sha256-+XYl4Bh0+8bs/FCqlig9egLg3SJCy2SRN2ovxWRE1Ok=";
  };
  translations = fetchFromGitHub {
    name = "actualbudget-translations-source";
    owner = "actualbudget";
    repo = "translations";
    # Note to updaters: this repo is not tagged, so just update this to the Git
    # tip at the time the update is performed.
    rev = "312fce7791e6722357e5d2f851407f4b7cf4ecb9";
    hash = "sha256-kDArpSFiNJJF5ZGCtcn7Ci7wCpI1cTSknDZ4sQgy/Nc=";
  };

  yarn_20 = yarn.override { nodejs = nodejs_20; };

  # We cannot use fetchYarnDeps because that doesn't support yarn2/berry
  # lockfiles (see https://github.com/NixOS/nixpkgs/issues/254369)
  offlineCache = stdenvNoCC.mkDerivation {
    name = "actual-server-${version}-offline-cache";
    inherit src;

    nativeBuildInputs = [
      cacert # needed for git
      gitMinimal # needed to download git dependencies
      yarn_20
    ];

  SUPPORTED_ARCHITECTURES = builtins.toJSON {
    os = [
      "darwin"
@@ -51,15 +50,35 @@ let
    ];
  };

  # We cannot use fetchYarnDeps because that doesn't support yarn2/berry
  # lockfiles (see https://github.com/NixOS/nixpkgs/issues/254369)
  offlineCache = stdenvNoCC.mkDerivation {
    name = "actual-server-${version}-offline-cache";
    inherit src;

    nativeBuildInputs = [
      cacert # needed for git
      gitMinimal # needed to download git dependencies
      yarn_20
    ];

    inherit SUPPORTED_ARCHITECTURES;

    buildPhase = ''
      runHook preBuild

      export HOME=$(mktemp -d)
      yarn config set enableTelemetry 0
      yarn config set cacheFolder $out
      # At this stage we don't need binaries yet, so we can skip preinstall
      # scripts here.
      yarn config set enableScripts false
      yarn config set --json supportedArchitectures "$SUPPORTED_ARCHITECTURES"

      yarn workspaces focus @actual-app/sync-server --production
      # Install dependencies for all workspaces, and include devDependencies,
      # to build web UI. Dependencies will be re-created in offline mode in the
      # package's install phase.
      yarn install --immutable

      runHook postBuild
    '';
@@ -76,14 +95,61 @@ let

    outputHashAlgo = "sha256";
    outputHashMode = "recursive";
    outputHash =
      {
        aarch64-darwin = "sha256-IJBfBA71PZeE/Zlu2kzQw8l/D4lVAV5I5loRyRfncKA=";
        aarch64-linux = "sha256-djE2lt/o/7kd7ci2TW3mhjSptD3etChbvtdbiWqp/wo=";
        x86_64-darwin = "sha256-AShd87VFwqDbJZoFJPg6HsdhTx7XMVdZ5sRWLXU8ldM=";
        x86_64-linux = "sha256-me0v+RuoleOKFRyJ7iyLTKRnV2Cz2Q1MLc/SE2sSSH8=";
      }
      .${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}");
    outputHash = "sha256-Tac2gOkdc2tzNKB3ARMfJad1MkOphudvN74gI8bGMtY=";
  };

  webUi = stdenvNoCC.mkDerivation {
    pname = "actual-server-webui";
    inherit version;
    srcs = [
      src
      translations
    ];
    sourceRoot = "${src.name}/";

    nativeBuildInputs = [
      nodejs_20
      yarn_20
    ];

    inherit SUPPORTED_ARCHITECTURES;

    postPatch = ''
      ln -sv ../../../${translations.name} ./packages/desktop-client/locale
      cp -r ${offlineCache}/node_modules ./node_modules

      patchShebangs --build ./bin ./packages/*/bin

      # Patch all references to `git` to a no-op `true`. This neuter automatic
      # translation update.
      substituteInPlace bin/package-browser \
        --replace-fail "git" "true"

      # Allow `remove-untranslated-languages` to do its job.
      chmod -R u+w ./packages/desktop-client/locale
    '';

    buildPhase = ''
      runHook preBuild

      export HOME=$(mktemp -d)
      yarn config set enableTelemetry 0
      yarn config set cacheFolder ${offlineCache}
      yarn config set --json supportedArchitectures "$SUPPORTED_ARCHITECTURES"

      yarn build:server

      runHook postBuild
    '';

    installPhase = ''
      runHook preInstall

      cp -r packages/desktop-client/build $out

      runHook postInstall
    '';
    dontFixup = true;
  };
in
stdenv.mkDerivation {
@@ -92,15 +158,35 @@ stdenv.mkDerivation {

  nativeBuildInputs = [
    makeWrapper
    (python3.withPackages (ps: [ ps.setuptools ])) # Used by node-gyp
    yarn_20
  ];

  inherit SUPPORTED_ARCHITECTURES;

  installPhase = ''
    runHook preInstall

    mkdir -p $out/{bin,lib,lib/actual/packages/sync-server}
    cp -r ${offlineCache}/node_modules/ $out/lib/actual
    mkdir -p $out/{bin,lib,lib/actual/packages/sync-server,lib/actual/packages/desktop-client}
    cp -r ./packages/sync-server/{app.js,src,migrations,package.json} $out/lib/actual/packages/sync-server
    # sync-server uses package.json to determine path to web ui.
    cp ./packages/desktop-client/package.json $out/lib/actual/packages/desktop-client
    cp -r ${webUi} $out/lib/actual/packages/desktop-client/build

    # Re-create node_modules/ to contain just production packages required for
    # sync-server itself, using existing offline cache. This will also now build
    # binaries.
    export HOME=$(mktemp -d)
    yarn config set enableNetwork false
    yarn config set enableOfflineMode true
    yarn config set enableTelemetry 0
    yarn config set cacheFolder ${offlineCache}
    yarn config set --json supportedArchitectures "$SUPPORTED_ARCHITECTURES"

    export npm_config_nodedir=${nodejs_20}

    yarn workspaces focus @actual-app/sync-server --production
    cp -r ./node_modules $out/lib/actual/

    makeWrapper ${lib.getExe nodejs_20} "$out/bin/actual-server" \
      --add-flags "$out/lib/actual/packages/sync-server/app.js" \
@@ -110,7 +196,7 @@ stdenv.mkDerivation {
  '';

  passthru = {
    inherit offlineCache;
    inherit offlineCache webUi;
    tests = nixosTests.actual;
    passthru.updateScript = nix-update-script { };
  };