Created
October 6, 2023 17:57
-
-
Save PedroHLC/b930cbbacdcb2a664e6cf20ab5acc82c to your computer and use it in GitHub Desktop.
A more complex version of writeShellScriptBin that generates a lib directory and make some other stuff easy too
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ lib | |
, runtimeShell | |
, stdenvNoCC | |
}@p: | |
{ pname | |
, lib ? p.lib | |
, runtimeShell ? p.runtimeShell | |
, stdenv ? stdenvNoCC | |
, version ? null | |
, critical ? false | |
, meta ? { } | |
, passthru ? { } | |
, checkPhase ? "${stdenv.shellDryRun} \"$mainProgram\"" | |
, extraScripts ? { } | |
, extraFiles ? { } | |
, resolve ? { } | |
, external ? [ ] | |
, depends ? [ ] | |
, path ? "" | |
}: userMainScript: | |
let | |
inherit (builtins) attrNames concatStringsSep foldl' map; | |
inherit (lib) escapeShellArg; | |
inherit (lib.strings) optionalString toUpper; | |
extraScriptsNames = | |
attrNames extraScripts; | |
extraScriptTarget = sName: "lib/${escapeShellArg pname}/${escapeShellArg sName}"; | |
# everybody deserves to be a file | |
prefixExtraScriptsName = sName: "script_${sName}"; | |
prefixExtraScripts = accu: sName: | |
let value = extraScripts.${sName}; in | |
if builtins.isPath value | |
then accu | |
else accu // { "${prefixExtraScriptsName sName}" = value; }; | |
prefixedExtraScripts = | |
foldl' prefixExtraScripts { } extraScriptsNames; | |
prefixedExtraScriptsNames = | |
attrNames prefixedExtraScripts; | |
resolved = | |
map | |
(rName: '' | |
function ${rName} { ${escapeShellArg resolve.${rName}} "$@"; } | |
'') | |
(attrNames resolve); | |
findExternals = | |
map | |
(eName: | |
let eUpName = toUpper eName; in '' | |
${eUpName}=''${${eUpName}:-$(which ${escapeShellArg eName})} | |
function ${eName} { "${"$" + eUpName}" "$@"; } | |
'') | |
external; | |
sourceDepends = | |
map (dName: "source ${escapeShellArg dName}") depends; | |
buddy = bName: '' | |
source "$BASH_SOURCE_DIRNAME"/${extraScriptTarget bName} | |
''; | |
buddies = | |
map buddy extraScriptsNames; | |
mainScript = | |
'' | |
#!${runtimeShell} | |
BASH_SOURCE_DIRNAME="''${BASH_SOURCE[0]%/*}/.." | |
'' + (optionalString critical '' | |
set -euo pipefail | |
'') + '' | |
${concatStringsSep "\n" (resolved ++ findExternals ++ sourceDepends)} | |
PATH=${escapeShellArg path} | |
'' + ( | |
concatStringsSep "\n" buddies | |
) + userMainScript; | |
extraScriptsWrite = sName: | |
if prefixedExtraScripts ? sName then | |
let | |
prefixedName = "$" + (prefixExtraScriptsName sName); | |
in | |
'' | |
writeTextFile $out/${extraScriptTarget sName} "${prefixedName}Path" "${prefixedName}" "y"; | |
'' | |
else '' | |
linkFile $out/${extraScriptTarget sName} "${extraScripts.${sName}}"; | |
''; | |
extraScriptsWrites = | |
concatStringsSep "\n" (map extraScriptsWrite extraScriptsNames); | |
extraFilesLink = fName: '' | |
linkFile $out/${escapeShellArg fName} ${escapeShellArg extraFiles.${fName}} | |
''; | |
extraFilesLinks = | |
concatStringsSep "\n" (map extraFilesLink (attrNames extraFiles)); | |
finalMeta = { mainProgram = "bin/${pname}"; } // meta; | |
name = | |
if version == null | |
then pname | |
else "${pname}-${version}"; | |
build = buildCommand: | |
stdenv.mkDerivation (prefixedExtraScripts // { | |
inherit name; | |
inherit buildCommand; | |
inherit passthru; | |
inherit mainScript; | |
strictDeps = true; | |
enableParallelBuilding = true; | |
passAsFile = [ "buildCommand" "mainScript" ] ++ prefixedExtraScriptsNames; | |
meta = finalMeta; | |
}); | |
in | |
build '' | |
function writeTextFile() { | |
target="$1" | |
textPath="$2" | |
text="$3" | |
executable="''${4:-n}" | |
mkdir -p "$(dirname "$target")" | |
if [ -e "$textPath" ]; then | |
mv "$textPath" "$target" | |
else | |
echo -n "$text" > "$target" | |
fi | |
if [[ "$executable" == "y" ]]; then | |
chmod +x "$target" | |
fi | |
} | |
function linkFile() { | |
target="$1" | |
source="$2" | |
mkdir -p "$(dirname "$target")" | |
ln -s "$source" "$target" | |
} | |
mainProgram=$out/${escapeShellArg finalMeta.mainProgram} | |
writeTextFile "$mainProgram" "$mainScriptPath" "$mainScript" "y" | |
${extraScriptsWrites} | |
${extraFilesLinks} | |
eval "$checkPhase" | |
'' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment