2021-12-19 01:06:50 +00:00
{ lib , stdenvNoCC , linkFarmFromDrvs , nuget-to-nix , writeScript , makeWrapper , fetchurl , xml2 , dotnetCorePackages , dotnetPackages , cacert }:
2021-10-14 00:43:12 +00:00
{ name ? " ${ args . pname } - ${ args . version } "
, enableParallelBuilding ? true
2021-12-06 16:07:01 +00:00
, doCheck ? false
2021-10-14 00:43:12 +00:00
# Flags to pass to `makeWrapper`. This is done to avoid double wrapping.
, makeWrapperArgs ? [ ]
# Flags to pass to `dotnet restore`.
, dotnetRestoreFlags ? [ ]
# Flags to pass to `dotnet build`.
, dotnetBuildFlags ? [ ]
2021-12-06 16:07:01 +00:00
# Flags to pass to `dotnet test`, if running tests is enabled.
, dotnetTestFlags ? [ ]
2021-10-14 00:43:12 +00:00
# Flags to pass to `dotnet install`.
, dotnetInstallFlags ? [ ]
2021-12-19 01:06:50 +00:00
# Flags to pass to `dotnet pack`.
, dotnetPackFlags ? [ ]
2021-10-14 00:43:12 +00:00
# Flags to pass to dotnet in all phases.
, dotnetFlags ? [ ]
# The binaries that should get installed to `$out/bin`, relative to `$out/lib/$pname/`. These get wrapped accordingly.
# Unfortunately, dotnet has no method for doing this automatically.
# If unset, all executables in the projects root will get installed. This may cause bloat!
, executables ? null
2021-12-19 01:06:50 +00:00
# Packs a 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`.
, packNupkg ? false
2021-12-06 16:07:01 +00:00
# The packages project file, which contains instructions on how to compile it. This can be an array of multiple project files as well.
2021-10-14 00:43:12 +00:00
, projectFile ? null
# The NuGet dependency file. This locks all NuGet dependency versions, as otherwise they cannot be deterministically fetched.
2021-12-19 01:06:50 +00:00
# This can be generated by running the `passthru.fetch-deps` script.
2021-10-14 00:43:12 +00:00
, nugetDeps ? null
2021-12-19 01:06:50 +00:00
# A list of derivations containing nupkg packages for local project references.
# Referenced derivations can be built with `buildDotnetModule` with `packNupkg=true` flag.
# Since we are sharing them as nugets they must be added to csproj/fsproj files as `PackageReference` as well.
# For example, your project has a local dependency:
# <ProjectReference Include="../foo/bar.fsproj" />
# To enable discovery through `projectReferences` you would need to add a line:
# <ProjectReference Include="../foo/bar.fsproj" />
# <PackageReference Include="bar" Version="*" Condition=" '$(ContinuousIntegrationBuild)'=='true' "/>
, projectReferences ? [ ]
2021-10-14 00:43:12 +00:00
# Libraries that need to be available at runtime should be passed through this.
# These get wrapped into `LD_LIBRARY_PATH`.
, runtimeDeps ? [ ]
2021-12-06 16:07:01 +00:00
# Tests to disable. This gets passed to `dotnet test --filter "FullyQualifiedName!={}"`, to ensure compatibility with all frameworks.
# See https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test#filter-option-details for more details.
, disabledTests ? [ ]
2021-12-24 04:21:11 +00:00
# The project file to run unit tests against. This is usually referenced in the regular project file, but sometimes it needs to be manually set.
# It gets restored and build, but not installed. You may need to regenerate your nuget lockfile after setting this.
, testProjectFile ? " "
2021-12-06 16:07:01 +00:00
2021-10-14 00:43:12 +00:00
# The type of build to perform. This is passed to `dotnet` with the `--configuration` flag. Possible values are `Release`, `Debug`, etc.
, buildType ? " R e l e a s e "
# The dotnet SDK to use.
, dotnet-sdk ? dotnetCorePackages . sdk_5_0
# The dotnet runtime to use.
2021-10-17 09:34:42 +00:00
, dotnet-runtime ? dotnetCorePackages . runtime_5_0
2021-12-06 16:07:01 +00:00
# The dotnet SDK to run tests against. This can differentiate from the SDK compiled against.
, dotnet-test-sdk ? dotnet-sdk
2021-10-14 00:43:12 +00:00
, . . . } @ args :
assert projectFile == null -> throw " D e f i n i n g t h e ` p r o j e c t F i l e ` a t t r i b u t e i s r e q u i r e d . T h i s i s u s u a l l y a n ` . c s p r o j ` , o r ` . s l n ` f i l e . " ;
# 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.
2021-12-19 01:06:50 +00:00
assert nugetDeps == null -> throw " D e f i n i n g t h e ` n u g e t D e p s ` a t t r i b u t e i s r e q u i r e d , a s t o l o c k t h e N u G e t d e p e n d e n c i e s . T h i s f i l e c a n b e g e n e r a t e d b y r u n n i n g t h e ` p a s s t h r u . f e t c h - d e p s ` s c r i p t . " ;
2021-10-14 00:43:12 +00:00
let
_nugetDeps = linkFarmFromDrvs " ${ name } - n u g e t - d e p s " ( import nugetDeps {
2021-12-24 04:21:11 +00:00
fetchNuGet = { pname , version , sha256 }: fetchurl {
name = " ${ pname } - ${ version } . n u p k g " ;
url = " h t t p s : / / w w w . n u g e t . o r g / a p i / v 2 / p a c k a g e / ${ pname } / ${ version } " ;
2021-10-14 00:43:12 +00:00
inherit sha256 ;
} ;
} ) ;
2021-12-19 01:06:50 +00:00
_localDeps = linkFarmFromDrvs " ${ name } - l o c a l - n u g e t - d e p s " projectReferences ;
2021-10-14 00:43:12 +00:00
2021-12-06 16:07:01 +00:00
nuget-source = stdenvNoCC . mkDerivation rec {
name = " ${ args . pname } - n u g e t - s o u r c e " ;
meta . description = " A N u g e t s o u r c e w i t h t h e d e p e n d e n c i e s f o r ${ args . pname } " ;
nativeBuildInputs = [ dotnetPackages . Nuget xml2 ] ;
buildCommand = ''
export HOME = $ ( mktemp - d )
mkdir - p $ out / { lib , share }
nuget sources Add - Name nixos - Source " $ o u t / l i b "
nuget init " ${ _nugetDeps } " " $ o u t / l i b "
2021-12-19 01:06:50 +00:00
$ { lib . optionalString ( projectReferences != [ ] )
" n u g e t i n i t \" ${ _localDeps } \" \" $ o u t / l i b \" " }
2021-12-06 16:07:01 +00:00
# Generates a list of all unique licenses' spdx ids.
find " $ o u t / l i b " - name " * . n u s p e c " - exec sh - c \
" x m l 2 < { } | g r e p " license = " | c u t - d ' = ' - f 2 " \ ; | sort - u > $ out/share/licenses
'' ;
} // { # This is done because we need data from `$out` for `meta`. We have to use overrides as to not hit infinite recursion.
meta . licence = let
depLicenses = lib . splitString " \n " ( builtins . readFile " ${ nuget-source } / s h a r e / l i c e n s e s " ) ;
getLicence = spdx : lib . filter ( license : license . spdxId or null == spdx ) ( builtins . attrValues lib . licenses ) ;
in ( lib . flatten ( lib . forEach depLicenses ( spdx :
if ( getLicence spdx ) != [ ] then ( getLicence spdx ) else [ ] ++ lib . optional ( spdx != " " ) spdx
) ) ) ;
} ;
package = stdenvNoCC . mkDerivation ( args // {
2021-10-28 06:52:43 +00:00
inherit buildType ;
2021-12-06 16:07:01 +00:00
nativeBuildInputs = args . nativeBuildInputs or [ ] ++ [ dotnet-sdk cacert makeWrapper ] ;
2021-10-14 00:43:12 +00:00
# Stripping breaks the executable
dontStrip = true ;
2021-12-24 04:21:11 +00:00
# gappsWrapperArgs gets included when wrapping for dotnet, as to avoid double wrapping
dontWrapGApps = true ;
2021-10-14 00:43:12 +00:00
DOTNET_NOLOGO = true ; # This disables the welcome message.
DOTNET_CLI_TELEMETRY_OPTOUT = true ;
2022-01-03 16:56:52 +00:00
passthru = {
fetch-deps = writeScript " f e t c h - ${ args . pname } - d e p s " ''
set - euo pipefail
cd " $ ( d i r n a m e " '' ${ BASH_SOURCE [ 0 ] } " ) "
export HOME = $ ( mktemp - d )
deps_file = " / t m p / ${ args . pname } - d e p s . n i x "
store_src = " ${ package . src } "
src = " $ ( m k t e m p - d / t m p / ${ args . pname } . X X X ) "
cp - rT " $ s t o r e _ s r c " " $ s r c "
chmod - R + w " $ s r c "
trap " r m - r f $ s r c $ H O M E " EXIT
pushd " $ s r c "
export DOTNET_NOLOGO = 1
export DOTNET_CLI_TELEMETRY_OPTOUT = 1
mkdir - p " $ H O M E / n u g e t _ p k g s "
for project in " ${ lib . concatStringsSep " \" \" " ( ( lib . toList projectFile ) ++ lib . optionals ( testProjectFile != " " ) ( lib . toList testProjectFile ) ) } " ; do
$ { dotnet-sdk } /bin/dotnet restore " $ p r o j e c t " \
$ { lib . optionalString ( ! enableParallelBuilding ) " - - d i s a b l e - p a r a l l e l " } \
- p:ContinuousIntegrationBuild=true \
- p:Deterministic=true \
- - packages " $ H O M E / n u g e t _ p k g s " \
" ' ' ${ dotnetRestoreFlags [ @ ] } " \
" ' ' ${ dotnetFlags [ @ ] } "
done
echo " W r i t i n g l o c k f i l e . . . "
$ { nuget-to-nix } /bin/nuget-to-nix " $ H O M E / n u g e t _ p k g s " > " $ d e p s _ f i l e "
echo " S u c c e s f u l l y w r o t e l o c k f i l e t o : $ d e p s _ f i l e "
'' ;
} // args . passthru or { } ;
2021-12-19 01:06:50 +00:00
2021-10-14 00:43:12 +00:00
configurePhase = args . configurePhase or ''
runHook preConfigure
export HOME = $ ( mktemp - d )
2021-12-24 04:21:11 +00:00
for project in '' ${ projectFile [ @ ] } ''$ { t e s t P r o j e c t F i l e [ @ ] } ; d o
2021-12-06 16:07:01 +00:00
dotnet restore " $ p r o j e c t " \
$ { lib . optionalString ( ! enableParallelBuilding ) " - - d i s a b l e - p a r a l l e l " } \
- p:ContinuousIntegrationBuild=true \
- p:Deterministic=true \
- - source " ${ nuget-source } / l i b " \
" ' ' ${ dotnetRestoreFlags [ @ ] } " \
" ' ' ${ dotnetFlags [ @ ] } "
done
2021-10-14 00:43:12 +00:00
runHook postConfigure
'' ;
buildPhase = args . buildPhase or ''
runHook preBuild
2021-12-24 04:21:11 +00:00
for project in '' ${ projectFile [ @ ] } ''$ { t e s t P r o j e c t F i l e [ @ ] } ; d o
2021-12-06 16:07:01 +00:00
dotnet build " $ p r o j e c t " \
- maxcpucount:$ { if enableParallelBuilding then " $ N I X _ B U I L D _ C O R E S " else " 1 " } \
- p:BuildInParallel=$ { if enableParallelBuilding then " t r u e " else " f a l s e " } \
- p:ContinuousIntegrationBuild=true \
- p:Deterministic=true \
- p:Version=$ { args . version } \
- - configuration " $ b u i l d T y p e " \
- - no-restore \
" ' ' ${ dotnetBuildFlags [ @ ] } " \
" ' ' ${ dotnetFlags [ @ ] } "
done
2021-10-14 00:43:12 +00:00
runHook postBuild
'' ;
2021-12-06 16:07:01 +00:00
checkPhase = args . checkPhase or ''
runHook preCheck
for project in '' ${ testProjectFile [ @ ] } ; d o
$ { lib . getBin dotnet-test-sdk } /bin/dotnet test " $ p r o j e c t " \
- maxcpucount:$ { if enableParallelBuilding then " $ N I X _ B U I L D _ C O R E S " else " 1 " } \
- p:ContinuousIntegrationBuild=true \
- p:Deterministic=true \
- - configuration " $ b u i l d T y p e " \
- - no-build \
- - logger " c o n s o l e ; v e r b o s i t y = n o r m a l " \
$ { lib . optionalString ( disabledTests != [ ] ) " - - f i l t e r \" F u l l y Q u a l i f i e d N a m e ! = ${ lib . concatStringsSep " & F u l l y Q u a l i f i e d N a m e ! = " disabledTests } \" " } \
" ' ' ${ dotnetTestFlags [ @ ] } " \
" ' ' ${ dotnetFlags [ @ ] } "
done
runHook postCheck
'' ;
2021-10-14 00:43:12 +00:00
installPhase = args . installPhase or ''
runHook preInstall
2021-12-06 16:07:01 +00:00
for project in '' ${ projectFile [ @ ] } ; d o
dotnet publish " $ p r o j e c t " \
- p:ContinuousIntegrationBuild=true \
- p:Deterministic=true \
- - output $ out/lib / $ { args . pname } \
- - configuration " $ b u i l d T y p e " \
- - no-build \
- - no-self-contained \
" ' ' ${ dotnetInstallFlags [ @ ] } " \
" ' ' ${ dotnetFlags [ @ ] } "
done
2022-01-19 23:45:15 +00:00
'' + l i b . o p t i o n a l S t r i n g p a c k N u p k g ''
2021-12-19 01:06:50 +00:00
for project in '' ${ projectFile [ @ ] } ; d o
dotnet pack " $ p r o j e c t " \
- p:ContinuousIntegrationBuild=true \
- p:Deterministic=true \
- - output $ out/share \
- - configuration " $ b u i l d T y p e " \
- - no-build \
" ' ' ${ dotnetPackFlags [ @ ] } " \
" ' ' ${ dotnetFlags [ @ ] } "
done
2022-01-19 23:45:15 +00:00
'' + ''
runHook postInstall
'' ;
preFixup = ''
_wrapDotnetProgram ( ) {
makeWrapper " $ 1 " " $ o u t / b i n / $ ( b a s e n a m e " $ executable " ) " \
- - set DOTNET_ROOT " ${ dotnet-runtime } " \
- - suffix LD_LIBRARY_PATH : " ${ lib . makeLibraryPath runtimeDeps } " \
" ' ' ${ gappsWrapperArgs [ @ ] } " \
" ' ' ${ makeWrapperArgs [ @ ] } "
}
'' + ( i f e x e c u t a b l e s ! = n u l l t h e n ''
for executable in '' ${ executables [ @ ] } ; d o
2021-10-14 00:43:12 +00:00
execPath = " $ o u t / l i b / ${ args . pname } / $ e x e c u t a b l e "
if [ [ - f " $ e x e c P a t h " && - x " $ e x e c P a t h " ] ] ; then
2022-01-19 23:45:15 +00:00
_wrapDotnetProgram $ execPath
2021-10-14 00:43:12 +00:00
else
echo " S p e c i f i e d b i n a r y \" $ e x e c u t a b l e \" i s e i t h e r n o t a n e x e c u t a b l e , o r d o e s n o t e x i s t ! "
exit 1
fi
done
'' e l s e ''
for executable in $ out/lib / $ { args . pname } /* ; d o
if [ [ - f " $ e x e c u t a b l e " && - x " $ e x e c u t a b l e " && " $ e x e c u t a b l e " != * " d l l " * ] ] ; then
2022-01-19 23:45:15 +00:00
_wrapDotnetProgram $ executable
2021-10-14 00:43:12 +00:00
fi
done
2022-01-19 23:45:15 +00:00
'' ) ;
2021-10-14 00:43:12 +00:00
} ) ;
in
package