├── README.md ├── commands ├── compress-man │ ├── compress-man.sh │ └── default.nix └── patch-shebangs │ ├── default.nix │ └── patch-shebangs.sh ├── perl ├── builder.sh ├── default.nix └── setup-perl.sh ├── stdenv ├── builder.sh ├── default.nix ├── generic-build │ ├── builder.sh │ ├── default.nix │ └── setup.sh ├── make-derivation │ ├── builder.sh │ ├── default.nix │ └── setup.sh ├── run-command │ ├── builder.sh │ ├── default.nix │ └── setup.sh ├── run-phases │ ├── builder.sh │ ├── default.nix │ └── setup.sh └── simple-derivation │ ├── default.nix │ └── setup.sh ├── tests ├── generic-build │ ├── CVE-2016-2037-out-of-bounds-write.patch │ ├── all-packages.nix │ ├── bzip2-wrapper │ │ ├── default.nix │ │ └── setup-hook.sh │ ├── cpio.nix │ ├── gcc-wrapper.nix │ ├── gnuhello.nix │ ├── gzip-wrapper │ │ ├── default.nix │ │ └── setup-hook.sh │ ├── hello.nix │ └── tar-wrapper │ │ ├── default.nix │ │ └── setup-hook.sh ├── make-derivation │ ├── all-packages.nix │ ├── bzip2.nix │ ├── file.nix │ ├── gcc-wrapper │ │ ├── default.nix │ │ └── setup-hook.sh │ ├── gnuhello.nix │ ├── tar-wrapper │ │ ├── default.nix │ │ └── setup-hook.sh │ ├── zlib-wrapper.nix │ └── zlib.nix ├── perl │ ├── all-packages.nix │ ├── perl-wrapper │ │ ├── default.nix │ │ └── setup-hook.sh │ └── xmlparser.nix ├── raw │ ├── test1 │ │ ├── default.nix │ │ └── test.sh │ └── test2 │ │ ├── default.nix │ │ └── test.sh ├── run-command │ ├── all-packages.nix │ ├── compress-raw-zlib.nix │ ├── gcc-wrapper.nix │ ├── gnuhello.nix │ ├── hello.nix │ └── perl-wrapper.nix ├── run-phases │ ├── all-packages.nix │ ├── fail.nix │ ├── hello.nix │ └── hello2 │ │ ├── builder.sh │ │ └── default.nix ├── setup-script │ ├── all-packages.nix │ ├── fetchurl.nix │ ├── gnuhello │ │ ├── builder.sh │ │ └── default.nix │ └── hello │ │ ├── builder.sh │ │ └── default.nix ├── simple-derivation │ ├── all-packages.nix │ ├── gnuhello │ │ ├── builder.sh │ │ └── default.nix │ └── hello │ │ ├── builder.sh │ │ └── default.nix └── write-text │ └── all-packages.nix └── write-text-file └── default.nix /README.md: -------------------------------------------------------------------------------- 1 | nix-lowlevel-experiments 2 | ======================== 3 | This repository contains a collection of low level Nix experiments in which 4 | various concepts of the [Nix package manager](http://nixos.org/nix) and the 5 | [NixOS](http://nixos.org/nix) Linux distribution are explored, as well as other 6 | related low-level system concepts. 7 | 8 | Currently, it only contains an implementation of the generic builder 9 | infrastructure that is similar to the version in Nixpkgs, but built in a 10 | different way. 11 | 12 | Prerequisites 13 | ============= 14 | * [The Nix package manager](http://nixos.org/nix) 15 | * [Nixpkgs](http://nixos.org/nixpkgs) 16 | 17 | The generic builder 18 | =================== 19 | This repository contains a generic builder implementation that consists of 20 | various abstraction layers -- it starts with a setup script that can be provided 21 | as a dependency to a raw `derivation {}` invocation and ends with a function 22 | abstraction that is comparable in features to the `stdenv.mkDerivation` function 23 | in Nixpkgs. 24 | 25 | Layer 1: setup script 26 | --------------------- 27 | Layer 1 is a simple setup script that can be used in a "raw" derivation to add 28 | some basic dependencies to the build environment so that basic shell tasks can 29 | be executed: 30 | 31 | ```nix 32 | {stdenv}: 33 | 34 | derivation { 35 | name = "hello"; 36 | inherit stdenv; 37 | builder = ./builder.sh; 38 | system = "x86_64-linux"; 39 | } 40 | ``` 41 | 42 | By adding stdenv as a parameter, we can execute the following builder script: 43 | 44 | ```bash 45 | #!/bin/sh -e 46 | source $stdenv/setup 47 | 48 | mkdir -p $out/bin 49 | 50 | cat > $out/bin/hello < hello <` or 201 | `post` hook. 202 | 203 | We can also define an `exitHook` to execute code when a build completes 204 | successfully or a `failureHook` to execute code when the build fails. 205 | 206 | Layer 5: The generic build abstraction 207 | -------------------------------------- 208 | The `stdenv.genericBuild` abstraction adds implementations for common build 209 | steps, such as a `unpack` phase that generically unpacks sources, a 210 | `patchShebangs` phase that fixes all shebang lines to correspond to Nix store 211 | paths, and a `strip` phase that strips debugging symbols. 212 | 213 | We can build GNU Hello with by writing fewer lines of code: 214 | 215 | ```nix 216 | {stdenv, fetchurl, gnumake, gnutar, gzip, gcc, binutils}: 217 | 218 | stdenv.genericBuild { 219 | name = "hello-2.10"; 220 | src = fetchurl { 221 | url = mirror://gnu/hello/hello-2.10.tar.gz; 222 | sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"; 223 | }; 224 | buildInputs = [ gnumake gnutar gzip gcc binutils ]; 225 | buildCommandPhase = '' 226 | ./configure --prefix=$out 227 | make 228 | make install 229 | ''; 230 | } 231 | ``` 232 | 233 | Compared to the previous example, we no longer have to specify how to unpack 234 | the sources or open the source directory. 235 | 236 | Layer 6: GNU Make/GNU Autotools abstraction 237 | ------------------------------------------- 238 | The `stdenv.mkDerivation` abstraction extends the previous function abstraction 239 | with a `configure`, `build`, `check` and `install` phase that carry out steps 240 | to build GNU Make/GNU Autotools projects. It also provides all base dependencies 241 | that you need to build such projects. 242 | 243 | We can build GNU Hello with this abstraction function with only a few lines of 244 | code: 245 | 246 | ```nix 247 | {stdenv, fetchurl}: 248 | 249 | stdenv.mkDerivation { 250 | name = "hello-2.10"; 251 | src = fetchurl { 252 | url = mirror://gnu/hello/hello-2.10.tar.gz; 253 | sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"; 254 | }; 255 | } 256 | ``` 257 | 258 | Test abstraction functions 259 | ========================== 260 | There are two example abstraction functions built around the functions that the 261 | generic builder provides. `writeTextFile` is a function that can be used to 262 | generate text files and `buildPerlPackage` is a function abstraction that builds 263 | Perl modules. 264 | 265 | Test cases 266 | ========== 267 | The `tests` directory contains test package sets for each abstraction layer. 268 | To run them, inspect the `all-packages.nix` file, and evaluate a desired 269 | attribute, such as: 270 | 271 | ```bash 272 | $ nix-build all-packages.nix -A gnuhello 273 | ``` 274 | 275 | License 276 | ======= 277 | The contents of this package is available under the same license as Nixpkgs -- 278 | the [MIT](https://opensource.org/licenses/MIT) license. 279 | -------------------------------------------------------------------------------- /commands/compress-man/compress-man.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [ "$1" = "" ] 4 | then 5 | echo "Usage: $0 DIRECTORY" 6 | exit 1 7 | fi 8 | 9 | dir="$1" 10 | 11 | if [ -L "$dir"/share ] || [ -L "$dir"/share/man ] || [ ! -d "$dir/share/man" ] 12 | then 13 | exit 14 | fi 15 | 16 | echo "gzipping man pages under $dir/share/man/" 17 | 18 | # Compress all uncompressed manpages. Don't follow symlinks, etc. 19 | find "$dir"/share/man/ -type f -a '!' -regex '.*\.\(bz2\|gz\)$' -print0 \ 20 | | while IFS= read -r -d $'\0' f 21 | do 22 | if gzip -c -n "$f" > "$f".gz 23 | then 24 | rm "$f" 25 | else 26 | rm "$f".gz 27 | fi 28 | done 29 | 30 | # Point symlinks to compressed manpages. 31 | find "$dir"/share/man/ -type l -a '!' -regex '.*\.\(bz2\|gz\)$' -print0 \ 32 | | while IFS= read -r -d $'\0' f 33 | do 34 | target="$(readlink -f "$f")" 35 | if [ -f "$target".gz ] 36 | then 37 | ln -sf "$target".gz "$f".gz && rm "$f" 38 | fi 39 | done 40 | -------------------------------------------------------------------------------- /commands/compress-man/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv}: 2 | 3 | stdenv.runCommand { 4 | name = "compress-man"; 5 | buildCommand = '' 6 | mkdir -p $out/bin 7 | sed -e "s|/bin/bash|$SHELL|" ${./compress-man.sh} > $out/bin/compress-man 8 | chmod +x $out/bin/compress-man 9 | ''; 10 | } 11 | -------------------------------------------------------------------------------- /commands/patch-shebangs/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv}: 2 | 3 | stdenv.runCommand { 4 | name = "patch-shebangs"; 5 | buildCommand = '' 6 | mkdir -p $out/bin 7 | sed -e "s|/bin/bash|$SHELL|" ${./patch-shebangs.sh} > $out/bin/patch-shebangs 8 | chmod +x $out/bin/patch-shebangs 9 | ''; 10 | } 11 | -------------------------------------------------------------------------------- /commands/patch-shebangs/patch-shebangs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | patchShebang() 4 | { 5 | local f="$1" 6 | local oldPath 7 | local newPath 8 | local arg0 9 | local args 10 | local oldInterpreterLine 11 | local newInterpreterLine 12 | 13 | if [ "$(head -1 "$f" | head -c+2)" != '#!' ]; then 14 | # missing shebang => not a script 15 | continue 16 | fi 17 | 18 | oldInterpreterLine=$(head -1 "$f" | tail -c+3) 19 | read -r oldPath arg0 args <<< "$oldInterpreterLine" 20 | 21 | if $(echo "$oldPath" | grep -q "/bin/env$"); then 22 | # Check for unsupported 'env' functionality: 23 | # - options: something starting with a '-' 24 | # - environment variables: foo=bar 25 | if $(echo "$arg0" | grep -q -- "^-.*\|.*=.*"); then 26 | echo "unsupported interpreter directive \"$oldInterpreterLine\" (set dontPatchShebangs=1 and handle shebang patching yourself)" 27 | exit 1 28 | fi 29 | newPath="$(command -v "$arg0" || true)" 30 | else 31 | if [ "$oldPath" = "" ]; then 32 | # If no interpreter is specified linux will use /bin/sh. Set 33 | # oldpath="/bin/sh" so that we get /nix/store/.../sh. 34 | oldPath="/bin/sh" 35 | fi 36 | newPath="$(command -v "$(basename "$oldPath")" || true)" 37 | args="$arg0 $args" 38 | fi 39 | 40 | # Strip trailing whitespace introduced when no arguments are present 41 | newInterpreterLine="$(echo "$newPath $args" | sed 's/[[:space:]]*$//')" 42 | 43 | if [ -n "$oldPath" -a "${oldPath:0:${#NIX_STORE}}" != "$NIX_STORE" ]; then 44 | if [ -n "$newPath" -a "$newPath" != "$oldPath" ]; then 45 | echo "$f: interpreter directive changed from \"$oldInterpreterLine\" to \"$newInterpreterLine\"" 46 | # escape the escape chars so that sed doesn't interpret them 47 | escapedInterpreterLine=$(echo "$newInterpreterLine" | sed 's|\\|\\\\|g') 48 | # Preserve times, see: https://github.com/NixOS/nixpkgs/pull/33281 49 | touch -r "$f" "$f.timestamp" 50 | sed -i -e "1 s|.*|#\!$escapedInterpreterLine|" "$f" 51 | touch -r "$f.timestamp" "$f" 52 | rm "$f.timestamp" 53 | fi 54 | fi 55 | } 56 | 57 | target="$1" 58 | 59 | if [ "$target" = "" ] 60 | then 61 | echo "No target provided!" 62 | exit 1 63 | elif [ -f "$target" ] 64 | then 65 | patchShebang "$target" 66 | elif [ -d "$target" ] 67 | then 68 | echo "patching script interpreter paths in $target" 69 | 70 | find "$target" -type f -perm -0100 | while read f; do 71 | patchShebang "$f" 72 | done 73 | fi 74 | -------------------------------------------------------------------------------- /perl/builder.sh: -------------------------------------------------------------------------------- 1 | source $setupPerl 2 | genericBuild 3 | -------------------------------------------------------------------------------- /perl/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv, perl}: 2 | {name, buildInputs ? [], ...}@args: 3 | 4 | let 5 | extraArgs = removeAttrs args [ "name" "buildInputs" ]; 6 | in 7 | stdenv.mkDerivation ({ 8 | name = "perl-${name}"; 9 | buildInputs = [ perl ] ++ buildInputs; 10 | builder = ./builder.sh; 11 | setupPerl = ./setup-perl.sh; 12 | } // extraArgs) 13 | -------------------------------------------------------------------------------- /perl/setup-perl.sh: -------------------------------------------------------------------------------- 1 | source $setupMakeDerivation 2 | 3 | configurePhase() 4 | { 5 | perl Makefile.PL PREFIX=$out INSTALLDIRS=site $makeMakerFlags 6 | } 7 | 8 | checkPhase() 9 | { 10 | if checkForMakefile 11 | then 12 | make SHELL=$SHELL $checkFlags $makeFlags test 13 | else 14 | echo "No makefile found" 15 | fi 16 | } 17 | 18 | propagateDependencies() 19 | { 20 | # If a user installs a Perl package, she probably also wants its 21 | # dependencies in the user environment (since Perl modules don't 22 | # have something like an RPATH, so the only way to find the 23 | # dependencies is to have them in the PERL5LIB variable). 24 | if [ -f $out/nix-support/propagated-build-inputs ] 25 | then 26 | ln -s $out/nix-support/propagated-build-inputs $out/nix-support/propagated-user-env-packages 27 | fi 28 | } 29 | 30 | phases="$preBuildPhases $buildPhases propagateDependencies $postBuildPhases" 31 | -------------------------------------------------------------------------------- /stdenv/builder.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | # Setup PATH for base packages 4 | for i in $basePackages 5 | do 6 | basePackagesPath="$basePackagesPath${basePackagesPath:+:}$i/bin" 7 | done 8 | 9 | export PATH="$basePackagesPath" 10 | 11 | # Create setup script 12 | mkdir $out 13 | cat > $out/setup < $out/nix-support/propagated-user-env-packages 22 | -------------------------------------------------------------------------------- /stdenv/default.nix: -------------------------------------------------------------------------------- 1 | {bash, basePackages, genericBuildPackages ? [], buildPackages ? [], system, __noChroot ? false}: 2 | 3 | let 4 | shell = "${bash}/bin/sh"; 5 | 6 | # Layer 1: stdenv package + basic configuration properties + setup script 7 | stdenvProperties = derivation { 8 | name = "stdenv"; 9 | inherit shell basePackages system __noChroot; 10 | builder = shell; 11 | args = [ "-e" ./builder.sh ]; 12 | }; 13 | 14 | stdenv = stdenvProperties // { 15 | # Layer 2: extra environment variables for purity, bash as builder, system set 16 | simpleDerivation = import ./simple-derivation { 17 | inherit stdenv __noChroot; 18 | inherit (stdenv) system shell; 19 | }; 20 | 21 | # Layer 3: run commands as string parameter + buildInputs and propagated buildInputs 22 | runCommand = import ./run-command { 23 | inherit stdenv; 24 | inherit (stdenv) system shell; 25 | }; 26 | 27 | # Layer 4: run phases with pre and post hooks + exit hook and failure hook 28 | runPhases = import ./run-phases { 29 | inherit (stdenv) runCommand; 30 | }; 31 | 32 | # Layer 5: unpack, patch, build command, strip, patch shebang 33 | genericBuild = import ./generic-build { 34 | inherit (stdenv) runPhases; 35 | inherit genericBuildPackages; 36 | }; 37 | 38 | # Layer 6: GNU Autotools/GNU Make support 39 | mkDerivation = import ./make-derivation { 40 | inherit (stdenv) genericBuild; 41 | inherit buildPackages; 42 | }; 43 | }; 44 | in 45 | stdenv 46 | -------------------------------------------------------------------------------- /stdenv/generic-build/builder.sh: -------------------------------------------------------------------------------- 1 | source $setupGenericBuild 2 | genericBuild 3 | -------------------------------------------------------------------------------- /stdenv/generic-build/default.nix: -------------------------------------------------------------------------------- 1 | {runPhases, genericBuildPackages}: 2 | {buildInputs ? [], ...}@args: 3 | 4 | let 5 | extraArgs = removeAttrs args [ "buildInputs" ]; 6 | in 7 | runPhases ({ 8 | setupGenericBuild = ./setup.sh; 9 | builder = ./builder.sh; 10 | buildInputs = genericBuildPackages ++ buildInputs; 11 | } // extraArgs) 12 | -------------------------------------------------------------------------------- /stdenv/generic-build/setup.sh: -------------------------------------------------------------------------------- 1 | source $setupRunPhases 2 | 3 | # Unpacks a specified file by determining what file type it is and by invoking 4 | # the appropriate unpack hook. 5 | 6 | unpackFile() 7 | { 8 | local src="$1" 9 | local hasUnpacked=0 10 | 11 | if [ -f "$src" ] 12 | then 13 | for unpackHook in ${unpackHooks[@]} 14 | do 15 | $unpackHook $src && hasUnpacked=1 16 | done 17 | elif [ -d "$src" ] 18 | then 19 | cp -a "$src" . && hasUnpacked=1 20 | fi 21 | 22 | if [ "$hasUnpacked" = "0" ] 23 | then 24 | echo "Don't know how to unpack: $src" 25 | exit 1 26 | fi 27 | } 28 | 29 | # Executes the unpack phase. It unpacks all provided sources, makes them 30 | # writable and then attempts to enter the source root directory. 31 | 32 | unpackPhase() 33 | { 34 | if [ -z "$srcs" ] && [ -n "$src" ] 35 | then 36 | srcs="$src" 37 | fi 38 | 39 | # Check the directory structure before unpacking 40 | local dirsBefore="" 41 | for i in * 42 | do 43 | if [ -d "$i" ] 44 | then 45 | dirsBefore="$dirsBefore $i " 46 | fi 47 | done 48 | 49 | # Unpack all sources 50 | for src in $srcs 51 | do 52 | unpackFile "$src" 53 | done 54 | 55 | # Attempt to determine the source root directory 56 | if [ -z "$sourceRoot" ] 57 | then 58 | # When no source root has been specified, compare the current directory 59 | # content with the last recorded directory contents 60 | for i in * 61 | do 62 | if [ -d "$i" ] 63 | then 64 | case $dirsBefore in 65 | *\ $i\ *) 66 | ;; 67 | *) 68 | if [ -n "$sourceRoot" ] 69 | then 70 | echo "unpacker produced multiple directories" 71 | exit 1 72 | fi 73 | sourceRoot="$i" 74 | ;; 75 | esac 76 | fi 77 | done 78 | 79 | if [ -z "$sourceRoot" ] 80 | then 81 | echo "unpack did not produce a directory" 82 | exit 1 83 | fi 84 | fi 85 | 86 | echo "source root is $sourceRoot" 87 | 88 | # Restore write permissions 89 | if [ "${dontMakeSourcesWritable:-0}" != 1 ] 90 | then 91 | chmod -R u+w -- "$sourceRoot" 92 | fi 93 | 94 | # Open the source root 95 | cd "$sourceRoot" 96 | } 97 | 98 | # Uncompresses a file by looking at the file type and invoking the appropriate 99 | # uncompress hook. 100 | 101 | uncompressFile() 102 | { 103 | local src="$1" 104 | local hasUncompressed=0 105 | 106 | for uncompressHook in ${uncompressHooks[@]} 107 | do 108 | $uncompressHook "$src" && hasUncompressed=1 109 | done 110 | 111 | if [ "$hasUncompressed" = "0" ] 112 | then 113 | cat "$src" 114 | fi 115 | } 116 | 117 | # Executes the patch phase by uncompression the patch files and applying them. 118 | 119 | patchPhase() 120 | { 121 | for i in $patches 122 | do 123 | echo "applying patch $i" 124 | uncompressFile "$i" 2>&1 | patch ${patchFlags:--p1} 125 | done 126 | } 127 | 128 | # Executes the strip phase that processes all binary directories and strips 129 | # debugging symbols from them 130 | 131 | stripPhase() 132 | { 133 | for target in ${outputs:-out} 134 | do 135 | cd ${!target} 136 | stripDebugList=${stripDebugList:-lib lib32 lib64 bin} 137 | 138 | for dir in $stripDebugList 139 | do 140 | if [ -d "$dir" ] 141 | then 142 | find $dir -type f -name \*.so -or -name \*.so.\* | while read i 143 | do 144 | strip --strip-debug "$i" 145 | done 146 | fi 147 | done 148 | done 149 | } 150 | 151 | # Executes a phase that patches shebang lines of all executables to Nix store 152 | # paths 153 | 154 | patchShebangsPhase() 155 | { 156 | for target in ${outputs:-out} 157 | do 158 | patch-shebangs ${!target}/bin 159 | done 160 | } 161 | 162 | # Executes a phases that compress all manual pages 163 | 164 | compressManPagesPhase() 165 | { 166 | for target in ${outputs:-out} 167 | do 168 | compress-man "${!target}" 169 | done 170 | } 171 | 172 | preBuildPhases="unpack patch" 173 | postBuildPhases="strip patchShebangs compressManPages" 174 | 175 | phases="$preBuildPhases buildCommand $postBuildPhases" 176 | -------------------------------------------------------------------------------- /stdenv/make-derivation/builder.sh: -------------------------------------------------------------------------------- 1 | source $setupMakeDerivation 2 | genericBuild 3 | -------------------------------------------------------------------------------- /stdenv/make-derivation/default.nix: -------------------------------------------------------------------------------- 1 | {genericBuild, buildPackages}: 2 | {buildInputs ? [], ...}@args: 3 | 4 | let 5 | extraArgs = removeAttrs args [ "buildInputs" ]; 6 | in 7 | genericBuild ({ 8 | setupMakeDerivation = ./setup.sh; 9 | builder = ./builder.sh; 10 | buildInputs = buildPackages ++ buildInputs; 11 | } // extraArgs) 12 | -------------------------------------------------------------------------------- /stdenv/make-derivation/setup.sh: -------------------------------------------------------------------------------- 1 | source $setupGenericBuild 2 | 3 | configurePhase() 4 | { 5 | configureScript=${configureScript:-./configure} 6 | 7 | if [ -x "$configureScript" ] 8 | then 9 | if [ "$dontAddPrefix" != "1" ] 10 | then 11 | configureFlags="--prefix=$out $configureFlags" 12 | fi 13 | 14 | # Add flags for multiple output dirs 15 | if [[ "$outputs" = *"bin"* ]] 16 | then 17 | configureFlags="--bindir=$bin/bin $configureFlags" 18 | fi 19 | 20 | if [[ "$outputs" = *"lib"* ]] 21 | then 22 | configureFlags="--libdir=$lib/lib $configureFlags" 23 | fi 24 | 25 | if [[ "$outputs" = *"man"* ]] 26 | then 27 | configureFlags="--mandir=$man/share/man $configureFlags" 28 | fi 29 | 30 | if [[ "$outputs" = *"info"* ]] 31 | then 32 | configureFlags="--infodir=$man/share/info $configureFlags" 33 | fi 34 | 35 | if [[ "$outputs" = *"dev"* ]] 36 | then 37 | configureFlags="--includedir=$dev/include --oldincludedir=$dev/include $configureFlags" 38 | installFlags="pkgconfigdir=$dev/lib/pkgconfig m4datadir=$dev/share/aclocal aclocaldir=$dev/share/aclocal $installFlags" 39 | fi 40 | 41 | eval $configureScript $configureFlags 42 | else 43 | echo "No executable configure script found" 44 | fi 45 | } 46 | 47 | checkForMakefile() 48 | { 49 | [ -n "$makefile" ] && [ -f "$makefile" ] || [ -f Makefile ] || [ -f makefile ] || [ -f GNUmakefile ] 50 | } 51 | 52 | buildPhase() 53 | { 54 | if [ "$makefile" != "" ] 55 | then 56 | makeFlags="-f $makefile $makeFlags" 57 | fi 58 | 59 | if checkForMakefile 60 | then 61 | eval make SHELL=$SHELL $buildFlags $makeFlags 62 | else 63 | echo "No makefile found" 64 | fi 65 | } 66 | 67 | checkPhase() 68 | { 69 | if checkForMakefile 70 | then 71 | eval make SHELL=$SHELL $checkFlags $makeFlags check 72 | else 73 | echo "No makefile found" 74 | fi 75 | } 76 | 77 | installPhase() 78 | { 79 | if checkForMakefile 80 | then 81 | eval make SHELL=$SHELL $installFlags $makeFlags install 82 | else 83 | echo "No makefile found" 84 | fi 85 | } 86 | 87 | buildPhases="configure build check install" 88 | phases="$preBuildPhases $buildPhases $postBuildPhases" 89 | dontCheck=1 90 | -------------------------------------------------------------------------------- /stdenv/run-command/builder.sh: -------------------------------------------------------------------------------- 1 | source $setupRunCommand 2 | runCommand 3 | -------------------------------------------------------------------------------- /stdenv/run-command/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv, system, shell}: 2 | {builder ? ./builder.sh, ...}@args: 3 | 4 | let 5 | extraArgs = removeAttrs args [ "builder" "meta" ]; 6 | in 7 | stdenv.simpleDerivation ({ 8 | inherit builder; 9 | setupRunCommand = ./setup.sh; 10 | } // extraArgs) 11 | -------------------------------------------------------------------------------- /stdenv/run-command/setup.sh: -------------------------------------------------------------------------------- 1 | source $setupSimpleDerivation 2 | 3 | # Process buildInputs to allow processes to find their dependencies 4 | PATH_DELIMITER=':' 5 | 6 | envHooks=("addToPATH") 7 | 8 | # Executes all function in the envHooks array and propagates the package path to 9 | # each of them. This can be used to make a package available to the environment, 10 | # typically by modifying environment variables containing search paths (e.g. 11 | # PATH). 12 | 13 | addToEnv() 14 | { 15 | local pkg="$1" 16 | 17 | for hook in "${envHooks[@]}" 18 | do 19 | $hook "$pkg" 20 | done 21 | } 22 | 23 | addToSearchPathWithCustomDelimeter() 24 | { 25 | local delimiter="$1" 26 | local varName="$2" 27 | local dir="$3" 28 | 29 | if [ -d "$dir" ] 30 | then 31 | eval export $varName="$dir${!varName:+$delimiter}${!varName}" 32 | fi 33 | } 34 | 35 | addToSearchPath() 36 | { 37 | addToSearchPathWithCustomDelimeter "$PATH_DELIMITER" "$1" "$2" 38 | } 39 | 40 | addToPATH() 41 | { 42 | addToSearchPath PATH "$1/bin" 43 | } 44 | 45 | findInputs() 46 | { 47 | local inputs="$1" 48 | 49 | for input in $inputs 50 | do 51 | if [ -f "$input/nix-support/setup-hook" ] 52 | then 53 | source "$input/nix-support/setup-hook" 54 | fi 55 | done 56 | 57 | for input in $inputs 58 | do 59 | addToEnv "$input" 60 | done 61 | 62 | for input in $inputs 63 | do 64 | if [ -f "$input/nix-support/propagated-build-inputs" ] 65 | then 66 | findInputs "$(cat $input/nix-support/propagated-build-inputs)" 67 | fi 68 | done 69 | } 70 | 71 | runCommand() 72 | { 73 | findInputs "$buildInputs" 74 | findInputs "$propagatedBuildInputs" 75 | 76 | # Write propagated build inputs to config file 77 | 78 | if [ -n "$propagatedBuildInputs" ] 79 | then 80 | mkdir -p $out/nix-support 81 | echo "$propagatedBuildInputs" > $out/nix-support/propagated-build-inputs 82 | fi 83 | 84 | # Write setup hooks to config file 85 | 86 | if [ -n "$setupHook" ] 87 | then 88 | mkdir -p $out/nix-support 89 | cp $setupHook $out/nix-support/setup-hook 90 | fi 91 | 92 | # Execute build command, if defined 93 | if [ -n "$buildCommandPath" ] 94 | then 95 | source "$buildCommandPath" 96 | elif [ -n "$buildCommand" ] 97 | then 98 | eval "$buildCommand" 99 | fi 100 | } 101 | -------------------------------------------------------------------------------- /stdenv/run-phases/builder.sh: -------------------------------------------------------------------------------- 1 | source $setupRunPhases 2 | genericBuild 3 | -------------------------------------------------------------------------------- /stdenv/run-phases/default.nix: -------------------------------------------------------------------------------- 1 | {runCommand}: 2 | args: 3 | 4 | runCommand ({ 5 | setupRunPhases = ./setup.sh; 6 | builder = ./builder.sh; 7 | } // args) 8 | -------------------------------------------------------------------------------- /stdenv/run-phases/setup.sh: -------------------------------------------------------------------------------- 1 | source $setupRunCommand 2 | 3 | # Run a hook. A hook can be defined as function/alias/builtin, a file 4 | # representing a script or process, or a string containing shell code 5 | 6 | runHook() 7 | { 8 | local hookName=$1 9 | local hookType=$(type -t $hookName) 10 | 11 | if [ -z "${!hookName}" ] 12 | then 13 | case "$hookType" in 14 | function|alias|builtin) # hook is a function/alias/builtin 15 | $hookName 16 | ;; 17 | file) 18 | source $hookName # hook is a file/process 19 | ;; 20 | *) 21 | eval "${!hookName}" # hook is a string 22 | ;; 23 | esac 24 | else 25 | eval "${!hookName}" # hook is a string 26 | fi 27 | } 28 | 29 | # Execute a particular phase. Every phase has a pre and 30 | # post hook, that can be configured by the user. Every phase can be 31 | # disabled by setting the dont to true / 1. 32 | # Disabled phases can be reenabled again with do set to true / 1 33 | 34 | executePhase() 35 | { 36 | local phase=$1 37 | local dontVariableName=dont${phase^} 38 | local doVariableName=do${phase^} 39 | 40 | if [ -z "${!dontVariableName}" ] || [ -n "${!doVariableName}" ] 41 | then 42 | runHook pre${phase^} 43 | runHook ${phase}Phase 44 | runHook post${phase^} 45 | fi 46 | } 47 | 48 | # Function that gets invoked when the build exists. 49 | # It can be used to execute a hook on failure or success. 50 | 51 | exitHandler() 52 | { 53 | exitCode="$?" 54 | 55 | if [ "$exitCode" = "0" ] 56 | then 57 | runHook exitHook 58 | else 59 | runHook failureHook 60 | fi 61 | 62 | exit "$exitCode" 63 | } 64 | 65 | # Executes the generic build procedure. If a build command is given 66 | # it will get executed, otherwise it will executed the specified phases. 67 | 68 | genericBuild() 69 | { 70 | runCommand 71 | 72 | # Only run phases if no buildCommand was given 73 | if [ -z "$buildCommand" ] && [ -z "$buildCommandPath" ] 74 | then 75 | # Execute phases 76 | for phase in $phases 77 | do 78 | echo "Executing phase: $phase" 79 | executePhase $phase 80 | done 81 | fi 82 | } 83 | 84 | trap "exitHandler" EXIT 85 | -------------------------------------------------------------------------------- /stdenv/simple-derivation/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv, system, shell, __noChroot}@composeArgs: 2 | {builder, __noChroot ? false, ...}@args: 3 | 4 | let 5 | extraArgs = removeAttrs args [ "builder" "__noChroot" "meta" ]; # meta attribute needs to be remove because it cannot be converted to an environment variable 6 | 7 | noChroot = composeArgs.__noChroot 8 | || args.__noChroot or false; 9 | 10 | buildResult = derivation ({ 11 | inherit system stdenv; 12 | builder = shell; # Make bash the default builder 13 | args = [ "-e" builder ]; # Pass builder executable as parameter to bash 14 | setupSimpleDerivation = ./setup.sh; 15 | __noChroot = noChroot; 16 | } // extraArgs); 17 | in 18 | buildResult // (if args ? meta then { inherit (args) meta; } else {}) # Readd the meta attribute to the resulting attribute set 19 | -------------------------------------------------------------------------------- /stdenv/simple-derivation/setup.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | shopt -s nullglob 3 | 4 | # Source the setup script to get basic UNIX utilities in our PATH 5 | source $stdenv/setup 6 | 7 | # Extra environment variable tweaks to make builds pure 8 | 9 | # Set the TZ (timezone) environment variable, otherwise commands like 10 | # `date' will complain (e.g., `Tue Mar 9 10:01:47 Local time zone must 11 | # be set--see zic manual page 2004'). 12 | export TZ=UTC 13 | 14 | # Set a fallback default value for SOURCE_DATE_EPOCH, used by some 15 | # build tools to provide a deterministic substitute for the "current" 16 | # time. Note that 1 = 1970-01-01 00:00:01. We don't use 0 because it 17 | # confuses some applications. 18 | export SOURCE_DATE_EPOCH 19 | : ${SOURCE_DATE_EPOCH:=1} 20 | -------------------------------------------------------------------------------- /tests/generic-build/CVE-2016-2037-out-of-bounds-write.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/copyin.c b/src/copyin.c 2 | index cde911e..032d35f 100644 3 | --- a/src/copyin.c 4 | +++ b/src/copyin.c 5 | @@ -1385,6 +1385,8 @@ process_copy_in () 6 | break; 7 | } 8 | 9 | + if (file_hdr.c_namesize <= 1) 10 | + file_hdr.c_name = xrealloc(file_hdr.c_name, 2); 11 | cpio_safer_name_suffix (file_hdr.c_name, false, !no_abs_paths_flag, 12 | false); 13 | 14 | diff --git a/src/util.c b/src/util.c 15 | index 6ff6032..2763ac1 100644 16 | --- a/src/util.c 17 | +++ b/src/util.c 18 | @@ -1411,7 +1411,10 @@ set_file_times (int fd, 19 | } 20 | 21 | /* Do we have to ignore absolute paths, and if so, does the filename 22 | - have an absolute path? */ 23 | + have an absolute path? 24 | + Before calling this function make sure that the allocated NAME buffer has 25 | + capacity at least 2 bytes to allow us to store the "." string inside. */ 26 | + 27 | void 28 | cpio_safer_name_suffix (char *name, bool link_target, bool absolute_names, 29 | bool strip_leading_dots) 30 | -------------------------------------------------------------------------------- /tests/generic-build/all-packages.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import { inherit system; } 2 | , system ? builtins.currentSystem 3 | }: 4 | 5 | let 6 | pkgsSetupScript = import ../setup-script/all-packages.nix { 7 | inherit pkgs system; 8 | }; 9 | in 10 | rec { 11 | stdenv = import ../../stdenv { 12 | inherit system; 13 | inherit (pkgs) bash; 14 | 15 | basePackages = [ 16 | pkgs.coreutils 17 | pkgs.findutils 18 | pkgs.diffutils 19 | pkgs.gnused 20 | pkgs.gnugrep 21 | pkgs.gawk 22 | pkgs.bash 23 | ]; 24 | 25 | genericBuildPackages = [ 26 | pkgs.patch 27 | compress-man 28 | patch-shebangs 29 | ]; 30 | }; 31 | 32 | compress-man = import ../../commands/compress-man { 33 | inherit (pkgsSetupScript) stdenv; 34 | }; 35 | 36 | patch-shebangs = import ../../commands/patch-shebangs { 37 | inherit (pkgsSetupScript) stdenv; 38 | }; 39 | 40 | tar-wrapper = import ./tar-wrapper { 41 | inherit stdenv; 42 | inherit (pkgs) gnutar; 43 | }; 44 | 45 | gzip-wrapper = import ./gzip-wrapper { 46 | inherit stdenv; 47 | inherit (pkgs) gzip; 48 | }; 49 | 50 | bzip2-wrapper = import ./bzip2-wrapper { 51 | inherit stdenv; 52 | inherit (pkgs) bzip2; 53 | }; 54 | 55 | gcc-wrapper = import ./gcc-wrapper.nix { 56 | inherit stdenv; 57 | inherit (pkgs) gcc; 58 | }; 59 | 60 | gnuhello = import ./gnuhello.nix { 61 | inherit stdenv; 62 | inherit (pkgsSetupScript) fetchurl; 63 | inherit (pkgs) gnumake; 64 | binutils = pkgs.binutils-unwrapped; 65 | gcc = gcc-wrapper; 66 | gnutar = tar-wrapper; 67 | gzip = gzip-wrapper; 68 | }; 69 | 70 | cpio = import ./cpio.nix { 71 | inherit stdenv; 72 | inherit (pkgsSetupScript) fetchurl; 73 | inherit (pkgs) gnumake; 74 | gcc = gcc-wrapper; 75 | binutils = pkgs.binutils-unwrapped; 76 | gnutar = tar-wrapper; 77 | bzip2 = bzip2-wrapper; 78 | }; 79 | 80 | hello = import ./hello.nix { 81 | inherit stdenv; 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /tests/generic-build/bzip2-wrapper/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv, bzip2}: 2 | 3 | stdenv.runCommand { 4 | name = "bzip2-wrapper"; 5 | buildCommand = '' 6 | mkdir -p $out/bin 7 | ln -s ${bzip2}/bin/bzip2 $out/bin 8 | ''; 9 | setupHook = ./setup-hook.sh; 10 | } 11 | -------------------------------------------------------------------------------- /tests/generic-build/bzip2-wrapper/setup-hook.sh: -------------------------------------------------------------------------------- 1 | _tryBunzip2() 2 | { 3 | case "$1" in 4 | *.bz|*.bz2) 5 | bzip2 -d "$1" 6 | ;; 7 | *) 8 | return 1 9 | ;; 10 | esac 11 | } 12 | 13 | uncompressHooks+=(_tryBunzip2) 14 | -------------------------------------------------------------------------------- /tests/generic-build/cpio.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, bzip2, gnutar, gnumake, gcc, binutils }: 2 | 3 | let 4 | version = "2.12"; 5 | name = "cpio-${version}"; 6 | in stdenv.genericBuild { 7 | inherit name; 8 | 9 | src = fetchurl { 10 | url = "mirror://gnu/cpio/${name}.tar.bz2"; 11 | sha256 = "0vi9q475h1rki53100zml75vxsykzyhrn70hidy41s5c2rc8r6bh"; 12 | }; 13 | 14 | buildInputs = [ bzip2 gnutar gnumake gcc binutils ]; 15 | 16 | patches = [ 17 | # Report: http://www.openwall.com/lists/oss-security/2016/01/19/4 18 | # Patch from https://lists.gnu.org/archive/html/bug-cpio/2016-01/msg00005.html 19 | ./CVE-2016-2037-out-of-bounds-write.patch 20 | ]; 21 | 22 | buildCommandPhase = '' 23 | ./configure --prefix=$out 24 | make 25 | make install 26 | ''; 27 | 28 | meta = { 29 | homepage = http://www.gnu.org/software/cpio/; 30 | description = "A program to create or extract from cpio archives"; 31 | priority = 6; # resolves collision with gnutar's "libexec/rmt" 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /tests/generic-build/gcc-wrapper.nix: -------------------------------------------------------------------------------- 1 | {stdenv, gcc}: 2 | 3 | stdenv.runCommand { 4 | name = "gcc-wrapper"; 5 | buildCommand = '' 6 | mkdir -p $out/bin 7 | for i in ${gcc}/bin/* 8 | do 9 | ln -s $i $out/bin 10 | done 11 | ''; 12 | } 13 | -------------------------------------------------------------------------------- /tests/generic-build/gnuhello.nix: -------------------------------------------------------------------------------- 1 | {stdenv, fetchurl, gnumake, gnutar, gzip, gcc, binutils}: 2 | 3 | stdenv.genericBuild { 4 | name = "hello-2.10"; 5 | src = fetchurl { 6 | url = mirror://gnu/hello/hello-2.10.tar.gz; 7 | sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"; 8 | }; 9 | buildInputs = [ gnumake gnutar gzip gcc binutils ]; 10 | buildCommandPhase = '' 11 | ./configure --prefix=$out 12 | make 13 | make install 14 | ''; 15 | } 16 | -------------------------------------------------------------------------------- /tests/generic-build/gzip-wrapper/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv, gzip}: 2 | 3 | stdenv.runCommand { 4 | name = "gzip-wrapper"; 5 | buildCommand = '' 6 | mkdir -p $out/bin 7 | ln -s ${gzip}/bin/gzip $out/bin 8 | ln -s ${gzip}/bin/gunzip $out/bin 9 | ''; 10 | setupHook = ./setup-hook.sh; 11 | } 12 | -------------------------------------------------------------------------------- /tests/generic-build/gzip-wrapper/setup-hook.sh: -------------------------------------------------------------------------------- 1 | _tryGunzip() 2 | { 3 | case "$1" in 4 | *.gz) 5 | gzip -d "$1" 6 | ;; 7 | *) 8 | return 1 9 | ;; 10 | esac 11 | } 12 | 13 | uncompressHooks+=(_tryGunzip) 14 | -------------------------------------------------------------------------------- /tests/generic-build/hello.nix: -------------------------------------------------------------------------------- 1 | {stdenv}: 2 | 3 | stdenv.genericBuild { 4 | name = "hello"; 5 | dontUnpack = true; 6 | buildCommandPhase = '' 7 | mkdir -p $out/bin 8 | cat > $out/bin/hello < { inherit system; } 2 | , system ? builtins.currentSystem 3 | }: 4 | 5 | let 6 | pkgsSetupScript = import ../setup-script/all-packages.nix { 7 | inherit pkgs system; 8 | }; 9 | in 10 | rec { 11 | stdenv = import ../../stdenv { 12 | inherit system; 13 | inherit (pkgs) bash; 14 | 15 | basePackages = [ 16 | pkgs.coreutils 17 | pkgs.findutils 18 | pkgs.diffutils 19 | pkgs.gnused 20 | pkgs.gnugrep 21 | pkgs.gawk 22 | pkgs.bash 23 | ]; 24 | 25 | genericBuildPackages = [ 26 | pkgs.patch 27 | compress-man 28 | patch-shebangs 29 | ]; 30 | 31 | buildPackages = [ 32 | tar-wrapper # pkgs.gnutar 33 | pkgs.gzip 34 | pkgs.bzip2 35 | pkgs.xz 36 | pkgs.gnumake 37 | pkgs.binutils-unwrapped 38 | gcc-wrapper 39 | ]; 40 | }; 41 | 42 | compress-man = import ../../commands/compress-man { 43 | inherit (pkgsSetupScript) stdenv; 44 | }; 45 | 46 | patch-shebangs = import ../../commands/patch-shebangs { 47 | inherit (pkgsSetupScript) stdenv; 48 | }; 49 | 50 | tar-wrapper = import ./tar-wrapper { 51 | inherit stdenv; 52 | inherit (pkgs) gnutar; 53 | }; 54 | 55 | gnuhello = import ./gnuhello.nix { 56 | inherit stdenv; 57 | inherit (pkgsSetupScript) fetchurl; 58 | }; 59 | 60 | bzip2 = import ./bzip2.nix { 61 | inherit stdenv; 62 | inherit (pkgsSetupScript) fetchurl; 63 | }; 64 | 65 | gcc-wrapper = import ./gcc-wrapper { 66 | inherit stdenv; 67 | inherit (pkgs) gcc; 68 | }; 69 | 70 | zlib = import ./zlib.nix { 71 | inherit stdenv; 72 | inherit (pkgsSetupScript) fetchurl; 73 | }; 74 | 75 | zlib-wrapper = import ./zlib-wrapper.nix { 76 | inherit stdenv zlib; 77 | }; 78 | 79 | file = import ./file.nix { 80 | inherit stdenv; 81 | zlib = zlib-wrapper; 82 | inherit (pkgsSetupScript) fetchurl; 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /tests/make-derivation/bzip2.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl }: 2 | 3 | stdenv.mkDerivation rec { 4 | name = "bzip2-${version}"; 5 | version = "1.0.6.0.1"; 6 | 7 | /* We use versions patched to use autotools style properly, 8 | saving lots of trouble. */ 9 | src = fetchurl { 10 | url = "http://ftp.uni-kl.de/pub/linux/suse/people/sbrabec/bzip2/tarballs/${name}.tar.gz"; 11 | sha256 = "0b5b5p8c7bslc6fslcr1nj9136412v3qcvbg6yxi9argq9g72v8c"; 12 | }; 13 | 14 | postPatch = '' 15 | sed -i -e '//s|\\|/|' bzip2.c 16 | ''; 17 | 18 | outputs = [ "bin" "dev" "out" "man" ]; 19 | 20 | meta = { 21 | homepage = http://www.bzip.org; 22 | description = "High-quality data compression program"; 23 | 24 | platforms = stdenv.lib.platforms.all; 25 | maintainers = []; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /tests/make-derivation/file.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, zlib }: 2 | 3 | stdenv.mkDerivation rec { 4 | name = "file-${version}"; 5 | version = "5.32"; 6 | 7 | src = fetchurl { 8 | url = "https://distfiles.macports.org/file/${name}.tar.gz"; 9 | sha256 = "0l1bfa0icng9vdwya00ff48fhvjazi5610ylbhl35qi13d6xqfc6"; 10 | }; 11 | 12 | buildInputs = [ zlib ]; 13 | 14 | meta = { 15 | homepage = http://darwinsys.com/file; 16 | description = "A program that shows the type of files"; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /tests/make-derivation/gcc-wrapper/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv, gcc}: 2 | 3 | stdenv.runCommand { 4 | name = "gcc-wrapper"; 5 | buildCommand = '' 6 | mkdir -p $out/bin 7 | for i in ${gcc}/bin/* 8 | do 9 | ln -s $i $out/bin 10 | done 11 | ''; 12 | setupHook = ./setup-hook.sh; 13 | } 14 | -------------------------------------------------------------------------------- /tests/make-derivation/gcc-wrapper/setup-hook.sh: -------------------------------------------------------------------------------- 1 | addToCPATH() 2 | { 3 | addToSearchPath CPATH $1/include 4 | } 5 | 6 | addToLIBRARY_PATH() 7 | { 8 | addToSearchPath LIBRARY_PATH $1/lib 9 | } 10 | 11 | envHooks+=(addToCPATH addToLIBRARY_PATH) 12 | -------------------------------------------------------------------------------- /tests/make-derivation/gnuhello.nix: -------------------------------------------------------------------------------- 1 | {stdenv, fetchurl}: 2 | 3 | stdenv.mkDerivation { 4 | name = "hello-2.10"; 5 | src = fetchurl { 6 | url = mirror://gnu/hello/hello-2.10.tar.gz; 7 | sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"; 8 | }; 9 | doCheck = true; 10 | } 11 | -------------------------------------------------------------------------------- /tests/make-derivation/tar-wrapper/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv, gnutar}: 2 | 3 | stdenv.runCommand { 4 | name = "tar-wrapper"; 5 | buildCommand = '' 6 | mkdir -p $out/bin 7 | ln -s ${gnutar}/bin/tar $out/bin 8 | ''; 9 | setupHook = ./setup-hook.sh; 10 | } 11 | -------------------------------------------------------------------------------- /tests/make-derivation/tar-wrapper/setup-hook.sh: -------------------------------------------------------------------------------- 1 | _tryUntar() 2 | { 3 | case "$1" in 4 | *.tar|*.tar.gz|*.tar.bz2|*.tar.lzma|*.tar.xz) 5 | tar xfv "$1" 6 | ;; 7 | *) 8 | return 1 9 | ;; 10 | esac 11 | } 12 | 13 | unpackHooks+=(_tryUntar) 14 | -------------------------------------------------------------------------------- /tests/make-derivation/zlib-wrapper.nix: -------------------------------------------------------------------------------- 1 | {stdenv, zlib}: 2 | 3 | stdenv.runCommand { 4 | name = "zlib-wrapper"; 5 | propagatedBuildInputs = [ zlib ]; 6 | buildCommand = '' 7 | mkdir -p $out/bin 8 | cat > $out/bin/wrap < { inherit system; } 2 | , system ? builtins.currentSystem 3 | }: 4 | 5 | let 6 | pkgsSetupScript = import ../setup-script/all-packages.nix { 7 | inherit pkgs system; 8 | }; 9 | 10 | pkgsMkDerivation = import ../make-derivation/all-packages.nix { 11 | inherit pkgs system; 12 | }; 13 | in 14 | rec { 15 | perl-wrapper = import ./perl-wrapper { 16 | inherit (pkgsMkDerivation) stdenv; 17 | inherit (pkgs) perl; 18 | }; 19 | 20 | buildPerlPackage = import ../../perl/default.nix { 21 | inherit (pkgsMkDerivation) stdenv; 22 | perl = perl-wrapper; 23 | }; 24 | 25 | xmlparser = import ./xmlparser.nix { 26 | inherit buildPerlPackage; 27 | inherit (pkgsSetupScript) fetchurl; 28 | inherit (pkgs) expat; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /tests/perl/perl-wrapper/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv, perl}: 2 | 3 | stdenv.mkDerivation { 4 | name = "perl-wrapper"; 5 | buildCommand = '' 6 | mkdir -p $out/bin 7 | cd $out/bin 8 | 9 | for i in ${perl}/bin/* 10 | do 11 | ln -s $i 12 | done 13 | ''; 14 | setupHook = ./setup-hook.sh; 15 | } 16 | -------------------------------------------------------------------------------- /tests/perl/perl-wrapper/setup-hook.sh: -------------------------------------------------------------------------------- 1 | addPerlLibPath() 2 | { 3 | addToSearchPath PERL5LIB $1/lib/perl5/site_perl 4 | } 5 | 6 | envHooks+=(addPerlLibPath) 7 | -------------------------------------------------------------------------------- /tests/perl/xmlparser.nix: -------------------------------------------------------------------------------- 1 | {buildPerlPackage, fetchurl, expat}: 2 | 3 | buildPerlPackage { 4 | name = "XML-Parser-2.41"; 5 | src = fetchurl { 6 | url = mirror://cpan/authors/id/T/TO/TODDR/XML-Parser-2.41.tar.gz; 7 | sha256 = "1sadi505g5qmxr36lgcbrcrqh3a5gcdg32b405gnr8k54b6rg0dl"; 8 | }; 9 | buildInputs = [ expat.out expat.dev ]; 10 | dontStrip = true; 11 | } 12 | -------------------------------------------------------------------------------- /tests/raw/test1/default.nix: -------------------------------------------------------------------------------- 1 | derivation { 2 | name = "test"; 3 | builder = ./test.sh; 4 | system = "x86_64-linux"; 5 | person = "Sander"; 6 | } 7 | -------------------------------------------------------------------------------- /tests/raw/test1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | echo "Hello $person" > $out 4 | -------------------------------------------------------------------------------- /tests/raw/test2/default.nix: -------------------------------------------------------------------------------- 1 | derivation { 2 | name = "test"; 3 | builder = ./test.sh; 4 | system = "x86_64-linux"; 5 | message = "Hello world"; 6 | outputs = [ "dev" "out" ]; 7 | } 8 | -------------------------------------------------------------------------------- /tests/raw/test2/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | echo "$message out" > $out 4 | echo "$message dev" > $dev 5 | -------------------------------------------------------------------------------- /tests/run-command/all-packages.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import { inherit system; } 2 | , system ? builtins.currentSystem 3 | }: 4 | 5 | let 6 | pkgsSetupScript = import ../setup-script/all-packages.nix { 7 | inherit pkgs system; 8 | }; 9 | in 10 | rec { 11 | stdenv = import ../../stdenv { 12 | inherit system; 13 | inherit (pkgs) bash; 14 | 15 | basePackages = [ 16 | pkgs.coreutils 17 | pkgs.findutils 18 | pkgs.diffutils 19 | pkgs.gnused 20 | pkgs.gnugrep 21 | pkgs.gawk 22 | pkgs.bash 23 | ]; 24 | }; 25 | 26 | hello = import ./hello.nix { 27 | inherit stdenv; 28 | }; 29 | 30 | gcc-wrapper = import ./gcc-wrapper.nix { 31 | inherit stdenv; 32 | inherit (pkgs) gcc; 33 | }; 34 | 35 | perl-wrapper = import ./perl-wrapper.nix { 36 | inherit stdenv; 37 | inherit (pkgs) perl; 38 | }; 39 | 40 | gnuhello = import ./gnuhello.nix { 41 | inherit stdenv; 42 | inherit (pkgsSetupScript) fetchurl; 43 | inherit (pkgs) gnumake gnutar gzip; 44 | binutils = pkgs.binutils-unwrapped; 45 | gcc = gcc-wrapper; 46 | }; 47 | 48 | compress-raw-zlib = import ./compress-raw-zlib.nix { 49 | inherit stdenv; 50 | inherit (pkgsSetupScript) fetchurl; 51 | inherit (pkgs) gnutar gzip gnumake zlib; 52 | binutils = pkgs.binutils-unwrapped; 53 | perl = perl-wrapper; 54 | gcc = gcc-wrapper; 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /tests/run-command/compress-raw-zlib.nix: -------------------------------------------------------------------------------- 1 | {stdenv, fetchurl, perl, gnutar, gzip, gnumake, gcc, binutils, zlib}: 2 | 3 | stdenv.runCommand rec { 4 | name = "Compress-Raw-Zlib-2.074"; 5 | 6 | src = fetchurl { 7 | url = "mirror://cpan/authors/id/P/PM/PMQS/${name}.tar.gz"; 8 | sha256 = "08bpx9v6i40n54rdcj6invlj294z20amrl8wvwf9b83aldwdwsd3"; 9 | }; 10 | 11 | buildInputs = [ perl gnutar gzip gnumake gcc binutils ]; 12 | 13 | buildCommand = '' 14 | tar xfv $src 15 | cd Compress-* 16 | 17 | cat > config.in < $out/bin/hello < { inherit system; } 2 | , system ? builtins.currentSystem 3 | }: 4 | 5 | rec { 6 | stdenv = import ../../stdenv { 7 | inherit system; 8 | inherit (pkgs) bash; 9 | 10 | basePackages = [ 11 | pkgs.coreutils 12 | pkgs.findutils 13 | pkgs.diffutils 14 | pkgs.gnused 15 | pkgs.gnugrep 16 | pkgs.gawk 17 | pkgs.bash 18 | ]; 19 | }; 20 | 21 | hello = import ./hello.nix { 22 | inherit stdenv; 23 | }; 24 | 25 | hello2 = import ./hello2 { 26 | inherit stdenv; 27 | }; 28 | 29 | fail = import ./fail.nix { 30 | inherit stdenv; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /tests/run-phases/fail.nix: -------------------------------------------------------------------------------- 1 | {stdenv}: 2 | 3 | stdenv.runPhases { 4 | name = "fail"; 5 | phases = [ "build" "install" ]; 6 | buildPhase = '' 7 | echo "EPIC FAIL" 8 | false; 9 | ''; 10 | installPhase = '' 11 | echo "SHOULD FAIL" > $out 12 | ''; 13 | failureHook = '' 14 | echo "THIS IS WHAT YOU SHOULD SEE AFTER FAILING" 15 | ''; 16 | } 17 | -------------------------------------------------------------------------------- /tests/run-phases/hello.nix: -------------------------------------------------------------------------------- 1 | {stdenv}: 2 | 3 | stdenv.runPhases { 4 | name = "hello"; 5 | phases = [ "build" "install" ]; 6 | buildPhase = '' 7 | cat > hello < hello < { inherit system; } 2 | , system ? builtins.currentSystem 3 | }: 4 | 5 | rec { 6 | stdenv = import ../../stdenv { 7 | inherit system; 8 | inherit (pkgs) bash; 9 | 10 | basePackages = [ 11 | pkgs.coreutils 12 | pkgs.findutils 13 | pkgs.diffutils 14 | pkgs.gnused 15 | pkgs.gnugrep 16 | pkgs.gawk 17 | pkgs.bash 18 | ]; 19 | }; 20 | 21 | fetchurl = import ./fetchurl.nix; 22 | 23 | hello = import ./hello { 24 | inherit stdenv; 25 | }; 26 | 27 | gnuhello = import ./gnuhello { 28 | inherit stdenv fetchurl; 29 | inherit (pkgs) gnumake gnutar gzip gcc; 30 | binutils = pkgs.binutils-unwrapped; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /tests/setup-script/fetchurl.nix: -------------------------------------------------------------------------------- 1 | args: 2 | 3 | import args 4 | -------------------------------------------------------------------------------- /tests/setup-script/gnuhello/builder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | source $stdenv/setup 3 | 4 | export PATH=$PATH:$gnumake/bin:$gnutar/bin:$gzip/bin:$gcc/bin:$binutils/bin 5 | 6 | tar xfv $src 7 | cd hello-* 8 | ./configure --prefix=$out 9 | make 10 | make install 11 | -------------------------------------------------------------------------------- /tests/setup-script/gnuhello/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv, fetchurl, gnumake, gnutar, gzip, gcc, binutils}: 2 | 3 | derivation { 4 | name = "hello-2.10"; 5 | src = fetchurl { 6 | url = mirror://gnu/hello/hello-2.10.tar.gz; 7 | sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"; 8 | }; 9 | inherit stdenv gnumake gnutar gzip gcc binutils; 10 | builder = ./builder.sh; 11 | system = builtins.currentSystem; 12 | } 13 | -------------------------------------------------------------------------------- /tests/setup-script/hello/builder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | source $stdenv/setup 3 | 4 | mkdir -p $out/bin 5 | 6 | cat > $out/bin/hello < { inherit system; } 2 | , system ? builtins.currentSystem 3 | }: 4 | 5 | let 6 | pkgsSetupScript = import ../setup-script/all-packages.nix { 7 | inherit pkgs system; 8 | }; 9 | in 10 | rec { 11 | stdenv = import ../../stdenv { 12 | inherit system; 13 | inherit (pkgs) bash; 14 | 15 | basePackages = [ 16 | pkgs.coreutils 17 | pkgs.findutils 18 | pkgs.diffutils 19 | pkgs.gnused 20 | pkgs.gnugrep 21 | pkgs.gawk 22 | pkgs.bash 23 | ]; 24 | }; 25 | 26 | hello = import ./hello { 27 | inherit stdenv; 28 | }; 29 | 30 | gnuhello = import ./gnuhello { 31 | inherit stdenv; 32 | inherit (pkgsSetupScript) fetchurl; 33 | inherit (pkgs) gnumake gnutar gzip gcc; 34 | binutils = pkgs.binutils-unwrapped; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /tests/simple-derivation/gnuhello/builder.sh: -------------------------------------------------------------------------------- 1 | source $setupSimpleDerivation 2 | 3 | export PATH=$PATH:$gnumake/bin:$gnutar/bin:$gzip/bin:$gcc/bin:$binutils/bin 4 | 5 | tar xfv $src 6 | cd hello-* 7 | ./configure --prefix=$out 8 | make 9 | make install 10 | -------------------------------------------------------------------------------- /tests/simple-derivation/gnuhello/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv, fetchurl, gnumake, gnutar, gzip, gcc, binutils}: 2 | 3 | stdenv.simpleDerivation { 4 | name = "hello-2.10"; 5 | src = fetchurl { 6 | url = mirror://gnu/hello/hello-2.10.tar.gz; 7 | sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"; 8 | }; 9 | inherit stdenv gnumake gnutar gzip gcc binutils; 10 | builder = ./builder.sh; 11 | } 12 | -------------------------------------------------------------------------------- /tests/simple-derivation/hello/builder.sh: -------------------------------------------------------------------------------- 1 | source $setupSimpleDerivation 2 | 3 | mkdir -p $out/bin 4 | 5 | cat > $out/bin/hello < { inherit system; } 2 | , system ? builtins.currentSystem 3 | }: 4 | 5 | let 6 | pkgsRunCommand = import ../run-command/all-packages.nix { 7 | inherit pkgs system; 8 | }; 9 | in 10 | rec { 11 | writeText = import ../../write-text-file { 12 | inherit (pkgsRunCommand) stdenv; 13 | }; 14 | 15 | textTest = writeText { 16 | name = "hello"; 17 | text = "Hello world!"; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /write-text-file/default.nix: -------------------------------------------------------------------------------- 1 | {stdenv}: 2 | 3 | { name # the name of the derivation 4 | , text 5 | , executable ? false # run chmod +x ? 6 | , destination ? "" # relative path appended to $out eg "/bin/foo" 7 | , checkPhase ? "" # syntax checks, e.g. for scripts 8 | }: 9 | 10 | stdenv.runCommand { 11 | inherit name text executable; 12 | passAsFile = [ "text" ]; 13 | 14 | # Pointless to do this on a remote machine. 15 | preferLocalBuild = true; 16 | allowSubstitutes = false; 17 | 18 | buildCommand = '' 19 | target=$out${destination} 20 | mkdir -p "$(dirname "$target")" 21 | 22 | if [ -e "$textPath" ] 23 | then 24 | mv "$textPath" "$target" 25 | else 26 | echo -n "$text" > "$target" 27 | fi 28 | 29 | [ "$executable" = "1" ] && chmod +x "$target" || true 30 | ''; 31 | } 32 | --------------------------------------------------------------------------------