prowlarr: build from sources

This commit is contained in:
Paul TREHIOU 2025-06-04 13:21:54 +00:00 committed by GitHub
parent 3e3afe5174
commit 4083a554cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 2050 additions and 123 deletions

1695
pkgs/by-name/pr/prowlarr/deps.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,100 +1,195 @@
{ {
lib, lib,
stdenv, stdenvNoCC,
fetchurl, fetchFromGitHub,
mono, buildDotnetModule,
libmediainfo, dotnetCorePackages,
sqlite, sqlite,
curl, fetchYarnDeps,
makeWrapper, yarn,
icu, fixup-yarn-lock,
dotnet-runtime, nodejs,
openssl,
nixosTests, nixosTests,
zlib, # update script
writers,
python3Packages,
nix,
prefetch-yarn-deps,
fetchpatch,
applyPatches,
}: }:
let let
pname = "prowlarr";
unsupported = throw "Unsupported system ${stdenv.hostPlatform.system} for ${pname}";
os =
if stdenv.hostPlatform.isDarwin then
"osx"
else if stdenv.hostPlatform.isLinux then
"linux"
else
unsupported;
arch =
{
aarch64-darwin = "arm64";
aarch64-linux = "arm64";
x86_64-darwin = "x64";
x86_64-linux = "x64";
}
.${stdenv.hostPlatform.system} or unsupported;
hash =
{
aarch64-darwin = "sha256-IkFkQoEPVaV+eVp2DkZECXTkzJyyNYTUBsCBdXCBZC8=";
aarch64-linux = "sha256-uwg5Ec9MC6jLwNdauF1tj2gSkhWdyhvWnUTLt8P1OZw=";
x86_64-darwin = "sha256-mdDZvKyhKXnHEKvZRH8Di6dZP80AEktnkMOnIZW+Gik=";
x86_64-linux = "sha256-N0KDb6MsGAJKSh5GSm7aiamjflHRXb06fL1KM2T1+bg=";
}
.${stdenv.hostPlatform.system} or unsupported;
in
stdenv.mkDerivation rec {
inherit pname;
version = "1.36.3.5071"; version = "1.36.3.5071";
# The dotnet8 compatibility patches also change `yarn.lock`, so we must pass
# the already patched lockfile to `fetchYarnDeps`.
src = applyPatches {
src = fetchFromGitHub {
owner = "Prowlarr";
repo = "Prowlarr";
tag = "v${version}";
hash = "sha256-n9G+do5aZ9ZEqjGyX8UH32IVTNWh7Eo3bfqi1nfIfHw=";
};
postPatch = ''
mv src/NuGet.config NuGet.Config
'';
patches = lib.optionals (lib.versionOlder version "2.0") [
# See https://github.com/Prowlarr/Prowlarr/pull/2399
# Unfortunately, the .NET 8 upgrade will be merged into the v2 branch,
# and it may take some time for that to become stable.
# However, the patches cleanly apply to v1 as well.
(fetchpatch {
name = "dotnet8-compatibility";
url = "https://github.com/Prowlarr/Prowlarr/commit/21c408a7dac8abaac91c05958f18a556220b2304.patch";
hash = "sha256-Es7JEXycOJPMXN+Kgv4wRnJA+l6zltUdP2i/wVodTBs=";
})
(fetchpatch {
name = "dotnet8-darwin-compatibility";
url = "https://github.com/Prowlarr/Prowlarr/commit/7a1fca5e23a3e75a9a2b2e1073a33eaa2ce865fe.patch";
hash = "sha256-bReCHXC3RHgm1MYmE2kGqStt4fuBHowcupLIXT3fEes=";
})
(fetchpatch {
name = "bump-swashbuckle-version";
url = "https://github.com/Prowlarr/Prowlarr/commit/8eec321a0eaa396e2f964576e5883890c719b202.patch";
hash = "sha256-SOdzGvq8FFYa451zTOw8yD1CDvM++AiFYFHhFW5Soco=";
})
];
};
rid = dotnetCorePackages.systemToDotnetRid stdenvNoCC.hostPlatform.system;
in
buildDotnetModule {
pname = "prowlarr";
inherit version src;
src = fetchurl { strictDeps = true;
url = "https://github.com/Prowlarr/Prowlarr/releases/download/v${version}/Prowlarr.master.${version}.${os}-core-${arch}.tar.gz"; nativeBuildInputs = [
inherit hash; nodejs
yarn
prefetch-yarn-deps
fixup-yarn-lock
];
yarnOfflineCache = fetchYarnDeps {
yarnLock = "${src}/yarn.lock";
hash = "sha256-QVyjo/Zshy+61qocGKa3tZS8gnHvvVqenf79FkiXDBM=";
}; };
nativeBuildInputs = [ makeWrapper ]; postConfigure = ''
yarn config --offline set yarn-offline-mirror "$yarnOfflineCache"
installPhase = '' fixup-yarn-lock yarn.lock
runHook preInstall yarn install --offline --frozen-lockfile --ignore-platform --ignore-scripts --no-progress --non-interactive
patchShebangs --build node_modules
mkdir -p $out/{bin,share/${pname}-${version}} '';
cp -r * $out/share/${pname}-${version}/. postBuild = ''
yarn --offline run build --env production
makeWrapper "${dotnet-runtime}/bin/dotnet" $out/bin/Prowlarr \ '';
--add-flags "$out/share/${pname}-${version}/Prowlarr.dll" \ postInstall = ''
--prefix LD_LIBRARY_PATH : ${ cp -a -- _output/UI "$out/lib/prowlarr/UI"
lib.makeLibraryPath [
curl
sqlite
libmediainfo
mono
openssl
icu
zlib
]
}
runHook postInstall
''; '';
nugetDeps = ./deps.json;
runtimeDeps = [ sqlite ];
dotnet-sdk = dotnetCorePackages.sdk_8_0;
dotnet-runtime = dotnetCorePackages.aspnetcore_8_0;
doCheck = true;
__darwinAllowLocalNetworking = true; # for tests
__structuredAttrs = true; # for Copyright property that contains spaces
executables = [ "Prowlarr" ];
projectFile = [
"src/NzbDrone.Console/Prowlarr.Console.csproj"
"src/NzbDrone.Mono/Prowlarr.Mono.csproj"
];
testProjectFile = [
"src/Prowlarr.Api.V1.Test/Prowlarr.Api.V1.Test.csproj"
"src/NzbDrone.Common.Test/Prowlarr.Common.Test.csproj"
"src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj"
"src/NzbDrone.Host.Test/Prowlarr.Host.Test.csproj"
"src/NzbDrone.Libraries.Test/Prowlarr.Libraries.Test.csproj"
"src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj"
"src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj"
];
dotnetFlags = [
"--property:TargetFramework=net8.0"
"--property:EnableAnalyzers=false"
"--property:SentryUploadSymbols=false" # Fix Sentry upload failed warnings
# Override defaults in src/Directory.Build.props that use current time.
"--property:Copyright=Copyright 2014-2025 prowlarr.com (GNU General Public v3)"
"--property:AssemblyVersion=${version}"
"--property:AssemblyConfiguration=master"
"--property:RuntimeIdentifier=${rid}"
];
# Skip manual, integration, automation and platform-dependent tests.
testFilters =
[
"TestCategory!=ManualTest"
"TestCategory!=IntegrationTest"
"TestCategory!=AutomationTest"
# makes real HTTP requests
"FullyQualifiedName!~NzbDrone.Core.Test.UpdateTests.UpdatePackageProviderFixture"
]
++ lib.optionals stdenvNoCC.buildPlatform.isDarwin [
# fails on macOS
"FullyQualifiedName!~NzbDrone.Core.Test.Http.HttpProxySettingsProviderFixture"
];
disabledTests = [
# setgid tests
"NzbDrone.Mono.Test.DiskProviderTests.DiskProviderFixture.should_preserve_setgid_on_set_folder_permissions"
"NzbDrone.Mono.Test.DiskProviderTests.DiskProviderFixture.should_clear_setgid_on_set_folder_permissions"
# we do not set application data directory during tests (i.e. XDG data directory)
"NzbDrone.Mono.Test.DiskProviderTests.FreeSpaceFixture.should_return_free_disk_space"
"NzbDrone.Common.Test.ServiceFactoryFixture.event_handlers_should_be_unique"
# attempts to read /etc/*release and fails since it does not exist
"NzbDrone.Mono.Test.EnvironmentInfo.ReleaseFileVersionAdapterFixture.should_get_version_info"
# fails to start test dummy because it cannot locate .NET runtime for some reason
"NzbDrone.Common.Test.ProcessProviderFixture.should_be_able_to_start_process"
"NzbDrone.Common.Test.ProcessProviderFixture.exists_should_find_running_process"
"NzbDrone.Common.Test.ProcessProviderFixture.kill_all_should_kill_all_process_with_name"
];
passthru = { passthru = {
updateScript = ./update.sh; tests = {
tests.smoke-test = nixosTests.prowlarr; inherit (nixosTests) prowlarr;
};
updateScript = writers.writePython3 "prowlarr-updater" {
libraries = with python3Packages; [ requests ];
flakeIgnore = [ "E501" ];
makeWrapperArgs = [
"--prefix"
"PATH"
":"
(lib.makeBinPath [
nix
prefetch-yarn-deps
])
];
} ./update.py;
}; };
meta = { meta = {
description = "Indexer manager/proxy built on the popular arr .net/reactjs base stack"; description = "Indexer manager/proxy built on the popular arr .net/reactjs base stack";
homepage = "https://wiki.servarr.com/prowlarr"; homepage = "https://prowlarr.com/";
changelog = "https://github.com/Prowlarr/Prowlarr/releases/tag/v${version}"; changelog = "https://github.com/Prowlarr/Prowlarr/releases/tag/v${version}";
license = lib.licenses.gpl3Only; license = lib.licenses.gpl3Only;
maintainers = with lib.maintainers; [ pizzapim ]; maintainers = with lib.maintainers; [
mainProgram = "Prowlarr"; pizzapim
platforms = [ nyanloutre
"aarch64-darwin"
"aarch64-linux"
"x86_64-darwin"
"x86_64-linux"
]; ];
mainProgram = "Prowlarr";
# platforms inherited from dotnet-sdk.
}; };
} }

View File

@ -0,0 +1,182 @@
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 weve 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", "prowlarr")
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.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 Prowlarr API instead of GitHub to fetch latest stable release.
# This corresponds to the Updates tab in the web UI. See also
# https://github.com/Prowlarr/Prowlarr/blob/7d813ef97a01af0f36a2beaec32e9cd854fc67f3/src/NzbDrone.Core/Update/UpdatePackageProvider.cs
# https://github.com/Prowlarr/Prowlarr/blob/7d813ef97a01af0f36a2beaec32e9cd854fc67f3/src/NzbDrone.Common/Cloud/ProwlarrCloudRequestBuilder.cs
version_update = requests.get(
f"https://prowlarr.servarr.com/v1/update/master?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/Prowlarr/Prowlarr/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)
package_dir = package_attrs["dir"]
package_file_name = "package.nix"
deps_file_name = "deps.json"
# 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,
})
# We need access to the patched and updated src to get the patched
# `yarn.lock`.
patched_src = os.path.join(work_dir, "patched-src")
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", patched_src,
"src",
],
check=True,
)
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(patched_src, "yarn.lock"),
],
stdout=subprocess.PIPE,
text=True,
check=True,
).stdout.rstrip())
replace_in_file(package_file, {
old_yarn_hash: new_yarn_hash,
})
# Generate nuget-to-json 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))

View File

@ -1,45 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl gnused nix-prefetch jq
set -eou pipefail
dirname="$(dirname "$0")"
updateHash()
{
# nixos
version=$1
system=$2
# prowlarr
arch=$3
os=$4
url="https://github.com/Prowlarr/Prowlarr/releases/download/v$version/Prowlarr.master.$version.$os-core-$arch.tar.gz"
hash=$(nix-prefetch-url --type sha256 $url)
sriHash="$(nix hash to-sri --type sha256 $hash)"
sed -i "s|$system = \"sha256-[a-zA-Z0-9\/+-=]*\";|$system = \"$sriHash\";|g" "$dirname/package.nix"
}
updateVersion()
{
sed -i "s/version = \"[0-9.]*\";/version = \"$1\";/g" "$dirname/package.nix"
}
currentVersion=$(cd $dirname && nix eval --raw -f ../../../.. prowlarr.version)
latestTag=$(curl https://api.github.com/repos/Prowlarr/Prowlarr/releases/latest | jq -r ".tag_name")
latestVersion="$(expr $latestTag : 'v\(.*\)')"
if [[ "$currentVersion" == "$latestVersion" ]]; then
echo "Prowlarr is up-to-date: ${currentVersion}"
exit 0
fi
updateVersion $latestVersion
updateHash $latestVersion aarch64-darwin arm64 osx
updateHash $latestVersion aarch64-linux arm64 linux
updateHash $latestVersion x86_64-darwin x64 osx
updateHash $latestVersion x86_64-linux x64 linux