unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
From: "Ludovic Courtès" <ludo@gnu.org>
To: 31755@debbugs.gnu.org
Subject: [bug#31755] [PATCH 03/19] store-copy: 'read-reference-graph' returns a list of records.
Date: Fri,  8 Jun 2018 11:34:35 +0200	[thread overview]
Message-ID: <20180608093451.27760-3-ludo@gnu.org> (raw)
In-Reply-To: <20180608093451.27760-1-ludo@gnu.org>

The previous implementation of 'read-reference-graph' was good enough
for many use cases, but it discarded the graph structure, which is
useful information in some cases.

* guix/build/store-copy.scm (<store-info>): New record type.
(read-reference-graph): Rewrite to return a list of <store-info>.
(closure-size, populate-store): Adjust accordingly.
* gnu/services/base.scm (references-file): Adjust accordingly.
* gnu/system/vm.scm (system-docker-image): Likewise.
* guix/scripts/pack.scm (squashfs-image, docker-image): Likewise.
* tests/gexp.scm ("gexp->derivation #:references-graphs"): Likewise.
---
 gnu/services/base.scm     |   5 +-
 gnu/system/vm.scm         |   6 +-
 guix/build/store-copy.scm | 120 +++++++++++++++++++++++++++++++++-----
 guix/scripts/pack.scm     |  10 ++--
 tests/gexp.scm            |  17 ++++--
 5 files changed, 128 insertions(+), 30 deletions(-)

diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index b34bb7132..68411439d 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -1592,8 +1592,9 @@ failed to register hydra.gnu.org public key: ~a~%" status))))))))
 
                            (call-with-output-file #$output
                              (lambda (port)
-                               (write (call-with-input-file "graph"
-                                        read-reference-graph)
+                               (write (map store-info-item
+                                           (call-with-input-file "graph"
+                                             read-reference-graph))
                                       port)))))
                      #:options `(#:local-build? #f
                                  #:references-graphs (("graph" ,item))))
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index 8cfbda226..2ffab15dd 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -455,8 +455,10 @@ should set REGISTER-CLOSURES? to #f."
                 (build-docker-image
                  (string-append "/xchg/" #$name) ;; The output file.
                  (cons* root-directory
-                        (call-with-input-file (string-append "/xchg/" #$graph)
-                          read-reference-graph))
+                        (map store-info-item
+                             (call-with-input-file
+                                 (string-append "/xchg/" #$graph)
+                               read-reference-graph)))
                  #$os-drv
                  #:compressor '(#+(file-append gzip "/bin/gzip") "-9n")
                  #:creation-time (make-time time-utc 0 1)
diff --git a/guix/build/store-copy.scm b/guix/build/store-copy.scm
index fe2eb6f69..bad1c09cb 100644
--- a/guix/build/store-copy.scm
+++ b/guix/build/store-copy.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2017 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -18,10 +18,21 @@
 
 (define-module (guix build store-copy)
   #:use-module (guix build utils)
+  #:use-module (guix sets)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-9)
+  #:use-module (srfi srfi-26)
+  #:use-module (ice-9 match)
   #:use-module (ice-9 rdelim)
   #:use-module (ice-9 ftw)
-  #:export (read-reference-graph
+  #:use-module (ice-9 vlist)
+  #:export (store-info?
+            store-info-item
+            store-info-deriver
+            store-info-references
+
+            read-reference-graph
+
             closure-size
             populate-store))
 
@@ -34,19 +45,94 @@
 ;;;
 ;;; Code:
 
+;; Information about a store item as produced by #:references-graphs.
+(define-record-type <store-info>
+  (store-info item deriver references)
+  store-info?
+  (item        store-info-item)                   ;string
+  (deriver     store-info-deriver)                ;#f | string
+  (references  store-info-references))            ;?
+
+;; TODO: Factorize with that in (guix store).
+(define (topological-sort nodes edges)
+  "Return NODES in topological order according to EDGES.  EDGES must be a
+one-argument procedure that takes a node and returns the nodes it is connected
+to."
+  (define (traverse)
+    ;; Do a simple depth-first traversal of all of PATHS.
+    (let loop ((nodes nodes)
+               (visited (setq))
+               (result '()))
+      (match nodes
+        ((head tail ...)
+         (if (set-contains? visited head)
+             (loop tail visited result)
+             (call-with-values
+                 (lambda ()
+                   (loop (edges head)
+                         (set-insert head visited)
+                         result))
+               (lambda (visited result)
+                 (loop tail visited (cons head result))))))
+        (()
+         (values visited result)))))
+
+  (call-with-values traverse
+    (lambda (_ result)
+      (reverse result))))
+
 (define (read-reference-graph port)
-  "Return a list of store paths from the reference graph at PORT.
-The data at PORT is the format produced by #:references-graphs."
-  (let loop ((line   (read-line port))
-             (result '()))
-    (cond ((eof-object? line)
-           (delete-duplicates result))
-          ((string-prefix? "/" line)
-           (loop (read-line port)
-                 (cons line result)))
-          (else
-           (loop (read-line port)
-                 result)))))
+  "Read the reference graph as produced by #:references-graphs from PORT and
+return it as a list of <store-info> records in topological order--i.e., leaves
+come first.  IOW, store items in the resulting list can be registered in the
+order in which they appear.
+
+The reference graph format consists of sequences of lines like this:
+
+     FILE
+     DERIVER
+     NUMBER-OF-REFERENCES
+     REF1
+     ...
+     REFN
+
+It is meant as an internal format."
+  (let loop ((result '())
+             (table vlist-null)
+             (referrers vlist-null))
+    (match (read-line port)
+      ((? eof-object?)
+       ;; 'guix-daemon' gives us something that's in "reverse topological
+       ;; order"--i.e., leaves (items with zero references) come last.  Here
+       ;; we compute the topological order that we want: leaves come first.
+       (let ((unreferenced? (lambda (item)
+                              (let ((referrers (vhash-fold* cons '()
+                                                            (store-info-item item)
+                                                            referrers)))
+                                (or (null? referrers)
+                                    (equal? (list item) referrers))))))
+         (topological-sort (filter unreferenced? result)
+                           (lambda (item)
+                             (map (lambda (item)
+                                    (match (vhash-assoc item table)
+                                      ((_ . node) node)))
+                                  (store-info-references item))))))
+      (item
+       (let* ((deriver (match (read-line port)
+                         ("" #f)
+                         (line line)))
+              (count   (string->number (read-line port)))
+              (refs    (unfold-right (cut >= <> count)
+                                     (lambda (n)
+                                       (read-line port))
+                                     1+
+                                     0))
+              (item    (store-info item deriver refs)))
+         (loop (cons item result)
+               (vhash-cons (store-info-item item) item table)
+               (fold (cut vhash-cons <> item <>)
+                     referrers
+                     refs)))))))
 
 (define (file-size file)
   "Return the size of bytes of FILE, entering it if FILE is a directory."
@@ -72,7 +158,8 @@ The data at PORT is the format produced by #:references-graphs."
   "Return an estimate of the size of the closure described by
 REFERENCE-GRAPHS, a list of reference-graph files."
   (define (graph-from-file file)
-    (call-with-input-file file read-reference-graph))
+    (map store-info-item
+         (call-with-input-file file read-reference-graph)))
 
   (define items
     (delete-duplicates (append-map graph-from-file reference-graphs)))
@@ -88,7 +175,8 @@ REFERENCE-GRAPHS, a list of reference-graph files."
   (define (things-to-copy)
     ;; Return the list of store files to copy to the image.
     (define (graph-from-file file)
-      (call-with-input-file file read-reference-graph))
+      (map store-info-item
+           (call-with-input-file file read-reference-graph)))
 
     (delete-duplicates (append-map graph-from-file reference-graphs)))
 
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index 76729d8e1..78bfd01ef 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -251,8 +251,9 @@ added to the pack."
           ;; ancestor directories and only keeps the basename.  We fix this
           ;; in the following invocations of mksquashfs.
           (apply invoke "mksquashfs"
-                 `(,@(call-with-input-file "profile"
-                       read-reference-graph)
+                 `(,@(map store-info-item
+                          (call-with-input-file "profile"
+                            read-reference-graph))
                    ,#$output
 
                    ;; Do not perform duplicate checking because we
@@ -352,8 +353,9 @@ the image."
             (setenv "PATH" (string-append #$archiver "/bin"))
 
             (build-docker-image #$output
-                                (call-with-input-file "profile"
-                                  read-reference-graph)
+                                (map store-info-item
+                                     (call-with-input-file "profile"
+                                       read-reference-graph))
                                 #$profile
                                 #:system (or #$target (utsname:machine (uname)))
                                 #:symlinks '#$symlinks
diff --git a/tests/gexp.scm b/tests/gexp.scm
index a560adfc5..83fe81154 100644
--- a/tests/gexp.scm
+++ b/tests/gexp.scm
@@ -615,6 +615,7 @@
                                                 `(("graph" ,two))
                                                 #:modules
                                                 '((guix build store-copy)
+                                                  (guix sets)
                                                   (guix build utils))))
                          (ok? (built-derivations (list drv)))
                          (out -> (derivation->output-path drv)))
@@ -815,21 +816,25 @@
        (two (gexp->derivation "two"
                               #~(symlink #$one #$output:chbouib)))
        (build -> (with-imported-modules '((guix build store-copy)
+                                          (guix sets)
                                           (guix build utils))
                    #~(begin
                        (use-modules (guix build store-copy))
                        (with-output-to-file #$output
                          (lambda ()
-                           (write (call-with-input-file "guile"
-                                    read-reference-graph))))
+                           (write (map store-info-item
+                                       (call-with-input-file "guile"
+                                         read-reference-graph)))))
                        (with-output-to-file #$output:one
                          (lambda ()
-                           (write (call-with-input-file "one"
-                                    read-reference-graph))))
+                           (write (map store-info-item
+                                       (call-with-input-file "one"
+                                         read-reference-graph)))))
                        (with-output-to-file #$output:two
                          (lambda ()
-                           (write (call-with-input-file "two"
-                                    read-reference-graph)))))))
+                           (write (map store-info-item
+                                       (call-with-input-file "two"
+                                         read-reference-graph))))))))
        (drv (gexp->derivation "ref-graphs" build
                               #:references-graphs `(("one" ,one)
                                                     ("two" ,two "chbouib")
-- 
2.17.1

  parent reply	other threads:[~2018-06-08  9:36 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-08  9:30 [bug#31755] [PATCH 00/19] Use (guix store database) instead of 'guix-register' Ludovic Courtès
2018-06-08  9:34 ` [bug#31755] [PATCH 01/19] database: 'with-database' can now initialize new databases Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 02/19] database: Fail registration when encountering unregistered references Ludovic Courtès
2018-06-08  9:34   ` Ludovic Courtès [this message]
2018-06-08  9:34   ` [bug#31755] [PATCH 04/19] build: Require Guile-SQLite3 Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 05/19] database: Provide a way to specify the schema location Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 06/19] database: 'register-path' creates the database directory if needed Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 07/19] deduplicate: Fix a couple of thinkos Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 08/19] database: Remove extra SQL parameter in 'update-or-insert' Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 09/19] database: Add #:reset-timestamps? to 'register-path' Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 10/19] database: Replace existing entries in Refs Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 11/19] database: 'reset-timestamps' sets file permissions as well Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 12/19] vm: 'expression->derivation-in-linux-vm' code can now use dlopen Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 13/19] install: Use (guix store database) instead of 'guix-register' Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 14/19] database: 'sqlite-register' takes a database, not a file name Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 15/19] database: Add 'register-items' Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 16/19] install: Use 'reset-timestamps' from (guix store database) Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 17/19] database: Allow for deterministic database construction Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 18/19] store: Remove 'register-path' Ludovic Courtès
2018-06-08  9:34   ` [bug#31755] [PATCH 19/19] Remove 'guix-register' and its traces Ludovic Courtès
2018-06-14  9:17 ` bug#31755: [PATCH 00/19] Use (guix store database) instead of 'guix-register' Ludovic Courtès
     [not found] ` <handler.31755.D31755.15289678758292.notifdone@debbugs.gnu.org>
2018-06-14  9:30   ` [bug#31755] closed (Re: [bug#31755] [PATCH 00/19] Use (guix store database) instead of 'guix-register') Ludovic Courtès

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180608093451.27760-3-ludo@gnu.org \
    --to=ludo@gnu.org \
    --cc=31755@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).