Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

buildDotnetModule: add passthru.fetch-deps #150587

Merged
merged 1 commit into from
Dec 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions doc/languages-frameworks/dotnet.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,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` has to be used for specifying the dotnet project file relative to the source root. These usually have `.sln` or `.csproj` file extensions. This can be an array of multiple projects as well.
* `nugetDeps` has to be used to specify the NuGet dependency file. Unfortunately, these cannot be deterministically fetched without a lockfile. This file should be generated using `nuget-to-nix` tool, which is available in nixpkgs.
* `nugetDeps` has to be used to specify the NuGet dependency file. Unfortunately, these cannot be deterministically fetched without a lockfile. A script to fetch these is available as `passthru.fetch-deps`. This file can also be generated manually using `nuget-to-nix` tool, which is available in nixpkgs.
* `packNupkg` is used to pack project as a `nupkg`, and installs it to `$out/share`. If set to `true`, the derivation can be used as a dependency for another dotnet project by adding it to `projectReferences`.
* `projectReferences` can be used to resolve `ProjectReference` project items. Referenced projects can be packed with `buildDotnetModule` by setting the `packNupkg = true` attribute and passing a list of derivations to `projectReferences`. Since we are sharing referenced projects as NuGets they must be added to csproj/fsproj files as `PackageReference` as well.
For example, your project has a local dependency:
Expand All @@ -99,6 +99,8 @@ To package Dotnet applications, you can use `buildDotnetModule`. This has simila
* `dotnetPackFlags` can be used to pass flags to `dotnet pack`. Used only if `packNupkg` is set to `true`.
* `dotnetFlags` can be used to pass flags to all of the above phases.

When packaging a new application, you need to fetch it's dependencies. You can set `nugetDeps` to an empty string to make the derivation temporarily evaluate, and then run `nix-build -A package.passthru.fetch-deps` to generate it's dependency fetching script. After running the script, you should have the location of the generated lockfile printed to the console. This can be copied to a stable directory. Note that if either `projectFile` or `nugetDeps` are unset, this script cannot be generated!

Here is an example `default.nix`, using some of the previously discussed arguments:
```nix
{ lib, buildDotnetModule, dotnetCorePackages, ffmpeg }:
Expand All @@ -112,7 +114,8 @@ in buildDotnetModule rec {
src = ./.;

projectFile = "src/project.sln";
nugetDeps = ./deps.nix; # File generated with `nuget-to-nix path/to/src > deps.nix`.
nugetDeps = ./deps.nix; # File generated with `nix-build -A package.passthru.fetch-deps`.

projectReferences = [ referencedProject ]; # `referencedProject` must contain `nupkg` in the folder structure.

dotnet-sdk = dotnetCorePackages.sdk_3_1;
Expand Down
41 changes: 38 additions & 3 deletions pkgs/build-support/build-dotnet-module/default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ lib, stdenvNoCC, linkFarmFromDrvs, makeWrapper, fetchurl, xml2, dotnetCorePackages, dotnetPackages, cacert }:
{ lib, stdenvNoCC, linkFarmFromDrvs, nuget-to-nix, writeScript, makeWrapper, fetchurl, xml2, dotnetCorePackages, dotnetPackages, cacert }:

{ name ? "${args.pname}-${args.version}"
, enableParallelBuilding ? true
Expand Down Expand Up @@ -28,7 +28,7 @@
# The packages project file, which contains instructions on how to compile it. This can be an array of multiple project files as well.
, projectFile ? null
# The NuGet dependency file. This locks all NuGet dependency versions, as otherwise they cannot be deterministically fetched.
# This can be generated using the `nuget-to-nix` tool.
# This can be generated by running the `passthru.fetch-deps` script.
, nugetDeps ? null
# A list of derivations containing nupkg packages for local project references.
# Referenced derivations can be built with `buildDotnetModule` with `packNupkg=true` flag.
Expand Down Expand Up @@ -63,7 +63,7 @@ assert projectFile == null -> throw "Defining the `projectFile` attribute is req

# TODO: Automatically generate a dependency file when a lockfile is present.
# This file is unfortunately almost never present, as Microsoft recommands not to push this in upstream repositories.
assert nugetDeps == null -> throw "Defining the `nugetDeps` attribute is required, as to lock the NuGet dependencies. This file can be generated using the `nuget-to-nix` tool.";
assert nugetDeps == null -> 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.";

let
_nugetDeps = linkFarmFromDrvs "${name}-nuget-deps" (import nugetDeps {
Expand Down Expand Up @@ -113,6 +113,41 @@ let
DOTNET_NOLOGO = true; # This disables the welcome message.
DOTNET_CLI_TELEMETRY_OPTOUT = true;

passthru.fetch-deps = args.passthru.fetch-deps or writeScript "fetch-${args.pname}-deps" ''
set -euo pipefail
cd "$(dirname "''${BASH_SOURCE[0]}")"

export HOME=$(mktemp -d)
deps_file="/tmp/${args.pname}-deps.nix"

store_src="${package.src}"
src="$(mktemp -d /tmp/${args.pname}.XXX)"
cp -rT "$store_src" "$src"
chmod -R +w "$src"

trap "rm -rf $src $HOME" EXIT
pushd "$src"

export DOTNET_NOLOGO=1
export DOTNET_CLI_TELEMETRY_OPTOUT=1

mkdir -p "$HOME/nuget_pkgs"

for project in "${lib.concatStringsSep "\" \"" (lib.toList projectFile)}"; do
${dotnet-sdk}/bin/dotnet restore "$project" \
${lib.optionalString (!enableParallelBuilding) "--disable-parallel"} \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
--packages "$HOME/nuget_pkgs" \
"''${dotnetRestoreFlags[@]}" \
"''${dotnetFlags[@]}"
done

echo "Writing lockfile..."
${nuget-to-nix}/bin/nuget-to-nix "$HOME/nuget_pkgs" > "$deps_file"
echo "Succesfully wrote lockfile to: $deps_file"
'';

configurePhase = args.configurePhase or ''
runHook preConfigure

Expand Down