From 286749bd4413bd9994fe2bc06a5596ebb02ea402 Mon Sep 17 00:00:00 2001
From: Pierre Neidhardt <mail@ambrevar.xyz>
Date: Mon, 21 Jan 2019 19:27:51 +0100
Subject: doc: Correct EFI-specific system configuration details.

* doc/guix.texi (Preparing for Installation): /boot/efi is arbitrary.
Mention /boot/efi consistently.
(Proceeding with the Installation): Make it explicit that the EFI mount point
must both be mounted and be specified in the system configuration.
---
 doc/guix.texi | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

(limited to 'doc')

diff --git a/doc/guix.texi b/doc/guix.texi
index 782c681cf1..b8071d17de 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -2106,8 +2106,8 @@ manual}).
 @cindex UEFI, installation
 @cindex ESP, EFI system partition
 If you instead wish to use EFI-based GRUB, a FAT32 @dfn{EFI System Partition}
-(ESP) is required.  This partition should be mounted at @file{/boot/efi} and
-must have the @code{esp} flag set.  E.g., for @command{parted}:
+(ESP) is required.  This partition can be mounted at @file{/boot/efi} for
+instance and must have the @code{esp} flag set.  E.g., for @command{parted}:
 
 @example
 parted /dev/sda set 1 esp on
@@ -2169,9 +2169,9 @@ mount LABEL=my-root /mnt
 @end example
 
 Also mount any other file systems you would like to use on the target
-system relative to this path.  If you have @file{/boot} on a separate
-partition for example, mount it at @file{/mnt/boot} now so it is found
-by @code{guix system init} afterwards.
+system relative to this path.  If you have opted for @file{/boot/efi} as an
+EFI mount point for example, mount it at @file{/mnt/boot/efi} now so it is
+found by @code{guix system init} afterwards.
 
 Finally, if you plan to use one or more swap partitions (@pxref{Memory
 Concepts, swap space,, libc, The GNU C Library Reference Manual}), make
@@ -2253,8 +2253,9 @@ you want to install GRUB on.  It should mention @code{grub-bootloader} if
 you are installing GRUB in the legacy way, or @code{grub-efi-bootloader}
 for newer UEFI systems.  For legacy systems, the @code{target} field
 names a device, like @code{/dev/sda}; for UEFI systems it names a path
-to a mounted EFI partition, like @code{/boot/efi}, and do make sure the
-path is actually mounted.
+to a mounted EFI partition, like @code{/boot/efi}; do make sure the path is
+currently mounted and a @code{file-sytem} entry is specified in your
+configuration.
 
 @item
 Be sure that your file system labels match the value of their respective
-- 
cgit v1.2.3


From b1c4dafbf1428b5e004c2c1c173eaa8b7a73ed39 Mon Sep 17 00:00:00 2001
From: Pierre Neidhardt <mail@ambrevar.xyz>
Date: Mon, 21 Jan 2019 20:24:44 +0100
Subject: doc: Replace some cons* with beginner-friendly (append (list ...)).

* doc/guix.texi (Base Services): Do it.
---
 doc/guix.texi | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

(limited to 'doc')

diff --git a/doc/guix.texi b/doc/guix.texi
index b8071d17de..afc0ef8615 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -10888,9 +10888,9 @@ system, you will want to append services to @var{%base-services}, like
 this:
 
 @example
-(cons* (service avahi-service-type)
-       (service openssh-service-type)
-       %base-services)
+(append (list (service avahi-service-type)
+              (service openssh-service-type))
+        %base-services)
 @end example
 @end defvr
 
@@ -11520,11 +11520,12 @@ well as in the @var{groups} field of the @var{operating-system} record.
   ;; @dots{}
 
   (services
-    (modify-services %desktop-services
-      (udev-service-type config =>
-       (udev-configuration (inherit config)
-       (rules (cons* android-udev-rules
-              (udev-configuration-rules config))))))))
+   (modify-services %desktop-services
+     (udev-service-type
+      config =>
+      (udev-configuration (inherit config)
+                          (rules (cons android-udev-rules
+                                       (udev-configuration-rules config))))))))
 @end example
 
 @defvr {Scheme Variable} urandom-seed-service-type
-- 
cgit v1.2.3


From bd414e273c2010132895a645b623035c218eb437 Mon Sep 17 00:00:00 2001
From: Ludovic Courtès <ludo@gnu.org>
Date: Fri, 25 Jan 2019 13:57:38 +0100
Subject: weather: Add '--coverage'.

* guix/scripts/weather.scm (show-help, %options): Add '--coverage'.
(package-partition-boundary, package->output-mapping)
(substitute-oracle, report-package-coverage-per-system)
(report-package-coverage): New procedures.
(guix-weather): Honor '--coverage'.
* doc/guix.texi (Invoking guix weather): Document it.
---
 doc/guix.texi            |  35 +++++++++-
 guix/scripts/weather.scm | 167 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 200 insertions(+), 2 deletions(-)

(limited to 'doc')

diff --git a/doc/guix.texi b/doc/guix.texi
index afc0ef8615..a182e1edee 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -9709,7 +9709,9 @@ key is authorized.  It also reports the size of the compressed archives
 (``nars'') provided by the server, the size the corresponding store
 items occupy in the store (assuming deduplication is turned off), and
 the server's throughput.  The second part gives continuous integration
-(CI) statistics, if the server supports it.
+(CI) statistics, if the server supports it.  In addition, using the
+@option{--coverage} option, @command{guix weather} can list ``important''
+package substitutes missing on the server (see below).
 
 To achieve that, @command{guix weather} queries over HTTP(S) meta-data
 (@dfn{narinfos}) for all the relevant store items.  Like @command{guix
@@ -9737,6 +9739,37 @@ Instead of querying substitutes for all the packages, only ask for those
 specified in @var{file}.  @var{file} must contain a @dfn{manifest}, as
 with the @code{-m} option of @command{guix package} (@pxref{Invoking
 guix package}).
+
+@item --coverage[=@var{count}]
+@itemx -c [@var{count}]
+Report on substitute coverage for packages: list packages with at least
+@var{count} dependents (zero by default) for which substitutes are
+unavailable.  Dependent packages themselves are not listed: if @var{b} depends
+on @var{a} and @var{a} has no substitutes, only @var{a} is listed, even though
+@var{b} usually lacks substitutes as well.  The result looks like this:
+
+@example
+$ guix weather --substitute-urls=https://ci.guix.info -c 10
+computing 8,983 package derivations for x86_64-linux...
+looking for 9,343 store items on https://ci.guix.info...
+updating substitutes from 'https://ci.guix.info'... 100.0%
+https://ci.guix.info
+  64.7% substitutes available (6,047 out of 9,343)
+@dots{}
+2502 packages are missing from 'https://ci.guix.info' for 'x86_64-linux', among which:
+    58  kcoreaddons@@5.49.0      /gnu/store/@dots{}-kcoreaddons-5.49.0
+    46  qgpgme@@1.11.1           /gnu/store/@dots{}-qgpgme-1.11.1
+    37  perl-http-cookiejar@@0.008  /gnu/store/@dots{}-perl-http-cookiejar-0.008
+    @dots{}
+@end example
+
+What this example shows is that @code{kcoreaddons} and presumably the 58
+packages that depend on it have no substitutes at @code{ci.guix.info};
+likewise for @code{qgpgme} and the 46 packages that depend on it.
+
+If you are a Guix developer, or if you are taking care of this build farm,
+you'll probably want to have a closer look at these packages: they may simply
+fail to build.
 @end table
 
 @node Invoking guix processes
diff --git a/guix/scripts/weather.scm b/guix/scripts/weather.scm
index bb326a651a..4b12f9550e 100644
--- a/guix/scripts/weather.scm
+++ b/guix/scripts/weather.scm
@@ -32,6 +32,9 @@ (define-module (guix scripts weather)
   #:use-module (guix scripts substitute)
   #:use-module (guix http-client)
   #:use-module (guix ci)
+  #:use-module (guix sets)
+  #:use-module (guix graph)
+  #:autoload   (guix scripts graph) (%bag-node-type)
   #:use-module (gnu packages)
   #:use-module (web uri)
   #:use-module (srfi srfi-1)
@@ -41,6 +44,7 @@ (define-module (guix scripts weather)
   #:use-module (srfi srfi-37)
   #:use-module (ice-9 match)
   #:use-module (ice-9 format)
+  #:use-module (ice-9 vlist)
   #:export (guix-weather))
 
 (define (all-packages)
@@ -257,6 +261,10 @@ (define (show-help)
   -m, --manifest=MANIFEST
                          look up substitutes for packages specified in MANIFEST"))
   (display (G_ "
+  -c, --coverage[=COUNT]
+                         show substitute coverage for packages with at least
+                         COUNT dependents"))
+  (display (G_ "
   -s, --system=SYSTEM    consider substitutes for SYSTEM--e.g., \"i686-linux\""))
   (newline)
   (display (G_ "
@@ -289,6 +297,11 @@ (define %options
          (option '(#\m "manifest") #t #f
                  (lambda (opt name arg result)
                    (alist-cons 'manifest arg result)))
+         (option '(#\c "coverage") #f #t
+                 (lambda (opt name arg result)
+                   (alist-cons 'coverage
+                               (if arg (string->number* arg) 0)
+                               result)))
          (option '(#\s "system") #t #f
                  (lambda (opt name arg result)
                    (alist-cons 'system arg result)))))
@@ -303,6 +316,153 @@ (define (load-manifest file)
     (map manifest-entry-item
          (manifest-transitive-entries manifest))))
 
+
+;;;
+;;; Missing package substitutes.
+;;;
+
+(define* (package-partition-boundary pred packages
+                                     #:key (system (%current-system)))
+  "Return the subset of PACKAGES that are at the \"boundary\" between those
+that match PRED and those that don't.  The returned packages themselves do not
+match PRED but they have at least one direct dependency that does.
+
+Note: The assumption is that, if P matches PRED, then all the dependencies of
+P match PRED as well."
+  ;; XXX: Graph theoreticians surely have something to teach us about this...
+  (let loop ((packages packages)
+             (result (setq))
+             (visited vlist-null))
+    (define (visited? package)
+      (vhash-assq package visited))
+
+    (match packages
+      ((package . rest)
+       (cond ((visited? package)
+              (loop rest result visited))
+             ((pred package)
+              (loop rest result (vhash-consq package #t visited)))
+             (else
+              (let* ((bag  (package->bag package system))
+                     (deps (filter-map (match-lambda
+                                         ((label (? package? package) . _)
+                                          (and (not (pred package))
+                                               package))
+                                         (_ #f))
+                                       (bag-direct-inputs bag))))
+                (loop (append deps rest)
+                      (if (null? deps)
+                          (set-insert package result)
+                          result)
+                      (vhash-consq package #t visited))))))
+      (()
+       (set->list result)))))
+
+(define (package->output-mapping packages system)
+  "Return a vhash that maps each item of PACKAGES to its corresponding output
+store file names for SYSTEM."
+  (foldm %store-monad
+         (lambda (package mapping)
+           (mlet %store-monad ((drv (package->derivation package system
+                                                         #:graft? #f)))
+             (return (vhash-consq package
+                                  (match (derivation->output-paths drv)
+                                    (((names . outputs) ...)
+                                     outputs))
+                                  mapping))))
+         vlist-null
+         packages))
+
+(define (substitute-oracle server items)
+  "Return a procedure that, when passed a store item (one of those listed in
+ITEMS), returns true if SERVER has a substitute for it, false otherwise."
+  (define available
+    (fold (lambda (narinfo set)
+            (set-insert (narinfo-path narinfo) set))
+          (set)
+          (lookup-narinfos server items)))
+
+  (cut set-contains? available <>))
+
+(define* (report-package-coverage-per-system server packages system
+                                             #:key (threshold 0))
+  "Report on the subset of PACKAGES that lacks SYSTEM substitutes on SERVER,
+sorted by decreasing number of dependents.  Do not display those with less
+than THRESHOLD dependents."
+  (mlet* %store-monad ((packages -> (package-closure packages #:system system))
+                       (mapping    (package->output-mapping packages system))
+                       (back-edges (node-back-edges %bag-node-type packages)))
+    (define items
+      (vhash-fold (lambda (package items result)
+                    (append items result))
+                  '()
+                  mapping))
+
+    (define substitutable?
+      (substitute-oracle server items))
+
+    (define substitutable-package?
+      (lambda (package)
+        (match (vhash-assq package mapping)
+          ((_ . items)
+           (find substitutable? items))
+          (#f
+           #f))))
+
+    (define missing
+      (package-partition-boundary substitutable-package? packages
+                                  #:system system))
+
+    (define missing-count
+      (length missing))
+
+    (if (zero? threshold)
+        (format #t (N_ "The following ~a package is missing from '~a' for \
+'~a':~%"
+                       "The following ~a packages are missing from '~a' for \
+'~a':~%"
+                       missing-count)
+                missing-count server system)
+        (format #t (N_ "~a package is missing from '~a' for '~a':~%"
+                       "~a packages are missing from '~a' for '~a', among \
+which:~%"
+                       missing-count)
+                missing-count server system))
+
+    (for-each (match-lambda
+                ((package count)
+                 (match (vhash-assq package mapping)
+                   ((_ . items)
+                    (when (>= count threshold)
+                      (format #t "  ~4d\t~a@~a\t~{~a ~}~%"
+                              count
+                              (package-name package) (package-version package)
+                              items)))
+                   (#f                      ;PACKAGE must be an internal thing
+                    #f))))
+              (sort (zip missing
+                         (map (lambda (package)
+                                (node-reachable-count (list package)
+                                                      back-edges))
+                              missing))
+                    (match-lambda*
+                      (((_ count1) (_ count2))
+                       (< count2 count1)))))
+    (return #t)))
+
+(define* (report-package-coverage server packages systems
+                                  #:key (threshold 0))
+  "Report on the substitute coverage for PACKAGES, for each of SYSTEMS, on
+SERVER.  Display information for packages with at least THRESHOLD dependents."
+  (with-store store
+    (run-with-store store
+      (foldm %store-monad
+             (lambda (system _)
+               (report-package-coverage-per-system server packages system
+                                                   #:threshold threshold))
+             #f
+             systems))))
+
 
 ;;;
 ;;; Entry point.
@@ -334,7 +494,12 @@ (define (guix-weather . args)
                                       (package-outputs packages system))
                                     systems)))))))
         (for-each (lambda (server)
-                    (report-server-coverage server items))
+                    (report-server-coverage server items)
+                    (match (assoc-ref opts 'coverage)
+                      (#f #f)
+                      (threshold
+                       (report-package-coverage server packages systems
+                                                #:threshold threshold))))
                   urls)))))
 
 ;;; Local Variables:
-- 
cgit v1.2.3