2018-10-27 18:05:26 +01:00
|
|
|
{ pkgs, lib }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
rec {
|
|
|
|
# Base implementation for non-compiled executables.
|
|
|
|
# Takes an interpreter, for example `${pkgs.bash}/bin/bash`
|
|
|
|
#
|
|
|
|
# Examples:
|
|
|
|
# writeBash = makeScriptWriter { interpreter = "${pkgs.bash}/bin/bash"; }
|
|
|
|
# makeScriptWriter { interpreter = "${pkgs.dash}/bin/dash"; } "hello" "echo hello world"
|
2018-12-01 23:56:16 +00:00
|
|
|
makeScriptWriter = { interpreter, check ? "" }: nameOrPath: content:
|
|
|
|
assert lib.or (types.path.check nameOrPath) (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null);
|
|
|
|
assert lib.or (types.path.check content) (types.string.check content);
|
|
|
|
let
|
|
|
|
name = last (builtins.split "/" nameOrPath);
|
|
|
|
in
|
2018-10-27 18:05:26 +01:00
|
|
|
|
2018-12-01 23:56:16 +00:00
|
|
|
pkgs.runCommand name (if (types.string.check content) then {
|
|
|
|
inherit content interpreter;
|
|
|
|
passAsFile = [ "content" ];
|
|
|
|
} else {
|
|
|
|
inherit interpreter;
|
|
|
|
contentPath = content;
|
|
|
|
}) ''
|
|
|
|
echo "#! $interpreter" > $out
|
|
|
|
cat "$contentPath" >> $out
|
|
|
|
chmod +x $out
|
|
|
|
${optionalString (types.path.check nameOrPath) ''
|
|
|
|
mv $out tmp
|
|
|
|
mkdir -p $out/$(dirname "${nameOrPath}")
|
|
|
|
mv tmp $out/${nameOrPath}
|
|
|
|
''}
|
|
|
|
'';
|
|
|
|
|
|
|
|
# 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"; }
|
|
|
|
makeBinWriter = { compileScript }: nameOrPath: content:
|
|
|
|
assert lib.or (types.path.check nameOrPath) (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null);
|
|
|
|
assert lib.or (types.path.check content) (types.string.check content);
|
|
|
|
let
|
|
|
|
name = last (builtins.split "/" nameOrPath);
|
|
|
|
in
|
|
|
|
pkgs.runCommand name (if (types.string.check content) then {
|
|
|
|
inherit content;
|
|
|
|
passAsFile = [ "content" ];
|
|
|
|
} else {
|
|
|
|
contentPath = content;
|
|
|
|
}) ''
|
|
|
|
${compileScript}
|
|
|
|
${optionalString (types.path.check nameOrPath) ''
|
|
|
|
mv $out tmp
|
|
|
|
mkdir -p $out/$(dirname "${nameOrPath}")
|
|
|
|
mv tmp $out/${nameOrPath}
|
|
|
|
''}
|
|
|
|
'';
|
2018-10-27 18:05:26 +01:00
|
|
|
|
|
|
|
# Like writeScript but the first line is a shebang to bash
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
# writeBash "example" ''
|
|
|
|
# echo hello world
|
|
|
|
# ''
|
|
|
|
writeBash = makeScriptWriter {
|
|
|
|
interpreter = "${pkgs.bash}/bin/bash";
|
|
|
|
};
|
|
|
|
|
|
|
|
# Like writeScriptBIn but the first line is a shebang to bash
|
|
|
|
writeBashBin = name:
|
|
|
|
writeBash "/bin/${name}";
|
|
|
|
|
|
|
|
# writeC writes an executable c package called `name` to `destination` using `libraries`.
|
|
|
|
#
|
|
|
|
# Examples:
|
|
|
|
# writeC "hello-world-ncurses" { libraries = [ pkgs.ncurses ]; } ''
|
|
|
|
# #include <ncurses.h>
|
|
|
|
# int main() {
|
|
|
|
# initscr();
|
|
|
|
# printw("Hello World !!!");
|
|
|
|
# refresh(); endwin();
|
|
|
|
# return 0;
|
|
|
|
# }
|
|
|
|
# ''
|
2018-12-01 23:56:16 +00:00
|
|
|
writeC = name: { libraries ? [] }:
|
|
|
|
makeBinWriter {
|
|
|
|
compileScript = ''
|
|
|
|
PATH=${makeBinPath [
|
|
|
|
pkgs.binutils-unwrapped
|
|
|
|
pkgs.coreutils
|
|
|
|
pkgs.gcc
|
|
|
|
pkgs.pkgconfig
|
|
|
|
]}
|
|
|
|
gcc \
|
|
|
|
${optionalString (libraries != [])
|
|
|
|
"$(pkgs.pkgconfig}/bin/pkg-config --cflags --libs ${
|
|
|
|
concatMapStringsSep " " (lib: escapeShellArg (builtins.parseDrvName lib.name).name) (libraries)
|
|
|
|
})"
|
|
|
|
} \
|
|
|
|
-O \
|
|
|
|
-o "$out" \
|
|
|
|
-Wall \
|
|
|
|
-x c \
|
|
|
|
"$contentPath"
|
|
|
|
strip --strip-unneeded "$out"
|
|
|
|
'';
|
|
|
|
} name;
|
2018-10-27 18:05:26 +01:00
|
|
|
|
|
|
|
# writeCBin takes the same arguments as writeC but outputs a directory (like writeScriptBin)
|
2018-12-01 23:56:16 +00:00
|
|
|
writeCBin = name:
|
|
|
|
writeC "/bin/${name}";
|
2018-10-27 18:05:26 +01:00
|
|
|
|
|
|
|
# Like writeScript but the first line is a shebang to dash
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
# writeDash "example" ''
|
|
|
|
# echo hello world
|
|
|
|
# ''
|
|
|
|
writeDash = makeScriptWriter {
|
|
|
|
interpreter = "${pkgs.dash}/bin/dash";
|
|
|
|
};
|
|
|
|
|
|
|
|
# Like writeScriptBin but the first line is a shebang to dash
|
|
|
|
writeDashBin = name:
|
|
|
|
writeDash "/bin/${name}";
|
|
|
|
|
|
|
|
# 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 ]; } ''
|
2018-12-01 23:56:16 +00:00
|
|
|
# import Acme.Missiles
|
2018-10-27 18:05:26 +01:00
|
|
|
#
|
|
|
|
# main = launchMissiles
|
|
|
|
# '';
|
|
|
|
writeHaskell = name: {
|
|
|
|
libraries ? [],
|
|
|
|
ghc ? pkgs.ghc
|
2018-12-01 23:56:16 +00:00
|
|
|
}:
|
|
|
|
makeBinWriter {
|
|
|
|
compileScript = ''
|
|
|
|
cp $contentPath tmp.hs
|
|
|
|
${ghc.withPackages (_: libraries )}/bin/ghc tmp.hs
|
|
|
|
mv tmp $out
|
|
|
|
'';
|
|
|
|
} name;
|
2018-10-27 18:05:26 +01:00
|
|
|
|
|
|
|
# writeHaskellBin takes the same arguments as writeHaskell but outputs a directory (like writeScriptBin)
|
2018-12-01 23:56:16 +00:00
|
|
|
writeHaskellBin = name:
|
|
|
|
writeHaskell "/bin/${name}";
|
2018-10-27 18:05:26 +01: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);
|
|
|
|
# ''
|
2018-12-01 23:56:16 +00:00
|
|
|
writeJS = name: { libraries ? [] }: content:
|
2018-10-27 18:05:26 +01:00
|
|
|
let
|
|
|
|
node-env = pkgs.buildEnv {
|
|
|
|
name = "node";
|
|
|
|
paths = libraries;
|
|
|
|
pathsToLink = [
|
|
|
|
"/lib/node_modules"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
in writeDash name ''
|
|
|
|
export NODE_PATH=${node-env}/lib/node_modules
|
2018-12-01 23:56:16 +00:00
|
|
|
exec ${pkgs.nodejs}/bin/node ${pkgs.writeText "js" content}
|
2018-10-27 18:05:26 +01:00
|
|
|
'';
|
|
|
|
|
|
|
|
# writeJSBin takes the same arguments as writeJS but outputs a directory (like writeScriptBin)
|
|
|
|
writeJSBin = name:
|
|
|
|
writeJS "/bin/${name}";
|
|
|
|
|
|
|
|
# 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;
|
|
|
|
# ''
|
|
|
|
writePerl = name: { libraries ? [] }:
|
|
|
|
let
|
|
|
|
perl-env = pkgs.buildEnv {
|
|
|
|
name = "perl-environment";
|
|
|
|
paths = libraries;
|
|
|
|
pathsToLink = [
|
|
|
|
"/lib/perl5/site_perl"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
in
|
|
|
|
makeScriptWriter {
|
|
|
|
interpreter = "${pkgs.perl}/bin/perl -I ${perl-env}/lib/perl5/site_perl";
|
|
|
|
} name;
|
|
|
|
|
|
|
|
# writePerlBin takes the same arguments as writePerl but outputs a directory (like writeScriptBin)
|
|
|
|
writePerlBin = name:
|
|
|
|
writePerl "/bin/${name}";
|
|
|
|
|
|
|
|
# writePython2 takes a name an attributeset with libraries and some python2 sourcecode and
|
|
|
|
# returns an executable
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
# writePython2 "test_python2" { libraries = [ pkgs.python2Packages.enum ]; } ''
|
|
|
|
# from enum import Enum
|
|
|
|
#
|
|
|
|
# class Test(Enum):
|
|
|
|
# a = "success"
|
|
|
|
#
|
|
|
|
# print Test.a
|
|
|
|
# ''
|
|
|
|
writePython2 = name: { libraries ? [], flakeIgnore ? [] }:
|
|
|
|
let
|
|
|
|
py = pkgs.python2.withPackages (ps: libraries);
|
|
|
|
ignoreAttribute = optionalString (flakeIgnore != []) "--ignore ${concatMapStringsSep "," escapeShellArg flakeIgnore}";
|
|
|
|
in
|
|
|
|
makeScriptWriter {
|
|
|
|
interpreter = "${py}/bin/python";
|
|
|
|
check = writeDash "python2check.sh" ''
|
|
|
|
exec ${pkgs.python2Packages.flake8}/bin/flake8 --show-source ${ignoreAttribute} "$1"
|
|
|
|
'';
|
|
|
|
} name;
|
|
|
|
|
|
|
|
# writePython2Bin takes the same arguments as writePython2 but outputs a directory (like writeScriptBin)
|
|
|
|
writePython2Bin = name:
|
|
|
|
writePython2 "/bin/${name}";
|
|
|
|
|
|
|
|
# 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'])
|
|
|
|
# ''
|
|
|
|
writePython3 = name: { libraries ? [], flakeIgnore ? [] }:
|
|
|
|
let
|
|
|
|
py = pkgs.python3.withPackages (ps: libraries);
|
|
|
|
ignoreAttribute = optionalString (flakeIgnore != []) "--ignore ${concatMapStringsSep "," escapeShellArg flakeIgnore}";
|
|
|
|
in
|
|
|
|
makeScriptWriter {
|
|
|
|
interpreter = "${py}/bin/python";
|
|
|
|
check = writeDash "python3check.sh" ''
|
|
|
|
exec ${pkgs.python3Packages.flake8}/bin/flake8 --show-source ${ignoreAttribute} "$1"
|
|
|
|
'';
|
|
|
|
} name;
|
|
|
|
|
|
|
|
# writePython3Bin takes the same arguments as writePython3 but outputs a directory (like writeScriptBin)
|
|
|
|
writePython3Bin = name:
|
|
|
|
writePython3 "/bin/${name}";
|
|
|
|
}
|