summaryrefslogtreecommitdiff
path: root/guix/store/database.scm
diff options
context:
space:
mode:
Diffstat (limited to 'guix/store/database.scm')
-rw-r--r--guix/store/database.scm79
1 files changed, 78 insertions, 1 deletions
diff --git a/guix/store/database.scm b/guix/store/database.scm
index 22f411597a..a659dea1cf 100644
--- a/guix/store/database.scm
+++ b/guix/store/database.scm
@@ -36,6 +36,7 @@
#:use-module (srfi srfi-26)
#:use-module (rnrs io ports)
#:use-module (ice-9 match)
+ #:use-module (ice-9 vlist)
#:use-module (system foreign)
#:export (sql-schema
%default-database-file
@@ -46,7 +47,10 @@
register-items
registered-derivation-outputs
%epoch
- reset-timestamps))
+ reset-timestamps
+ outputs-exist?
+ file-closure
+ all-transitive-inputs))
;;; Code for working with the store database directly.
@@ -403,3 +407,76 @@ it')."
(register db item)
(report))
items)))))))))
+
+(define output-path-id-sql
+ "SELECT id FROM ValidPaths WHERE path IN (SELECT path FROM DerivationOutputs
+WHERE DerivationOutputs.id = :id AND drv IN (SELECT id FROM ValidPaths WHERE
+path = :drvpath))")
+
+(define* (outputs-exist? drv-path outputs
+ #:optional (database %default-database-file))
+ "Determine whether all output labels in OUTPUTS exist as built outputs of
+DRV-PATH."
+ (with-database database db
+ (let ((stmt (sqlite-prepare db output-path-id-sql)))
+ (sqlite-bind-arguments stmt #:drvpath drv-path)
+ (let ((result (every (lambda (out-id)
+ (sqlite-reset stmt)
+ (sqlite-bind-arguments stmt #:id out-id)
+ (sqlite-step stmt))
+ outputs)))
+ (sqlite-finalize stmt)
+ result))))
+
+(define references-sql
+ "SELECT path FROM ValidPaths WHERE id IN (SELECT reference FROM Refs WHERE
+referrer IN (SELECT id FROM ValidPaths WHERE path = :path))")
+
+(define* (file-closure path #:key
+ (database %default-database-file)
+ (list-so-far vlist-null))
+ "Return a vlist containing the store paths referenced by PATH, the store
+paths referenced by those paths, and so on."
+ (with-database database db
+ (let ((get-references (sqlite-prepare db references-sql)))
+ ;; to make it possible to go depth-first we need to get all the
+ ;; references of an item first or we'll have re-entrancy issues with
+ ;; the get-references statement.
+ (define (references-of path)
+ ;; There are no problems with resetting an already-reset
+ ;; statement.
+ (sqlite-reset get-references)
+ (sqlite-bind-arguments get-references #:path path)
+ (sqlite-fold (lambda (row prev)
+ (cons (vector-ref row 0) prev))
+ '()
+ get-references))
+
+ (let ((result
+ (let %file-closure ((path path)
+ (references-vlist list-so-far))
+ (if (vhash-assoc path references-vlist)
+ references-vlist
+ (fold %file-closure
+ (vhash-cons path #t references-vlist)
+ (references-of path))))))
+ (sqlite-finalize get-references)
+ result))))
+
+(define (all-input-output-paths drv)
+ "Return a list containing the output paths this derivation's inputs need to
+provide."
+ (apply append (map derivation-input-output-paths
+ (derivation-inputs drv))))
+
+(define (all-transitive-inputs drv)
+ "Produce a list of all inputs and all of their references."
+ (let ((input-paths (all-input-output-paths drv)))
+ (vhash-fold (lambda (key val prev)
+ (cons key prev))
+ '()
+ (fold (lambda (input list-so-far)
+ (file-closure input #:list-so-far list-so-far))
+ vlist-null
+ `(,@(derivation-sources drv)
+ ,@input-paths)))))