aboutsummaryrefslogtreecommitdiff
path: root/pkgs
diff options
context:
space:
mode:
authorJörg Thalheim <Mic92@users.noreply.github.com>2018-11-27 07:17:03 +0000
committerGitHub <noreply@github.com>2018-11-27 07:17:03 +0000
commitf12bd000b9a7f72965c726012fd0d6cca6d4c629 (patch)
treead6b4382a7e6ff499c190a141cbf24f95c432c0d /pkgs
parent134e0dde366e39bfc21d887208281ffb5c55c2fe (diff)
parent2d02cd7790a2f12227e715800c8fe524de04f196 (diff)
Merge pull request #49290 from krebs/nix-writers
get nix-writers into nixpkgs
Diffstat (limited to 'pkgs')
-rw-r--r--pkgs/build-support/writers/default.nix239
-rw-r--r--pkgs/build-support/writers/test.nix149
-rw-r--r--pkgs/test/default.nix2
-rw-r--r--pkgs/top-level/all-packages.nix2
4 files changed, 392 insertions, 0 deletions
diff --git a/pkgs/build-support/writers/default.nix b/pkgs/build-support/writers/default.nix
new file mode 100644
index 000000000000..8aa3e52f5e8b
--- /dev/null
+++ b/pkgs/build-support/writers/default.nix
@@ -0,0 +1,239 @@
+{ 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"
+ makeScriptWriter = { interpreter, check ? "" }: name: text:
+ assert lib.or (types.path.check name) (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" name != null);
+
+ pkgs.writeTextFile {
+ name = last (builtins.split "/" name);
+ executable = true;
+ destination = if types.path.check name then name else "";
+ text = ''
+ #! ${interpreter}
+ ${text}
+ '';
+ checkPhase = check;
+ };
+
+ # 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;
+ # }
+ # ''
+ writeC = name: {
+ libraries ? [],
+ }: text: pkgs.runCommand name {
+ inherit text;
+ buildInputs = [ pkgs.pkgconfig ] ++ libraries;
+ passAsFile = [ "text" ];
+ } ''
+ PATH=${makeBinPath [
+ pkgs.binutils-unwrapped
+ pkgs.coreutils
+ pkgs.gcc
+ pkgs.pkgconfig
+ ]}
+ mkdir -p "$(dirname "$out")"
+ gcc \
+ ${optionalString (libraries != [])
+ "$(pkg-config --cflags --libs ${
+ concatMapStringsSep " " (lib: escapeShellArg (builtins.parseDrvName lib.name).name) (libraries)
+ })"
+ } \
+ -O \
+ -o "$out" \
+ -Wall \
+ -x c \
+ "$textPath"
+ strip --strip-unneeded "$out"
+ '';
+
+ # writeCBin takes the same arguments as writeC but outputs a directory (like writeScriptBin)
+ writeCBin = name: spec: text:
+ pkgs.runCommand name {
+ } ''
+ mkdir -p $out/bin
+ ln -s ${writeC name spec text} $out/bin/${name}
+ '';
+
+ # 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 ]; } ''
+ # Import Acme.Missiles
+ #
+ # main = launchMissiles
+ # '';
+ writeHaskell = name: {
+ libraries ? [],
+ ghc ? pkgs.ghc
+ }: text: pkgs.runCommand name {
+ inherit text;
+ passAsFile = [ "text" ];
+ } ''
+ cp $textPath ${name}.hs
+ ${ghc.withPackages (_: libraries )}/bin/ghc ${name}.hs
+ cp ${name} $out
+ '';
+
+ # writeHaskellBin takes the same arguments as writeHaskell but outputs a directory (like writeScriptBin)
+ writeHaskellBin = name: spec: text:
+ pkgs.runCommand name {
+ } ''
+ mkdir -p $out/bin
+ ln -s ${writeHaskell name spec text} $out/bin/${name}
+ '';
+
+ # 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);
+ # ''
+ writeJS = name: { libraries ? [] }: text:
+ 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 ${pkgs.nodejs}/bin/node ${pkgs.writeText "js" text}
+ '';
+
+ # 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}";
+}
diff --git a/pkgs/build-support/writers/test.nix b/pkgs/build-support/writers/test.nix
new file mode 100644
index 000000000000..68b7b27e6130
--- /dev/null
+++ b/pkgs/build-support/writers/test.nix
@@ -0,0 +1,149 @@
+{ stdenv, lib, runCommand, haskellPackages, nodePackages, perlPackages, python2Packages, python3Packages, writers}:
+with writers;
+let
+
+ bin = {
+ bash = writeBashBin "test_writers" ''
+ if [[ "test" == "test" ]]; then echo "success"; fi
+ '';
+
+ c = writeCBin "test_writers" { libraries = [ ]; } ''
+ #include <stdio.h>
+ int main() {
+ printf("success\n");
+ return 0;
+ }
+ '';
+
+ dash = writeDashBin "test_writers" ''
+ test '~' = '~' && echo 'success'
+ '';
+
+ haskell = writeHaskellBin "test_writers" { libraries = [ haskellPackages.acme-default ]; } ''
+ import Data.Default
+
+ int :: Int
+ int = def
+
+ main :: IO ()
+ main = case int of
+ 18871 -> putStrLn $ id "success"
+ _ -> print "fail"
+ '';
+
+ js = writeJSBin "test_writers" { libraries = [ nodePackages.semver ]; } ''
+ var semver = require('semver');
+
+ if (semver.valid('1.2.3')) {
+ console.log('success')
+ } else {
+ console.log('fail')
+ }
+ '';
+
+ perl = writePerlBin "test_writers" { libraries = [ perlPackages.boolean ]; } ''
+ use boolean;
+ print "success\n" if true;
+ '';
+
+ python2 = writePython2Bin "test_writers" { libraries = [ python2Packages.enum ]; } ''
+ from enum import Enum
+
+ class Test(Enum):
+ a = "success"
+
+ print Test.a
+ '';
+
+ python3 = writePython3Bin "test_writers" { libraries = [ python3Packages.pyyaml ]; } ''
+ import yaml
+
+ y = yaml.load("""
+ - test: success
+ """)
+ print(y[0]['test'])
+ '';
+ };
+
+ simple = {
+ bash = writeBash "test_bash" ''
+ if [[ "test" == "test" ]]; then echo "success"; fi
+ '';
+
+ c = writeC "test_c" { libraries = [ ]; } ''
+ #include <stdio.h>
+ int main() {
+ printf("success\n");
+ return 0;
+ }
+ '';
+
+ dash = writeDash "test_dash" ''
+ test '~' = '~' && echo 'success'
+ '';
+
+ haskell = writeHaskell "test_haskell" { libraries = [ haskellPackages.acme-default ]; } ''
+ import Data.Default
+
+ int :: Int
+ int = def
+
+ main :: IO ()
+ main = case int of
+ 18871 -> putStrLn $ id "success"
+ _ -> print "fail"
+ '';
+
+ js = writeJS "test_js" { libraries = [ nodePackages.semver ]; } ''
+ var semver = require('semver');
+
+ if (semver.valid('1.2.3')) {
+ console.log('success')
+ } else {
+ console.log('fail')
+ }
+ '';
+
+ perl = writePerl "test_perl" { libraries = [ perlPackages.boolean ]; } ''
+ use boolean;
+ print "success\n" if true;
+ '';
+
+ python2 = writePython2 "test_python2" { libraries = [ python2Packages.enum ]; } ''
+ from enum import Enum
+
+ class Test(Enum):
+ a = "success"
+
+ print Test.a
+ '';
+
+ python3 = writePython3 "test_python3" { libraries = [ python3Packages.pyyaml ]; } ''
+ import yaml
+
+ y = yaml.load("""
+ - test: success
+ """)
+ print(y[0]['test'])
+ '';
+ };
+
+ writeTest = expectedValue: test:
+ writeDash "test-writers" ''
+ if test "$(${test})" != "${expectedValue}"; then
+ echo 'test ${test} failed'
+ exit 1
+ fi
+ '';
+
+in runCommand "test-writers" {
+ passthru = { inherit writeTest bin simple; };
+ meta.platforms = stdenv.lib.platforms.all;
+} ''
+ ${lib.concatMapStringsSep "\n" (test: writeTest "success" "${test}/bin/test_writers") (lib.attrValues bin)}
+ ${lib.concatMapStringsSep "\n" (test: writeTest "success" "${test}") (lib.attrValues simple)}
+
+ echo 'nix-writers successfully tested' >&2
+ touch $out
+''
+
diff --git a/pkgs/test/default.nix b/pkgs/test/default.nix
index 9315595f8eca..809b2d0b553c 100644
--- a/pkgs/test/default.nix
+++ b/pkgs/test/default.nix
@@ -33,4 +33,6 @@ with pkgs;
nixos-functions = callPackage ./nixos-functions {};
patch-shebangs = callPackage ./patch-shebangs {};
+
+ writers = callPackage ../build-support/writers/test.nix {};
}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 80e7f5fbc237..00b1a7c0542d 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -420,6 +420,8 @@ with pkgs;
iconConvTools = callPackage ../build-support/icon-conv-tools {};
+ #package writers
+ writers = callPackage ../build-support/writers {};
### TOOLS