2022-09-14 18:05:37 +00:00
{ lib
, stdenvNoCC
, callPackage
, linkFarmFromDrvs
, dotnetCorePackages
, dotnetPackages
, mkNugetSource
, mkNugetDeps
, srcOnly
, writeShellScript
, writeText
, makeWrapper
, nuget-to-nix
, cacert
, symlinkJoin
, coreutils
} :
2021-10-14 00:43:12 +00:00
{ name ? " ${ args . pname } - ${ args . version } "
2022-03-05 16:20:37 +00:00
, pname ? name
2021-10-14 00:43:12 +00:00
, 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 ? [ ]
2022-03-05 16:20:37 +00:00
# The path to publish the project to. When unset, the directory "$out/lib/$pname" is used.
, installPath ? null
2021-10-14 00:43:12 +00:00
# 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 "
2022-08-12 12:06:08 +00:00
# If set to true, builds the application as a self-contained - removing the runtime dependency on dotnet
, selfContainedBuild ? false
2021-10-14 00:43:12 +00:00
# The dotnet SDK to use.
2022-06-16 17:23:12 +00:00
, dotnet-sdk ? dotnetCorePackages . sdk_6_0
2021-10-14 00:43:12 +00:00
# The dotnet runtime to use.
2022-06-16 17:23:12 +00:00
, dotnet-runtime ? dotnetCorePackages . runtime_6_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
2022-03-05 16:20:37 +00:00
inherit ( callPackage ./hooks {
inherit dotnet-sdk dotnet-test-sdk disabledTests nuget-source dotnet-runtime runtimeDeps buildType ;
} ) dotnetConfigureHook dotnetBuildHook dotnetCheckHook dotnetInstallHook dotnetFixupHook ;
2022-04-27 09:35:20 +00:00
localDeps = if ( projectReferences != [ ] )
then linkFarmFromDrvs " ${ name } - p r o j e c t - r e f e r e n c e s " projectReferences
else null ;
2022-06-26 10:26:21 +00:00
_nugetDeps = if lib . isDerivation nugetDeps
then nugetDeps
else mkNugetDeps { inherit name ; nugetDeps = import nugetDeps ; } ;
2021-10-14 00:43:12 +00:00
2022-08-21 13:32:41 +00:00
# contains the actual package dependencies
_dependenciesSource = mkNugetSource {
name = " ${ name } - d e p e n d e n c i e s - s o u r c e " ;
2022-04-27 09:35:20 +00:00
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 ${ name } " ;
deps = [ _nugetDeps ] ++ lib . optional ( localDeps != null ) localDeps ;
2021-12-06 16:07:01 +00:00
} ;
2022-08-21 13:32:41 +00:00
# this contains all the nuget packages that are implictly referenced by the dotnet
# build system. having them as separate deps allows us to avoid having to regenerate
# a packages dependencies when the dotnet-sdk version changes
_sdkDeps = mkNugetDeps {
name = " d o t n e t - s d k - ${ dotnet-sdk . version } - d e p s " ;
nugetDeps = dotnet-sdk . passthru . packages ;
} ;
_sdkSource = mkNugetSource {
name = " d o t n e t - s d k - ${ dotnet-sdk . version } - s o u r c e " ;
deps = [ _sdkDeps ] ;
} ;
nuget-source = symlinkJoin {
name = " ${ name } - n u g e t - s o u r c e " ;
paths = [ _dependenciesSource _sdkSource ] ;
} ;
2022-03-05 16:20:37 +00:00
in stdenvNoCC . mkDerivation ( args // {
nativeBuildInputs = args . nativeBuildInputs or [ ] ++ [
dotnetConfigureHook
dotnetBuildHook
dotnetCheckHook
dotnetInstallHook
dotnetFixupHook
2021-10-14 00:43:12 +00:00
2022-03-05 16:20:37 +00:00
cacert
makeWrapper
2022-07-18 16:21:45 +00:00
dotnet-sdk
] ;
makeWrapperArgs = args . makeWrapperArgs or [ ] ++ [
" - - p r e f i x L D _ L I B R A R Y _ P A T H : ${ dotnet-sdk . icu } / l i b "
2022-03-05 16:20:37 +00:00
] ;
2022-01-03 16:56:52 +00:00
2022-03-05 16:20:37 +00:00
# Stripping breaks the executable
dontStrip = args . dontStrip or true ;
2022-01-03 16:56:52 +00:00
2022-03-05 16:20:37 +00:00
# gappsWrapperArgs gets included when wrapping for dotnet, as to avoid double wrapping
dontWrapGApps = args . dontWrapGApps or true ;
2022-01-03 16:56:52 +00:00
2022-03-05 16:20:37 +00:00
passthru = {
2022-04-27 09:35:20 +00:00
inherit nuget-source ;
2022-08-21 13:32:41 +00:00
fetch-deps = let
2022-09-14 18:05:37 +00:00
# Because this list is rather long its put in its own store path to maintain readability of the generated script
exclusions = writeText " n u g e t - p a c k a g e - e x c l u s i o n s " ( lib . concatStringsSep " \n " ( dotnet-sdk . passthru . packages { fetchNuGet = attrs : attrs . pname ; } ) ) ;
runtimeIds = map ( system : dotnet-sdk . systemToDotnetRid system ) ( args . meta . platforms or dotnet-sdk . meta . platforms ) ;
# Derivations may set flags such as `--runtime <rid>` based on the host platform to avoid restoring/building nuget dependencies they dont have or dont need.
# This introduces an issue; In this script we loop over all platforms from `meta` and add the RID flag for it, as to fetch all required dependencies.
# The script would inherit the RID flag from the derivation based on the platform building the script, and set the flag for any iteration we do over the RIDs.
# That causes conflicts. To circumvent it we remove all occurances of the flag.
flags =
let
hasRid = flag : lib . any ( v : v ) ( map ( rid : lib . hasInfix rid flag ) ( lib . attrValues dotnet-sdk . runtimeIdentifierMap ) ) ;
in
builtins . filter ( flag : ! ( hasRid flag ) ) ( dotnetFlags ++ dotnetRestoreFlags ) ;
2022-08-21 13:32:41 +00:00
in writeShellScript " f e t c h - ${ pname } - d e p s " ''
2022-03-05 16:20:37 +00:00
set - euo pipefail
2022-08-21 13:32:41 +00:00
2022-09-14 18:05:37 +00:00
export PATH = " ${ lib . makeBinPath [ coreutils dotnet-sdk nuget-to-nix ] } "
2021-10-14 00:43:12 +00:00
2022-09-14 18:05:37 +00:00
case " ' ' ${ 1 - } " in
- - help | - h )
echo " u s a g e : $ 0 < o u t p u t p a t h > [ - - h e l p ] "
echo " < o u t p u t p a t h > T h e p a t h t o w r i t e t h e l o c k f i l e t o "
echo " - - h e l p S h o w t h i s h e l p m e s s a g e "
exit
; ;
esac
deps_file = " $ ( r e a l p a t h " '' ${ 1 : - $ ( mktemp - t " X X X X X X - ${ pname } - d e p s . n i x " ) } " ) "
export HOME = $ ( mktemp - td " X X X X X X - ${ pname } - h o m e " )
mkdir - p " $ H O M E / n u g e t _ p k g s "
2021-10-14 00:43:12 +00:00
2022-06-26 10:26:21 +00:00
store_src = " ${ srcOnly args } "
2022-09-14 18:05:37 +00:00
src = " $ ( m k t e m p - t d " XXXXXX- $ { pname } - src " ) "
2022-03-05 16:20:37 +00:00
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
2022-09-14 18:05:37 +00:00
cd " $ s r c "
echo " R e s t o r i n g p r o j e c t . . . "
2021-10-14 00:43:12 +00:00
2022-03-05 16:20:37 +00:00
export DOTNET_NOLOGO = 1
export DOTNET_CLI_TELEMETRY_OPTOUT = 1
2021-10-14 00:43:12 +00:00
2022-09-14 18:05:37 +00:00
for rid in " ${ lib . concatStringsSep " \" \" " runtimeIds } " ; do
for project in " ${ lib . concatStringsSep " \" \" " ( ( lib . toList projectFile ) ++ lib . optionals ( testProjectFile != " " ) ( lib . toList testProjectFile ) ) } " ; do
dotnet restore " $ p r o j e c t " \
- p:ContinuousIntegrationBuild=true \
- p:Deterministic=true \
- - packages " $ H O M E / n u g e t _ p k g s " \
- - runtime " $ r i d " \
$ { lib . optionalString ( ! enableParallelBuilding ) " - - d i s a b l e - p a r a l l e l " } \
$ { lib . optionalString ( flags != [ ] ) ( toString flags ) }
done
2021-12-06 16:07:01 +00:00
done
2022-09-14 18:05:37 +00:00
echo " S u c c e s f u l l y r e s t o r e d p r o j e c t "
2022-08-21 13:32:41 +00:00
2022-03-05 16:20:37 +00:00
echo " W r i t i n g l o c k f i l e . . . "
2022-09-14 18:05:37 +00:00
echo - e " # T h i s f i l e w a s a u t o m a t i c a l l y g e n e r a t e d b y p a s s t h r u . f e t c h - d e p s . \n # P l e a s e d o n t e d i t i t m a n u a l l y , y o u r c h a n g e s m i g h t g e t o v e r w r i t t e n ! \n " > " $ d e p s _ f i l e "
nuget-to-nix " $ H O M E / n u g e t _ p k g s " " ${ exclusions } " > > " $ d e p s _ f i l e "
2022-03-05 16:20:37 +00:00
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 "
2021-12-06 16:07:01 +00:00
'' ;
2022-03-05 16:20:37 +00:00
} // args . passthru or { } ;
2022-09-14 18:05:37 +00:00
meta = {
platforms = dotnet-sdk . meta . platforms ;
} // args . meta or { } ;
2022-03-05 16:20:37 +00:00
} )