push sheeet
Some checks failed
Periodic Merges (6h) / master → staging-nixos (push) Failing after 12m50s
Periodic Merges (6h) / master → staging-next (push) Failing after 12m54s
Periodic Merges (24h) / merge-base(master,staging) → haskell-updates (push) Failing after 11m54s
Periodic Merges (6h) / staging-next → staging (push) Failing after 12m13s
Periodic Merges (24h) / staging-next-25.05 → staging-25.05 (push) Failing after 13m24s
Periodic Merges (24h) / release-25.05 → staging-next-25.05 (push) Failing after 14m28s

This commit is contained in:
Dark Steveneq
2025-10-09 14:15:47 +02:00
commit 646b892680
49168 changed files with 5897842 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
{
writeShellScript,
runtimeShell,
nix,
lib,
replaceVarsWith,
nixfmt,
nuget-to-json,
cacert,
fetchNupkg,
callPackage,
}:
{
/**
A list of nuget packages.
Should be a JSON file with arguments to `fetchNupkg`:
```json
[
{
"pname": "AsyncIO",
"version": "0.1.69",
"hash": "sha256-JQKq/U71NQTfPuUqj7z5bALe+d7G1o3GcI8kvVDxy6o="
}
]
```
(to generate this file, use the script generated by `passthru.fetch-deps`)
Or a derivation (or list of derivations) containing nuget packages.
*/
nugetDeps,
overrideFetchAttrs ? x: { },
}:
fnOrAttrs: finalAttrs:
let
attrs = if builtins.isFunction fnOrAttrs then fnOrAttrs finalAttrs else fnOrAttrs;
deps =
if nugetDeps == null then
[ ]
else if lib.isDerivation nugetDeps then
[ nugetDeps ]
else if lib.isList nugetDeps then
nugetDeps
else if lib.hasSuffix ".nix" nugetDeps then
assert (lib.isPath nugetDeps);
callPackage nugetDeps { fetchNuGet = fetchNupkg; }
else
map fetchNupkg (lib.importJSON nugetDeps);
finalPackage = finalAttrs.finalPackage;
in
attrs
// {
buildInputs = attrs.buildInputs or [ ] ++ deps;
passthru =
attrs.passthru or { }
// {
nugetDeps = deps;
}
// lib.optionalAttrs (nugetDeps == null || lib.isPath nugetDeps) rec {
fetch-drv =
let
pkg' = finalPackage.overrideAttrs (old: {
buildInputs = attrs.buildInputs or [ ];
nativeBuildInputs = old.nativeBuildInputs or [ ] ++ [ cacert ];
keepNugetConfig = true;
dontBuild = true;
doCheck = false;
dontInstall = true;
doInstallCheck = false;
dontFixup = true;
doDist = false;
});
in
pkg'.overrideAttrs overrideFetchAttrs;
fetch-deps =
let
drv = builtins.unsafeDiscardOutputDependency fetch-drv.drvPath;
innerScript = replaceVarsWith {
src = ./fetch-deps.sh;
isExecutable = true;
replacements = {
binPath = lib.makeBinPath [
nixfmt
nuget-to-json
];
};
};
defaultDepsFile =
# Wire in the depsFile 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 nugetDeps && !lib.isStorePath nugetDeps then
toString nugetDeps
else
''$(mktemp -t "${finalAttrs.pname or finalPackage.name}-deps-XXXXXX.nix")'';
in
writeShellScript "${finalPackage.name}-fetch-deps" ''
set -euo pipefail
echo 'fetching dependencies for' ${lib.escapeShellArg finalPackage.name} >&2
# this needs to be before TMPDIR is changed, so the output isn't deleted
# if it uses mktemp
${lib.toShellVars { inherit defaultDepsFile; }}
depsFile=$(realpath "''${1:-$defaultDepsFile}")
export TMPDIR
TMPDIR=$(mktemp -d -t fetch-deps-${lib.escapeShellArg finalPackage.name}.XXXXXX)
trap 'chmod -R +w "$TMPDIR" && rm -fr "$TMPDIR"' EXIT
export NUGET_HTTP_CACHE_PATH=''${NUGET_HTTP_CACHE_PATH-~/.local/share/NuGet/v3-cache}
HOME=$TMPDIR/home
mkdir "$HOME"
cd "$TMPDIR"
NIX_BUILD_SHELL=${lib.escapeShellArg runtimeShell} ${nix}/bin/nix-shell \
--pure --keep NUGET_HTTP_CACHE_PATH --run 'source '${lib.escapeShellArg innerScript}' '"''${depsFile@Q}" "${drv}"
'';
};
}

View File

@@ -0,0 +1,12 @@
# shellcheck shell=bash
set -e
export PATH="@binPath@:$PATH"
LOCKFILE_OUTPUT="$1"
genericBuild
nuget-to-json "${NUGET_PACKAGES%/}" >"$LOCKFILE_OUTPUT"
echo "Successfully wrote lockfile to $LOCKFILE_OUTPUT"

View File

@@ -0,0 +1,118 @@
#!@shell@
# shellcheck shell=bash
declare -a autoPatchcilLibs
declare -a extraAutoPatchcilLibs
gatherLibraries() {
if [ -d "$1/lib" ]; then
autoPatchcilLibs+=("$1/lib")
fi
}
addEnvHooks "${targetOffset:?}" gatherLibraries
# Can be used to manually add additional directories with shared object files
# to be included for the next autoPatchcil invocation.
addAutoPatchcilSearchPath() {
local -a findOpts=()
while [ $# -gt 0 ]; do
case "$1" in
--)
shift
break
;;
--no-recurse)
shift
findOpts+=("-maxdepth" 1)
;;
--*)
echo "addAutoPatchcilSearchPath: ERROR: Invalid command line" \
"argument: $1" >&2
return 1
;;
*) break ;;
esac
done
local dir=
while IFS= read -r -d '' dir; do
extraAutoPatchcilLibs+=("$dir")
done < <(
find "$@" "${findOpts[@]}" \! -type d \
\( -name '*.so' -o -name '*.so.*' \) -print0 |
sed -z 's#/[^/]*$##' |
uniq -z
)
}
autoPatchcil() {
local rid=
local norecurse=
while [ $# -gt 0 ]; do
case "$1" in
--)
shift
break
;;
--rid)
rid="$2"
shift 2
;;
--no-recurse)
shift
norecurse=1
;;
--*)
echo "autoPatchcil: ERROR: Invalid command line" \
"argument: $1" >&2
return 1
;;
*) break ;;
esac
done
if [ -z "$rid" ]; then
echo "autoPatchcil: ERROR: No RID (Runtime ID) provided." >&2
return 1
fi
local ignoreMissingDepsArray=("--ignore-missing")
concatTo ignoreMissingDepsArray autoPatchcilIgnoreMissingDeps
if [ ${#ignoreMissingDepsArray[@]} -lt 2 ]; then
ignoreMissingDepsArray=()
fi
local autoPatchcilFlags=(
${norecurse:+--no-recurse}
--rid "$rid"
"${ignoreMissingDepsArray[@]}"
--paths "$@"
--libs "${autoPatchcilLibs[@]}"
)
# shellcheck disable=SC2016
echoCmd 'patchcil auto flags' "${autoPatchcilFlags[@]}"
@patchcil@ auto "${autoPatchcilFlags[@]}"
}
autoPatchcilFixupOutput() {
if [[ -z "${dontAutoPatchcil-}" ]]; then
if [ -n "${dotnetRuntimeIds+x}" ]; then
if [[ -n $__structuredAttrs ]]; then
local dotnetRuntimeIdsArray=("${dotnetRuntimeIds[@]}")
else
# shellcheck disable=SC2206 # Intentionally expanding it to preserve old behavior
local dotnetRuntimeIdsArray=($dotnetRuntimeIds)
fi
else
local dotnetRuntimeIdsArray=("")
fi
autoPatchcil --rid "${autoPatchcilRuntimeId:-${dotnetRuntimeIdsArray[0]}}" -- "${prefix:?}"
fi
}
fixupOutputHooks+=(autoPatchcilFixupOutput)

View File

@@ -0,0 +1,14 @@
{
lib,
bash,
patchcil,
makeSetupHook,
}:
makeSetupHook {
name = "auto-patchcil-hook";
substitutions = {
shell = lib.getExe bash;
patchcil = lib.getExe patchcil;
};
} ./auto-patchcil.sh

View File

@@ -0,0 +1,80 @@
{
buildDotnetModule,
emptyDirectory,
fetchNupkg,
dotnet-sdk,
lib,
}:
fnOrAttrs:
buildDotnetModule (
finalAttrs:
(
{
pname,
version,
# Name of the nuget package to install, if different from pname
nugetName ? pname,
# Hash of the nuget package to install, will be given on first build
# nugetHash uses SRI hash and should be preferred
nugetHash ? "",
nugetSha256 ? "",
# Additional nuget deps needed by the tool package
nugetDeps ? (_: [ ]),
# Executables to wrap into `$out/bin`, same as in `buildDotnetModule`, but with
# a default of `pname` instead of null, to avoid auto-wrapping everything
executables ? pname,
# The dotnet runtime to use, dotnet tools need a full SDK to function
dotnet-runtime ? dotnet-sdk,
...
}@args:
let
nupkg = fetchNupkg {
pname = nugetName;
inherit version;
sha256 = nugetSha256;
hash = nugetHash;
installable = true;
};
in
args
// {
inherit
pname
version
dotnet-runtime
executables
;
src = emptyDirectory;
buildInputs = [ nupkg ];
dotnetGlobalTool = true;
useDotnetFromEnv = true;
dontBuild = true;
installPhase = ''
runHook preInstall
dotnet tool install --tool-path $out/lib/${pname} ${nugetName} --version ${version}
# remove files that contain nix store paths to temp nuget sources we made
find $out -name 'project.assets.json' -delete
find $out -name '.nupkg.metadata' -delete
runHook postInstall
'';
passthru = {
updateScript = ./update.sh;
nupkg = nupkg;
}
// args.passthru or { };
}
)
(if lib.isFunction fnOrAttrs then fnOrAttrs finalAttrs else fnOrAttrs)
)

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env nix-shell
#!nix-shell -I nixpkgs=./. -i bash -p curl jq nix common-updater-scripts
# shellcheck shell=bash
set -euo pipefail
attr=$UPDATE_NIX_ATTR_PATH
nixeval() {
nix --extra-experimental-features nix-command eval --json --impure -f . "$1" | jq -r .
}
nugetName=$(nixeval "$attr.nupkg.pname")
# always skip prerelease versions for now
version=$(curl -fsSL "https://api.nuget.org/v3-flatcontainer/$nugetName/index.json" |
jq -er '.versions | last(.[] | select(match("^[0-9]+\\.[0-9]+\\.[0-9]+$")))')
if [[ $version == $(nixeval "$attr.version") ]]; then
echo "$attr" is already version "$version"
exit 0
fi
update-source-version "$attr" "$version" --source-key=nupkg.src

View File

@@ -0,0 +1,235 @@
{
lib,
runtimeShell,
stdenvNoCC,
callPackage,
writeShellScript,
makeWrapper,
dotnetCorePackages,
cacert,
addNuGetDeps,
dotnet-sdk,
}:
let
default-sdk = dotnet-sdk;
transformArgs =
finalAttrs:
{
enableParallelBuilding ? true,
# 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.
installPath ? null,
# 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!
executables ? null,
# 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,
# 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 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.
# 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 ? [ ],
# 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,
# Test filters. This gets passed to `dotnet test --filter`, concatenated using `&`.
# You may also use `disabledTests` to filter tests based on their name.
# See https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test#filter-option-details for more details.
testFilters ? [ ],
# Tests to disable. This gets passed to `dotnet test --filter "FullyQualifiedName!={}"`, to ensure compatibility with all frameworks.
# You may also use `testFilters` to pass more generic filters to `dotnet test --filter`.
# 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.
testProjectFile ? null,
# The type of build to perform. This is passed to `dotnet` with the `--configuration` flag. Possible values are `Release`, `Debug`, etc.
buildType ? "Release",
# If set to true, builds the application as a self-contained - removing the runtime dependency on dotnet
selfContainedBuild ? false,
# 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 enabled
useAppHost ? true,
# The dotnet SDK to use.
dotnet-sdk ? default-sdk,
# The dotnet runtime to use.
dotnet-runtime ? dotnet-sdk.runtime,
...
}@args:
let
projectFiles = lib.optionals (projectFile != null) (lib.toList projectFile);
testProjectFiles = lib.optionals (testProjectFile != null) (lib.toList testProjectFile);
platforms =
if args ? meta.platforms then
lib.intersectLists args.meta.platforms dotnet-sdk.meta.platforms
else
dotnet-sdk.meta.platforms;
hook = callPackage ./hook { inherit dotnet-runtime; };
inherit (dotnetCorePackages) systemToDotnetRid;
in
args
// {
dotnetInstallPath = installPath;
dotnetExecutables = executables;
dotnetBuildType = buildType;
dotnetProjectFiles = projectFiles;
dotnetTestProjectFiles = testProjectFiles;
dotnetTestFilters = testFilters;
dotnetDisabledTests = disabledTests;
dotnetRuntimeIds = lib.singleton (
if runtimeId != null then runtimeId else systemToDotnetRid stdenvNoCC.hostPlatform.system
);
dotnetRuntimeDeps = map lib.getLib runtimeDeps;
dotnetSelfContainedBuild = selfContainedBuild;
dotnetUseAppHost = useAppHost;
inherit
enableParallelBuilding
dotnetRestoreFlags
dotnetBuildFlags
dotnetTestFlags
dotnetInstallFlags
dotnetPackFlags
dotnetFlags
packNupkg
useDotnetFromEnv
nugetDeps
runtimeId
dotnet-sdk
;
nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
hook
cacert
makeWrapper
dotnet-sdk
];
buildInputs = args.buildInputs or [ ] ++ dotnet-sdk.packages ++ projectReferences;
# 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 "version" 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 [ ] ++ [
"--prefix"
"LD_LIBRARY_PATH"
":"
"${dotnet-sdk.icu}/lib"
];
# Stripping breaks the executable
dontStrip = args.dontStrip or true;
# gappsWrapperArgs gets included when wrapping for dotnet, as to avoid double wrapping
dontWrapGApps = args.dontWrapGApps or true;
# propagate the runtime sandbox profile since the contents apply to published
# executables
propagatedSandboxProfile = lib.optionalString (dotnet-runtime != null) (
toString dotnet-runtime.__propagatedSandboxProfile
);
meta = (args.meta or { }) // {
inherit platforms;
};
};
in
fnOrAttrs:
stdenvNoCC.mkDerivation (
finalAttrs:
let
args = if lib.isFunction fnOrAttrs then fnOrAttrs (args' // finalAttrs) else fnOrAttrs;
args' = transformArgs finalAttrs args;
inherit (args')
nugetDeps
runtimeId
meta
dotnet-sdk
;
args'' = removeAttrs args' [
"nugetDeps"
"runtimeId"
"installPath"
"executables"
"projectFile"
"projectReferences"
"runtimeDeps"
"disabledTests"
"testProjectFile"
"buildType"
"selfContainedBuild"
"useDotnet"
"useAppHost"
"dotnet-sdk"
];
in
if nugetDeps != null then
addNuGetDeps {
inherit nugetDeps;
overrideFetchAttrs =
old:
lib.optionalAttrs ((args'.runtimeId or null) == null) rec {
dotnetRuntimeIds = map (system: dotnetCorePackages.systemToDotnetRid system) meta.platforms;
buildInputs =
old.buildInputs
++ lib.concatLists (lib.attrValues (lib.getAttrs dotnetRuntimeIds dotnet-sdk.targetPackages));
};
} args'' finalAttrs
else
args''
)

View File

@@ -0,0 +1,18 @@
{
lib,
which,
coreutils,
makeSetupHook,
# Passed from ../default.nix
dotnet-runtime,
}:
makeSetupHook {
name = "dotnet-hook";
substitutions = {
dotnetRuntime = dotnet-runtime;
wrapperPath = lib.makeBinPath [
which
coreutils
];
};
} ./dotnet-hook.sh

View File

@@ -0,0 +1,450 @@
# shellcheck shell=bash
_dotnetIsSolution() {
dotnet sln ${1:+"$1"} list 2>/dev/null
}
dotnetConfigurePhase() {
echo "Executing dotnetConfigureHook"
runHook preConfigure
local -a projectFiles flags runtimeIds
concatTo projectFiles dotnetProjectFiles dotnetTestProjectFiles
concatTo flags dotnetFlags dotnetRestoreFlags
concatTo runtimeIds dotnetRuntimeIds
if [[ -z ${enableParallelBuilding-} ]]; then
flags+=(--disable-parallel)
fi
if [[ -v dotnetSelfContainedBuild ]]; then
if [[ -n $dotnetSelfContainedBuild ]]; then
flags+=("-p:SelfContained=true")
else
flags+=("-p:SelfContained=false")
fi
fi
dotnetRestore() {
local -r projectFile="${1-}"
for runtimeId in "${runtimeIds[@]}"; do
dotnet restore ${1+"$projectFile"} \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
-p:NuGetAudit=false \
--runtime "$runtimeId" \
"${flags[@]}"
done
}
if [[ -f .config/dotnet-tools.json || -f dotnet-tools.json ]]; then
dotnet tool restore
fi
# dotnetGlobalTool is set in buildDotnetGlobalTool to patch dependencies but
# avoid other project-specific logic. This is a hack, but the old behavior
# is worse as it relied on a bug: setting projectFile to an empty string
# made the hooks actually skip all project-specific logic. Its hard to keep
# backwards compatibility with this odd behavior now since we are using
# arrays, so instead we just pass a variable to indicate that we dont have
# projects.
if [[ -z ${dotnetGlobalTool-} ]]; then
if (( ${#projectFiles[@]} == 0 )); then
dotnetRestore
fi
local projectFile
for projectFile in "${projectFiles[@]}"; do
dotnetRestore "$projectFile"
done
fi
runHook postConfigure
echo "Finished dotnetConfigureHook"
}
if [[ -z "${dontDotnetConfigure-}" && -z "${configurePhase-}" ]]; then
configurePhase=dotnetConfigurePhase
fi
dotnetBuildPhase() {
echo "Executing dotnetBuildHook"
runHook preBuild
local -r dotnetBuildType="${dotnetBuildType-Release}"
local -a projectFiles flags runtimeIds
concatTo projectFiles dotnetProjectFiles dotnetTestProjectFiles
concatTo flags dotnetFlags dotnetBuildFlags
concatTo runtimeIds dotnetRuntimeIds
if [[ -n "${enableParallelBuilding-}" ]]; then
local -r maxCpuFlag="$NIX_BUILD_CORES"
local -r parallelBuildFlag="true"
else
local -r maxCpuFlag="1"
local -r parallelBuildFlag="false"
fi
if [[ -v dotnetSelfContainedBuild ]]; then
if [[ -n $dotnetSelfContainedBuild ]]; then
flags+=("-p:SelfContained=true")
else
flags+=("-p:SelfContained=false")
fi
fi
if [[ -n ${dotnetUseAppHost-} ]]; then
flags+=("-p:UseAppHost=true")
fi
if [[ -n ${version-} ]]; then
flags+=("-p:InformationalVersion=$version")
fi
if [[ -n ${versionForDotnet-} ]]; then
flags+=("-p:Version=$versionForDotnet")
fi
dotnetBuild() {
local -r projectFile="${1-}"
local useRuntime=
_dotnetIsSolution "$projectFile" || useRuntime=1
for runtimeId in "${runtimeIds[@]}"; do
local runtimeIdFlags=()
if [[ -n $useRuntime ]]; then
runtimeIdFlags+=("--runtime" "$runtimeId")
fi
dotnet build ${1+"$projectFile"} \
-maxcpucount:"$maxCpuFlag" \
-p:BuildInParallel="$parallelBuildFlag" \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
-p:OverwriteReadOnlyFiles=true \
--configuration "$dotnetBuildType" \
--no-restore \
"${runtimeIdFlags[@]}" \
"${flags[@]}"
done
}
if (( ${#projectFiles[@]} == 0 )); then
dotnetBuild
fi
local projectFile
for projectFile in "${projectFiles[@]}"; do
dotnetBuild "$projectFile"
done
runHook postBuild
echo "Finished dotnetBuildHook"
}
if [[ -z ${dontDotnetBuild-} && -z ${buildPhase-} ]]; then
buildPhase=dotnetBuildPhase
fi
dotnetCheckPhase() {
echo "Executing dotnetCheckHook"
runHook preCheck
local -r dotnetBuildType="${dotnetBuildType-Release}"
local -a projectFiles testProjectFiles testFilters disabledTests flags runtimeIds runtimeDeps
concatTo projectFiles dotnetProjectFiles
concatTo testProjectFiles dotnetTestProjectFiles
concatTo testFilters dotnetTestFilters
concatTo disabledTests dotnetDisabledTests
concatTo flags dotnetFlags dotnetTestFlags
concatTo runtimeIds dotnetRuntimeIds
concatTo runtimeDeps dotnetRuntimeDeps
if (( ${#disabledTests[@]} > 0 )); then
local disabledTestsFilters=("${disabledTests[@]/#/FullyQualifiedName!=}")
testFilters=( "${testFilters[@]}" "${disabledTestsFilters[@]//,/%2C}" )
fi
if (( ${#testFilters[@]} > 0 )); then
local OLDIFS="$IFS" IFS='&'
flags+=("--filter:${testFilters[*]}")
IFS="$OLDIFS"
fi
local libraryPath="${LD_LIBRARY_PATH-}"
if (( ${#runtimeDeps[@]} > 0 )); then
local libraryPaths=("${runtimeDeps[@]/%//lib}")
local OLDIFS="$IFS" IFS=':'
libraryPath="${libraryPaths[*]}${libraryPath:+':'}$libraryPath"
IFS="$OLDIFS"
fi
if [[ -n ${enableParallelBuilding-} ]]; then
local -r maxCpuFlag="$NIX_BUILD_CORES"
else
local -r maxCpuFlag="1"
fi
local projectFile runtimeId
for projectFile in "${testProjectFiles[@]-${projectFiles[@]}}"; do
local useRuntime=
_dotnetIsSolution "$projectFile" || useRuntime=1
for runtimeId in "${runtimeIds[@]}"; do
local runtimeIdFlags=()
if [[ -n $useRuntime ]]; then
runtimeIdFlags=("--runtime" "$runtimeId")
fi
LD_LIBRARY_PATH=$libraryPath \
dotnet test "$projectFile" \
-maxcpucount:"$maxCpuFlag" \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
--configuration "$dotnetBuildType" \
--no-restore \
--no-build \
--logger "console;verbosity=normal" \
"${runtimeIdFlags[@]}" \
"${flags[@]}"
done
done
runHook postCheck
echo "Finished dotnetCheckHook"
}
if [[ -z "${dontDotnetCheck-}" && -z "${checkPhase-}" ]]; then
checkPhase=dotnetCheckPhase
fi
# For compatibility, convert makeWrapperArgs to an array unless we are using
# structured attributes. That is, we ensure that makeWrapperArgs is always an
# array.
# See https://github.com/NixOS/nixpkgs/blob/858f4db3048c5be3527e183470e93c1a72c5727c/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-fixup-hook.sh#L1-L3
# and https://github.com/NixOS/nixpkgs/pull/313005#issuecomment-2175482920
# shellcheck disable=2206
if [[ -z $__structuredAttrs ]]; then
makeWrapperArgs=( ${makeWrapperArgs-} )
fi
# First argument is the executable you want to wrap,
# the second is the destination for the wrapper.
wrapDotnetProgram() {
local -r dotnetRuntime=@dotnetRuntime@
local -r wrapperPath=@wrapperPath@
# shellcheck disable=2016
local -r dotnetFromEnvScript='dotnetFromEnv() {
local dotnetPath
if command -v dotnet 2>&1 >/dev/null; then
dotnetPath=$(which dotnet) && \
dotnetPath=$(realpath "$dotnetPath") && \
dotnetPath=$(dirname "$dotnetPath") && \
export DOTNET_ROOT="$dotnetPath"
fi
}
dotnetFromEnv'
# shellcheck disable=2206
local -a runtimeDeps
concatTo runtimeDeps dotnetRuntimeDeps
local wrapperFlags=()
if (( ${#runtimeDeps[@]} > 0 )); then
local libraryPath=("${runtimeDeps[@]/%//lib}")
local OLDIFS="$IFS" IFS=':'
wrapperFlags+=("--suffix" "LD_LIBRARY_PATH" ":" "${libraryPath[*]}")
IFS="$OLDIFS"
fi
if [[ -z ${dotnetSelfContainedBuild-} ]]; then
if [[ -n ${useDotnetFromEnv-} ]]; then
# if dotnet CLI is available, set DOTNET_ROOT based on it. Otherwise set to default .NET runtime
wrapperFlags+=("--suffix" "PATH" ":" "$wrapperPath")
wrapperFlags+=("--run" "$dotnetFromEnvScript")
if [[ -n $dotnetRuntime ]]; then
wrapperFlags+=("--set-default" "DOTNET_ROOT" "$dotnetRuntime/share/dotnet")
wrapperFlags+=("--suffix" "PATH" ":" "$dotnetRuntime/bin")
fi
elif [[ -n $dotnetRuntime ]]; then
wrapperFlags+=("--set" "DOTNET_ROOT" "$dotnetRuntime/share/dotnet")
wrapperFlags+=("--prefix" "PATH" ":" "$dotnetRuntime/bin")
fi
fi
# shellcheck disable=2154
makeWrapper "$1" "$2" \
"${wrapperFlags[@]}" \
"${gappsWrapperArgs[@]}" \
"${makeWrapperArgs[@]}"
echo "installed wrapper to $2"
}
dotnetFixupPhase() {
local -r dotnetInstallPath="${dotnetInstallPath-$out/lib/$pname}"
local executable executableBasename
# check if dotnetExecutables is declared (including empty values, in which case we generate no executables)
# shellcheck disable=2154
if declare -p dotnetExecutables &>/dev/null; then
# shellcheck disable=2206
local -a executables
concatTo executables dotnetExecutables
for executable in "${executables[@]}"; do
executableBasename=$(basename "$executable")
local path="$dotnetInstallPath/$executable"
if test -x "$path"; then
wrapDotnetProgram "$path" "$out/bin/$executableBasename"
else
echo "Specified binary \"$executable\" is either not an executable or does not exist!"
echo "Looked in $path"
exit 1
fi
done
else
while IFS= read -r -d '' executable; do
executableBasename=$(basename "$executable")
wrapDotnetProgram "$executable" "$out/bin/$executableBasename" \;
done < <(find "$dotnetInstallPath" ! -name "*.dll" -executable -type f -print0)
fi
}
if [[ -z "${dontFixup-}" && -z "${dontDotnetFixup-}" ]]; then
appendToVar preFixupPhases dotnetFixupPhase
fi
dotnetInstallPhase() {
echo "Executing dotnetInstallHook"
runHook preInstall
local -r dotnetInstallPath="${dotnetInstallPath-$out/lib/$pname}"
local -r dotnetBuildType="${dotnetBuildType-Release}"
local -a projectFiles flags installFlags packFlags runtimeIds
concatTo projectFiles dotnetProjectFiles
concatTo flags dotnetFlags
concatTo installFlags dotnetInstallFlags
concatTo packFlags dotnetPackFlags
concatTo runtimeIds dotnetRuntimeIds
if [[ -v dotnetSelfContainedBuild ]]; then
if [[ -n $dotnetSelfContainedBuild ]]; then
installFlags+=("--self-contained")
else
installFlags+=("--no-self-contained")
# https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained
# Trimming is only available for self-contained build, so force disable it here
installFlags+=("-p:PublishTrimmed=false")
fi
fi
if [[ -n ${dotnetUseAppHost-} ]]; then
installFlags+=("-p:UseAppHost=true")
fi
if [[ -n ${enableParallelBuilding-} ]]; then
local -r maxCpuFlag="$NIX_BUILD_CORES"
else
local -r maxCpuFlag="1"
fi
dotnetPublish() {
local -r projectFile="${1-}"
local useRuntime=
_dotnetIsSolution "$projectFile" || useRuntime=1
for runtimeId in "${runtimeIds[@]}"; do
local runtimeIdFlags=()
if [[ -n $useRuntime ]]; then
runtimeIdFlags+=("--runtime" "$runtimeId")
fi
dotnet publish ${1+"$projectFile"} \
-maxcpucount:"$maxCpuFlag" \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
-p:OverwriteReadOnlyFiles=true \
--output "$dotnetInstallPath" \
--configuration "$dotnetBuildType" \
--no-restore \
--no-build \
"${runtimeIdFlags[@]}" \
"${flags[@]}" \
"${installFlags[@]}"
done
}
dotnetPack() {
local -r projectFile="${1-}"
local useRuntime=
_dotnetIsSolution "$projectFile" || useRuntime=1
for runtimeId in "${runtimeIds[@]}"; do
local runtimeIdFlags=()
if [[ -n $useRuntime ]]; then
runtimeIdFlags+=("--runtime" "$runtimeId")
# set RuntimeIdentifier because --runtime is broken:
# https://github.com/dotnet/sdk/issues/13983
runtimeIdFlags+=(-p:RuntimeIdentifier="$runtimeId")
fi
dotnet pack ${1+"$projectFile"} \
-maxcpucount:"$maxCpuFlag" \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
-p:OverwriteReadOnlyFiles=true \
--output "$out/share/nuget/source" \
--configuration "$dotnetBuildType" \
--no-restore \
--no-build \
"${runtimeIdFlags[@]}" \
"${flags[@]}" \
"${packFlags[@]}"
done
}
if (( ${#projectFiles[@]} == 0 )); then
dotnetPublish
else
local projectFile
for projectFile in "${projectFiles[@]}"; do
dotnetPublish "$projectFile"
done
fi
if [[ -n ${packNupkg-} ]]; then
if (( ${#projectFiles[@]} == 0 )); then
dotnetPack
else
local projectFile
for projectFile in "${projectFiles[@]}"; do
dotnetPack "$projectFile"
done
fi
fi
runHook postInstall
echo "Finished dotnetInstallHook"
}
if [[ -z "${dontDotnetInstall-}" && -z "${installPhase-}" ]]; then
installPhase=dotnetInstallPhase
fi

View File

@@ -0,0 +1,125 @@
{
stdenv,
lib,
makeWrapper,
pkg-config,
mono,
dotnetbuildhelpers,
}:
attrsOrig@{
pname,
version,
nativeBuildInputs ? [ ],
xBuildFiles ? [ ],
xBuildFlags ? [ "/p:Configuration=Release" ],
outputFiles ? [ "bin/Release/*" ],
dllFiles ? [ "*.dll" ],
exeFiles ? [ "*.exe" ],
# Additional arguments to pass to the makeWrapper function, which wraps
# generated binaries.
makeWrapperArgs ? [ ],
...
}:
let
arrayToShell = (a: toString (map (lib.escape (lib.stringToCharacters "\\ ';$`()|<>\t")) a));
attrs = {
inherit pname version;
nativeBuildInputs = [
pkg-config
makeWrapper
dotnetbuildhelpers
mono
]
++ nativeBuildInputs;
configurePhase = ''
runHook preConfigure
[ -z "''${dontPlacateNuget-}" ] && placate-nuget.sh
[ -z "''${dontPlacatePaket-}" ] && placate-paket.sh
[ -z "''${dontPatchFSharpTargets-}" ] && patch-fsharp-targets.sh
runHook postConfigure
'';
buildPhase = ''
runHook preBuild
echo Building dotNET packages...
# Probably needs to be moved to fsharp
if pkg-config FSharp.Core
then
export FSharpTargetsPath="$(dirname $(pkg-config FSharp.Core --variable=Libraries))/Microsoft.FSharp.Targets"
fi
ran=""
for xBuildFile in ${arrayToShell xBuildFiles} ''${xBuildFilesExtra}
do
ran="yes"
xbuild ${arrayToShell xBuildFlags} ''${xBuildFlagsArray} $xBuildFile
done
[ -z "$ran" ] && xbuild ${arrayToShell xBuildFlags} ''${xBuildFlagsArray}
runHook postBuild
'';
dontStrip = true;
installPhase = ''
runHook preInstall
target="$out/lib/dotnet/${pname}"
mkdir -p "$target"
cp -rv ${arrayToShell outputFiles} "''${outputFilesArray[@]}" "$target"
if [ -z "''${dontRemoveDuplicatedDlls-}" ]
then
pushd "$out"
remove-duplicated-dlls.sh
popd
fi
set -f
for dllPattern in ${arrayToShell dllFiles} ''${dllFilesArray[@]}
do
set +f
for dll in "$target"/$dllPattern
do
[ -f "$dll" ] || continue
if pkg-config $(basename -s .dll "$dll")
then
echo "$dll already exported by a buildInputs, not re-exporting"
else
create-pkg-config-for-dll.sh "$out/lib/pkgconfig" "$dll"
fi
done
done
set -f
for exePattern in ${arrayToShell exeFiles} ''${exeFilesArray[@]}
do
set +f
for exe in "$target"/$exePattern
do
[ -f "$exe" ] || continue
mkdir -p "$out"/bin
commandName="$(basename -s .exe "$(echo "$exe" | tr "[A-Z]" "[a-z]")")"
makeWrapper \
"${mono}/bin/mono" \
"$out"/bin/"$commandName" \
--add-flags "\"$exe\"" \
''${makeWrapperArgs}
done
done
runHook postInstall
'';
};
in
stdenv.mkDerivation (attrs // (removeAttrs attrsOrig [ "nativeBuildInputs" ]))

View File

@@ -0,0 +1,88 @@
{
symlinkJoin,
fetchurl,
stdenvNoCC,
lib,
unzip,
patchNupkgs,
nugetPackageHook,
callPackage,
overrides ? callPackage ./overrides.nix { },
}:
lib.makeOverridable (
{
pname,
version,
sha256 ? "",
hash ? "",
url ? "https://www.nuget.org/api/v2/package/${pname}/${version}",
installable ? false,
}:
let
package = stdenvNoCC.mkDerivation rec {
inherit pname version;
src = fetchurl {
name = "${pname}.${version}.nupkg";
# There is no need to verify whether both sha256 and hash are
# valid here, because nuget-to-json does not generate a deps.nix
# containing both.
inherit
url
sha256
hash
version
;
};
nativeBuildInputs = [
unzip
patchNupkgs
nugetPackageHook
];
unpackPhase = ''
runHook preUnpack
unpackNupkg "$src" source
cd source
runHook postUnpack
'';
prePatch = ''
shopt -s nullglob
local dir
for dir in tools runtimes/*/native; do
[[ ! -d "$dir" ]] || chmod -R +x "$dir"
done
rm -rf .signature.p7s
'';
installPhase = ''
runHook preInstall
dir=$out/share/nuget/packages/${lib.toLower pname}/${lib.toLower version}
mkdir -p $dir
cp -r . $dir
echo {} > "$dir"/.nupkg.metadata
runHook postInstall
'';
preFixup = ''
patch-nupkgs $out/share/nuget/packages
'';
createInstallableNugetSource = installable;
meta = {
sourceProvenance = with lib.sourceTypes; [
binaryBytecode
binaryNativeCode
];
};
};
in
overrides.${pname} or lib.id package
)

View File

@@ -0,0 +1,85 @@
{
autoPatchelfHook,
dotnetCorePackages,
fontconfig,
lib,
libICE,
libSM,
libX11,
stdenv,
writeText,
}:
{
# e.g.
# "Package.Id" =
# package:
# package.overrideAttrs (old: {
# buildInputs = old.buildInputs or [ ] ++ [ hello ];
# });
"Avalonia" =
package:
package.overrideAttrs (
old:
let
# These versions have a runtime error when built with `dotnet publish --no-build`
# When attempting to draw a window, Avalonia will throw "No precompiled XAML found"
#
# Introduced in https://github.com/AvaloniaUI/Avalonia/pull/13840
# Fixed by https://github.com/AvaloniaUI/Avalonia/pull/16835
affectedVersions = [
"11.1.0-beta1"
"11.1.0-beta2"
"11.1.0-rc1"
"11.1.0-rc2"
"11.1.0"
"11.1.1"
"11.1.2-rc1"
"11.1.2"
"11.1.3"
"11.2.0-beta1"
];
in
lib.optionalAttrs (builtins.elem old.version affectedVersions) {
postPatch = ''
substituteInPlace {build,buildTransitive}/AvaloniaBuildTasks.targets \
--replace-fail 'BeforeTargets="CopyFilesToOutputDirectory;BuiltProjectOutputGroup"' \
'BeforeTargets="CopyFilesToOutputDirectory;BuiltProjectOutputGroup;ComputeResolvedFilesToPublishList"'
'';
}
);
"Avalonia.X11" =
package:
package.overrideAttrs (
old:
lib.optionalAttrs (!stdenv.hostPlatform.isDarwin) {
setupHook = writeText "setupHook.sh" ''
prependToVar dotnetRuntimeDeps \
"${lib.getLib libICE}" \
"${lib.getLib libSM}" \
"${lib.getLib libX11}"
'';
}
);
"SkiaSharp.NativeAssets.Linux" =
package:
package.overrideAttrs (
old:
lib.optionalAttrs stdenv.hostPlatform.isLinux {
nativeBuildInputs = old.nativeBuildInputs or [ ] ++ [ autoPatchelfHook ];
buildInputs = old.buildInputs or [ ] ++ [ fontconfig ];
preInstall = old.preInstall or "" + ''
cd runtimes
for platform in *; do
[[ $platform == "${dotnetCorePackages.systemToDotnetRid stdenv.hostPlatform.system}" ]] ||
rm -r "$platform"
done
cd - >/dev/null
'';
}
);
}

View File

@@ -0,0 +1,57 @@
{
lib,
fetchurl,
buildDotnetPackage,
unzip,
}:
attrs@{
pname,
version,
url ? "https://www.nuget.org/api/v2/package/${pname}/${version}",
sha256 ? "",
hash ? "",
md5 ? "",
...
}:
if md5 != "" then
throw "fetchnuget does not support md5 anymore, please use 'hash' attribute with SRI hash: ${
lib.generators.toPretty { } attrs
}"
# This is also detected in fetchurl, but we just throw here to avoid confusion
else if (sha256 != "" && hash != "") then
throw "multiple hashes passed to fetchNuGet: ${lib.generators.toPretty { } url}"
else
buildDotnetPackage (
{
src = fetchurl {
inherit url sha256 hash;
name = "${pname}.${version}.zip";
};
sourceRoot = ".";
nativeBuildInputs = [ unzip ];
dontBuild = true;
preInstall = ''
function traverseRename () {
for e in *
do
t="$(echo "$e" | sed -e "s/%20/\ /g" -e "s/%2B/+/g")"
[ "$t" != "$e" ] && mv -vn "$e" "$t"
if [ -d "$t" ]
then
cd "$t"
traverseRename
cd ..
fi
done
}
traverseRename
'';
}
// attrs
)

View File

@@ -0,0 +1,33 @@
{
symlinkJoin,
lib,
fetchNupkg,
}:
lib.makeOverridable (
{
name,
nugetDeps ? null,
sourceFile ? null,
installable ? false,
}:
(symlinkJoin {
name = "${name}-nuget-deps";
paths =
let
loadDeps =
if nugetDeps != null then
nugetDeps
else if lib.hasSuffix ".nix" sourceFile then
assert (lib.isPath sourceFile);
import sourceFile
else
{ fetchNuGet }: map fetchNuGet (lib.importJSON sourceFile);
in
loadDeps {
fetchNuGet = args: fetchNupkg (args // { inherit installable; });
};
})
// {
inherit sourceFile;
}
)

View File

@@ -0,0 +1,43 @@
{
lib,
python3,
stdenvNoCC,
}:
{
name,
description ? "",
deps ? [ ],
...
}@args:
stdenvNoCC.mkDerivation (
lib.recursiveUpdate
{
inherit name;
nativeBuildInputs = [ python3 ];
buildCommand = ''
mkdir -p $out/{lib,share}
# use -L to follow symbolic links. When `projectReferences` is used in
# buildDotnetModule, one of the deps will be a symlink farm.
find -L ${lib.concatStringsSep " " deps} -type f -name '*.nupkg' -exec \
ln -s '{}' -t $out/lib ';'
# Generates a list of all licenses' spdx ids, if available.
# Note that this currently ignores any license provided in plain text (e.g. "LICENSE.txt")
python ${./extract-licenses-from-nupkgs.py} $out/lib > $out/share/licenses
'';
meta.description = description;
}
(
removeAttrs args [
"name"
"description"
"deps"
]
)
)

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python3
"""
Opens each .nupkg file in a directory, and extracts the SPDX license identifiers
from them if they exist. The SPDX license identifier is stored in the
'<license type="expression">...</license>' tag in the .nuspec file.
All found license identifiers will be printed to stdout.
"""
from glob import glob
from pathlib import Path
import sys
import xml.etree.ElementTree as ET
import zipfile
all_licenses = set()
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} DIRECTORY")
sys.exit(1)
nupkg_dir = Path(sys.argv[1])
for nupkg_name in glob("*.nupkg", root_dir=nupkg_dir):
with zipfile.ZipFile(nupkg_dir / nupkg_name) as nupkg:
for nuspec_name in [name for name in nupkg.namelist() if name.endswith(".nuspec")]:
with nupkg.open(nuspec_name) as nuspec_stream:
nuspec = ET.parse(nuspec_stream)
licenses = nuspec.findall(".//{*}license[@type='expression']")
all_licenses.update([license.text for license in licenses])
print("\n".join(sorted(all_licenses)))