2022-09-14 18:05:37 +00:00
{ lib
2024-07-27 06:49:29 +00:00
, runtimeShell
2022-09-14 18:05:37 +00:00
, stdenvNoCC
, callPackage
2024-07-27 06:49:29 +00:00
, substituteAll
2022-09-30 11:47:45 +00:00
, writeShellScript
, srcOnly
2022-09-14 18:05:37 +00:00
, linkFarmFromDrvs
2022-09-30 11:47:45 +00:00
, symlinkJoin
, makeWrapper
2022-09-14 18:05:37 +00:00
, dotnetCorePackages
, mkNugetSource
, mkNugetDeps
, nuget-to-nix
, cacert
, coreutils
2023-07-15 17:15:38 +00:00
, runtimeShellPackage
2022-09-14 18:05:37 +00:00
} :
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
2022-09-30 11:47:45 +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 ? [ ]
# Flags to pass to `dotnet test`, if running tests is enabled.
, dotnetTestFlags ? [ ]
# Flags to pass to `dotnet install`.
, dotnetInstallFlags ? [ ]
# Flags to pass to `dotnet pack`.
, dotnetPackFlags ? [ ]
# Flags to pass to dotnet in all phases.
, dotnetFlags ? [ ]
# The path to publish the project to. When unset, the directory "$out/lib/$pname" is used.
2022-03-05 16:20:37 +00:00
, installPath ? null
2024-01-13 08:15:51 +00:00
# The binaries that should get installed to `$out/bin`, relative to `$installPath/`. These get wrapped accordingly.
2022-09-30 11:47:45 +00:00
# Unfortunately, dotnet has no method for doing this automatically.
# If unset, all executables in the projects root will get installed. This may cause bloat!
2021-10-14 00:43:12 +00:00
, executables ? null
2022-09-30 11:47:45 +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`.
2021-12-19 01:06:50 +00:00
, packNupkg ? false
2022-09-30 11:47:45 +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
2022-09-30 11:47:45 +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.
2021-10-14 00:43:12 +00:00
, nugetDeps ? null
2022-09-30 11:47:45 +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 ? [ ]
# Libraries that need to be available at runtime should be passed through this.
# These get wrapped into `LD_LIBRARY_PATH`.
, runtimeDeps ? [ ]
2022-12-28 21:21:41 +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.
, runtimeId ? null
2022-09-30 11:47:45 +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 ? [ ]
# 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-20 14:57:18 +00:00
, testProjectFile ? null
2021-12-06 16:07:01 +00:00
2022-09-30 11:47:45 +00:00
# The type of build to perform. This is passed to `dotnet` with the `--configuration` flag. Possible values are `Release`, `Debug`, etc.
2021-10-14 00:43:12 +00:00
, buildType ? " R e l e a s e "
2022-09-30 11:47:45 +00:00
# If set to true, builds the application as a self-contained - removing the runtime dependency on dotnet
2022-08-12 12:06:08 +00:00
, selfContainedBuild ? false
2023-07-15 17:15:38 +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
, useDotnetFromEnv ? false
# Whether to explicitly enable UseAppHost when building. This is redundant if useDotnetFromEnv is enabledz
2022-12-28 21:21:41 +00:00
, useAppHost ? true
2022-09-30 11:47:45 +00:00
# The dotnet SDK to use.
2022-06-16 17:23:12 +00:00
, dotnet-sdk ? dotnetCorePackages . sdk_6_0
2022-09-30 11:47:45 +00:00
# The dotnet runtime to use.
2022-06-16 17:23:12 +00:00
, dotnet-runtime ? dotnetCorePackages . runtime_6_0
2022-09-30 11:47:45 +00:00
, . . .
} @ args :
2021-10-14 00:43:12 +00:00
let
2024-06-20 14:57:18 +00:00
projectFiles =
lib . optionals ( projectFile != null ) ( lib . toList projectFile ) ;
testProjectFiles =
lib . optionals ( testProjectFile != null ) ( lib . toList testProjectFile ) ;
2022-10-06 18:32:54 +00:00
platforms =
if args ? meta . platforms
then lib . intersectLists args . meta . platforms dotnet-sdk . meta . platforms
else dotnet-sdk . meta . platforms ;
2022-03-05 16:20:37 +00:00
inherit ( callPackage ./hooks {
2024-06-20 14:57:18 +00:00
inherit dotnet-sdk dotnet-runtime ;
2022-03-05 16:20:37 +00:00
} ) dotnetConfigureHook dotnetBuildHook dotnetCheckHook dotnetInstallHook dotnetFixupHook ;
2022-09-30 11:47:45 +00:00
localDeps =
if ( projectReferences != [ ] )
2022-04-27 09:35:20 +00:00
then linkFarmFromDrvs " ${ name } - p r o j e c t - r e f e r e n c e s " projectReferences
else null ;
2022-09-30 11:47:45 +00:00
_nugetDeps =
if ( nugetDeps != null ) then
if lib . isDerivation nugetDeps
then nugetDeps
2023-07-15 17:15:38 +00:00
else mkNugetDeps {
inherit name ;
sourceFile = nugetDeps ;
}
2022-09-30 11:47:45 +00:00
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 . " ;
2021-10-14 00:43:12 +00:00
2022-08-21 13:32:41 +00:00
# contains the actual package dependencies
2022-09-30 11:47:45 +00:00
dependenciesSource = mkNugetSource {
2022-08-21 13:32:41 +00:00
name = " ${ name } - d e p e n d e n c i e s - s o u r c e " ;
2024-06-20 14:57:18 +00:00
description = " 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 } " ;
2022-04-27 09:35:20 +00:00
deps = [ _nugetDeps ] ++ lib . optional ( localDeps != null ) localDeps ;
2021-12-06 16:07:01 +00:00
} ;
2022-12-28 21:21:41 +00:00
# this contains all the nuget packages that are implicitly referenced by the dotnet
2022-08-21 13:32:41 +00:00
# build system. having them as separate deps allows us to avoid having to regenerate
# a packages dependencies when the dotnet-sdk version changes
2023-03-24 00:07:29 +00:00
sdkDeps = lib . lists . flatten [ dotnet-sdk . packages ] ;
2022-08-21 13:32:41 +00:00
2023-03-24 00:07:29 +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 ;
2022-08-21 13:32:41 +00:00
} ;
nuget-source = symlinkJoin {
name = " ${ name } - n u g e t - s o u r c e " ;
2022-09-30 11:47:45 +00:00
paths = [ dependenciesSource sdkSource ] ;
2022-08-21 13:32:41 +00:00
} ;
2023-07-15 17:15:38 +00:00
nugetDepsFile = _nugetDeps . sourceFile ;
2022-09-30 11:47:45 +00:00
in
stdenvNoCC . mkDerivation ( args // {
2024-06-20 14:57:18 +00:00
dotnetInstallPath = installPath ;
dotnetExecutables = executables ;
dotnetBuildType = buildType ;
dotnetProjectFiles = projectFiles ;
dotnetTestProjectFiles = testProjectFiles ;
dotnetDisabledTests = disabledTests ;
dotnetRuntimeId = runtimeId ;
nugetSource = nuget-source ;
dotnetRuntimeDeps = map lib . getLib runtimeDeps ;
dotnetSelfContainedBuild = selfContainedBuild ;
dotnetUseAppHost = useAppHost ;
inherit useDotnetFromEnv ;
2022-09-30 11:47:45 +00:00
nativeBuildInputs = args . nativeBuildInputs or [ ] ++ [
2022-03-05 16:20:37 +00:00
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
] ;
2023-11-16 04:20:00 +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 ) )
2024-01-02 11:29:13 +00:00
( lib . filter ( x : ( lib . toIntBase10 x ) < 65535 ) ) # one version component in dotnet has to fit in 16 bits
2023-11-16 04:20:00 +00:00
] ;
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 [ ] ) ) ;
2022-07-18 16:21:45 +00:00
makeWrapperArgs = args . makeWrapperArgs or [ ] ++ [
2024-06-20 14:57:18 +00:00
" - - 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
2024-05-15 15:35:15 +00:00
# propagate the runtime sandbox profile since the contents apply to published
# executables
propagatedSandboxProfile = toString dotnet-runtime . __propagatedSandboxProfile ;
2022-03-05 16:20:37 +00:00
passthru = {
2022-04-27 09:35:20 +00:00
inherit nuget-source ;
2023-11-16 04:20:00 +00:00
} // lib . optionalAttrs ( ! lib . isDerivation nugetDeps ) {
2024-07-27 06:49:29 +00:00
fetch-deps = let
flagsList = dotnetFlags ++ dotnetRestoreFlags ;
flags = lib . concatStringsSep " " ( map lib . escapeShellArg flagsList ) ;
disableParallel =
lib . optionalString ( ! enableParallelBuilding ) " - - d i s a b l e - p a r a l l e l " ;
runtimeIdsList = if runtimeId != null then
[ runtimeId ]
else
map ( system : dotnetCorePackages . systemToDotnetRid system ) platforms ;
runtimeIds =
lib . concatStringsSep " " ( map lib . escapeShellArg runtimeIdsList ) ;
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 " ) '' ;
storeSrc = srcOnly args ;
projectFileStr = lib . escapeShellArgs projectFiles ;
testProjectFileStr = lib . escapeShellArgs testProjectFiles ;
path = lib . makeBinPath [
coreutils
runtimeShellPackage
dotnet-sdk
( nuget-to-nix . override { inherit dotnet-sdk ; } )
] ;
dotnetSdkPath = toString dotnet-sdk ;
excludedSources =
lib . concatStringsSep " " ( map lib . escapeShellArg sdkDeps ) ;
in substituteAll {
name = " f e t c h - d e p s " ;
src = ./fetch-deps.sh ;
isExecutable = true ;
inherit pname defaultDepsFile runtimeIds storeSrc flags disableParallel
projectFileStr testProjectFileStr path dotnetSdkPath excludedSources
runtimeShell ;
} ;
2022-09-30 11:47:45 +00:00
} // args . passthru or { } ;
2022-09-14 18:05:37 +00:00
2022-10-06 18:32:54 +00:00
meta = ( args . meta or { } ) // { inherit platforms ; } ;
2024-05-15 15:35:15 +00:00
} )