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.
This commit is contained in:
parent
af77219e8a
commit
bd414e273c
|
@ -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
|
(``nars'') provided by the server, the size the corresponding store
|
||||||
items occupy in the store (assuming deduplication is turned off), and
|
items occupy in the store (assuming deduplication is turned off), and
|
||||||
the server's throughput. The second part gives continuous integration
|
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
|
To achieve that, @command{guix weather} queries over HTTP(S) meta-data
|
||||||
(@dfn{narinfos}) for all the relevant store items. Like @command{guix
|
(@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
|
specified in @var{file}. @var{file} must contain a @dfn{manifest}, as
|
||||||
with the @code{-m} option of @command{guix package} (@pxref{Invoking
|
with the @code{-m} option of @command{guix package} (@pxref{Invoking
|
||||||
guix package}).
|
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
|
@end table
|
||||||
|
|
||||||
@node Invoking guix processes
|
@node Invoking guix processes
|
||||||
|
|
|
@ -32,6 +32,9 @@
|
||||||
#:use-module (guix scripts substitute)
|
#:use-module (guix scripts substitute)
|
||||||
#:use-module (guix http-client)
|
#:use-module (guix http-client)
|
||||||
#:use-module (guix ci)
|
#: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 (gnu packages)
|
||||||
#:use-module (web uri)
|
#:use-module (web uri)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
|
@ -41,6 +44,7 @@
|
||||||
#:use-module (srfi srfi-37)
|
#:use-module (srfi srfi-37)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (ice-9 format)
|
#:use-module (ice-9 format)
|
||||||
|
#:use-module (ice-9 vlist)
|
||||||
#:export (guix-weather))
|
#:export (guix-weather))
|
||||||
|
|
||||||
(define (all-packages)
|
(define (all-packages)
|
||||||
|
@ -257,6 +261,10 @@ Report the availability of substitutes.\n"))
|
||||||
-m, --manifest=MANIFEST
|
-m, --manifest=MANIFEST
|
||||||
look up substitutes for packages specified in MANIFEST"))
|
look up substitutes for packages specified in MANIFEST"))
|
||||||
(display (G_ "
|
(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\""))
|
-s, --system=SYSTEM consider substitutes for SYSTEM--e.g., \"i686-linux\""))
|
||||||
(newline)
|
(newline)
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
|
@ -289,6 +297,11 @@ Report the availability of substitutes.\n"))
|
||||||
(option '(#\m "manifest") #t #f
|
(option '(#\m "manifest") #t #f
|
||||||
(lambda (opt name arg result)
|
(lambda (opt name arg result)
|
||||||
(alist-cons 'manifest 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
|
(option '(#\s "system") #t #f
|
||||||
(lambda (opt name arg result)
|
(lambda (opt name arg result)
|
||||||
(alist-cons 'system arg result)))))
|
(alist-cons 'system arg result)))))
|
||||||
|
@ -303,6 +316,153 @@ Report the availability of substitutes.\n"))
|
||||||
(map manifest-entry-item
|
(map manifest-entry-item
|
||||||
(manifest-transitive-entries manifest))))
|
(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.
|
;;; Entry point.
|
||||||
|
@ -334,7 +494,12 @@ Report the availability of substitutes.\n"))
|
||||||
(package-outputs packages system))
|
(package-outputs packages system))
|
||||||
systems)))))))
|
systems)))))))
|
||||||
(for-each (lambda (server)
|
(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)))))
|
urls)))))
|
||||||
|
|
||||||
;;; Local Variables:
|
;;; Local Variables:
|
||||||
|
|
Loading…
Reference in New Issue