diff options
Diffstat (limited to 'pkgs/build-support')
18 files changed, 830 insertions, 272 deletions
diff --git a/pkgs/build-support/agda/default.nix b/pkgs/build-support/agda/default.nix index 681d1ea681bb4..44c9ade02ffb8 100644 --- a/pkgs/build-support/agda/default.nix +++ b/pkgs/build-support/agda/default.nix @@ -2,14 +2,28 @@ { stdenv, lib, self, Agda, runCommand, makeWrapper, writeText, ghcWithPackages, nixosTests }: -with lib.strings; - let + inherit (lib) + attrValues + elem + filter + filterAttrs + isAttrs + isList + platforms + ; + + inherit (lib.strings) + concatMapStrings + concatMapStringsSep + optionalString + ; + withPackages' = { pkgs, ghc ? ghcWithPackages (p: with p; [ ieee754 ]) }: let - pkgs' = if builtins.isList pkgs then pkgs else pkgs self; + pkgs' = if isList pkgs then pkgs else pkgs self; library-file = writeText "libraries" '' ${(concatMapStringsSep "\n" (p: "${p}/${p.libraryFile}") pkgs')} ''; @@ -23,7 +37,7 @@ let inherit withPackages; tests = { inherit (nixosTests) agda; - allPackages = withPackages (lib.filter self.lib.isUnbrokenAgdaPackage (lib.attrValues self)); + allPackages = withPackages (filter self.lib.isUnbrokenAgdaPackage (attrValues self)); }; }; inherit (Agda) meta; @@ -35,7 +49,7 @@ let ln -s ${Agda}/bin/agda-mode $out/bin/agda-mode ''; - withPackages = arg: if builtins.isAttrs arg then withPackages' arg else withPackages' { pkgs = arg; }; + withPackages = arg: if isAttrs arg then withPackages' arg else withPackages' { pkgs = arg; }; extensions = [ "agda" @@ -62,7 +76,7 @@ let , extraExtensions ? [] , ... }: let - agdaWithArgs = withPackages (builtins.filter (p: p ? isAgdaDerivation) buildInputs); + agdaWithArgs = withPackages (filter (p: p ? isAgdaDerivation) buildInputs); includePathArgs = concatMapStrings (path: "-i" + path + " ") (includePaths ++ [(dirOf everythingFile)]); in { @@ -91,13 +105,13 @@ let # darwin, it seems that there is no standard such locale; luckily, # the referenced issue doesn't seem to surface on darwin. Hence let's # set this only on non-darwin. - LC_ALL = lib.optionalString (!stdenv.isDarwin) "C.UTF-8"; + LC_ALL = optionalString (!stdenv.isDarwin) "C.UTF-8"; - meta = if meta.broken or false then meta // { hydraPlatforms = lib.platforms.none; } else meta; + meta = if meta.broken or false then meta // { hydraPlatforms = platforms.none; } else meta; # Retrieve all packages from the finished package set that have the current package as a dependency and build them - passthru.tests = with builtins; - lib.filterAttrs (name: pkg: self.lib.isUnbrokenAgdaPackage pkg && elem pname (map (pkg: pkg.pname) pkg.buildInputs)) self; + passthru.tests = + filterAttrs (name: pkg: self.lib.isUnbrokenAgdaPackage pkg && elem pname (map (pkg: pkg.pname) pkg.buildInputs)) self; }; in { diff --git a/pkgs/build-support/bintools-wrapper/default.nix b/pkgs/build-support/bintools-wrapper/default.nix index 1a32f365bab2a..b2545d0ad0e57 100644 --- a/pkgs/build-support/bintools-wrapper/default.nix +++ b/pkgs/build-support/bintools-wrapper/default.nix @@ -35,7 +35,7 @@ # Note: the hardening flags are part of the bintools-wrapper, rather than # the cc-wrapper, because a few of them are handled by the linker. -, defaultHardeningFlags ? with stdenvNoCC; [ +, defaultHardeningFlags ? [ "bindnow" "format" "fortify" @@ -44,7 +44,7 @@ "relro" "stackprotector" "strictoverflow" - ] ++ lib.optional ( + ] ++ lib.optional (with stdenvNoCC; # Musl-based platforms will keep "pie", other platforms will not. # If you change this, make sure to update section `{#sec-hardening-in-nixpkgs}` # in the nixpkgs manual to inform users about the defaults. @@ -59,15 +59,30 @@ , postLinkSignHook ? null, signingUtils ? null }: -with lib; - assert nativeTools -> !propagateDoc && nativePrefix != ""; -assert !nativeTools -> - bintools != null && coreutils != null && gnugrep != null; +assert !nativeTools -> bintools != null && coreutils != null && gnugrep != null; assert !(nativeLibc && noLibc); assert (noLibc || nativeLibc) == (libc == null); let + inherit (lib) + attrByPath + concatStringsSep + getBin + getDev + getLib + getName + getVersion + hasSuffix + optional + optionalAttrs + optionals + optionalString + platforms + removePrefix + replaceStrings + ; + stdenv = stdenvNoCC; inherit (stdenv) hostPlatform targetPlatform; @@ -75,18 +90,18 @@ let # # TODO(@Ericson2314) Make unconditional, or optional but always true by # default. - targetPrefix = lib.optionalString (targetPlatform != hostPlatform) + targetPrefix = optionalString (targetPlatform != hostPlatform) (targetPlatform.config + "-"); - bintoolsVersion = lib.getVersion bintools; - bintoolsName = lib.removePrefix targetPrefix (lib.getName bintools); + bintoolsVersion = getVersion bintools; + bintoolsName = removePrefix targetPrefix (getName bintools); - libc_bin = lib.optionalString (libc != null) (getBin libc); - libc_dev = lib.optionalString (libc != null) (getDev libc); - libc_lib = lib.optionalString (libc != null) (getLib libc); - bintools_bin = lib.optionalString (!nativeTools) (getBin bintools); + libc_bin = optionalString (libc != null) (getBin libc); + libc_dev = optionalString (libc != null) (getDev libc); + libc_lib = optionalString (libc != null) (getLib libc); + bintools_bin = optionalString (!nativeTools) (getBin bintools); # The wrapper scripts use 'cat' and 'grep', so we may need coreutils. - coreutils_bin = lib.optionalString (!nativeTools) (getBin coreutils); + coreutils_bin = optionalString (!nativeTools) (getBin coreutils); # See description in cc-wrapper. suffixSalt = replaceStrings ["-" "."] ["_" "_"] targetPlatform.config; @@ -114,11 +129,11 @@ let else if targetPlatform.isLoongArch64 then "${sharedLibraryLoader}/lib/ld-linux-loongarch*.so.1" else if targetPlatform.isDarwin then "/usr/lib/dyld" else if targetPlatform.isFreeBSD then "/libexec/ld-elf.so.1" - else if lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1" + else if hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1" else ""; expand-response-params = - lib.optionalString (buildPackages ? stdenv && buildPackages.stdenv.hasCC && buildPackages.stdenv.cc != "/dev/null") + optionalString (buildPackages ? stdenv && buildPackages.stdenv.hasCC && buildPackages.stdenv.cc != "/dev/null") (import ../expand-response-params { inherit (buildPackages) stdenv; }); in @@ -126,7 +141,7 @@ in stdenv.mkDerivation { pname = targetPrefix + (if name != "" then name else "${bintoolsName}-wrapper"); - version = lib.optionalString (bintools != null) bintoolsVersion; + version = optionalString (bintools != null) bintoolsVersion; preferLocalBuild = true; @@ -196,7 +211,7 @@ stdenv.mkDerivation { # as it must have both the GNU assembler from cctools (installed as `gas`) # and the Clang integrated assembler (installed as `as`). # See pkgs/os-specific/darwin/binutils/default.nix for details. - + lib.optionalString wrapGas '' + + optionalString wrapGas '' if [ -e $ldPath/${targetPrefix}gas ]; then ln -s $ldPath/${targetPrefix}gas $out/bin/${targetPrefix}gas fi @@ -273,7 +288,7 @@ stdenv.mkDerivation { ${if targetPlatform.isDarwin then '' printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook - '' else lib.optionalString (sharedLibraryLoader != null) '' + '' else optionalString (sharedLibraryLoader != null) '' if [ -e ${sharedLibraryLoader}/lib/32/ld-linux.so.2 ]; then echo ${sharedLibraryLoader}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32 fi @@ -290,7 +305,7 @@ stdenv.mkDerivation { # install the wrapper, you get tools like objdump (same for any # binaries of libc). + optionalString (!nativeTools) '' - printWords ${bintools_bin} ${lib.optionalString (libc != null) libc_bin} > $out/nix-support/propagated-user-env-packages + printWords ${bintools_bin} ${optionalString (libc != null) libc_bin} > $out/nix-support/propagated-user-env-packages '' ## @@ -406,7 +421,7 @@ stdenv.mkDerivation { # for substitution in utils.bash expandResponseParams = "${expand-response-params}/bin/expand-response-params"; shell = getBin shell + shell.shellPath or ""; - gnugrep_bin = lib.optionalString (!nativeTools) gnugrep; + gnugrep_bin = optionalString (!nativeTools) gnugrep; wrapperName = "BINTOOLS_WRAPPER"; inherit dynamicLinker targetPrefix suffixSalt coreutils_bin; inherit bintools_bin libc_bin libc_dev libc_lib; @@ -414,13 +429,13 @@ stdenv.mkDerivation { }; meta = - let bintools_ = lib.optionalAttrs (bintools != null) bintools; in - (lib.optionalAttrs (bintools_ ? meta) (removeAttrs bintools.meta ["priority"])) // + let bintools_ = optionalAttrs (bintools != null) bintools; in + (optionalAttrs (bintools_ ? meta) (removeAttrs bintools.meta ["priority"])) // { description = - lib.attrByPath ["meta" "description"] "System binary utilities" bintools_ + attrByPath ["meta" "description"] "System binary utilities" bintools_ + " (wrapper script)"; priority = 10; } // optionalAttrs useMacosReexportHack { - platforms = lib.platforms.darwin; + platforms = platforms.darwin; }; } diff --git a/pkgs/build-support/build-fhsenv-bubblewrap/default.nix b/pkgs/build-support/build-fhsenv-bubblewrap/default.nix index 5b4de2dd04cab..e06fb51dd4b67 100644 --- a/pkgs/build-support/build-fhsenv-bubblewrap/default.nix +++ b/pkgs/build-support/build-fhsenv-bubblewrap/default.nix @@ -31,10 +31,20 @@ assert (pname != null || version != null) -> (name == null && pname != null); # You must declare either a name or pname + version (preferred). -with builtins; let + inherit (lib) + concatLines + concatStringsSep + escapeShellArgs + filter + optionalString + splitString + ; + + inherit (lib.attrsets) removeAttrs; + pname = if args ? name && args.name != null then args.name else args.pname; - versionStr = lib.optionalString (version != null) ("-" + version); + versionStr = optionalString (version != null) ("-" + version); name = pname + versionStr; buildFHSEnv = callPackage ./buildFHSEnv.nix { }; @@ -116,10 +126,10 @@ let exec ${run} "$@" ''; - indentLines = str: lib.concatLines (map (s: " " + s) (filter (s: s != "") (lib.splitString "\n" str))); + indentLines = str: concatLines (map (s: " " + s) (filter (s: s != "") (splitString "\n" str))); bwrapCmd = { initArgs ? "" }: '' ${extraPreBwrapCmds} - ignored=(/nix /dev /proc /etc ${lib.optionalString privateTmp "/tmp"}) + ignored=(/nix /dev /proc /etc ${optionalString privateTmp "/tmp"}) ro_mounts=() symlinks=() etc_ignored=() @@ -164,7 +174,7 @@ let fi # link selected etc entries from the actual root - for i in ${lib.escapeShellArgs etcBindEntries}; do + for i in ${escapeShellArgs etcBindEntries}; do if [[ "''${etc_ignored[@]}" =~ "$i" ]]; then continue fi @@ -195,7 +205,7 @@ let x11_args+=(--ro-bind-try "$local_socket" "$local_socket") fi - ${lib.optionalString privateTmp '' + ${optionalString privateTmp '' # sddm places XAUTHORITY in /tmp if [[ "$XAUTHORITY" == /tmp/* ]]; then x11_args+=(--ro-bind-try "$XAUTHORITY" "$XAUTHORITY") @@ -220,15 +230,15 @@ let --dev-bind /dev /dev --proc /proc --chdir "$(pwd)" - ${lib.optionalString unshareUser "--unshare-user"} - ${lib.optionalString unshareIpc "--unshare-ipc"} - ${lib.optionalString unsharePid "--unshare-pid"} - ${lib.optionalString unshareNet "--unshare-net"} - ${lib.optionalString unshareUts "--unshare-uts"} - ${lib.optionalString unshareCgroup "--unshare-cgroup"} - ${lib.optionalString dieWithParent "--die-with-parent"} + ${optionalString unshareUser "--unshare-user"} + ${optionalString unshareIpc "--unshare-ipc"} + ${optionalString unsharePid "--unshare-pid"} + ${optionalString unshareNet "--unshare-net"} + ${optionalString unshareUts "--unshare-uts"} + ${optionalString unshareCgroup "--unshare-cgroup"} + ${optionalString dieWithParent "--die-with-parent"} --ro-bind /nix /nix - ${lib.optionalString privateTmp "--tmpfs /tmp"} + ${optionalString privateTmp "--tmpfs /tmp"} # Our glibc will look for the cache in its own path in `/nix/store`. # As such, we need a cache to exist there, because pressure-vessel # depends on the existence of an ld cache. However, adding one @@ -242,7 +252,7 @@ let --symlink /etc/ld.so.cache ${glibc}/etc/ld.so.cache \ --ro-bind ${glibc}/etc/rpc ${glibc}/etc/rpc \ --remount-ro ${glibc}/etc \ - '' + lib.optionalString (stdenv.isx86_64 && stdenv.isLinux) (indentLines '' + '' + optionalString (stdenv.isx86_64 && stdenv.isLinux) (indentLines '' --tmpfs ${pkgsi686Linux.glibc}/etc \ --symlink /etc/ld.so.conf ${pkgsi686Linux.glibc}/etc/ld.so.conf \ --symlink /etc/ld.so.cache ${pkgsi686Linux.glibc}/etc/ld.so.cache \ diff --git a/pkgs/build-support/coq/default.nix b/pkgs/build-support/coq/default.nix index eb045ddf6865a..6036d0f05dd53 100644 --- a/pkgs/build-support/coq/default.nix +++ b/pkgs/build-support/coq/default.nix @@ -1,10 +1,33 @@ { lib, stdenv, coqPackages, coq, which, fetchzip }@args: -let lib = import ./extra-lib.nix {inherit (args) lib;}; in -with builtins; with lib; + let + lib = import ./extra-lib.nix { + inherit (args) lib; + }; + + inherit (lib) + concatStringsSep + flip + foldl + isFunction + isString + optional + optionalAttrs + optionals + optionalString + pred + remove + switch + versions + ; + + inherit (lib.attrsets) removeAttrs; + inherit (lib.strings) match; + isGitHubDomain = d: match "^github.*" d != null; isGitLabDomain = d: match "^gitlab.*" d != null; in + { pname, version ? null, fetcher ? null, diff --git a/pkgs/build-support/coq/extra-lib.nix b/pkgs/build-support/coq/extra-lib.nix index 3c226b4920b62..94de7c0113d84 100644 --- a/pkgs/build-support/coq/extra-lib.nix +++ b/pkgs/build-support/coq/extra-lib.nix @@ -1,5 +1,25 @@ { lib }: -with builtins; with lib; recursiveUpdate lib (rec { + +let + inherit (lib) + all + concatStringsSep + findFirst + flip + getAttr + head + isFunction + length + recursiveUpdate + splitVersion + tail + take + versionAtLeast + versionOlder + zipListsWith + ; +in +recursiveUpdate lib (rec { versions = let diff --git a/pkgs/build-support/coq/meta-fetch/default.nix b/pkgs/build-support/coq/meta-fetch/default.nix index 82c29fb760b78..daed9faa3efed 100644 --- a/pkgs/build-support/coq/meta-fetch/default.nix +++ b/pkgs/build-support/coq/meta-fetch/default.nix @@ -1,8 +1,33 @@ { lib, stdenv, fetchzip }@args: -let lib' = lib; in -let lib = import ../extra-lib.nix {lib = lib';}; in -with builtins; with lib; + let + lib = import ../extra-lib.nix { + inherit (args) lib; + }; + + inherit (lib) + attrNames + fakeSha256 + filter + findFirst + head + isAttrs + isPath + isString + last + length + optionalAttrs + pathExists + pred + sort + switch + switch-if + versionAtLeast + versions + ; + + inherit (lib.strings) match split; + default-fetcher = {domain ? "github.com", owner ? "", repo, rev, name ? "source", sha256 ? null, ...}@args: let ext = if args?sha256 then "zip" else "tar.gz"; fmt = if args?sha256 then "zip" else "tarball"; @@ -17,7 +42,7 @@ let { cond = (match "(www.)?mpi-sws.org" domain) != null; out = "https://www.mpi-sws.org/~${owner}/${repo}/download/${repo}-${rev}.${ext}";} ] (throw "meta-fetch: no fetcher found for domain ${domain} on ${rev}"); - fetch = x: if args?sha256 then fetchzip (x // { inherit sha256; }) else fetchTarball x; + fetch = x: if args?sha256 then fetchzip (x // { inherit sha256; }) else builtins.fetchTarball x; in fetch { inherit url ; }; in { @@ -38,11 +63,12 @@ switch arg [ { case = isNull; out = { version = "broken"; src = ""; broken = true; }; } { case = isPathString; out = { version = "dev"; src = arg; }; } { case = pred.union isVersion isShortVersion; - out = let v = if isVersion arg then arg else shortVersion arg; in - let - given-sha256 = release.${v}.sha256 or ""; - sha256 = if given-sha256 == "" then lib.fakeSha256 else given-sha256; - rv = release.${v} // { inherit sha256; }; in + out = let + v = if isVersion arg then arg else shortVersion arg; + given-sha256 = release.${v}.sha256 or ""; + sha256 = if given-sha256 == "" then fakeSha256 else given-sha256; + rv = release.${v} // { inherit sha256; }; + in { version = rv.version or v; src = rv.src or fetcher (location // { rev = releaseRev v; } // rv); diff --git a/pkgs/build-support/fetchrepoproject/default.nix b/pkgs/build-support/fetchrepoproject/default.nix index 78b8caeb8091e..a5e79c8d4ef97 100644 --- a/pkgs/build-support/fetchrepoproject/default.nix +++ b/pkgs/build-support/fetchrepoproject/default.nix @@ -9,9 +9,14 @@ assert repoRepoRev != "" -> repoRepoURL != ""; assert createMirror -> !useArchive; -with lib; - let + inherit (lib) + concatMapStringsSep + concatStringsSep + fetchers + optionalString + ; + extraRepoInitFlags = [ (optionalString (repoRepoURL != "") "--repo-url=${repoRepoURL}") (optionalString (repoRepoRev != "") "--repo-branch=${repoRepoRev}") diff --git a/pkgs/build-support/fetchsourcehut/default.nix b/pkgs/build-support/fetchsourcehut/default.nix index ed6e85bd639b2..42d437b3555e6 100644 --- a/pkgs/build-support/fetchsourcehut/default.nix +++ b/pkgs/build-support/fetchsourcehut/default.nix @@ -1,6 +1,14 @@ { fetchgit, fetchhg, fetchzip, lib }: -lib.makeOverridable ( +let + inherit (lib) + assertOneOf + makeOverridable + optionalString + ; +in + +makeOverridable ( { owner , repo, rev , domain ? "sr.ht" @@ -10,9 +18,7 @@ lib.makeOverridable ( , ... # For hash agility } @ args: -with lib; - -assert (lib.assertOneOf "vc" vc [ "hg" "git" ]); +assert (assertOneOf "vc" vc [ "hg" "git" ]); let urlFor = resource: "https://${resource}.${domain}/${owner}/${repo}"; diff --git a/pkgs/build-support/nix-gitignore/default.nix b/pkgs/build-support/nix-gitignore/default.nix index c047bfc7d9a28..849720675c892 100644 --- a/pkgs/build-support/nix-gitignore/default.nix +++ b/pkgs/build-support/nix-gitignore/default.nix @@ -7,9 +7,32 @@ # - zero or more directories. For example, "a/**/b" matches "a/b", # - "a/x/b", "a/x/y/b" and so on. -with builtins; - let + inherit (builtins) filterSource; + + inherit (lib) + concatStringsSep + elemAt + filter + head + isList + length + optionals + optionalString + pathExists + readFile + removePrefix + replaceStrings + stringLength + sub + substring + toList + trace + ; + + + inherit (lib.strings) match split typeOf; + debug = a: trace a a; last = l: elemAt l ((length l) - 1); in rec { @@ -17,7 +40,7 @@ in rec { filterPattern = patterns: root: (name: _type: let - relPath = lib.removePrefix ((toString root) + "/") name; + relPath = removePrefix ((toString root) + "/") name; matches = pair: (match (head pair) relPath) != null; matched = map (pair: [(matches pair) (last pair)]) patterns; in @@ -45,7 +68,7 @@ in rec { escs = "\\*?"; splitString = let recurse = str : [(substring 0 1 str)] ++ - (lib.optionals (str != "") (recurse (substring 1 (stringLength(str)) str) )); + (optionals (str != "") (recurse (substring 1 (stringLength(str)) str) )); in str : recurse str; chars = s: filter (c: c != "" && !isList c) (splitString s); escape = s: map (c: "\\" + c) (chars s); @@ -66,7 +89,7 @@ in rec { handleSlashPrefix = l: let split = (match "^(/?)(.*)" l); - findSlash = l: lib.optionalString ((match ".+/.+" l) == null) l; + findSlash = l: optionalString ((match ".+/.+" l) == null) l; hasSlash = mapAroundCharclass findSlash l != l; in (if (elemAt split 0) == "/" || hasSlash @@ -94,12 +117,12 @@ in rec { gitignoreCompileIgnore = file_str_patterns: root: let onPath = f: a: if typeOf a == "path" then f a else a; - str_patterns = map (onPath readFile) (lib.toList file_str_patterns); + str_patterns = map (onPath readFile) (toList file_str_patterns); in concatStringsSep "\n" str_patterns; - gitignoreFilterPure = filter: patterns: root: name: type: + gitignoreFilterPure = predicate: patterns: root: name: type: gitignoreFilter (gitignoreCompileIgnore patterns root) root name type - && filter name type; + && predicate name type; # This is a very hacky way of programming this! # A better way would be to reuse existing filtering by making multiple gitignore functions per each root. @@ -145,23 +168,23 @@ in rec { ''); withGitignoreFile = patterns: root: - lib.toList patterns ++ [ ".git" ] ++ [(root + "/.gitignore")]; + toList patterns ++ [ ".git" ] ++ [(root + "/.gitignore")]; withRecursiveGitignoreFile = patterns: root: - lib.toList patterns ++ [ ".git" ] ++ [(compileRecursiveGitignore root)]; + toList patterns ++ [ ".git" ] ++ [(compileRecursiveGitignore root)]; # filterSource derivatives - gitignoreFilterSourcePure = filter: patterns: root: - filterSource (gitignoreFilterPure filter patterns root) root; + gitignoreFilterSourcePure = predicate: patterns: root: + filterSource (gitignoreFilterPure predicate patterns root) root; - gitignoreFilterSource = filter: patterns: root: - gitignoreFilterSourcePure filter (withGitignoreFile patterns root) root; + gitignoreFilterSource = predicate: patterns: root: + gitignoreFilterSourcePure predicate (withGitignoreFile patterns root) root; - gitignoreFilterRecursiveSource = filter: patterns: root: - gitignoreFilterSourcePure filter (withRecursiveGitignoreFile patterns root) root; + gitignoreFilterRecursiveSource = predicate: patterns: root: + gitignoreFilterSourcePure predicate (withRecursiveGitignoreFile patterns root) root; - # "Filter"-less alternatives + # "Predicate"-less alternatives gitignoreSourcePure = gitignoreFilterSourcePure (_: _: true); gitignoreSource = patterns: let type = typeOf patterns; in diff --git a/pkgs/build-support/pkg-config-wrapper/default.nix b/pkgs/build-support/pkg-config-wrapper/default.nix index f409ca3a7d4b6..c7856bd1f8765 100644 --- a/pkgs/build-support/pkg-config-wrapper/default.nix +++ b/pkgs/build-support/pkg-config-wrapper/default.nix @@ -10,9 +10,17 @@ , extraPackages ? [], extraBuildCommands ? "" }: -with lib; - let + inherit (lib) + attrByPath + getBin + optional + optionalAttrs + optionals + optionalString + replaceStrings + ; + stdenv = stdenvNoCC; inherit (stdenv) hostPlatform targetPlatform; @@ -20,7 +28,7 @@ let # # TODO(@Ericson2314) Make unconditional, or optional but always true by # default. - targetPrefix = lib.optionalString (targetPlatform != hostPlatform) + targetPrefix = optionalString (targetPlatform != hostPlatform) (targetPlatform.config + "-"); # See description in cc-wrapper. @@ -49,7 +57,7 @@ stdenv.mkDerivation { dontUnpack = true; # Additional flags passed to pkg-config. - addFlags = lib.optional stdenv.targetPlatform.isStatic "--static"; + addFlags = optional stdenv.targetPlatform.isStatic "--static"; installPhase = '' @@ -119,10 +127,10 @@ stdenv.mkDerivation { }; meta = - let pkg-config_ = lib.optionalAttrs (pkg-config != null) pkg-config; in - (lib.optionalAttrs (pkg-config_ ? meta) (removeAttrs pkg-config.meta ["priority"])) // + let pkg-config_ = optionalAttrs (pkg-config != null) pkg-config; in + (optionalAttrs (pkg-config_ ? meta) (removeAttrs pkg-config.meta ["priority"])) // { description = - lib.attrByPath ["meta" "description"] "pkg-config" pkg-config_ + attrByPath ["meta" "description"] "pkg-config" pkg-config_ + " (wrapper script)"; priority = 10; }; diff --git a/pkgs/build-support/release/default.nix b/pkgs/build-support/release/default.nix index 1cc6a5812f1f5..f5ab2db1a7541 100644 --- a/pkgs/build-support/release/default.nix +++ b/pkgs/build-support/release/default.nix @@ -1,6 +1,24 @@ { lib, pkgs }: -with pkgs; +let + inherit (lib) optionalString; + + inherit (pkgs) + autoconf + automake + checkinstall + clang-analyzer + cov-build + enableGCOVInstrumentation + lcov + libtool + makeGCOVReport + runCommand + stdenv + vmTools + xz + ; +in rec { @@ -91,7 +109,7 @@ rec { dontConfigure = true; dontBuild = true; - patchPhase = lib.optionalString isNixOS '' + patchPhase = optionalString isNixOS '' touch .update-on-nixos-rebuild ''; diff --git a/pkgs/build-support/replace-dependency.nix b/pkgs/build-support/replace-dependency.nix index 5b4c127cdd8e7..7912d21bfd692 100644 --- a/pkgs/build-support/replace-dependency.nix +++ b/pkgs/build-support/replace-dependency.nix @@ -19,9 +19,20 @@ # (and all of its dependencies) without rebuilding further. { drv, oldDependency, newDependency, verbose ? true }: -with lib; - let + inherit (lib) + any + attrNames + concatStringsSep + elem + filter + filterAttrs + listToAttrs + mapAttrsToList + stringLength + substring + ; + warn = if verbose then builtins.trace else (x: y: y); references = import (runCommandLocal "references.nix" { exportReferencesGraph = [ "graph" drv ]; } '' (echo { @@ -54,7 +65,7 @@ let (drv: { name = discard (toString drv); value = elem oldStorepath (referencesOf drv) || any dependsOnOld (referencesOf drv); - }) (builtins.attrNames references)); + }) (attrNames references)); dependsOnOld = drv: dependsOnOldMemo.${discard (toString drv)}; @@ -74,9 +85,9 @@ let rewriteMemo = listToAttrs (map (drv: { name = discard (toString drv); value = rewriteHashes (builtins.storePath drv) - (filterAttrs (n: v: builtins.elem (builtins.storePath (discard (toString n))) (referencesOf drv)) rewriteMemo); + (filterAttrs (n: v: elem (builtins.storePath (discard (toString n))) (referencesOf drv)) rewriteMemo); }) - (filter dependsOnOld (builtins.attrNames references))) // rewrittenDeps; + (filter dependsOnOld (attrNames references))) // rewrittenDeps; drvHash = discard (toString drv); in assert (stringLength (drvName (toString oldDependency)) == stringLength (drvName (toString newDependency))); diff --git a/pkgs/build-support/setup-hooks/auto-patchelf.sh b/pkgs/build-support/setup-hooks/auto-patchelf.sh index 9f6366b3feaed..783ea45f8eeb1 100644 --- a/pkgs/build-support/setup-hooks/auto-patchelf.sh +++ b/pkgs/build-support/setup-hooks/auto-patchelf.sh @@ -88,22 +88,21 @@ autoPatchelf() { --extra-args "${patchelfFlagsArray[@]}" } -# XXX: This should ultimately use fixupOutputHooks but we currently don't have -# a way to enforce the order. If we have $runtimeDependencies set, the setup -# hook of patchelf is going to ruin everything and strip out those additional -# RPATHs. -# -# So what we do here is basically run in postFixup and emulate the same -# behaviour as fixupOutputHooks because the setup hook for patchelf is run in -# fixupOutput and the postFixup hook runs later. -# -# shellcheck disable=SC2016 -# (Expressions don't expand in single quotes, use double quotes for that.) -postFixupHooks+=(' - if [ -z "${dontAutoPatchelf-}" ]; then +autoPatchelfPostFixup() { + # XXX: This should ultimately use fixupOutputHooks but we currently don't have + # a way to enforce the order. If we have $runtimeDependencies set, the setup + # hook of patchelf is going to ruin everything and strip out those additional + # RPATHs. + # + # So what we do here is basically run in postFixup and emulate the same + # behaviour as fixupOutputHooks because the setup hook for patchelf is run in + # fixupOutput and the postFixup hook runs later. + if [[ -z "${dontAutoPatchelf-}" ]]; then autoPatchelf -- $(for output in $(getAllOutputNames); do [ -e "${!output}" ] || continue echo "${!output}" done) fi -') +} + +postFixupHooks+=(autoPatchelfPostFixup) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper/make-binary-wrapper.sh index 6cd01f6bf6307..3948342a36fc9 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper/make-binary-wrapper.sh @@ -19,6 +19,7 @@ assertExecutable() { # (if unset or empty, defaults to EXECUTABLE) # --inherit-argv0 : the executable inherits argv0 from the wrapper. # (use instead of --argv0 '$0') +# --resolve-argv0 : if argv0 doesn't include a / character, resolve it against PATH # --set VAR VAL : add VAR with value VAL to the executable's environment # --set-default VAR VAL : like --set, but only adds VAR if not already set in # the environment @@ -87,6 +88,7 @@ makeDocumentedCWrapper() { makeCWrapper() { local argv0 inherit_argv0 n params cmd main flagsBefore flagsAfter flags executable length local uses_prefix uses_suffix uses_assert uses_assert_success uses_stdio uses_asprintf + local resolve_path executable=$(escapeStringLiteral "$1") params=("$@") length=${#params[*]} @@ -169,6 +171,12 @@ makeCWrapper() { # Whichever comes last of --argv0 and --inherit-argv0 wins inherit_argv0=1 ;; + --resolve-argv0) + # this gets processed after other argv0 flags + uses_stdio=1 + uses_string=1 + resolve_argv0=1 + ;; *) # Using an error macro, we will make sure the compiler gives an understandable error message main="$main#error makeCWrapper: Unknown argument ${p}"$'\n' ;; @@ -176,6 +184,7 @@ makeCWrapper() { done [[ -z "$flagsBefore" && -z "$flagsAfter" ]] || main="$main"${main:+$'\n'}$(addFlags "$flagsBefore" "$flagsAfter")$'\n'$'\n' [ -z "$inherit_argv0" ] && main="${main}argv[0] = \"${argv0:-${executable}}\";"$'\n' + [ -z "$resolve_argv0" ] || main="${main}argv[0] = resolve_argv0(argv[0]);"$'\n' main="${main}return execv(\"${executable}\", argv);"$'\n' [ -z "$uses_asprintf" ] || printf '%s\n' "#define _GNU_SOURCE /* See feature_test_macros(7) */" @@ -183,9 +192,11 @@ makeCWrapper() { printf '%s\n' "#include <stdlib.h>" [ -z "$uses_assert" ] || printf '%s\n' "#include <assert.h>" [ -z "$uses_stdio" ] || printf '%s\n' "#include <stdio.h>" + [ -z "$uses_string" ] || printf '%s\n' "#include <string.h>" [ -z "$uses_assert_success" ] || printf '\n%s\n' "#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)" [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)" [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)" + [ -z "$resolve_argv0" ] || printf '\n%s\n' "$(resolveArgv0Fn)" printf '\n%s' "int main(int argc, char **argv) {" printf '\n%s' "$(indent4 "$main")" printf '\n%s\n' "}" @@ -338,6 +349,41 @@ void set_env_suffix(char *env, char *sep, char *suffix) { " } +resolveArgv0Fn() { + printf '%s' "\ +char *resolve_argv0(char *argv0) { + if (strchr(argv0, '/') != NULL) { + return argv0; + } + char *path = getenv(\"PATH\"); + if (path == NULL) { + return argv0; + } + char *path_copy = strdup(path); + if (path_copy == NULL) { + return argv0; + } + char *dir = strtok(path_copy, \":\"); + while (dir != NULL) { + char *candidate = malloc(strlen(dir) + strlen(argv0) + 2); + if (candidate == NULL) { + free(path_copy); + return argv0; + } + sprintf(candidate, \"%s/%s\", dir, argv0); + if (access(candidate, X_OK) == 0) { + free(path_copy); + return candidate; + } + free(candidate); + dir = strtok(NULL, \":\"); + } + free(path_copy); + return argv0; +} +" +} + # Embed a C string which shows up as readable text in the compiled binary wrapper, # giving instructions for recreating the wrapper. # Keep in sync with makeBinaryWrapper.extractCmd diff --git a/pkgs/build-support/setup-hooks/make-wrapper.sh b/pkgs/build-support/setup-hooks/make-wrapper.sh index 11b332bfc3eb2..cba158bd31ea9 100644 --- a/pkgs/build-support/setup-hooks/make-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-wrapper.sh @@ -15,6 +15,7 @@ assertExecutable() { # (if unset or empty, defaults to EXECUTABLE) # --inherit-argv0 : the executable inherits argv0 from the wrapper. # (use instead of --argv0 '$0') +# --resolve-argv0 : if argv0 doesn't include a / character, resolve it against PATH # --set VAR VAL : add VAR with value VAL to the executable's environment # --set-default VAR VAL : like --set, but only adds VAR if not already set in # the environment @@ -177,6 +178,9 @@ makeShellWrapper() { elif [[ "$p" == "--inherit-argv0" ]]; then # Whichever comes last of --argv0 and --inherit-argv0 wins argv0='$0' + elif [[ "$p" == "--resolve-argv0" ]]; then + # this is noop in shell wrappers, since bash will always resolve $0 + resolve_argv0=1 else die "makeWrapper doesn't understand the arg $p" fi diff --git a/pkgs/build-support/vm/test.nix b/pkgs/build-support/vm/test.nix index ae6a10dea3b9c..50dbfeb750be5 100644 --- a/pkgs/build-support/vm/test.nix +++ b/pkgs/build-support/vm/test.nix @@ -1,5 +1,21 @@ -with import ../../.. { }; -with vmTools; +let + pkgs = import ../../.. { }; + + inherit (pkgs) + hello + patchelf + pcmanfm + stdenv + ; + + inherit (pkgs.vmTools) + buildRPM + diskImages + makeImageTestScript + runInLinuxImage + runInLinuxVM + ; +in { diff --git a/pkgs/build-support/writers/scripts.nix b/pkgs/build-support/writers/scripts.nix index 1dd25c500719b..06d763ca9d6af 100644 --- a/pkgs/build-support/writers/scripts.nix +++ b/pkgs/build-support/writers/scripts.nix @@ -1,4 +1,14 @@ -{ pkgs, buildPackages, lib, stdenv, libiconv, mkNugetDeps, mkNugetSource, gixy }: +{ + buildPackages, + gixy, + lib, + libiconv, + makeBinaryWrapper, + mkNugetDeps, + mkNugetSource, + pkgs, + stdenv, +}: let inherit (lib) concatMapStringsSep @@ -6,7 +16,6 @@ let escapeShellArg last optionalString - stringLength strings types ; @@ -18,137 +27,285 @@ rec { # Examples: # writeBash = makeScriptWriter { interpreter = "${pkgs.bash}/bin/bash"; } # makeScriptWriter { interpreter = "${pkgs.dash}/bin/dash"; } "hello" "echo hello world" - makeScriptWriter = { interpreter, check ? "" }: nameOrPath: content: + makeScriptWriter = { interpreter, check ? "", makeWrapperArgs ? [], }: nameOrPath: content: assert (types.path.check nameOrPath) || (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null); assert (types.path.check content) || (types.str.check content); let + nameIsPath = types.path.check nameOrPath; name = last (builtins.split "/" nameOrPath); - in + path = if nameIsPath then nameOrPath else "/bin/${name}"; + # The inner derivation which creates the executable under $out/bin (never at $out directly) + # This is required in order to support wrapping, as wrapped programs consist of at least two files: the executable and the wrapper. + inner = + pkgs.runCommandLocal name ( + { + inherit makeWrapperArgs; + nativeBuildInputs = [ + makeBinaryWrapper + ]; + meta.mainProgram = name; + } + // ( + if (types.str.check content) then { + inherit content interpreter; + passAsFile = [ "content" ]; + } else { + inherit interpreter; + contentPath = content; + } + ) + ) + '' + # On darwin a script cannot be used as an interpreter in a shebang but + # there doesn't seem to be a limit to the size of shebang and multiple + # arguments to the interpreter are allowed. + if [[ -n "${toString pkgs.stdenvNoCC.isDarwin}" ]] && isScript $interpreter + then + wrapperInterpreterLine=$(head -1 "$interpreter" | tail -c+3) + # Get first word from the line (note: xargs echo remove leading spaces) + wrapperInterpreter=$(echo "$wrapperInterpreterLine" | xargs echo | cut -d " " -f1) + + if isScript $wrapperInterpreter + then + echo "error: passed interpreter ($interpreter) is a script which has another script ($wrapperInterpreter) as an interpreter, which is not supported." + exit 1 + fi + + # This should work as long as wrapperInterpreter is a shell, which is + # the case for programs wrapped with makeWrapper, like + # python3.withPackages etc. + interpreterLine="$wrapperInterpreterLine $interpreter" + else + interpreterLine=$interpreter + fi + + echo "#! $interpreterLine" > $out + cat "$contentPath" >> $out + ${optionalString (check != "") '' + ${check} $out + ''} + chmod +x $out + + # Relocate executable + # Wrap it if makeWrapperArgs are specified + mv $out tmp + mkdir -p $out/$(dirname "${path}") + mv tmp $out/${path} + if [ -n "''${makeWrapperArgs+''${makeWrapperArgs[@]}}" ]; then + wrapProgram $out/${path} ''${makeWrapperArgs[@]} + fi + ''; + in + if nameIsPath + then inner + # In case nameOrPath is a name, the user intends the executable to be located at $out. + # This is achieved by creating a separate derivation containing a symlink at $out linking to ${inner}/bin/${name}. + # This breaks the override pattern. + # In case this turns out to be a problem, we can still add more magic + else pkgs.runCommandLocal name {} '' + ln -s ${inner}/bin/${name} $out + ''; - pkgs.runCommandLocal name ( - lib.optionalAttrs (nameOrPath == "/bin/${name}") { - meta.mainProgram = name; - } - // ( - if (types.str.check content) then { - inherit content interpreter; - passAsFile = [ "content" ]; - } else { - inherit interpreter; - contentPath = content; - } - ) - ) - '' - # On darwin a script cannot be used as an interpreter in a shebang but - # there doesn't seem to be a limit to the size of shebang and multiple - # arguments to the interpreter are allowed. - if [[ -n "${toString pkgs.stdenvNoCC.isDarwin}" ]] && isScript $interpreter - then - wrapperInterpreterLine=$(head -1 "$interpreter" | tail -c+3) - # Get first word from the line (note: xargs echo remove leading spaces) - wrapperInterpreter=$(echo "$wrapperInterpreterLine" | xargs echo | cut -d " " -f1) - - if isScript $wrapperInterpreter - then - echo "error: passed interpreter ($interpreter) is a script which has another script ($wrapperInterpreter) as an interpreter, which is not supported." - exit 1 - fi - - # This should work as long as wrapperInterpreter is a shell, which is - # the case for programs wrapped with makeWrapper, like - # python3.withPackages etc. - interpreterLine="$wrapperInterpreterLine $interpreter" - else - interpreterLine=$interpreter - fi - - echo "#! $interpreterLine" > $out - cat "$contentPath" >> $out - ${optionalString (check != "") '' - ${check} $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, strip ? true }: nameOrPath: content: + makeBinWriter = { compileScript, strip ? true, makeWrapperArgs ? [] }: nameOrPath: content: assert (types.path.check nameOrPath) || (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null); assert (types.path.check content) || (types.str.check content); let + nameIsPath = types.path.check nameOrPath; name = last (builtins.split "/" nameOrPath); + path = if nameIsPath then nameOrPath else "/bin/${name}"; + # The inner derivation which creates the executable under $out/bin (never at $out directly) + # This is required in order to support wrapping, as wrapped programs consist of at least two files: the executable and the wrapper. + inner = + pkgs.runCommandLocal name ( + { + inherit makeWrapperArgs; + nativeBuildInputs = [ + makeBinaryWrapper + ]; + meta.mainProgram = name; + } + // ( + if (types.str.check content) then { + inherit content; + passAsFile = [ "content" ]; + } else { + contentPath = content; + } + ) + ) + '' + ${compileScript} + ${lib.optionalString strip + "${lib.getBin buildPackages.bintools-unwrapped}/bin/${buildPackages.bintools-unwrapped.targetPrefix}strip -S $out"} + # Sometimes binaries produced for darwin (e. g. by GHC) won't be valid + # mach-o executables from the get-go, but need to be corrected somehow + # which is done by fixupPhase. + ${lib.optionalString pkgs.stdenvNoCC.hostPlatform.isDarwin "fixupPhase"} + mv $out tmp + mkdir -p $out/$(dirname "${path}") + mv tmp $out/${path} + if [ -n "''${makeWrapperArgs+''${makeWrapperArgs[@]}}" ]; then + wrapProgram $out/${path} ''${makeWrapperArgs[@]} + fi + ''; in - pkgs.runCommand name ((if (types.str.check content) then { - inherit content; - passAsFile = [ "content" ]; - } else { - contentPath = content; - }) // lib.optionalAttrs (nameOrPath == "/bin/${name}") { - meta.mainProgram = name; - }) '' - ${compileScript} - ${lib.optionalString strip - "${lib.getBin buildPackages.bintools-unwrapped}/bin/${buildPackages.bintools-unwrapped.targetPrefix}strip -S $out"} - # Sometimes binaries produced for darwin (e. g. by GHC) won't be valid - # mach-o executables from the get-go, but need to be corrected somehow - # which is done by fixupPhase. - ${lib.optionalString pkgs.stdenvNoCC.hostPlatform.isDarwin "fixupPhase"} - ${optionalString (types.path.check nameOrPath) '' - mv $out tmp - mkdir -p $out/$(dirname "${nameOrPath}") - mv tmp $out/${nameOrPath} - ''} - ''; + if nameIsPath + then inner + # In case nameOrPath is a name, the user intends the executable to be located at $out. + # This is achieved by creating a separate derivation containing a symlink at $out linking to ${inner}/bin/${name}. + # This breaks the override pattern. + # In case this turns out to be a problem, we can still add more magic + else pkgs.runCommandLocal name {} '' + ln -s ${inner}/bin/${name} $out + ''; # Like writeScript but the first line is a shebang to bash # - # Example: + # Can be called with or without extra arguments. + # + # Example without arguments: # writeBash "example" '' # echo hello world # '' - writeBash = makeScriptWriter { - interpreter = "${lib.getExe pkgs.bash}"; - }; + # + # Example with arguments: + # writeBash "example" + # { + # makeWrapperArgs = [ + # "--prefix" "PATH" ":" "${pkgs.hello}/bin" + # ]; + # } + # '' + # hello + # '' + writeBash = name: argsOrScript: + if lib.isAttrs argsOrScript && ! lib.isDerivation argsOrScript + then makeScriptWriter (argsOrScript // { interpreter = "${lib.getExe pkgs.bash}"; }) name + else makeScriptWriter { interpreter = "${lib.getExe pkgs.bash}"; } name argsOrScript; # Like writeScriptBin but the first line is a shebang to bash + # + # Can be called with or without extra arguments. + # + # Example without arguments: + # writeBashBin "example" '' + # echo hello world + # '' + # + # Example with arguments: + # writeBashBin "example" + # { + # makeWrapperArgs = [ + # "--prefix", "PATH", ":", "${pkgs.hello}/bin", + # ]; + # } + # '' + # hello + # '' writeBashBin = name: writeBash "/bin/${name}"; # Like writeScript but the first line is a shebang to dash # - # Example: + # Can be called with or without extra arguments. + # + # Example without arguments: # writeDash "example" '' # echo hello world # '' - writeDash = makeScriptWriter { - interpreter = "${lib.getExe pkgs.dash}"; - }; + # + # Example with arguments: + # writeDash "example" + # { + # makeWrapperArgs = [ + # "--prefix", "PATH", ":", "${pkgs.hello}/bin", + # ]; + # } + # '' + # hello + # '' + writeDash = name: argsOrScript: + if lib.isAttrs argsOrScript && ! lib.isDerivation argsOrScript + then makeScriptWriter (argsOrScript // { interpreter = "${lib.getExe pkgs.dash}"; }) name + else makeScriptWriter { interpreter = "${lib.getExe pkgs.dash}"; } name argsOrScript; # Like writeScriptBin but the first line is a shebang to dash + # + # Can be called with or without extra arguments. + # + # Example without arguments: + # writeDashBin "example" '' + # echo hello world + # '' + # + # Example with arguments: + # writeDashBin "example" + # { + # makeWrapperArgs = [ + # "--prefix", "PATH", ":", "${pkgs.hello}/bin", + # ]; + # } + # '' + # hello + # '' writeDashBin = name: writeDash "/bin/${name}"; # Like writeScript but the first line is a shebang to fish # - # Example: + # Can be called with or without extra arguments. + # + # Example without arguments: # writeFish "example" '' # echo hello world # '' - writeFish = makeScriptWriter { - interpreter = "${lib.getExe pkgs.fish} --no-config"; - check = "${lib.getExe pkgs.fish} --no-config --no-execute"; # syntax check only - }; + # + # Example with arguments: + # writeFish "example" + # { + # makeWrapperArgs = [ + # "--prefix", "PATH", ":", "${pkgs.hello}/bin", + # ]; + # } + # '' + # hello + # '' + writeFish = name: argsOrScript: + if lib.isAttrs argsOrScript && ! lib.isDerivation argsOrScript + then makeScriptWriter (argsOrScript // { + interpreter = "${lib.getExe pkgs.fish} --no-config"; + check = "${lib.getExe pkgs.fish} --no-config --no-execute"; # syntax check only + }) name + else makeScriptWriter { + interpreter = "${lib.getExe pkgs.fish} --no-config"; + check = "${lib.getExe pkgs.fish} --no-config --no-execute"; # syntax check only + } name argsOrScript; # Like writeScriptBin but the first line is a shebang to fish + # + # Can be called with or without extra arguments. + # + # Example without arguments: + # writeFishBin "example" '' + # echo hello world + # '' + # + # Example with arguments: + # writeFishBin "example" + # { + # makeWrapperArgs = [ + # "--prefix", "PATH", ":", "${pkgs.hello}/bin", + # ]; + # } + # '' + # hello + # '' writeFishBin = name: writeFish "/bin/${name}"; @@ -162,11 +319,12 @@ rec { # main = launchMissiles # ''; writeHaskell = name: { - libraries ? [], ghc ? pkgs.ghc, ghcArgs ? [], + libraries ? [], + makeWrapperArgs ? [], + strip ? true, threadedRuntime ? true, - strip ? true }: let appendIfNotSet = el: list: if elem el list then list else list ++ [ el ]; @@ -178,7 +336,7 @@ rec { ${(ghc.withPackages (_: libraries ))}/bin/ghc ${lib.escapeShellArgs ghcArgs'} tmp.hs mv tmp $out ''; - inherit strip; + inherit makeWrapperArgs strip; } name; # writeHaskellBin takes the same arguments as writeHaskell but outputs a directory (like writeScriptBin) @@ -187,36 +345,72 @@ rec { # Like writeScript but the first line is a shebang to nu # - # Example: + # Can be called with or without extra arguments. + # + # Example without arguments: # writeNu "example" '' # echo hello world # '' - writeNu = makeScriptWriter { - interpreter = "${lib.getExe pkgs.nushell} --no-config-file"; - }; + # + # Example with arguments: + # writeNu "example" + # { + # makeWrapperArgs = [ + # "--prefix", "PATH", ":", "${pkgs.hello}/bin", + # ]; + # } + # '' + # hello + # '' + writeNu = name: argsOrScript: + if lib.isAttrs argsOrScript && ! lib.isDerivation argsOrScript + then makeScriptWriter (argsOrScript // { interpreter = "${lib.getExe pkgs.nushell} --no-config-file"; }) name + else makeScriptWriter { interpreter = "${lib.getExe pkgs.nushell} --no-config-file"; } name argsOrScript; + # Like writeScriptBin but the first line is a shebang to nu + # + # Can be called with or without extra arguments. + # + # Example without arguments: + # writeNuBin "example" '' + # echo hello world + # '' + # + # Example with arguments: + # writeNuBin "example" + # { + # makeWrapperArgs = [ + # "--prefix", "PATH", ":", "${pkgs.hello}/bin", + # ]; + # } + # '' + # hello + # '' writeNuBin = name: writeNu "/bin/${name}"; # makeRubyWriter takes ruby and compatible rubyPackages and produces ruby script writer, # If any libraries are specified, ruby.withPackages is used as interpreter, otherwise the "bare" ruby is used. - makeRubyWriter = ruby: rubyPackages: buildRubyPackages: name: { libraries ? [], }: - makeScriptWriter { - interpreter = - if libraries == [] - then "${ruby}/bin/ruby" - else "${(ruby.withPackages (ps: libraries))}/bin/ruby"; - # Rubocop doesnt seem to like running in this fashion. - #check = (writeDash "rubocop.sh" '' - # exec ${lib.getExe buildRubyPackages.rubocop} "$1" - #''); - } name; + makeRubyWriter = ruby: rubyPackages: buildRubyPackages: name: { libraries ? [], ... } @ args: + makeScriptWriter ( + (builtins.removeAttrs args ["libraries"]) + // { + interpreter = + if libraries == [] + then "${ruby}/bin/ruby" + else "${(ruby.withPackages (ps: libraries))}/bin/ruby"; + # Rubocop doesn't seem to like running in this fashion. + #check = (writeDash "rubocop.sh" '' + # exec ${lib.getExe buildRubyPackages.rubocop} "$1" + #''); + } + ) name; # Like writeScript but the first line is a shebang to ruby # # Example: - # writeRuby "example" '' + # writeRuby "example" { libraries = [ pkgs.rubyPackages.git ]; } '' # puts "hello world" # '' writeRuby = makeRubyWriter pkgs.ruby pkgs.rubyPackages buildPackages.rubyPackages; @@ -227,17 +421,20 @@ rec { # makeLuaWriter takes lua and compatible luaPackages and produces lua script writer, # which validates the script with luacheck at build time. If any libraries are specified, # lua.withPackages is used as interpreter, otherwise the "bare" lua is used. - makeLuaWriter = lua: luaPackages: buildLuaPackages: name: { libraries ? [], }: - makeScriptWriter { - interpreter = lua.interpreter; - # if libraries == [] - # then lua.interpreter - # else (lua.withPackages (ps: libraries)).interpreter - # This should support packages! I just cant figure out why some dependency collision happens whenever I try to run this. - check = (writeDash "luacheck.sh" '' - exec ${buildLuaPackages.luacheck}/bin/luacheck "$1" - ''); - } name; + makeLuaWriter = lua: luaPackages: buildLuaPackages: name: { libraries ? [], ... } @ args: + makeScriptWriter ( + (builtins.removeAttrs args ["libraries"]) + // { + interpreter = lua.interpreter; + # if libraries == [] + # then lua.interpreter + # else (lua.withPackages (ps: libraries)).interpreter + # This should support packages! I just cant figure out why some dependency collision happens whenever I try to run this. + check = (writeDash "luacheck.sh" '' + exec ${buildLuaPackages.luacheck}/bin/luacheck "$1" + ''); + } + ) name; # writeLua takes a name an attributeset with libraries and some lua source code and # returns an executable (should also work with luajit) @@ -265,9 +462,10 @@ rec { writeLua "/bin/${name}"; writeRust = name: { - rustc ? pkgs.rustc, - rustcArgs ? [], - strip ? true + makeWrapperArgs ? [], + rustc ? pkgs.rustc, + rustcArgs ? [], + strip ? true, }: let darwinArgs = lib.optionals stdenv.isDarwin [ "-L${lib.getLib libiconv}/lib" ]; @@ -277,7 +475,7 @@ rec { cp "$contentPath" tmp.rs PATH=${lib.makeBinPath [pkgs.gcc]} ${rustc}/bin/rustc ${lib.escapeShellArgs rustcArgs} ${lib.escapeShellArgs darwinArgs} -o "$out" tmp.rs ''; - inherit strip; + inherit makeWrapperArgs strip; } name; writeRustBin = name: @@ -337,10 +535,13 @@ rec { # use boolean; # print "Howdy!\n" if true; # '' - writePerl = name: { libraries ? [] }: - makeScriptWriter { - interpreter = "${lib.getExe (pkgs.perl.withPackages (p: libraries))}"; - } name; + writePerl = name: { libraries ? [], ... } @ args: + makeScriptWriter ( + (builtins.removeAttrs args ["libraries"]) + // { + interpreter = "${lib.getExe (pkgs.perl.withPackages (p: libraries))}"; + } + ) name; # writePerlBin takes the same arguments as writePerl but outputs a directory (like writeScriptBin) writePerlBin = name: @@ -349,22 +550,27 @@ rec { # makePythonWriter takes python and compatible pythonPackages and produces python script writer, # which validates the script with flake8 at build time. If any libraries are specified, # python.withPackages is used as interpreter, otherwise the "bare" python is used. - makePythonWriter = python: pythonPackages: buildPythonPackages: name: { libraries ? [], flakeIgnore ? [] }: + makePythonWriter = python: pythonPackages: buildPythonPackages: name: { libraries ? [], flakeIgnore ? [], ... } @ args: let ignoreAttribute = optionalString (flakeIgnore != []) "--ignore ${concatMapStringsSep "," escapeShellArg flakeIgnore}"; in - makeScriptWriter { - interpreter = - if pythonPackages != pkgs.pypy2Packages || pythonPackages != pkgs.pypy3Packages then - if libraries == [] - then python.interpreter - else (python.withPackages (ps: libraries)).interpreter - else python.interpreter - ; - check = optionalString python.isPy3k (writeDash "pythoncheck.sh" '' - exec ${buildPythonPackages.flake8}/bin/flake8 --show-source ${ignoreAttribute} "$1" - ''); - } name; + makeScriptWriter + ( + (builtins.removeAttrs args ["libraries" "flakeIgnore"]) + // { + interpreter = + if pythonPackages != pkgs.pypy2Packages || pythonPackages != pkgs.pypy3Packages then + if libraries == [] + then python.interpreter + else (python.withPackages (ps: libraries)).interpreter + else python.interpreter + ; + check = optionalString python.isPy3k (writeDash "pythoncheck.sh" '' + exec ${buildPythonPackages.flake8}/bin/flake8 --show-source ${ignoreAttribute} "$1" + ''); + } + ) + name; # writePyPy2 takes a name an attributeset with libraries and some pypy2 sourcecode and # returns an executable @@ -421,7 +627,7 @@ rec { writePyPy3 "/bin/${name}"; - makeFSharpWriter = { dotnet-sdk ? pkgs.dotnet-sdk, fsi-flags ? "", libraries ? _: [] }: nameOrPath: + makeFSharpWriter = { dotnet-sdk ? pkgs.dotnet-sdk, fsi-flags ? "", libraries ? _: [], ... } @ args: nameOrPath: let fname = last (builtins.split "/" nameOrPath); path = if strings.hasSuffix ".fsx" nameOrPath then nameOrPath else "${nameOrPath}.fsx"; @@ -442,9 +648,12 @@ rec { ${lib.getExe dotnet-sdk} fsi --quiet --nologo --readline- ${fsi-flags} "$@" < "$script" ''; - in content: makeScriptWriter { - interpreter = fsi; - } path + in content: makeScriptWriter ( + (builtins.removeAttrs args ["dotnet-sdk" "fsi-flags" "libraries"]) + // { + interpreter = fsi; + } + ) path '' #i "nuget: ${nuget-source}/lib" ${ content } @@ -456,5 +665,4 @@ rec { writeFSharpBin = name: writeFSharp "/bin/${name}"; - } diff --git a/pkgs/build-support/writers/test.nix b/pkgs/build-support/writers/test.nix index 982c550d28e08..656d127930fad 100644 --- a/pkgs/build-support/writers/test.nix +++ b/pkgs/build-support/writers/test.nix @@ -1,13 +1,8 @@ -{ glib -, haskellPackages +{ haskellPackages , lib , nodePackages , perlPackages -, pypy2Packages , python3Packages -, pypy3Packages -, luaPackages -, rubyPackages , runCommand , testers , writers @@ -16,8 +11,38 @@ # If you are reading this, you can test these writers by running: nix-build . -A tests.writers -with writers; let + inherit (lib) getExe recurseIntoAttrs; + + inherit (writers) + makeFSharpWriter + writeBash + writeBashBin + writeDash + writeDashBin + writeFish + writeFishBin + writeFSharp + writeHaskell + writeHaskellBin + writeJS + writeJSBin + writeJSON + writeLua + writeNu + writePerl + writePerlBin + writePyPy3 + writePython3 + writePython3Bin + writeRuby + writeRust + writeRustBin + writeText + writeTOML + writeYAML + ; + expectSuccess = test: runCommand "run-${test.name}" {} '' if [[ "$(${test})" != success ]]; then @@ -30,7 +55,7 @@ let expectSuccessBin = test: runCommand "run-${test.name}" {} '' - if [[ "$(${lib.getExe test})" != success ]]; then + if [[ "$(${getExe test})" != success ]]; then echo 'test ${test.name} failed' exit 1 fi @@ -44,8 +69,8 @@ let in testers.testEqualContents { expected = expectedFile; actual = file; assertion = "${file.name} matches"; }; in -lib.recurseIntoAttrs { - bin = lib.recurseIntoAttrs { +recurseIntoAttrs { + bin = recurseIntoAttrs { bash = expectSuccessBin (writeBashBin "test-writers-bash-bin" '' if [[ "test" == "test" ]]; then echo "success"; fi ''); @@ -145,7 +170,7 @@ lib.recurseIntoAttrs { #''); }; - simple = lib.recurseIntoAttrs { + simple = recurseIntoAttrs { bash = expectSuccess (writeBash "test-writers-bash" '' if [[ "test" == "test" ]]; then echo "success"; fi ''); @@ -270,7 +295,7 @@ lib.recurseIntoAttrs { ''); }; - path = lib.recurseIntoAttrs { + path = recurseIntoAttrs { bash = expectSuccess (writeBash "test-writers-bash-path" (writeText "test" '' if [[ "test" == "test" ]]; then echo "success"; fi '')); @@ -310,4 +335,85 @@ lib.recurseIntoAttrs { expected = "hello: world\n"; }; }; + + wrapping = recurseIntoAttrs { + bash-bin = expectSuccessBin ( + writeBashBin "test-writers-wrapping-bash-bin" + { + makeWrapperArgs = [ + "--set" + "ThaigerSprint" + "Thailand" + ]; + } + '' + if [[ "$ThaigerSprint" == "Thailand" ]]; then + echo "success" + fi + '' + ); + + bash = expectSuccess ( + writeBash "test-writers-wrapping-bash" + { + makeWrapperArgs = [ + "--set" + "ThaigerSprint" + "Thailand" + ]; + } + '' + if [[ "$ThaigerSprint" == "Thailand" ]]; then + echo "success" + fi + '' + ); + + python = expectSuccess ( + writePython3 "test-writers-wrapping-python" + { + makeWrapperArgs = [ + "--set" + "ThaigerSprint" + "Thailand" + ]; + } + '' + import os + + if os.environ.get("ThaigerSprint") == "Thailand": + print("success") + '' + ); + + rust = expectSuccess ( + writeRust "test-writers-wrapping-rust" + { + makeWrapperArgs = [ + "--set" + "ThaigerSprint" + "Thailand" + ]; + } + '' + fn main(){ + if std::env::var("ThaigerSprint").unwrap() == "Thailand" { + println!("success") + } + } + '' + ); + + no-empty-wrapper = let + bin = writeBashBin "bin" { makeWrapperArgs = []; } ''true''; + in runCommand "run-test-writers-wrapping-no-empty-wrapper" {} '' + ls -A ${bin}/bin + if [ $(ls -A ${bin}/bin | wc -l) -eq 1 ]; then + touch $out + else + echo "Error: Empty wrapper was created" >&2 + exit 1 + fi + ''; + }; } |