diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2015-07-20 04:30:16 +0200 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2016-11-16 18:19:47 +0100 |
| commit | 94d92c7796a3dd50c27d532315f7d497ac99f08e (patch) | |
| tree | 505902f5583fe528ceceacfd15d1f43828c4ad79 | |
| parent | 17ab08bcf0ae27ec6a1f07766080ebfbea8837d9 (diff) | |
daemon: Add "builtin:download" derivation builder.
This ensures that 1) the derivation doesn't change when Guix changes;
2) the derivation closure doesn't contain Guix and its dependencies; 3)
we don't have to rely on ugly chroot hacks.
Adapted from Nix commit 0a2bee307b20411f5b0dda0c662b1f9bb9e0e131.
* nix/libstore/build.cc (DerivationGoal::runChild): Add special case for
'isBuiltin(drv)'. Disable chroot when 'isBuiltin(drv)'.
* nix/libstore/builtins.cc, nix/libstore/builtins.hh,
nix/scripts/download.in, guix/scripts/perform-download.scm: New files.
* guix/ui.scm (show-guix-help)[internal?]: Add 'perform-download'.
* nix/local.mk (libstore_a_SOURCES): Add builtins.cc.
(libstore_headers): Add builtins.hh.
(nodist_pkglibexec_SCRIPTS): Add 'scripts/download'.
* config-daemon.ac: Emit 'scripts/download'.
* Makefile.am (MODULES): Add 'guix/scripts/perform-download.scm'.
* tests/derivations.scm ("unknown built-in builder")
("'download' built-in builder")
("'download' built-in builder, invalid hash")
("'download' built-in builder, not found")
("'download' built-in builder, not fixed-output"): New tests.
Co-authored-by: Eelco Dolstra <eelco.dolstra@logicblox.com>
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | config-daemon.ac | 2 | ||||
| -rw-r--r-- | guix/scripts/perform-download.scm | 113 | ||||
| -rw-r--r-- | guix/ui.scm | 3 | ||||
| -rw-r--r-- | nix/libstore/build.cc | 36 | ||||
| -rw-r--r-- | nix/libstore/builtins.cc | 69 | ||||
| -rw-r--r-- | nix/libstore/builtins.hh | 41 | ||||
| -rw-r--r-- | nix/local.mk | 5 | ||||
| -rw-r--r-- | nix/scripts/download.in | 11 | ||||
| -rw-r--r-- | tests/derivations.scm | 70 |
11 files changed, 343 insertions, 9 deletions
diff --git a/.gitignore b/.gitignore index 6e892ca6875..329d489713f 100644 --- a/.gitignore +++ b/.gitignore | |||
| @@ -125,3 +125,4 @@ config.cache | |||
| 125 | stamp-h[0-9] | 125 | stamp-h[0-9] |
| 126 | tmp | 126 | tmp |
| 127 | /doc/os-config-lightweight-desktop.texi | 127 | /doc/os-config-lightweight-desktop.texi |
| 128 | /nix/scripts/download | ||
diff --git a/Makefile.am b/Makefile.am index 5d3639747f2..9d62f480241 100644 --- a/Makefile.am +++ b/Makefile.am | |||
| @@ -123,6 +123,7 @@ MODULES = \ | |||
| 123 | guix/import/elpa.scm \ | 123 | guix/import/elpa.scm \ |
| 124 | guix/scripts.scm \ | 124 | guix/scripts.scm \ |
| 125 | guix/scripts/download.scm \ | 125 | guix/scripts/download.scm \ |
| 126 | guix/scripts/perform-download.scm \ | ||
| 126 | guix/scripts/build.scm \ | 127 | guix/scripts/build.scm \ |
| 127 | guix/scripts/archive.scm \ | 128 | guix/scripts/archive.scm \ |
| 128 | guix/scripts/import.scm \ | 129 | guix/scripts/import.scm \ |
diff --git a/config-daemon.ac b/config-daemon.ac index f66f31269df..8a3e6d8b601 100644 --- a/config-daemon.ac +++ b/config-daemon.ac | |||
| @@ -144,6 +144,8 @@ if test "x$guix_build_daemon" = "xyes"; then | |||
| 144 | 144 | ||
| 145 | AC_CONFIG_FILES([nix/scripts/list-runtime-roots], | 145 | AC_CONFIG_FILES([nix/scripts/list-runtime-roots], |
| 146 | [chmod +x nix/scripts/list-runtime-roots]) | 146 | [chmod +x nix/scripts/list-runtime-roots]) |
| 147 | AC_CONFIG_FILES([nix/scripts/download], | ||
| 148 | [chmod +x nix/scripts/download]) | ||
| 147 | AC_CONFIG_FILES([nix/scripts/substitute], | 149 | AC_CONFIG_FILES([nix/scripts/substitute], |
| 148 | [chmod +x nix/scripts/substitute]) | 150 | [chmod +x nix/scripts/substitute]) |
| 149 | AC_CONFIG_FILES([nix/scripts/guix-authenticate], | 151 | AC_CONFIG_FILES([nix/scripts/guix-authenticate], |
diff --git a/guix/scripts/perform-download.scm b/guix/scripts/perform-download.scm new file mode 100644 index 00000000000..0d2e7089aab --- /dev/null +++ b/guix/scripts/perform-download.scm | |||
| @@ -0,0 +1,113 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2016 Ludovic Courtès <ludo@gnu.org> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (guix scripts perform-download) | ||
| 20 | #:use-module (guix ui) | ||
| 21 | #:use-module (guix derivations) | ||
| 22 | #:use-module ((guix store) #:select (derivation-path?)) | ||
| 23 | #:use-module (guix build download) | ||
| 24 | #:use-module (ice-9 match) | ||
| 25 | #:export (guix-perform-download)) | ||
| 26 | |||
| 27 | ;; This program is a helper for the daemon's 'download' built-in builder. | ||
| 28 | |||
| 29 | (define-syntax derivation-let | ||
| 30 | (syntax-rules () | ||
| 31 | ((_ drv ((id name) rest ...) body ...) | ||
| 32 | (let ((id (assoc-ref (derivation-builder-environment-vars drv) | ||
| 33 | name))) | ||
| 34 | (derivation-let drv (rest ...) body ...))) | ||
| 35 | ((_ drv () body ...) | ||
| 36 | (begin body ...)))) | ||
| 37 | |||
| 38 | (define %user-module | ||
| 39 | ;; Module in which content-address mirror procedures are evaluated. | ||
| 40 | (let ((module (make-fresh-user-module))) | ||
| 41 | (module-use! module (resolve-interface '(guix base32))) | ||
| 42 | module)) | ||
| 43 | |||
| 44 | (define (perform-download drv) | ||
| 45 | "Perform the download described by DRV, a fixed-output derivation." | ||
| 46 | (derivation-let drv ((url "url") | ||
| 47 | (output "out") | ||
| 48 | (executable "executable") | ||
| 49 | (mirrors "mirrors") | ||
| 50 | (content-addressed-mirrors "content-addressed-mirrors")) | ||
| 51 | (unless url | ||
| 52 | (leave (_ "~a: missing URL~%") (derivation-file-name drv))) | ||
| 53 | |||
| 54 | (let* ((url (call-with-input-string url read)) | ||
| 55 | (drv-output (assoc-ref (derivation-outputs drv) "out")) | ||
| 56 | (algo (derivation-output-hash-algo drv-output)) | ||
| 57 | (hash (derivation-output-hash drv-output))) | ||
| 58 | (unless (and algo hash) | ||
| 59 | (leave (_ "~a is not a fixed-output derivation~%") | ||
| 60 | (derivation-file-name drv))) | ||
| 61 | |||
| 62 | ;; We're invoked by the daemon, which gives us write access to OUTPUT. | ||
| 63 | (when (url-fetch url output | ||
| 64 | #:mirrors (if mirrors | ||
| 65 | (call-with-input-file mirrors read) | ||
| 66 | '()) | ||
| 67 | #:content-addressed-mirrors | ||
| 68 | (if content-addressed-mirrors | ||
| 69 | (call-with-input-file content-addressed-mirrors | ||
| 70 | (lambda (port) | ||
| 71 | (eval (read port) %user-module))) | ||
| 72 | '()) | ||
| 73 | #:hashes `((,algo . ,hash)) | ||
| 74 | |||
| 75 | ;; Since DRV's output hash is known, X.509 certificate | ||
| 76 | ;; validation is pointless. | ||
| 77 | #:verify-certificate? #f) | ||
| 78 | (when (and executable (string=? executable "1")) | ||
| 79 | (chmod output #o755)))))) | ||
| 80 | |||
| 81 | (define (assert-low-privileges) | ||
| 82 | (when (zero? (getuid)) | ||
| 83 | (leave (_ "refusing to run with elevated privileges (UID ~a)~%") | ||
| 84 | (getuid)))) | ||
| 85 | |||
| 86 | (define (guix-perform-download . args) | ||
| 87 | "Perform the download described by the given fixed-output derivation. | ||
| 88 | |||
| 89 | This is an \"out-of-band\" download in that this code is executed directly by | ||
| 90 | the daemon and not explicitly described as an input of the derivation. This | ||
| 91 | allows us to sidestep bootstrapping problems, such downloading the source code | ||
| 92 | of GnuTLS over HTTPS, before we have built GnuTLS. See | ||
| 93 | <http://bugs.gnu.org/22774>." | ||
| 94 | (with-error-handling | ||
| 95 | (match args | ||
| 96 | (((? derivation-path? drv)) | ||
| 97 | ;; This program must be invoked by guix-daemon under an unprivileged | ||
| 98 | ;; UID to prevent things downloading from 'file:///etc/shadow' or | ||
| 99 | ;; arbitrary code execution via the content-addressed mirror | ||
| 100 | ;; procedures. (That means we exclude users who did not pass | ||
| 101 | ;; '--build-users-group'.) | ||
| 102 | (assert-low-privileges) | ||
| 103 | (perform-download (call-with-input-file drv read-derivation))) | ||
| 104 | (("--version") | ||
| 105 | (show-version-and-exit)) | ||
| 106 | (x | ||
| 107 | (leave (_ "fixed-output derivation name expected~%")))))) | ||
| 108 | |||
| 109 | ;; Local Variables: | ||
| 110 | ;; eval: (put 'derivation-let 'scheme-indent-function 2) | ||
| 111 | ;; End: | ||
| 112 | |||
| 113 | ;; perform-download.scm ends here | ||
diff --git a/guix/ui.scm b/guix/ui.scm index 9af86482115..b9fbbfd0e33 100644 --- a/guix/ui.scm +++ b/guix/ui.scm | |||
| @@ -1184,7 +1184,8 @@ optionally contain a version number and an output name, as in these examples: | |||
| 1184 | 1184 | ||
| 1185 | (define (show-guix-help) | 1185 | (define (show-guix-help) |
| 1186 | (define (internal? command) | 1186 | (define (internal? command) |
| 1187 | (member command '("substitute" "authenticate" "offload"))) | 1187 | (member command '("substitute" "authenticate" "offload" |
| 1188 | "perform-download"))) | ||
| 1188 | 1189 | ||
| 1189 | (format #t (_ "Usage: guix COMMAND ARGS... | 1190 | (format #t (_ "Usage: guix COMMAND ARGS... |
| 1190 | Run COMMAND with ARGS.\n")) | 1191 | Run COMMAND with ARGS.\n")) |
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc index ae78e651992..889ee3d2bd2 100644 --- a/nix/libstore/build.cc +++ b/nix/libstore/build.cc | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "util.hh" | 8 | #include "util.hh" |
| 9 | #include "archive.hh" | 9 | #include "archive.hh" |
| 10 | #include "affinity.hh" | 10 | #include "affinity.hh" |
| 11 | #include "builtins.hh" | ||
| 11 | 12 | ||
| 12 | #include <map> | 13 | #include <map> |
| 13 | #include <sstream> | 14 | #include <sstream> |
| @@ -2047,7 +2048,12 @@ void DerivationGoal::runChild() | |||
| 2047 | commonChildInit(builderOut); | 2048 | commonChildInit(builderOut); |
| 2048 | 2049 | ||
| 2049 | #if CHROOT_ENABLED | 2050 | #if CHROOT_ENABLED |
| 2050 | if (useChroot) { | 2051 | /* Note: built-in builders are *not* running in a chroot environment |
| 2052 | so that we can easily implement them in Guile without having it as | ||
| 2053 | a derivation input (they are running under a separate build user, | ||
| 2054 | though). */ | ||
| 2055 | |||
| 2056 | if (useChroot && !isBuiltin(drv)) { | ||
| 2051 | /* Initialise the loopback interface. */ | 2057 | /* Initialise the loopback interface. */ |
| 2052 | AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)); | 2058 | AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)); |
| 2053 | if (fd == -1) throw SysError("cannot open IP socket"); | 2059 | if (fd == -1) throw SysError("cannot open IP socket"); |
| @@ -2255,6 +2261,28 @@ void DerivationGoal::runChild() | |||
| 2255 | throw SysError("setuid failed"); | 2261 | throw SysError("setuid failed"); |
| 2256 | } | 2262 | } |
| 2257 | 2263 | ||
| 2264 | restoreSIGPIPE(); | ||
| 2265 | |||
| 2266 | /* Indicate that we managed to set up the build environment. */ | ||
| 2267 | writeFull(STDERR_FILENO, "\n"); | ||
| 2268 | |||
| 2269 | /* Execute the program. This should not return. */ | ||
| 2270 | if (isBuiltin(drv)) { | ||
| 2271 | try { | ||
| 2272 | logType = ltFlat; | ||
| 2273 | |||
| 2274 | auto buildDrv = lookupBuiltinBuilder(drv.builder); | ||
| 2275 | if (buildDrv != NULL) | ||
| 2276 | buildDrv(drv, drvPath); | ||
| 2277 | else | ||
| 2278 | throw Error(format("unsupported builtin function '%1%'") % string(drv.builder, 8)); | ||
| 2279 | _exit(0); | ||
| 2280 | } catch (std::exception & e) { | ||
| 2281 | writeFull(STDERR_FILENO, "error: " + string(e.what()) + "\n"); | ||
| 2282 | _exit(1); | ||
| 2283 | } | ||
| 2284 | } | ||
| 2285 | |||
| 2258 | /* Fill in the arguments. */ | 2286 | /* Fill in the arguments. */ |
| 2259 | Strings args; | 2287 | Strings args; |
| 2260 | string builderBasename = baseNameOf(drv.builder); | 2288 | string builderBasename = baseNameOf(drv.builder); |
| @@ -2262,12 +2290,6 @@ void DerivationGoal::runChild() | |||
| 2262 | foreach (Strings::iterator, i, drv.args) | 2290 | foreach (Strings::iterator, i, drv.args) |
| 2263 | args.push_back(rewriteHashes(*i, rewritesToTmp)); | 2291 | args.push_back(rewriteHashes(*i, rewritesToTmp)); |
| 2264 | 2292 | ||
| 2265 | restoreSIGPIPE(); | ||
| 2266 | |||
| 2267 | /* Indicate that we managed to set up the build environment. */ | ||
| 2268 | writeFull(STDERR_FILENO, "\n"); | ||
| 2269 | |||
| 2270 | /* Execute the program. This should not return. */ | ||
| 2271 | execve(drv.builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); | 2293 | execve(drv.builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); |
| 2272 | 2294 | ||
| 2273 | throw SysError(format("executing `%1%'") % drv.builder); | 2295 | throw SysError(format("executing `%1%'") % drv.builder); |
diff --git a/nix/libstore/builtins.cc b/nix/libstore/builtins.cc new file mode 100644 index 00000000000..605e44079a1 --- /dev/null +++ b/nix/libstore/builtins.cc | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /* GNU Guix --- Functional package management for GNU | ||
| 2 | Copyright (C) 2016 Ludovic Courtès <ludo@gnu.org> | ||
| 3 | |||
| 4 | This file is part of GNU Guix. | ||
| 5 | |||
| 6 | GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 18 | |||
| 19 | #include <builtins.hh> | ||
| 20 | #include <util.hh> | ||
| 21 | #include <globals.hh> | ||
| 22 | |||
| 23 | #include <unistd.h> | ||
| 24 | |||
| 25 | namespace nix { | ||
| 26 | |||
| 27 | static void builtinDownload(const Derivation &drv, | ||
| 28 | const std::string &drvPath) | ||
| 29 | { | ||
| 30 | /* Invoke 'guix perform-download'. */ | ||
| 31 | Strings args; | ||
| 32 | args.push_back("perform-download"); | ||
| 33 | args.push_back(drvPath); | ||
| 34 | |||
| 35 | /* Close all other file descriptors. */ | ||
| 36 | closeMostFDs(set<int>()); | ||
| 37 | |||
| 38 | const char *const argv[] = { "download", drvPath.c_str(), NULL }; | ||
| 39 | |||
| 40 | /* XXX: Hack our way to use the 'download' script from 'LIBEXECDIR/guix' | ||
| 41 | or just 'LIBEXECDIR', depending on whether we're running uninstalled or | ||
| 42 | not. */ | ||
| 43 | const string subdir = getenv("GUIX_UNINSTALLED") != NULL | ||
| 44 | ? "" : "/guix"; | ||
| 45 | |||
| 46 | const string program = settings.nixLibexecDir + subdir + "/download"; | ||
| 47 | execv(program.c_str(), (char *const *) argv); | ||
| 48 | |||
| 49 | throw SysError(format("failed to run download program '%1%'") % program); | ||
| 50 | } | ||
| 51 | |||
| 52 | static const std::map<std::string, derivationBuilder> builtins = | ||
| 53 | { | ||
| 54 | { "download", builtinDownload } | ||
| 55 | }; | ||
| 56 | |||
| 57 | derivationBuilder lookupBuiltinBuilder(const std::string & name) | ||
| 58 | { | ||
| 59 | if (name.substr(0, 8) == "builtin:") | ||
| 60 | { | ||
| 61 | auto realName = name.substr(8); | ||
| 62 | auto builder = builtins.find(realName); | ||
| 63 | return builder == builtins.end() ? NULL : builder->second; | ||
| 64 | } | ||
| 65 | else | ||
| 66 | return NULL; | ||
| 67 | } | ||
| 68 | |||
| 69 | } | ||
diff --git a/nix/libstore/builtins.hh b/nix/libstore/builtins.hh new file mode 100644 index 00000000000..0c6db651ab1 --- /dev/null +++ b/nix/libstore/builtins.hh | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* GNU Guix --- Functional package management for GNU | ||
| 2 | Copyright (C) 2016 Ludovic Courtès <ludo@gnu.org> | ||
| 3 | |||
| 4 | This file is part of GNU Guix. | ||
| 5 | |||
| 6 | GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 18 | |||
| 19 | /* Interface to built-in derivation builders. */ | ||
| 20 | |||
| 21 | #pragma once | ||
| 22 | |||
| 23 | #include <derivations.hh> | ||
| 24 | #include <map> | ||
| 25 | #include <string> | ||
| 26 | |||
| 27 | namespace nix { | ||
| 28 | |||
| 29 | inline bool isBuiltin(const Derivation & drv) | ||
| 30 | { | ||
| 31 | return string(drv.builder, 0, 8) == "builtin:"; | ||
| 32 | } | ||
| 33 | |||
| 34 | /* Build DRV, which lives at DRVPATH. */ | ||
| 35 | typedef void (*derivationBuilder) (const Derivation &drv, | ||
| 36 | const std::string &drvPath); | ||
| 37 | |||
| 38 | /* Return the built-in builder called BUILDER, or NULL if none was | ||
| 39 | found. */ | ||
| 40 | derivationBuilder lookupBuiltinBuilder(const std::string &builder); | ||
| 41 | } | ||
diff --git a/nix/local.mk b/nix/local.mk index c666edd0332..86ef7695492 100644 --- a/nix/local.mk +++ b/nix/local.mk | |||
| @@ -87,6 +87,7 @@ libstore_a_SOURCES = \ | |||
| 87 | %D%/libstore/build.cc \ | 87 | %D%/libstore/build.cc \ |
| 88 | %D%/libstore/pathlocks.cc \ | 88 | %D%/libstore/pathlocks.cc \ |
| 89 | %D%/libstore/derivations.cc \ | 89 | %D%/libstore/derivations.cc \ |
| 90 | %D%/libstore/builtins.cc \ | ||
| 90 | %D%/libstore/sqlite.cc | 91 | %D%/libstore/sqlite.cc |
| 91 | 92 | ||
| 92 | libstore_headers = \ | 93 | libstore_headers = \ |
| @@ -98,6 +99,7 @@ libstore_headers = \ | |||
| 98 | %D%/libstore/misc.hh \ | 99 | %D%/libstore/misc.hh \ |
| 99 | %D%/libstore/local-store.hh \ | 100 | %D%/libstore/local-store.hh \ |
| 100 | %D%/libstore/sqlite.hh \ | 101 | %D%/libstore/sqlite.hh \ |
| 102 | %D%/libstore/builtins.hh \ | ||
| 101 | %D%/libstore/store-api.hh | 103 | %D%/libstore/store-api.hh |
| 102 | 104 | ||
| 103 | libstore_a_CPPFLAGS = \ | 105 | libstore_a_CPPFLAGS = \ |
| @@ -166,7 +168,8 @@ noinst_HEADERS = \ | |||
| 166 | 168 | ||
| 167 | nodist_pkglibexec_SCRIPTS = \ | 169 | nodist_pkglibexec_SCRIPTS = \ |
| 168 | %D%/scripts/list-runtime-roots \ | 170 | %D%/scripts/list-runtime-roots \ |
| 169 | %D%/scripts/substitute | 171 | %D%/scripts/substitute \ |
| 172 | %D%/scripts/download | ||
| 170 | 173 | ||
| 171 | if BUILD_DAEMON_OFFLOAD | 174 | if BUILD_DAEMON_OFFLOAD |
| 172 | 175 | ||
diff --git a/nix/scripts/download.in b/nix/scripts/download.in new file mode 100644 index 00000000000..4d7088a9933 --- /dev/null +++ b/nix/scripts/download.in | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #!@SHELL@ | ||
| 2 | # A shorthand for "guix perform-download", for use by the daemon. | ||
| 3 | |||
| 4 | if test "x$GUIX_UNINSTALLED" = "x" | ||
| 5 | then | ||
| 6 | prefix="@prefix@" | ||
| 7 | exec_prefix="@exec_prefix@" | ||
| 8 | exec "@bindir@/guix" perform-download "$@" | ||
| 9 | else | ||
| 10 | exec guix perform-download "$@" | ||
| 11 | fi | ||
diff --git a/tests/derivations.scm b/tests/derivations.scm index d8553b223eb..449fb47832d 100644 --- a/tests/derivations.scm +++ b/tests/derivations.scm | |||
| @@ -16,6 +16,8 @@ | |||
| 16 | ;;; You should have received a copy of the GNU General Public License | 16 | ;;; You should have received a copy of the GNU General Public License |
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. |
| 18 | 18 | ||
| 19 | (unsetenv "http_proxy") | ||
| 20 | |||
| 19 | (define-module (test-derivations) | 21 | (define-module (test-derivations) |
| 20 | #:use-module (guix derivations) | 22 | #:use-module (guix derivations) |
| 21 | #:use-module (guix grafts) | 23 | #:use-module (guix grafts) |
| @@ -24,6 +26,7 @@ | |||
| 24 | #:use-module (guix hash) | 26 | #:use-module (guix hash) |
| 25 | #:use-module (guix base32) | 27 | #:use-module (guix base32) |
| 26 | #:use-module (guix tests) | 28 | #:use-module (guix tests) |
| 29 | #:use-module (guix tests http) | ||
| 27 | #:use-module ((guix packages) #:select (package-derivation base32)) | 30 | #:use-module ((guix packages) #:select (package-derivation base32)) |
| 28 | #:use-module ((guix build utils) #:select (executable-file?)) | 31 | #:use-module ((guix build utils) #:select (executable-file?)) |
| 29 | #:use-module ((gnu packages) #:select (search-bootstrap-binary)) | 32 | #:use-module ((gnu packages) #:select (search-bootstrap-binary)) |
| @@ -75,6 +78,9 @@ | |||
| 75 | (lambda (e1 e2) | 78 | (lambda (e1 e2) |
| 76 | (string<? (car e1) (car e2))))) | 79 | (string<? (car e1) (car e2))))) |
| 77 | 80 | ||
| 81 | ;; Avoid collisions with other tests. | ||
| 82 | (%http-server-port 10500) | ||
| 83 | |||
| 78 | 84 | ||
| 79 | (test-begin "derivations") | 85 | (test-begin "derivations") |
| 80 | 86 | ||
| @@ -205,6 +211,70 @@ | |||
| 205 | (= (stat:ino (lstat file1)) | 211 | (= (stat:ino (lstat file1)) |
| 206 | (stat:ino (lstat file2)))))))) | 212 | (stat:ino (lstat file2)))))))) |
| 207 | 213 | ||
| 214 | (test-assert "unknown built-in builder" | ||
| 215 | (let ((drv (derivation %store "ohoh" "builtin:does-not-exist" '()))) | ||
| 216 | (guard (c ((nix-protocol-error? c) | ||
| 217 | (string-contains (nix-protocol-error-message c) "failed"))) | ||
| 218 | (build-derivations %store (list drv)) | ||
| 219 | #f))) | ||
| 220 | |||
| 221 | (unless (force %http-server-socket) | ||
| 222 | (test-skip 1)) | ||
| 223 | (test-assert "'download' built-in builder" | ||
| 224 | (let ((text (random-text))) | ||
| 225 | (with-http-server 200 text | ||
| 226 | (let* ((drv (derivation %store "world" | ||
| 227 | "builtin:download" '() | ||
| 228 | #:env-vars `(("url" | ||
| 229 | . ,(object->string (%local-url)))) | ||
| 230 | #:hash-algo 'sha256 | ||
| 231 | #:hash (sha256 (string->utf8 text))))) | ||
| 232 | (and (build-derivations %store (list drv)) | ||
| 233 | (string=? (call-with-input-file (derivation->output-path drv) | ||
| 234 | get-string-all) | ||
| 235 | text)))))) | ||
| 236 | |||
| 237 | (unless (force %http-server-socket) | ||
| 238 | (test-skip 1)) | ||
| 239 | (test-assert "'download' built-in builder, invalid hash" | ||
| 240 | (with-http-server 200 "hello, world!" | ||
| 241 | (let* ((drv (derivation %store "world" | ||
| 242 | "builtin:download" '() | ||
| 243 | #:env-vars `(("url" | ||
| 244 | . ,(object->string (%local-url)))) | ||
| 245 | #:hash-algo 'sha256 | ||
| 246 | #:hash (sha256 (random-bytevector 100))))) ;wrong | ||
| 247 | (guard (c ((nix-protocol-error? c) | ||
| 248 | (string-contains (nix-protocol-error-message c) "failed"))) | ||
| 249 | (build-derivations %store (list drv)) | ||
| 250 | #f)))) | ||
| 251 | |||
| 252 | (unless (force %http-server-socket) | ||
| 253 | (test-skip 1)) | ||
| 254 | (test-assert "'download' built-in builder, not found" | ||
| 255 | (with-http-server 404 "not found" | ||
| 256 | (let* ((drv (derivation %store "will-never-be-found" | ||
| 257 | "builtin:download" '() | ||
| 258 | #:env-vars `(("url" | ||
| 259 | . ,(object->string (%local-url)))) | ||
| 260 | #:hash-algo 'sha256 | ||
| 261 | #:hash (sha256 (random-bytevector 100))))) | ||
| 262 | (guard (c ((nix-protocol-error? c) | ||
| 263 | (string-contains (nix-protocol-error-message (pk c)) "failed"))) | ||
| 264 | (build-derivations %store (list drv)) | ||
| 265 | #f)))) | ||
| 266 | |||
| 267 | (test-assert "'download' built-in builder, not fixed-output" | ||
| 268 | (let* ((source (add-text-to-store %store "hello" "hi!")) | ||
| 269 | (url (string-append "file://" source)) | ||
| 270 | (drv (derivation %store "world" | ||
| 271 | "builtin:download" '() | ||
| 272 | #:env-vars `(("url" . ,(object->string url)))))) | ||
| 273 | (guard (c ((nix-protocol-error? c) | ||
| 274 | (string-contains (nix-protocol-error-message c) "failed"))) | ||
| 275 | (build-derivations %store (list drv)) | ||
| 276 | #f))) | ||
| 277 | |||
| 208 | (test-equal "derivation-name" | 278 | (test-equal "derivation-name" |
| 209 | "foo-0.0" | 279 | "foo-0.0" |
| 210 | (let ((drv (derivation %store "foo-0.0" %bash '()))) | 280 | (let ((drv (derivation %store "foo-0.0" %bash '()))) |
