2024-06-30 08:16:52 +00:00
{
lib ,
stdenvNoCC ,
callPackage ,
writeShellScript ,
srcOnly ,
linkFarmFromDrvs ,
symlinkJoin ,
makeWrapper ,
dotnetCorePackages ,
mkNugetSource ,
mkNugetDeps ,
nuget-to-nix ,
cacert ,
coreutils ,
runtimeShellPackage ,
2024-05-02 00:46:19 +00:00
} :
2024-06-30 08:16:52 +00:00
{
name ? " ${ args . pname } - ${ args . version } " ,
pname ? name ,
enableParallelBuilding ? true ,
doCheck ? false ,
2024-05-02 00:46:19 +00:00
# Flags to pass to `makeWrapper`. This is done to avoid double wrapping.
2024-06-30 08:16:52 +00:00
makeWrapperArgs ? [ ] ,
2024-05-02 00:46:19 +00:00
# Flags to pass to `dotnet restore`.
2024-06-30 08:16:52 +00:00
dotnetRestoreFlags ? [ ] ,
2024-05-02 00:46:19 +00:00
# Flags to pass to `dotnet build`.
2024-06-30 08:16:52 +00:00
dotnetBuildFlags ? [ ] ,
2024-05-02 00:46:19 +00:00
# Flags to pass to `dotnet test`, if running tests is enabled.
2024-06-30 08:16:52 +00:00
dotnetTestFlags ? [ ] ,
2024-05-02 00:46:19 +00:00
# Flags to pass to `dotnet install`.
2024-06-30 08:16:52 +00:00
dotnetInstallFlags ? [ ] ,
2024-05-02 00:46:19 +00:00
# Flags to pass to `dotnet pack`.
2024-06-30 08:16:52 +00:00
dotnetPackFlags ? [ ] ,
2024-05-02 00:46:19 +00:00
# Flags to pass to dotnet in all phases.
2024-06-30 08:16:52 +00:00
dotnetFlags ? [ ] ,
2024-05-02 00:46:19 +00:00
# The path to publish the project to. When unset, the directory "$out/lib/$pname" is used.
2024-06-30 08:16:52 +00:00
installPath ? null ,
2024-05-02 00:46:19 +00:00
# The binaries that should get installed to `$out/bin`, relative to `$installPath/`. 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!
2024-06-30 08:16:52 +00:00
executables ? null ,
2024-05-02 00:46:19 +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`.
2024-06-30 08:16:52 +00:00
packNupkg ? false ,
2024-05-02 00:46:19 +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.
2024-06-30 08:16:52 +00:00
projectFile ? null ,
2024-05-02 00:46:19 +00:00
# The NuGet dependency file. This locks all NuGet dependency versions, as otherwise they cannot be deterministically fetched.
# This can be generated by running the `passthru.fetch-deps` script.
2024-06-30 08:16:52 +00:00
nugetDeps ? null ,
2024-05-02 00:46:19 +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' "/>
2024-06-30 08:16:52 +00:00
projectReferences ? [ ] ,
2024-05-02 00:46:19 +00:00
# Libraries that need to be available at runtime should be passed through this.
# These get wrapped into `LD_LIBRARY_PATH`.
2024-06-30 08:16:52 +00:00
runtimeDeps ? [ ] ,
2024-05-02 00:46:19 +00:00
# The dotnet runtime ID. If null, fetch-deps will gather dependencies for all
# platforms in meta.platforms which are supported by the sdk.
2024-06-30 08:16:52 +00:00
runtimeId ? null ,
2024-05-02 00:46:19 +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.
2024-06-30 08:16:52 +00:00
disabledTests ? [ ] ,
2024-05-02 00:46:19 +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.
2024-06-30 08:16:52 +00:00
testProjectFile ? " " ,
2024-05-02 00:46:19 +00:00
# The type of build to perform. This is passed to `dotnet` with the `--configuration` flag. Possible values are `Release`, `Debug`, etc.
2024-06-30 08:16:52 +00:00
buildType ? " R e l e a s e " ,
2024-05-02 00:46:19 +00:00
# If set to true, builds the application as a self-contained - removing the runtime dependency on dotnet
2024-06-30 08:16:52 +00:00
selfContainedBuild ? false ,
2024-05-02 00:46:19 +00:00
# Whether to use an alternative wrapper, that executes the application DLL using the dotnet runtime from the user environment. `dotnet-runtime` is provided as a default in case no .NET is installed
# This is useful for .NET tools and applications that may need to run under different .NET runtimes
2024-06-30 08:16:52 +00:00
useDotnetFromEnv ? false ,
2024-05-02 00:46:19 +00:00
# Whether to explicitly enable UseAppHost when building. This is redundant if useDotnetFromEnv is enabledz
2024-06-30 08:16:52 +00:00
useAppHost ? true ,
2024-05-02 00:46:19 +00:00
# The dotnet SDK to use.
2024-06-30 08:16:52 +00:00
dotnet-sdk ? dotnetCorePackages . sdk_6_0 ,
2024-05-02 00:46:19 +00:00
# The dotnet runtime to use.
2024-06-30 08:16:52 +00:00
dotnet-runtime ? dotnetCorePackages . runtime_6_0 ,
2024-05-02 00:46:19 +00:00
# The dotnet SDK to run tests against. This can differentiate from the SDK compiled against.
2024-06-30 08:16:52 +00:00
dotnet-test-sdk ? dotnet-sdk ,
. . .
} @ args :
2024-05-02 00:46:19 +00:00
let
platforms =
2024-06-30 08:16:52 +00:00
if args ? meta . platforms then
lib . intersectLists args . meta . platforms dotnet-sdk . meta . platforms
else
dotnet-sdk . meta . platforms ;
inherit
( callPackage ./hooks {
inherit
dotnet-sdk
dotnet-test-sdk
disabledTests
nuget-source
dotnet-runtime
runtimeDeps
buildType
;
runtimeId =
if runtimeId != null then
runtimeId
else
dotnetCorePackages . systemToDotnetRid stdenvNoCC . targetPlatform . system ;
} )
dotnetConfigureHook
dotnetBuildHook
dotnetCheckHook
dotnetInstallHook
dotnetFixupHook
;
2024-05-02 00:46:19 +00:00
localDeps =
2024-06-30 08:16:52 +00:00
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 ;
2024-05-02 00:46:19 +00:00
_nugetDeps =
if ( nugetDeps != null ) then
2024-06-30 08:16:52 +00:00
if lib . isDerivation nugetDeps then
nugetDeps
else
mkNugetDeps {
inherit name ;
sourceFile = nugetDeps ;
}
else
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 . " ;
2024-05-02 00:46:19 +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 " ;
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 ;
} ;
# this contains all the nuget packages that are implicitly 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 = lib . lists . flatten [ dotnet-sdk . packages ] ;
2024-06-30 08:16:52 +00:00
sdkSource =
let
version = dotnet-sdk . version or ( lib . concatStringsSep " - " dotnet-sdk . versions ) ;
in
mkNugetSource {
name = " d o t n e t - s d k - ${ version } - s o u r c e " ;
deps = sdkDeps ;
} ;
2024-05-02 00:46:19 +00:00
nuget-source = symlinkJoin {
name = " ${ name } - n u g e t - s o u r c e " ;
2024-06-30 08:16:52 +00:00
paths = [
dependenciesSource
sdkSource
] ;
2024-05-02 00:46:19 +00:00
} ;
nugetDepsFile = _nugetDeps . sourceFile ;
in
2024-06-30 08:16:52 +00:00
stdenvNoCC . mkDerivation (
args
// {
nativeBuildInputs = args . nativeBuildInputs or [ ] ++ [
dotnetConfigureHook
dotnetBuildHook
dotnetCheckHook
dotnetInstallHook
dotnetFixupHook
cacert
makeWrapper
dotnet-sdk
2024-05-02 00:46:19 +00:00
] ;
2024-06-30 08:16:52 +00:00
# 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
versionForDotnet =
if ! ( lib . hasAttr " v e r s i o n " args ) || args . version == null then
null
else
let
components = lib . pipe args . version [
lib . splitVersion
( lib . filter ( x : ( lib . strings . match " [ 0 - 9 ] + " x ) != null ) )
( lib . filter ( x : ( lib . toIntBase10 x ) < 65535 ) ) # one version component in dotnet has to fit in 16 bits
] ;
in
if ( lib . length components ) == 0 then
null
else
lib . concatStringsSep " . " (
( lib . take 4 components )
++ ( if ( lib . length components ) < 4 then lib . replicate ( 4 - ( lib . length components ) ) " 0 " else [ ] )
) ;
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 "
] ;
2024-05-02 00:46:19 +00:00
2024-06-30 08:16:52 +00:00
# Stripping breaks the executable
dontStrip = args . dontStrip or true ;
2024-05-02 00:46:19 +00:00
2024-06-30 08:16:52 +00:00
# gappsWrapperArgs gets included when wrapping for dotnet, as to avoid double wrapping
dontWrapGApps = args . dontWrapGApps or true ;
2024-05-02 00:46:19 +00:00
2024-06-30 08:16:52 +00:00
inherit selfContainedBuild useAppHost useDotnetFromEnv ;
2024-05-02 00:46:19 +00:00
2024-06-30 08:16:52 +00:00
passthru =
{
inherit nuget-source ;
}
// lib . optionalAttrs ( ! lib . isDerivation nugetDeps ) {
fetch-deps =
let
flags = dotnetFlags ++ dotnetRestoreFlags ;
runtimeIds =
if runtimeId != null then
[ runtimeId ]
else
map ( system : dotnetCorePackages . systemToDotnetRid system ) platforms ;
defaultDepsFile =
# Wire in the nugetDeps file such that running the script with no args
# runs it agains the correct deps file by default.
# 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
toString nugetDepsFile
else
'' $( m k t e m p - t " ${ pname } - d e p s - X X X X X X . n i x " ) '' ;
in
writeShellScript " f e t c h - ${ pname } - d e p s " ''
set - euo pipefail
export PATH = " ${
lib . makeBinPath [
coreutils
runtimeShellPackage
dotnet-sdk
( nuget-to-nix . override { inherit dotnet-sdk ; } )
]
} "
for arg in " $ @ " ; do
case " $ a r g " in
- - keep-sources | - k )
keepSources = 1
shift
; ;
- - help | - h )
echo " u s a g e : $ 0 [ - - k e e p - s o u r c e s ] [ - - h e l p ] < o u t p u t p a t h > "
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 . A t e m p o r a r y f i l e i s u s e d i f t h i s i s n o t s e t "
echo " - - k e e p - s o u r c e s D o n t r e m o v e t e m p o r a r y d i r e c t o r i e s u p o n e x i t , u s e f u l f o r d e b u g g i n g "
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
done
2024-05-02 00:46:19 +00:00
2024-06-30 08:16:52 +00:00
if [ [ '' ${ TMPDIR:- } = = / r u n / u s e r / * ] ] ; t h e n
# /run/user is usually a tmpfs in RAM, which may be too small
# to store all downloaded dotnet packages
unset TMPDIR
fi
2024-05-02 00:46:19 +00:00
2024-06-30 08:16:52 +00:00
export tmp = $ ( mktemp - td " d e p s - ${ pname } - X X X X X X " )
HOME = $ tmp/home
exitTrap ( ) {
test - n " ' ' ${ ranTrap- } " && return
ranTrap = 1
if test - n " ' ' ${ keepSources- } " ; then
echo - e " P a t h t o t h e s o u r c e : $ t m p / s r c \n P a t h t o t h e f a k e h o m e : $ t m p / h o m e "
else
rm - rf " $ t m p "
fi
# Since mktemp is used this will be empty if the script didnt succesfully complete
if ! test - s " $ d e p s F i l e " ; then
rm - rf " $ d e p s F i l e "
fi
}
trap exitTrap EXIT INT TERM
dotnetRestore ( ) {
local - r project = " ' ' ${ 1 - } "
local - r rid = " $ 2 "
dotnet restore '' ${ project- } \
- p:ContinuousIntegrationBuild=true \
- p:Deterministic=true \
- - packages " $ t m p / n u g e t _ p k g s " \
- - runtime " $ r i d " \
- - no-cache \
- - force \
$ { lib . optionalString ( ! enableParallelBuilding ) " - - d i s a b l e - p a r a l l e l " } \
$ { lib . optionalString ( flags != [ ] ) ( toString flags ) }
}
declare - a projectFiles = ( $ { toString ( lib . toList projectFile ) } )
declare - a testProjectFiles = ( $ { toString ( lib . toList testProjectFile ) } )
export DOTNET_NOLOGO = 1
export DOTNET_CLI_TELEMETRY_OPTOUT = 1
depsFile = $ ( realpath " ' ' ${ 1 : - $ { defaultDepsFile } } " )
echo Will write lockfile to " $ d e p s F i l e "
mkdir - p " $ t m p / n u g e t _ p k g s "
storeSrc = " ${ srcOnly args } "
src = $ tmp/src
cp - rT " $ s t o r e S r c " " $ s r c "
chmod - R + w " $ s r c "
cd " $ s r c "
echo " R e s t o r i n g p r o j e c t . . . "
$ { dotnet-sdk } /bin/dotnet tool restore
cp - r $ HOME/.nuget/packages /* $ t m p / n u g e t _ p k g s | | t r u e
for rid in " ${ lib . concatStringsSep " \" \" " runtimeIds } " ; do
( ( '' ${ #projectFiles[@]} == 0 )) && dotnetRestore "" "$rid"
for project in '' ${ projectFiles [ @ ] - } ''$ { t e s t P r o j e c t F i l e s [ @ ] - } ; d o
dotnetRestore " $ p r o j e c t " " $ r i d "
done
done
# Second copy, makes sure packages restored by ie. paket are included
cp - r $ HOME/.nuget/packages /* $ t m p / n u g e t _ p k g s | | t r u e
2024-05-02 00:46:19 +00:00
2024-06-30 08:16:52 +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 "
2024-05-02 00:46:19 +00:00
2024-06-30 08:16:52 +00:00
echo " W r i t i n g l o c k f i l e . . . "
2024-05-02 00:46:19 +00:00
2024-06-30 08:16:52 +00:00
excluded_sources = " ${ lib . concatStringsSep " " sdkDeps } "
for excluded_source in '' ${ excluded_sources [ @ ] } ; d o
ls " $ e x c l u d e d _ s o u r c e " > > " $ t m p / e x c l u d e d _ l i s t "
2024-05-02 00:46:19 +00:00
done
2024-06-30 08:16:52 +00:00
tmpFile = " $ t m p " /deps.nix
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 " > " $ t m p F i l e "
nuget-to-nix " $ t m p / n u g e t _ p k g s " " $ t m p / e x c l u d e d _ l i s t " > > " $ t m p F i l e "
mv " $ t m p F i l e " " $ 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 { } ;
meta = ( args . meta or { } ) // {
inherit platforms ;
} ;
}
2024-05-02 00:46:19 +00:00
# ICU tries to unconditionally load files from /usr/share/icu on Darwin, which makes builds fail
# in the sandbox, so disable ICU on Darwin. This, as far as I know, shouldn't cause any built packages
# to behave differently, just the dotnet build tool.
2024-06-30 08:16:52 +00:00
// lib . optionalAttrs stdenvNoCC . isDarwin { DOTNET_SYSTEM_GLOBALIZATION_INVARIANT = 1 ; }
)