From 9b5364a3afb03414bd6e3ded2fbfdacabe4e8870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Wed, 11 Jan 2017 17:06:31 +0100 Subject: [PATCH] daemon: Allow check builds of 'builtin:download' derivations. Fixes . Reported by Leo Famulari . * nix/libstore/build.cc (DerivationGoal::runChild): In the 'isBuiltin' case, check whether DRV's output is in 'redirectedOutputs', and pass an 'output' argument to the built-in builder. (DerivationGoal::addHashRewrite): Add 'printMsg' call. * nix/libstore/builtins.hh (derivationBuilder): Add 'output' parameter. * nix/libstore/builtins.cc (builtinDownload): Likewise. Add OUTPUT to ARGV. * guix/scripts/perform-download.scm (perform-download): Add 'output' parameter. (guix-perform-download): Adjust 'match' clauses accordingly. * tests/derivations.scm ("'download' built-in builder, check mode"): New test. --- guix/scripts/perform-download.scm | 21 +++++++++++++-------- nix/libstore/build.cc | 15 +++++++++++++-- nix/libstore/builtins.cc | 10 +++++++--- nix/libstore/builtins.hh | 5 +++-- tests/derivations.scm | 27 ++++++++++++++++++++++++++- 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/guix/scripts/perform-download.scm b/guix/scripts/perform-download.scm index 0d2e7089aa..58a7377141 100644 --- a/guix/scripts/perform-download.scm +++ b/guix/scripts/perform-download.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2016 Ludovic Courtès +;;; Copyright © 2016, 2017 Ludovic Courtès ;;; ;;; This file is part of GNU Guix. ;;; @@ -19,7 +19,7 @@ (define-module (guix scripts perform-download) #:use-module (guix ui) #:use-module (guix derivations) - #:use-module ((guix store) #:select (derivation-path?)) + #:use-module ((guix store) #:select (derivation-path? store-path?)) #:use-module (guix build download) #:use-module (ice-9 match) #:export (guix-perform-download)) @@ -41,10 +41,13 @@ (define %user-module (module-use! module (resolve-interface '(guix base32))) module)) -(define (perform-download drv) - "Perform the download described by DRV, a fixed-output derivation." +(define (perform-download drv output) + "Perform the download described by DRV, a fixed-output derivation, to +OUTPUT. + +Note: We don't read the value of 'out' in DRV since the actual output is +different from that when we're doing a 'bmCheck' or 'bmRepair' build." (derivation-let drv ((url "url") - (output "out") (executable "executable") (mirrors "mirrors") (content-addressed-mirrors "content-addressed-mirrors")) @@ -93,18 +96,20 @@ (define (guix-perform-download . args) ." (with-error-handling (match args - (((? derivation-path? drv)) + (((? derivation-path? drv) (? store-path? output)) ;; This program must be invoked by guix-daemon under an unprivileged ;; UID to prevent things downloading from 'file:///etc/shadow' or ;; arbitrary code execution via the content-addressed mirror ;; procedures. (That means we exclude users who did not pass ;; '--build-users-group'.) (assert-low-privileges) - (perform-download (call-with-input-file drv read-derivation))) + (perform-download (call-with-input-file drv read-derivation) + output)) (("--version") (show-version-and-exit)) (x - (leave (_ "fixed-output derivation name expected~%")))))) + (leave + (_ "fixed-output derivation and output file name expected~%")))))) ;; Local Variables: ;; eval: (put 'derivation-let 'scheme-indent-function 2) diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc index 38048ceebc..cebc404d1c 100644 --- a/nix/libstore/build.cc +++ b/nix/libstore/build.cc @@ -2271,8 +2271,17 @@ void DerivationGoal::runChild() logType = ltFlat; auto buildDrv = lookupBuiltinBuilder(drv.builder); - if (buildDrv != NULL) - buildDrv(drv, drvPath); + if (buildDrv != NULL) { + /* Check what the output file name is. When doing a + 'bmCheck' build, the output file name is different from + that specified in DRV due to hash rewriting. */ + Path output = drv.outputs["out"].path; + auto redirected = redirectedOutputs.find(output); + if (redirected != redirectedOutputs.end()) + output = redirected->second; + + buildDrv(drv, drvPath, output); + } else throw Error(format("unsupported builtin function '%1%'") % string(drv.builder, 8)); _exit(0); @@ -2742,6 +2751,8 @@ Path DerivationGoal::addHashRewrite(const Path & path) rewritesToTmp[h1] = h2; rewritesFromTmp[h2] = h1; redirectedOutputs[path] = p; + printMsg(lvlChatty, format("output '%1%' redirected to '%2%'") + % path % p); return p; } diff --git a/nix/libstore/builtins.cc b/nix/libstore/builtins.cc index 32af767dc4..7ed75e5079 100644 --- a/nix/libstore/builtins.cc +++ b/nix/libstore/builtins.cc @@ -1,5 +1,5 @@ /* GNU Guix --- Functional package management for GNU - Copyright (C) 2016 Ludovic Courtès + Copyright (C) 2016, 2017 Ludovic Courtès This file is part of GNU Guix. @@ -25,7 +25,8 @@ namespace nix { static void builtinDownload(const Derivation &drv, - const std::string &drvPath) + const std::string &drvPath, + const std::string &output) { /* Invoke 'guix perform-download'. */ Strings args; @@ -35,7 +36,10 @@ static void builtinDownload(const Derivation &drv, /* Close all other file descriptors. */ closeMostFDs(set()); - const char *const argv[] = { "download", drvPath.c_str(), NULL }; + const char *const argv[] = + { + "download", drvPath.c_str(), output.c_str(), NULL + }; /* XXX: Hack our way to use the 'download' script from 'LIBEXECDIR/guix' or just 'LIBEXECDIR', depending on whether we're running uninstalled or diff --git a/nix/libstore/builtins.hh b/nix/libstore/builtins.hh index 79171fcb6c..396ea14ebc 100644 --- a/nix/libstore/builtins.hh +++ b/nix/libstore/builtins.hh @@ -1,5 +1,5 @@ /* GNU Guix --- Functional package management for GNU - Copyright (C) 2016 Ludovic Courtès + Copyright (C) 2016, 2017 Ludovic Courtès This file is part of GNU Guix. @@ -33,7 +33,8 @@ namespace nix { /* Build DRV, which lives at DRVPATH. */ typedef void (*derivationBuilder) (const Derivation &drv, - const std::string &drvPath); + const std::string &drvPath, + const std::string &output); /* Return the built-in builder called BUILDER, or NULL if none was found. */ diff --git a/tests/derivations.scm b/tests/derivations.scm index 2b5aa796d4..3fbfec3793 100644 --- a/tests/derivations.scm +++ b/tests/derivations.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès +;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès ;;; ;;; This file is part of GNU Guix. ;;; @@ -279,6 +279,27 @@ (define prefix-len (string-length dir)) (build-derivations %store (list drv)) #f))) +(unless (force %http-server-socket) + (test-skip 1)) +(test-assert "'download' built-in builder, check mode" + ;; Make sure rebuilding the 'builtin:download' derivation in check mode + ;; works. See . + (let* ((text (random-text)) + (drv (derivation %store "world" + "builtin:download" '() + #:env-vars `(("url" + . ,(object->string (%local-url)))) + #:hash-algo 'sha256 + #:hash (sha256 (string->utf8 text))))) + (and (with-http-server 200 text + (build-derivations %store (list drv))) + (with-http-server 200 text + (build-derivations %store (list drv) + (build-mode check))) + (string=? (call-with-input-file (derivation->output-path drv) + get-string-all) + text)))) + (test-equal "derivation-name" "foo-0.0" (let ((drv (derivation %store "foo-0.0" %bash '()))) @@ -1109,3 +1130,7 @@ (define (deps path . deps) (call-with-input-file out get-string-all)))) (test-end) + +;; Local Variables: +;; eval: (put 'with-http-server 'scheme-indent-function 2) +;; End: