;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org>
;;; Copyright © 2019, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2020 Florian Pelz <pelzflorian@pelzflorian.de>
add-to-store
add-file-tree-to-store
binary-file
+ with-build-handler
build-things
build
query-failed-paths
(hash-set! cache tree result)
result)))))
+(define current-build-prompt
+ ;; When true, this is the prompt to abort to when 'build-things' is called.
+ (make-parameter #f))
+
+(define (call-with-build-handler handler thunk)
+ "Register HANDLER as a \"build handler\" and invoke THUNK."
+ (define tag
+ (make-prompt-tag "build handler"))
+
+ (parameterize ((current-build-prompt tag))
+ (call-with-prompt tag
+ thunk
+ (lambda (k . args)
+ ;; Since HANDLER may call K, which in turn may call 'build-things'
+ ;; again, reinstate a prompt (thus, it's not a tail call.)
+ (call-with-build-handler handler
+ (lambda ()
+ (apply handler k args)))))))
+
+(define (invoke-build-handler store things mode)
+ "Abort to 'current-build-prompt' if it is set."
+ (or (not (current-build-prompt))
+ (abort-to-prompt (current-build-prompt) store things mode)))
+
+(define-syntax-rule (with-build-handler handler exp ...)
+ "Register HANDLER as a \"build handler\" and invoke THUNK. When
+'build-things' is called within the dynamic extent of the call to THUNK,
+HANDLER is invoked like so:
+
+ (HANDLER CONTINUE STORE THINGS MODE)
+
+where CONTINUE is the continuation, and the remaining arguments are those that
+were passed to 'build-things'.
+
+Build handlers are useful to announce a build plan with 'show-what-to-build'
+and to implement dry runs (by not invoking CONTINUE) in a way that gracefully
+deals with \"dynamic dependencies\" such as grafts---derivations that depend
+on the build output of a previous derivation."
+ (call-with-build-handler handler (lambda () exp ...)))
+
(define build-things
(let ((build (operation (build-things (string-list things)
(integer mode))
that are not derivations can only be substituted and not built locally.
Alternately, an element of THING can be a derivation/output name pair, in
which case the daemon will attempt to substitute just the requested output of
-the derivation. Return #t on success."
- (let ((things (map (match-lambda
- ((drv . output) (string-append drv "!" output))
- (thing thing))
- things)))
- (parameterize ((current-store-protocol-version
- (store-connection-version store)))
- (if (>= (store-connection-minor-version store) 15)
- (build store things mode)
- (if (= mode (build-mode normal))
- (build/old store things)
- (raise (condition (&store-protocol-error
- (message "unsupported build mode")
- (status 1)))))))))))
+the derivation. Return #t on success.
+
+When a handler is installed with 'with-build-handler', it is called any time
+'build-things' is called."
+ (or (not (invoke-build-handler store things mode))
+ (let ((things (map (match-lambda
+ ((drv . output) (string-append drv "!" output))
+ (thing thing))
+ things)))
+ (parameterize ((current-store-protocol-version
+ (store-connection-version store)))
+ (if (>= (store-connection-minor-version store) 15)
+ (build store things mode)
+ (if (= mode (build-mode normal))
+ (build/old store things)
+ (raise (condition (&store-protocol-error
+ (message "unsupported build mode")
+ (status 1))))))))))))
(define-operation (add-temp-root (store-path path))
"Make PATH a temporary root for the duration of the current session.
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
(equal? (valid-derivers %store o)
(list (derivation-file-name d))))))
+(test-equal "with-build-handler"
+ 'success
+ (let* ((b (add-text-to-store %store "build" "echo $foo > $out" '()))
+ (s (add-to-store %store "bash" #t "sha256"
+ (search-bootstrap-binary "bash"
+ (%current-system))))
+ (d1 (derivation %store "the-thing"
+ s `("-e" ,b)
+ #:env-vars `(("foo" . ,(random-text)))
+ #:sources (list b s)))
+ (d2 (derivation %store "the-thing"
+ s `("-e" ,b)
+ #:env-vars `(("foo" . ,(random-text))
+ ("bar" . "baz"))
+ #:sources (list b s)))
+ (o1 (derivation->output-path d1))
+ (o2 (derivation->output-path d2)))
+ (with-build-handler
+ (let ((counter 0))
+ (lambda (continue store things mode)
+ (match things
+ ((drv)
+ (set! counter (+ 1 counter))
+ (if (string=? drv (derivation-file-name d1))
+ (continue #t)
+ (and (string=? drv (derivation-file-name d2))
+ (= counter 2)
+ 'success))))))
+ (build-derivations %store (list d1))
+ (build-derivations %store (list d2))
+ 'fail)))
+
(test-assert "topologically-sorted, one item"
(let* ((a (add-text-to-store %store "a" "a"))
(b (add-text-to-store %store "b" "b" (list a)))