core/pkgs/build-support/writers/scripts.nix

642 lines
21 KiB
Nix
Raw Normal View History

2024-05-13 21:24:10 +00:00
{ buildPackages, gixy, lib, libiconv, makeBinaryWrapper, mkNugetDeps
, mkNugetSource, pkgs, stdenv, }:
2024-05-02 00:46:19 +00:00
let
inherit (lib)
2024-05-13 21:24:10 +00:00
concatMapStringsSep elem escapeShellArg last optionalString strings types;
in rec {
2024-05-02 00:46:19 +00:00
# Base implementation for non-compiled executables.
# Takes an interpreter, for example `${lib.getExe pkgs.bash}`
#
# Examples:
# writeBash = makeScriptWriter { interpreter = "${pkgs.bash}/bin/bash"; }
# makeScriptWriter { interpreter = "${pkgs.dash}/bin/dash"; } "hello" "echo hello world"
2024-05-13 21:24:10 +00:00
makeScriptWriter = { interpreter, check ? "", makeWrapperArgs ? [ ], }:
nameOrPath: content:
assert (types.path.check nameOrPath)
|| (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null);
2024-05-02 00:46:19 +00:00
assert (types.path.check content) || (types.str.check content);
let
nameIsPath = types.path.check nameOrPath;
name = last (builtins.split "/" nameOrPath);
path = if nameIsPath then nameOrPath else "/bin/${name}";
# The inner derivation which creates the executable under $out/bin (never at $out directly)
# This is required in order to support wrapping, as wrapped programs consist of at least two files: the executable and the wrapper.
2024-05-13 21:24:10 +00:00
inner = pkgs.runCommandLocal name ({
inherit makeWrapperArgs;
nativeBuildInputs = [ makeBinaryWrapper ];
meta.mainProgram = name;
} // (if (types.str.check content) then {
inherit content interpreter;
passAsFile = [ "content" ];
} else {
inherit interpreter;
contentPath = content;
})) ''
# On darwin a script cannot be used as an interpreter in a shebang but
# there doesn't seem to be a limit to the size of shebang and multiple
# arguments to the interpreter are allowed.
if [[ -n "${
toString pkgs.stdenvNoCC.isDarwin
}" ]] && isScript $interpreter
then
wrapperInterpreterLine=$(head -1 "$interpreter" | tail -c+3)
# Get first word from the line (note: xargs echo remove leading spaces)
wrapperInterpreter=$(echo "$wrapperInterpreterLine" | xargs echo | cut -d " " -f1)
if isScript $wrapperInterpreter
2024-05-02 00:46:19 +00:00
then
2024-05-13 21:24:10 +00:00
echo "error: passed interpreter ($interpreter) is a script which has another script ($wrapperInterpreter) as an interpreter, which is not supported."
exit 1
2024-05-02 00:46:19 +00:00
fi
2024-05-13 21:24:10 +00:00
# This should work as long as wrapperInterpreter is a shell, which is
# the case for programs wrapped with makeWrapper, like
# python3.withPackages etc.
interpreterLine="$wrapperInterpreterLine $interpreter"
else
interpreterLine=$interpreter
fi
echo "#! $interpreterLine" > $out
cat "$contentPath" >> $out
${optionalString (check != "") ''
${check} $out
''}
chmod +x $out
# Relocate executable
# Wrap it if makeWrapperArgs are specified
mv $out tmp
mkdir -p $out/$(dirname "${path}")
mv tmp $out/${path}
if [ -n "''${makeWrapperArgs+''${makeWrapperArgs[@]}}" ]; then
wrapProgram $out/${path} ''${makeWrapperArgs[@]}
fi
'';
in if nameIsPath then
inner
# In case nameOrPath is a name, the user intends the executable to be located at $out.
# This is achieved by creating a separate derivation containing a symlink at $out linking to ${inner}/bin/${name}.
# This breaks the override pattern.
# In case this turns out to be a problem, we can still add more magic
else
pkgs.runCommandLocal name { } ''
ln -s ${inner}/bin/${name} $out
'';
2024-05-02 00:46:19 +00:00
# Base implementation for compiled executables.
# Takes a compile script, which in turn takes the name as an argument.
#
# Examples:
# writeSimpleC = makeBinWriter { compileScript = name: "gcc -o $out $contentPath"; }
2024-05-13 21:24:10 +00:00
makeBinWriter = { compileScript, strip ? true, makeWrapperArgs ? [ ] }:
nameOrPath: content:
assert (types.path.check nameOrPath)
|| (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null);
2024-05-02 00:46:19 +00:00
assert (types.path.check content) || (types.str.check content);
let
nameIsPath = types.path.check nameOrPath;
name = last (builtins.split "/" nameOrPath);
path = if nameIsPath then nameOrPath else "/bin/${name}";
# The inner derivation which creates the executable under $out/bin (never at $out directly)
# This is required in order to support wrapping, as wrapped programs consist of at least two files: the executable and the wrapper.
2024-05-13 21:24:10 +00:00
inner = pkgs.runCommandLocal name ({
inherit makeWrapperArgs;
nativeBuildInputs = [ makeBinaryWrapper ];
meta.mainProgram = name;
} // (if (types.str.check content) then {
inherit content;
passAsFile = [ "content" ];
} else {
contentPath = content;
})) ''
${compileScript}
${lib.optionalString strip "${
lib.getBin buildPackages.bintools-unwrapped
}/bin/${buildPackages.bintools-unwrapped.targetPrefix}strip -S $out"}
# Sometimes binaries produced for darwin (e. g. by GHC) won't be valid
# mach-o executables from the get-go, but need to be corrected somehow
# which is done by fixupPhase.
${lib.optionalString pkgs.stdenvNoCC.hostPlatform.isDarwin "fixupPhase"}
mv $out tmp
mkdir -p $out/$(dirname "${path}")
mv tmp $out/${path}
if [ -n "''${makeWrapperArgs+''${makeWrapperArgs[@]}}" ]; then
wrapProgram $out/${path} ''${makeWrapperArgs[@]}
fi
'';
in if nameIsPath then
inner
2024-05-02 00:46:19 +00:00
# In case nameOrPath is a name, the user intends the executable to be located at $out.
# This is achieved by creating a separate derivation containing a symlink at $out linking to ${inner}/bin/${name}.
# This breaks the override pattern.
# In case this turns out to be a problem, we can still add more magic
2024-05-13 21:24:10 +00:00
else
pkgs.runCommandLocal name { } ''
2024-05-02 00:46:19 +00:00
ln -s ${inner}/bin/${name} $out
'';
# Like writeScript but the first line is a shebang to bash
#
# Can be called with or without extra arguments.
#
# Example without arguments:
# writeBash "example" ''
# echo hello world
# ''
#
# Example with arguments:
# writeBash "example"
# {
# makeWrapperArgs = [
# "--prefix" "PATH" ":" "${pkgs.hello}/bin"
# ];
# }
# ''
# hello
# ''
writeBash = name: argsOrScript:
2024-05-13 21:24:10 +00:00
if lib.isAttrs argsOrScript && !lib.isDerivation argsOrScript then
makeScriptWriter
(argsOrScript // { interpreter = "${lib.getExe pkgs.bash}"; }) name
else
makeScriptWriter { interpreter = "${lib.getExe pkgs.bash}"; } name
argsOrScript;
2024-05-02 00:46:19 +00:00
# Like writeScriptBin but the first line is a shebang to bash
#
# Can be called with or without extra arguments.
#
# Example without arguments:
# writeBashBin "example" ''
# echo hello world
# ''
#
# Example with arguments:
# writeBashBin "example"
# {
# makeWrapperArgs = [
# "--prefix", "PATH", ":", "${pkgs.hello}/bin",
# ];
# }
# ''
# hello
# ''
2024-05-13 21:24:10 +00:00
writeBashBin = name: writeBash "/bin/${name}";
2024-05-02 00:46:19 +00:00
# Like writeScript but the first line is a shebang to dash
#
# Can be called with or without extra arguments.
#
# Example without arguments:
# writeDash "example" ''
# echo hello world
# ''
#
# Example with arguments:
# writeDash "example"
# {
# makeWrapperArgs = [
# "--prefix", "PATH", ":", "${pkgs.hello}/bin",
# ];
# }
# ''
# hello
# ''
writeDash = name: argsOrScript:
2024-05-13 21:24:10 +00:00
if lib.isAttrs argsOrScript && !lib.isDerivation argsOrScript then
makeScriptWriter
(argsOrScript // { interpreter = "${lib.getExe pkgs.dash}"; }) name
else
makeScriptWriter { interpreter = "${lib.getExe pkgs.dash}"; } name
argsOrScript;
2024-05-02 00:46:19 +00:00
# Like writeScriptBin but the first line is a shebang to dash
#
# Can be called with or without extra arguments.
#
# Example without arguments:
# writeDashBin "example" ''
# echo hello world
# ''
#
# Example with arguments:
# writeDashBin "example"
# {
# makeWrapperArgs = [
# "--prefix", "PATH", ":", "${pkgs.hello}/bin",
# ];
# }
# ''
# hello
# ''
2024-05-13 21:24:10 +00:00
writeDashBin = name: writeDash "/bin/${name}";
2024-05-02 00:46:19 +00:00
# Like writeScript but the first line is a shebang to fish
#
# Can be called with or without extra arguments.
#
# Example without arguments:
# writeFish "example" ''
# echo hello world
# ''
#
# Example with arguments:
# writeFish "example"
# {
# makeWrapperArgs = [
# "--prefix", "PATH", ":", "${pkgs.hello}/bin",
# ];
# }
# ''
# hello
# ''
writeFish = name: argsOrScript:
2024-05-13 21:24:10 +00:00
if lib.isAttrs argsOrScript && !lib.isDerivation argsOrScript then
makeScriptWriter (argsOrScript // {
interpreter = "${lib.getExe pkgs.fish} --no-config";
check = "${
lib.getExe pkgs.fish
} --no-config --no-execute"; # syntax check only
}) name
else
makeScriptWriter {
interpreter = "${lib.getExe pkgs.fish} --no-config";
check = "${
lib.getExe pkgs.fish
} --no-config --no-execute"; # syntax check only
} name argsOrScript;
2024-05-02 00:46:19 +00:00
# Like writeScriptBin but the first line is a shebang to fish
#
# Can be called with or without extra arguments.
#
# Example without arguments:
# writeFishBin "example" ''
# echo hello world
# ''
#
# Example with arguments:
# writeFishBin "example"
# {
# makeWrapperArgs = [
# "--prefix", "PATH", ":", "${pkgs.hello}/bin",
# ];
# }
# ''
# hello
# ''
2024-05-13 21:24:10 +00:00
writeFishBin = name: writeFish "/bin/${name}";
2024-05-02 00:46:19 +00:00
# writeHaskell takes a name, an attrset with libraries and haskell version (both optional)
# and some haskell source code and returns an executable.
#
# Example:
# writeHaskell "missiles" { libraries = [ pkgs.haskellPackages.acme-missiles ]; } ''
# import Acme.Missiles
#
# main = launchMissiles
# '';
2024-05-13 21:24:10 +00:00
writeHaskell = name:
{ ghc ? pkgs.ghc, ghcArgs ? [ ], libraries ? [ ], makeWrapperArgs ? [ ]
, strip ? true, threadedRuntime ? true, }:
2024-05-02 00:46:19 +00:00
let
appendIfNotSet = el: list: if elem el list then list else list ++ [ el ];
2024-05-13 21:24:10 +00:00
ghcArgs' =
if threadedRuntime then appendIfNotSet "-threaded" ghcArgs else ghcArgs;
2024-05-02 00:46:19 +00:00
in makeBinWriter {
compileScript = ''
cp $contentPath tmp.hs
2024-05-13 21:24:10 +00:00
${(ghc.withPackages (_: libraries))}/bin/ghc ${
lib.escapeShellArgs ghcArgs'
} tmp.hs
2024-05-02 00:46:19 +00:00
mv tmp $out
'';
inherit makeWrapperArgs strip;
} name;
# writeHaskellBin takes the same arguments as writeHaskell but outputs a directory (like writeScriptBin)
2024-05-13 21:24:10 +00:00
writeHaskellBin = name: writeHaskell "/bin/${name}";
2024-05-02 00:46:19 +00:00
# Like writeScript but the first line is a shebang to nu
#
# Can be called with or without extra arguments.
#
# Example without arguments:
# writeNu "example" ''
# echo hello world
# ''
#
# Example with arguments:
# writeNu "example"
# {
# makeWrapperArgs = [
# "--prefix", "PATH", ":", "${pkgs.hello}/bin",
# ];
# }
# ''
# hello
# ''
writeNu = name: argsOrScript:
2024-05-13 21:24:10 +00:00
if lib.isAttrs argsOrScript && !lib.isDerivation argsOrScript then
makeScriptWriter (argsOrScript // {
interpreter = "${lib.getExe pkgs.nushell} --no-config-file";
}) name
else
makeScriptWriter {
interpreter = "${lib.getExe pkgs.nushell} --no-config-file";
} name argsOrScript;
2024-05-02 00:46:19 +00:00
# Like writeScriptBin but the first line is a shebang to nu
#
# Can be called with or without extra arguments.
#
# Example without arguments:
# writeNuBin "example" ''
# echo hello world
# ''
#
# Example with arguments:
# writeNuBin "example"
# {
# makeWrapperArgs = [
# "--prefix", "PATH", ":", "${pkgs.hello}/bin",
# ];
# }
# ''
# hello
# ''
2024-05-13 21:24:10 +00:00
writeNuBin = name: writeNu "/bin/${name}";
2024-05-02 00:46:19 +00:00
# makeRubyWriter takes ruby and compatible rubyPackages and produces ruby script writer,
# If any libraries are specified, ruby.withPackages is used as interpreter, otherwise the "bare" ruby is used.
2024-05-13 21:24:10 +00:00
makeRubyWriter = ruby: rubyPackages: buildRubyPackages: name:
{ libraries ? [ ], ... }@args:
makeScriptWriter ((builtins.removeAttrs args [ "libraries" ]) // {
interpreter = if libraries == [ ] then
"${ruby}/bin/ruby"
else
"${(ruby.withPackages (ps: libraries))}/bin/ruby";
2024-05-02 00:46:19 +00:00
# Rubocop doesn't seem to like running in this fashion.
#check = (writeDash "rubocop.sh" ''
# exec ${lib.getExe buildRubyPackages.rubocop} "$1"
#'');
2024-05-13 21:24:10 +00:00
}) name;
2024-05-02 00:46:19 +00:00
# Like writeScript but the first line is a shebang to ruby
#
# Example:
# writeRuby "example" { libraries = [ pkgs.rubyPackages.git ]; } ''
# puts "hello world"
# ''
2024-05-13 21:24:10 +00:00
writeRuby =
makeRubyWriter pkgs.ruby pkgs.rubyPackages buildPackages.rubyPackages;
2024-05-02 00:46:19 +00:00
2024-05-13 21:24:10 +00:00
writeRubyBin = name: writeRuby "/bin/${name}";
2024-05-02 00:46:19 +00:00
# makeLuaWriter takes lua and compatible luaPackages and produces lua script writer,
# which validates the script with luacheck at build time. If any libraries are specified,
# lua.withPackages is used as interpreter, otherwise the "bare" lua is used.
2024-05-13 21:24:10 +00:00
makeLuaWriter = lua: luaPackages: buildLuaPackages: name:
{ libraries ? [ ], ... }@args:
makeScriptWriter ((builtins.removeAttrs args [ "libraries" ]) // {
2024-05-02 00:46:19 +00:00
interpreter = lua.interpreter;
2024-05-13 21:24:10 +00:00
# if libraries == []
# then lua.interpreter
# else (lua.withPackages (ps: libraries)).interpreter
# This should support packages! I just cant figure out why some dependency collision happens whenever I try to run this.
2024-05-02 00:46:19 +00:00
check = (writeDash "luacheck.sh" ''
exec ${buildLuaPackages.luacheck}/bin/luacheck "$1"
'');
2024-05-13 21:24:10 +00:00
}) name;
2024-05-02 00:46:19 +00:00
# writeLua takes a name an attributeset with libraries and some lua source code and
# returns an executable (should also work with luajit)
#
# Example:
# writeLua "test_lua" { libraries = [ pkgs.luaPackages.say ]; } ''
# s = require("say")
# s:set_namespace("en")
#
# s:set('money', 'I have %s dollars')
# s:set('wow', 'So much money!')
#
# print(s('money', {1000})) -- I have 1000 dollars
#
# s:set_namespace("fr") -- switch to french!
# s:set('wow', "Tant d'argent!")
#
# print(s('wow')) -- Tant d'argent!
# s:set_namespace("en") -- switch back to english!
# print(s('wow')) -- So much money!
# ''
writeLua = makeLuaWriter pkgs.lua pkgs.luaPackages buildPackages.luaPackages;
2024-05-13 21:24:10 +00:00
writeLuaBin = name: writeLua "/bin/${name}";
writeRust = name:
{ makeWrapperArgs ? [ ], rustc ? pkgs.rustc, rustcArgs ? [ ], strip ? true,
}:
let
darwinArgs =
lib.optionals stdenv.isDarwin [ "-L${lib.getLib libiconv}/lib" ];
in makeBinWriter {
2024-05-02 00:46:19 +00:00
compileScript = ''
cp "$contentPath" tmp.rs
2024-05-13 21:24:10 +00:00
PATH=${lib.makeBinPath [ pkgs.gcc ]} ${rustc}/bin/rustc ${
lib.escapeShellArgs rustcArgs
} ${lib.escapeShellArgs darwinArgs} -o "$out" tmp.rs
2024-05-02 00:46:19 +00:00
'';
inherit makeWrapperArgs strip;
} name;
2024-05-13 21:24:10 +00:00
writeRustBin = name: writeRust "/bin/${name}";
2024-05-02 00:46:19 +00:00
# writeJS takes a name an attributeset with libraries and some JavaScript sourcecode and
# returns an executable
#
# Example:
# writeJS "example" { libraries = [ pkgs.nodePackages.uglify-js ]; } ''
# var UglifyJS = require("uglify-js");
# var code = "function add(first, second) { return first + second; }";
# var result = UglifyJS.minify(code);
# console.log(result.code);
# ''
2024-05-13 21:24:10 +00:00
writeJS = name:
{ libraries ? [ ] }:
content:
let
node-env = pkgs.buildEnv {
name = "node";
paths = libraries;
pathsToLink = [ "/lib/node_modules" ];
};
in writeDash name ''
export NODE_PATH=${node-env}/lib/node_modules
exec ${lib.getExe pkgs.nodejs} ${pkgs.writeText "js" content} "$@"
'';
2024-05-02 00:46:19 +00:00
# writeJSBin takes the same arguments as writeJS but outputs a directory (like writeScriptBin)
2024-05-13 21:24:10 +00:00
writeJSBin = name: writeJS "/bin/${name}";
2024-05-02 00:46:19 +00:00
awkFormatNginx = builtins.toFile "awkFormat-nginx.awk" ''
awk -f
{sub(/^[ \t]+/,"");idx=0}
/\{/{ctx++;idx=1}
/\}/{ctx--}
{id="";for(i=idx;i<ctx;i++)id=sprintf("%s%s", id, "\t");printf "%s%s\n", id, $0}
'';
2024-05-13 21:24:10 +00:00
writeNginxConfig = name: text:
pkgs.runCommandLocal name {
inherit text;
passAsFile = [ "text" ];
nativeBuildInputs = [ gixy ];
} # sh
''
# nginx-config-formatter has an error - https://github.com/1connect/nginx-config-formatter/issues/16
awk -f ${awkFormatNginx} "$textPath" | sed '/^\s*$/d' > $out
gixy $out
'';
2024-05-02 00:46:19 +00:00
# writePerl takes a name an attributeset with libraries and some perl sourcecode and
# returns an executable
#
# Example:
# writePerl "example" { libraries = [ pkgs.perlPackages.boolean ]; } ''
# use boolean;
# print "Howdy!\n" if true;
# ''
2024-05-13 21:24:10 +00:00
writePerl = name:
{ libraries ? [ ], ... }@args:
makeScriptWriter ((builtins.removeAttrs args [ "libraries" ]) // {
interpreter = "${lib.getExe (pkgs.perl.withPackages (p: libraries))}";
}) name;
2024-05-02 00:46:19 +00:00
# writePerlBin takes the same arguments as writePerl but outputs a directory (like writeScriptBin)
2024-05-13 21:24:10 +00:00
writePerlBin = name: writePerl "/bin/${name}";
2024-05-02 00:46:19 +00:00
# makePythonWriter takes python and compatible pythonPackages and produces python script writer,
# which validates the script with flake8 at build time. If any libraries are specified,
# python.withPackages is used as interpreter, otherwise the "bare" python is used.
2024-05-13 21:24:10 +00:00
makePythonWriter = python: pythonPackages: buildPythonPackages: name:
{ libraries ? [ ], flakeIgnore ? [ ], ... }@args:
let
ignoreAttribute = optionalString (flakeIgnore != [ ])
"--ignore ${concatMapStringsSep "," escapeShellArg flakeIgnore}";
in makeScriptWriter
((builtins.removeAttrs args [ "libraries" "flakeIgnore" ]) // {
interpreter = if pythonPackages != pkgs.pypy2Packages || pythonPackages
!= pkgs.pypy3Packages then
if libraries == [ ] then
python.interpreter
else
(python.withPackages (ps: libraries)).interpreter
else
python.interpreter;
check = optionalString python.isPy3k (writeDash "pythoncheck.sh" ''
exec ${buildPythonPackages.flake8}/bin/flake8 --show-source ${ignoreAttribute} "$1"
'');
}) name;
2024-05-02 00:46:19 +00:00
# writePyPy2 takes a name an attributeset with libraries and some pypy2 sourcecode and
# returns an executable
#
# Example:
# writePyPy2 "test_pypy2" { libraries = [ pkgs.pypy2Packages.enum ]; } ''
# from enum import Enum
#
# class Test(Enum):
# a = "success"
#
# print Test.a
# ''
2024-05-13 21:24:10 +00:00
writePyPy2 =
makePythonWriter pkgs.pypy2 pkgs.pypy2Packages buildPackages.pypy2Packages;
2024-05-02 00:46:19 +00:00
# writePyPy2Bin takes the same arguments as writePyPy2 but outputs a directory (like writeScriptBin)
2024-05-13 21:24:10 +00:00
writePyPy2Bin = name: writePyPy2 "/bin/${name}";
2024-05-02 00:46:19 +00:00
# writePython3 takes a name an attributeset with libraries and some python3 sourcecode and
# returns an executable
#
# Example:
# writePython3 "test_python3" { libraries = [ pkgs.python3Packages.pyyaml ]; } ''
# import yaml
#
# y = yaml.load("""
# - test: success
# """)
# print(y[0]['test'])
# ''
2024-05-13 21:24:10 +00:00
writePython3 = makePythonWriter pkgs.python3 pkgs.python3Packages
buildPackages.python3Packages;
2024-05-02 00:46:19 +00:00
# writePython3Bin takes the same arguments as writePython3 but outputs a directory (like writeScriptBin)
2024-05-13 21:24:10 +00:00
writePython3Bin = name: writePython3 "/bin/${name}";
2024-05-02 00:46:19 +00:00
# writePyPy3 takes a name an attributeset with libraries and some pypy3 sourcecode and
# returns an executable
#
# Example:
# writePyPy3 "test_pypy3" { libraries = [ pkgs.pypy3Packages.pyyaml ]; } ''
# import yaml
#
# y = yaml.load("""
# - test: success
# """)
# print(y[0]['test'])
# ''
2024-05-13 21:24:10 +00:00
writePyPy3 =
makePythonWriter pkgs.pypy3 pkgs.pypy3Packages buildPackages.pypy3Packages;
2024-05-02 00:46:19 +00:00
# writePyPy3Bin takes the same arguments as writePyPy3 but outputs a directory (like writeScriptBin)
2024-05-13 21:24:10 +00:00
writePyPy3Bin = name: writePyPy3 "/bin/${name}";
makeFSharpWriter = { dotnet-sdk ? pkgs.dotnet-sdk, fsi-flags ? ""
, libraries ? _: [ ], ... }@args:
nameOrPath:
let
fname = last (builtins.split "/" nameOrPath);
path = if strings.hasSuffix ".fsx" nameOrPath then
nameOrPath
else
"${nameOrPath}.fsx";
_nugetDeps = mkNugetDeps {
name = "${fname}-nuget-deps";
nugetDeps = libraries;
};
nuget-source = mkNugetSource {
name = "${fname}-nuget-source";
description = "A Nuget source with the dependencies for ${fname}";
deps = [ _nugetDeps ];
};
fsi = writeBash "fsi" ''
export HOME=$NIX_BUILD_TOP/.home
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_NOLOGO=1
script="$1"; shift
${
lib.getExe dotnet-sdk
} fsi --quiet --nologo --readline- ${fsi-flags} "$@" < "$script"
'';
2024-05-02 00:46:19 +00:00
2024-05-13 21:24:10 +00:00
in content:
makeScriptWriter
((builtins.removeAttrs args [ "dotnet-sdk" "fsi-flags" "libraries" ]) // {
2024-05-02 00:46:19 +00:00
interpreter = fsi;
2024-05-13 21:24:10 +00:00
}) path ''
#i "nuget: ${nuget-source}/lib"
${content}
exit 0
'';
2024-05-02 00:46:19 +00:00
2024-05-13 21:24:10 +00:00
writeFSharp = makeFSharpWriter { };
2024-05-02 00:46:19 +00:00
2024-05-13 21:24:10 +00:00
writeFSharpBin = name: writeFSharp "/bin/${name}";
2024-05-02 00:46:19 +00:00
}