Skip to content

Commit

Permalink
dotnet: add override mechanism for nuget packages (#339953)
Browse files Browse the repository at this point in the history
  • Loading branch information
corngood authored Sep 7, 2024
2 parents a6a1dbb + 14c908c commit 13a9751
Show file tree
Hide file tree
Showing 33 changed files with 268 additions and 227 deletions.
2 changes: 1 addition & 1 deletion doc/languages-frameworks/dotnet.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ The `dotnetCorePackages.sdk` contains both a runtime and the full sdk of a given
To package Dotnet applications, you can use `buildDotnetModule`. This has similar arguments to `stdenv.mkDerivation`, with the following additions:

* `projectFile` is used for specifying the dotnet project file, relative to the source root. These have `.sln` (entire solution) or `.csproj` (single project) file extensions. This can be a list of multiple projects as well. When omitted, will attempt to find and build the solution (`.sln`). If running into problems, make sure to set it to a file (or a list of files) with the `.csproj` extension - building applications as entire solutions is not fully supported by the .NET CLI.
* `nugetDeps` takes either a path to a `deps.nix` file, or a derivation. The `deps.nix` file can be generated using the script attached to `passthru.fetch-deps`. If the argument is a derivation, it will be used directly and assume it has the same output as `mkNugetDeps`.
* `nugetDeps` takes either a path to a `deps.nix` file, or a derivation. The `deps.nix` file can be generated using the script attached to `passthru.fetch-deps`. For compatibility, if the argument is a list of derivations, they will be added to `buildInputs`.
::: {.note}
For more detail about managing the `deps.nix` file, see [Generating and updating NuGet dependencies](#generating-and-updating-nuget-dependencies)
:::
Expand Down
2 changes: 1 addition & 1 deletion maintainers/scripts/update-dotnet-lockfiles.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
update scripts.
*/
let
pkgs = import ../.. {};
pkgs = import ../.. { config.allowAliases = false; };

inherit (pkgs) lib;

Expand Down
7 changes: 0 additions & 7 deletions pkgs/applications/audio/openutau/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
, dotnetCorePackages
, dbus
, fontconfig
, libICE
, libSM
, libX11
, portaudio
}:

Expand All @@ -32,10 +29,6 @@ buildDotnetModule rec {

runtimeDeps = [
dbus
fontconfig
libICE
libSM
libX11
portaudio
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,16 @@
, fetchFromGitHub
, buildDotnetModule
, dotnetCorePackages
, libX11
, libICE
, libSM
, fontconfig
, libsecret
, git
, git-credential-manager
, gnupg
, pass
, testers
, withGuiSupport ? true
, withLibsecretSupport ? true
, withGpgSupport ? true
}:

assert withLibsecretSupport -> withGuiSupport;
buildDotnetModule rec {
pname = "git-credential-manager";
version = "2.5.1";
Expand All @@ -36,9 +30,8 @@ buildDotnetModule rec {
dotnetInstallFlags = [ "--framework" "net8.0" ];
executables = [ "git-credential-manager" ];

runtimeDeps = [ fontconfig ]
++ lib.optionals withGuiSupport [ libX11 libICE libSM ]
++ lib.optional withLibsecretSupport libsecret;
runtimeDeps =
lib.optional withLibsecretSupport libsecret;
makeWrapperArgs = [
"--prefix PATH : ${lib.makeBinPath ([ git ] ++ lib.optionals withGpgSupport [ gnupg pass ])}"
];
Expand Down
18 changes: 10 additions & 8 deletions pkgs/build-support/dotnet/build-dotnet-global-tool/default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ buildDotnetModule, emptyDirectory, mkNugetDeps, dotnet-sdk }:
{ buildDotnetModule, emptyDirectory, fetchNupkg, dotnet-sdk }:

{ pname
, version
Expand All @@ -23,13 +23,15 @@ buildDotnetModule (args // {

src = emptyDirectory;

nugetDeps = mkNugetDeps {
name = pname;
nugetDeps = { fetchNuGet }: [
(fetchNuGet { pname = nugetName; inherit version; sha256 = nugetSha256; hash = nugetHash; })
] ++ (nugetDeps fetchNuGet);
installable = true;
};
buildInputs = [
(fetchNupkg {
pname = nugetName;
inherit version;
sha256 = nugetSha256;
hash = nugetHash;
installable = true;
})
];

dotnetGlobalTool = true;

Expand Down
64 changes: 39 additions & 25 deletions pkgs/build-support/dotnet/build-dotnet-module/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
writeShellScript,
makeWrapper,
dotnetCorePackages,
mkNugetDeps,
fetchNupkg,
nuget-to-nix,
cacert,
unzip,
Expand All @@ -18,10 +18,7 @@ let
transformArgs =
finalAttrs:
{
name ? "${args.pname}-${args.version}",
pname ? name,
enableParallelBuilding ? true,
doCheck ? false,
# Flags to pass to `makeWrapper`. This is done to avoid double wrapping.
makeWrapperArgs ? [ ],

Expand Down Expand Up @@ -115,22 +112,36 @@ let
_nugetDeps =
if (nugetDeps != null) then
if lib.isDerivation nugetDeps then
[ nugetDeps ]
else if lib.isList nugetDeps then
nugetDeps
else
mkNugetDeps {
inherit name;
sourceFile = nugetDeps;
}
assert (lib.isPath nugetDeps);
callPackage nugetDeps { fetchNuGet = fetchNupkg; }
else
throw "Defining the `nugetDeps` attribute is required, as to lock the NuGet dependencies. This file can be generated by running the `passthru.fetch-deps` script.";
[ ];

nugetDepsFile = _nugetDeps.sourceFile;
nugetDepsFile = if lib.isPath nugetDeps then nugetDeps else null;

inherit (dotnetCorePackages) systemToDotnetRid;
in
# Not all args need to be passed through to mkDerivation
# TODO: We should probably filter out even more attrs
removeAttrs args [ "nugetDeps" ]
removeAttrs args [
"nugetDeps"
"installPath"
"executables"
"projectFile"
"projectReferences"
"runtimeDeps"
"runtimeId"
"disabledTests"
"testProjectFile"
"buildType"
"selfContainedBuild"
"useDotnet"
"useAppHost"
]
// {
dotnetInstallPath = installPath;
dotnetExecutables = executables;
Expand All @@ -145,9 +156,18 @@ let
dotnetRuntimeDeps = map lib.getLib runtimeDeps;
dotnetSelfContainedBuild = selfContainedBuild;
dotnetUseAppHost = useAppHost;
inherit useDotnetFromEnv;

inherit enableParallelBuilding;
inherit
enableParallelBuilding
dotnetRestoreFlags
dotnetBuildFlags
dotnetTestFlags
dotnetInstallFlags
dotnetPackFlags
dotnetFlags
packNupkg
useDotnetFromEnv
;

nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
dotnetConfigureHook
Expand All @@ -163,13 +183,7 @@ let
yq
];

buildInputs =
args.buildInputs or [ ]
++ [
dotnet-sdk.packages
_nugetDeps
]
++ projectReferences;
buildInputs = args.buildInputs or [ ] ++ [ dotnet-sdk.packages ] ++ _nugetDeps ++ projectReferences;

# Parse the version attr into a format acceptable for the Version msbuild property
# The actual version attr is saved in InformationalVersion, which accepts an arbitrary string
Expand Down Expand Up @@ -213,13 +227,13 @@ let
{
nugetDeps = _nugetDeps;
}
// lib.optionalAttrs (!lib.isDerivation nugetDeps) {
// lib.optionalAttrs (nugetDeps == null || lib.isPath nugetDeps) {
fetch-deps =
let
pkg = finalAttrs.finalPackage.overrideAttrs (
old:
{
buildInputs = lib.remove _nugetDeps old.buildInputs;
buildInputs = lib.subtractLists _nugetDeps old.buildInputs;
keepNugetConfig = true;
}
// lib.optionalAttrs (runtimeId == null) {
Expand All @@ -238,15 +252,15 @@ let
# Note that toString is necessary here as it results in the path at
# eval time (i.e. to the file in your local Nixpkgs checkout) rather
# than the Nix store path of the path after it's been imported.
if lib.isPath nugetDepsFile && !lib.hasPrefix "${builtins.storeDir}/" (toString nugetDepsFile) then
if lib.isPath nugetDeps && !lib.isStorePath nugetDepsFile then
toString nugetDepsFile
else
''$(mktemp -t "${pname}-deps-XXXXXX.nix")'';
''$(mktemp -t "${finalAttrs.pname ? finalAttrs.finalPackage.name}-deps-XXXXXX.nix")'';
nugetToNix = (nuget-to-nix.override { inherit dotnet-sdk; });
};

in
writeShellScript "${name}-fetch-deps" ''
writeShellScript "${finalAttrs.finalPackage.name}-fetch-deps" ''
NIX_BUILD_SHELL="${runtimeShell}" exec ${nix}/bin/nix-shell \
--pure --run 'source "${innerScript}"' "${drv}"
'';
Expand Down
2 changes: 2 additions & 0 deletions pkgs/build-support/dotnet/build-dotnet-module/fetch-deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ tmp=$(mktemp -d)
trap 'chmod -R +w "$tmp" && rm -fr "$tmp"' EXIT

HOME=$tmp/.home
export TMPDIR="$tmp/.tmp"
mkdir "$HOME" "$TMPDIR"
cd "$tmp"

phases="
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ dotnetConfigureHook() {
fi
done

if [[ -f .config/dotnet-tools.json || -f .dotnet-tools.json ]]; then
if [[ -f .config/dotnet-tools.json || -f dotnet-tools.json ]]; then
dotnet tool restore
fi

Expand Down
80 changes: 80 additions & 0 deletions pkgs/build-support/dotnet/fetch-nupkg/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
symlinkJoin,
fetchurl,
stdenvNoCC,
lib,
unzip,
patchNupkgs,
nugetPackageHook,
callPackage,
overrides ? callPackage ./overrides.nix { },
}:
{
pname,
version,
sha256 ? "",
hash ? "",
url ? "https://www.nuget.org/api/v2/package/${pname}/${version}",
installable ? false,
}:
let
package = stdenvNoCC.mkDerivation rec {
inherit pname version;

src = fetchurl {
name = "${pname}.${version}.nupkg";
# There is no need to verify whether both sha256 and hash are
# valid here, because nuget-to-nix does not generate a deps.nix
# containing both.
inherit
url
sha256
hash
version
;
};

nativeBuildInputs = [
unzip
patchNupkgs
nugetPackageHook
];

unpackPhase = ''
runHook preUnpack
unzip -nqd source $src
chmod -R +rw source
cd source
runHook postUnpack
'';

prePatch = ''
shopt -s nullglob
local dir
for dir in tools runtimes/*/native; do
[[ ! -d "$dir" ]] || chmod -R +x "$dir"
done
rm -rf .signature.p7s
'';

installPhase = ''
runHook preInstall
dir=$out/share/nuget/packages/${lib.toLower pname}/${lib.toLower version}
mkdir -p $dir
cp -r . $dir
echo {} > "$dir"/.nupkg.metadata
runHook postInstall
'';

preFixup = ''
patch-nupkgs $out/share/nuget/packages
'';

createInstallableNugetSource = installable;
};
in
overrides.${pname} or lib.id package
55 changes: 55 additions & 0 deletions pkgs/build-support/dotnet/fetch-nupkg/overrides.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
autoPatchelfHook,
dotnetCorePackages,
fontconfig,
lib,
libICE,
libSM,
libX11,
stdenv,
writeText,
}:
{
# e.g.
# "Package.Id" =
# package:
# package.overrideAttrs (old: {
# buildInputs = old.buildInputs or [ ] ++ [ hello ];
# });

"Avalonia.X11" =
package:
package.overrideAttrs (
old:
lib.optionalAttrs (!stdenv.isDarwin) {
setupHook = writeText "setupHook.sh" ''
prependToVar dotnetRuntimeDeps \
"${lib.getLib libICE}" \
"${lib.getLib libSM}" \
"${lib.getLib libX11}"
'';
}
);

"SkiaSharp.NativeAssets.Linux" =
package:
package.overrideAttrs (
old:
lib.optionalAttrs stdenv.isLinux {
nativeBuildInputs = old.nativeBuildInputs or [ ] ++ [ autoPatchelfHook ];

buildInputs = old.buildInputs or [ ] ++ [ fontconfig ];

preInstall =
old.preInstall or ""
+ ''
cd runtimes
for platform in *; do
[[ $platform == "${dotnetCorePackages.systemToDotnetRid stdenv.hostPlatform.system}" ]] ||
rm -r "$platform"
done
cd - >/dev/null
'';
}
);
}
Loading

0 comments on commit 13a9751

Please sign in to comment.