about summary refs log tree commit diff
path: root/nixpkgs/pkgs/build-support/writers
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2019-01-07 02:18:36 +0000
committerAlyssa Ross <hi@alyssa.is>2019-01-07 02:18:47 +0000
commit36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2 (patch)
treeb3faaf573407b32aa645237a4d16b82778a39a92 /nixpkgs/pkgs/build-support/writers
parent4e31070265257dc67d120c27e0f75c2344fdfa9a (diff)
parentabf060725d7614bd3b9f96764262dfbc2f9c2199 (diff)
downloadnixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.gz
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.bz2
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.lz
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.xz
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.zst
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.zip
Add 'nixpkgs/' from commit 'abf060725d7614bd3b9f96764262dfbc2f9c2199'
git-subtree-dir: nixpkgs
git-subtree-mainline: 4e31070265257dc67d120c27e0f75c2344fdfa9a
git-subtree-split: abf060725d7614bd3b9f96764262dfbc2f9c2199
Diffstat (limited to 'nixpkgs/pkgs/build-support/writers')
-rw-r--r--nixpkgs/pkgs/build-support/writers/default.nix262
-rw-r--r--nixpkgs/pkgs/build-support/writers/test.nix168
2 files changed, 430 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/build-support/writers/default.nix b/nixpkgs/pkgs/build-support/writers/default.nix
new file mode 100644
index 000000000000..ef520f68320a
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/writers/default.nix
@@ -0,0 +1,262 @@
+{ 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 ? "" }: 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 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}
+      ''}
+    '';
+
+  # 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 ? [] }:
+    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;
+
+  # writeCBin takes the same arguments as writeC but outputs a directory (like writeScriptBin)
+  writeCBin = name:
+    writeC "/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
+  }:
+    makeBinWriter {
+      compileScript = ''
+        cp $contentPath tmp.hs
+        ${ghc.withPackages (_: libraries )}/bin/ghc tmp.hs
+        mv tmp $out
+      '';
+    } name;
+
+  # writeHaskellBin takes the same arguments as writeHaskell but outputs a directory (like writeScriptBin)
+  writeHaskellBin = name:
+    writeHaskell "/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 ? [] }: 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 ${pkgs.nodejs}/bin/node ${pkgs.writeText "js" content}
+  '';
+
+  # 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/nixpkgs/pkgs/build-support/writers/test.nix b/nixpkgs/pkgs/build-support/writers/test.nix
new file mode 100644
index 000000000000..80e9543f9c85
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/writers/test.nix
@@ -0,0 +1,168 @@
+{ stdenv, lib, runCommand, haskellPackages, nodePackages, perlPackages, python2Packages, python3Packages, writers, writeText }:
+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'])
+    '';
+  };
+
+
+  path = {
+    bash = writeBash "test_bash" (writeText "test" ''
+      if [[ "test" == "test" ]]; then echo "success"; fi
+    '');
+    haskell = writeHaskell "test_haskell" { libraries = [ haskellPackages.acme-default ]; } (writeText "test" ''
+      import Data.Default
+
+      int :: Int
+      int = def
+
+      main :: IO ()
+      main = case int of
+        18871 -> putStrLn $ id "success"
+        _ -> print "fail"
+    '');
+  };
+
+  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)}
+  ${lib.concatMapStringsSep "\n" (test: writeTest "success" "${test}") (lib.attrValues path)}
+
+  echo 'nix-writers successfully tested' >&2
+  touch $out
+''
+