From mboxrd@z Thu Jan 1 00:00:00 1970 From: Catonano Subject: =?UTF-8?B?UmU6IFdoYXTigJlzIHRoZSB3ZWF0aGVyIGxpa2U/?= Date: Sun, 23 Jul 2017 09:25:32 +0200 Message-ID: References: <87bmodkem5.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="089e0822423cef6cd00554f700b2" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:48866) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dZBGm-0006Y2-Rw for guix-devel@gnu.org; Sun, 23 Jul 2017 03:25:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dZBGk-0000tk-5S for guix-devel@gnu.org; Sun, 23 Jul 2017 03:25:40 -0400 In-Reply-To: <87bmodkem5.fsf@gnu.org> List-Id: "Development of GNU Guix and the GNU System distribution." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-devel-bounces+gcggd-guix-devel=m.gmane.org@gnu.org Sender: "Guix-devel" To: =?UTF-8?Q?Ludovic_Court=C3=A8s?= Cc: guix-devel --089e0822423cef6cd00554f700b2 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable 2017-07-21 17:13 GMT+02:00 Ludovic Court=C3=A8s : > Hello Guix! > > Lately we=E2=80=99ve had a lot of nar URLs return 404, mostly for server-= side > issues (setup issue on hydra.gnu.org that broke =E2=80=98guix publish=E2= =80=99 cache > management, and a =E2=80=98guix publish=E2=80=99 cache eviction policy th= at=E2=80=99s too > aggressive.) > > The attached tool allows you to query the status a substitute server > (and, as a side effect, triggers a nar regeneration if the server uses > =E2=80=98guix publish --cache=E2=80=99). So it goes like this: > > --8<---------------cut here---------------start------------->8--- > $ ./pre-inst-env guix weather --substitute-urls=3Dhttps://hydra.gnu.org > computing 5,864 package derivations for x86_64-linux... > looking for 6,121 store items on https://hydra.gnu.org... > updating list of substitutes from 'https://hydra.gnu.org'... 100.0% > https://hydra.gnu.org > 81.2% substitutes available (4,970 out of 6,121) > 17,852.6 MiB of nars (compressed) > 46,415.5 MiB on disk (uncompressed) > 0.050 seconds per request (306.0 seconds in total) > 20.0 requests per second > --8<---------------cut here---------------end--------------->8--- > > Here it=E2=80=99s telling us that hydra.gnu.org has 81% of the substitute= s for > x86_64 of the current public packages (those shown by =E2=80=9Cguix packa= ge > -A=E2=80=9D). > > We can add multiple -s flags, thought that quickly takes ages, > especially on that box. > > Thoughts? > > Ludo=E2=80=99. > This message has been sitting here for 2 days without receiving any comment. How is that ? This is very interesting but I have a few remarks First: having never being involved with binaries publishing I don't know what you mean with "if the server uses =E2=80=98guix publish --cache=E2=80=99" or with "We can add multiple -s flags" Having said that, I think it would be interesting to have the percentage of missing binaries for a specific operation rathher than for the whole server For example, if I want to reconfigure my system or if I want to create a VM image, how many binaries are missing in order to do that ? But even like this, I think it's useful Thanks ! > ;;; GNU Guix --- Functional package management for GNU > ;;; Copyright =C2=A9 2017 Ludovic Court=C3=A8s > ;;; > ;;; This file is part of GNU Guix. > ;;; > ;;; GNU Guix is free software; you can redistribute it and/or modify it > ;;; under the terms of the GNU General Public License as published by > ;;; the Free Software Foundation; either version 3 of the License, or (at > ;;; your option) any later version. > ;;; > ;;; GNU Guix is distributed in the hope that it will be useful, but > ;;; WITHOUT ANY WARRANTY; without even the implied warranty of > ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > ;;; GNU General Public License for more details. > ;;; > ;;; You should have received a copy of the GNU General Public License > ;;; along with GNU Guix. If not, see . > > (define-module (guix scripts weather) > #:use-module (guix ui) > #:use-module (guix scripts) > #:use-module (guix packages) > #:use-module (guix derivations) > #:use-module (guix monads) > #:use-module (guix store) > #:use-module (guix grafts) > #:use-module (guix build syscalls) > #:use-module (guix scripts substitute) > #:use-module (gnu packages) > #:use-module (srfi srfi-1) > #:use-module (srfi srfi-19) > #:use-module (srfi srfi-37) > #:use-module (ice-9 match) > #:use-module (ice-9 format) > #:export (guix-weather)) > > > (define (all-packages) > "Return the list of public packages we are going to query." > (fold-packages (lambda (package result) > (match (package-replacement package) > ((? package? replacement) > (cons* replacement package result)) > (#f > (cons package result)))) > '())) > > (define* (package-outputs packages > #:optional (system (%current-system))) > "Return the list of outputs of all of PACKAGES for the given SYSTEM." > (define update-progress! > (let ((total (length packages)) > (done 0) > (width (max 10 (- (terminal-columns) 10)))) > (lambda () > (set! done (+ 1 done)) > (let* ((ratio (/ done total 1.)) > (done (inexact->exact (round (* width ratio)))) > (left (- width done))) > (format (current-error-port) "~5,1f% [~a~a]\r" > (* ratio 100.) > (make-string done #\#) > (make-string left #\space)) > (when (>=3D done total) > (newline (current-error-port))) > (force-output (current-error-port)))))) > > (format (current-error-port) > (G_ "computing ~h package derivations for ~a...~%") > (length packages) system) > > (foldm %store-monad > (lambda (package result) > (mlet %store-monad ((drv (package->derivation package system > #:graft? #f))) > (update-progress!) > (match (derivation->output-paths drv) > (((names . items) ...) > (return (append items result)))))) > '() > packages)) > > (cond-expand > (guile-2.2 > ;; Guile 2.2.2 has a bug whereby 'time-monotonic' objects have seconds > and > ;; nanoseconds swapped (fixed in Guile commit 886ac3e). Work around i= t. > (define time-monotonic time-tai)) > (else #t)) > > (define (call-with-time thunk kont) > "Call THUNK and pass KONT the elapsed time followed by THUNK's return > values." > (let* ((start (current-time time-monotonic)) > (result (call-with-values thunk list)) > (end (current-time time-monotonic))) > (apply kont (time-difference end start) result))) > > (define-syntax-rule (let/time ((time result exp)) body ...) > (call-with-time (lambda () exp) (lambda (time result) body ...))) > > (define (report-server-coverage server items) > "Report the subset of ITEMS available as substitutes on SERVER." > (define MiB (* (expt 2 20) 1.)) > > (format #t (G_ "looking for ~h store items on ~a...~%") > (length items) server) > > (let/time ((time narinfos (lookup-narinfos server items))) > (format #t "~a~%" server) > (let ((obtained (length narinfos)) > (requested (length items)) > (sizes (filter-map narinfo-file-size narinfos)) > (time (+ (time-second time) > (/ (time-nanosecond time) 1e9)))) > (format #t (G_ " ~2,1f% substitutes available (~h out of ~h)~%") > (* 100. (/ obtained requested 1.)) > obtained requested) > (let ((total (/ (reduce + 0 sizes) MiB))) > (match (length sizes) > ((? zero?) > (format #t (G_ "unknown substitute sizes~%"))) > (len > (if (=3D len obtained) > (format #t (G_ " ~,1h MiB of nars (compressed)~%") total) > (format #t (G_ " at least ~,1h MiB of nars (compressed)~%= ") > total))))) > (format #t (G_ " ~,1h MiB on disk (uncompressed)~%") > (/ (reduce + 0 (map narinfo-size narinfos)) MiB)) > (format #t (G_ " ~,3h seconds per request (~,1h seconds in > total)~%") > (/ time requested 1.) time) > (format #t (G_ " ~,1h requests per second~%") > (/ requested time 1.))))) > > > ;;; > ;;; Command-line options. > ;;; > > (define (show-help) > (display (G_ "Usage: guix weather [OPTIONS] > Report the availability of substitutes.\n")) > (display (G_ " > --substitute-urls=3DURLS > check for available substitutes at URLS")) > (display (G_ " > -s, --system=3DSYSTEM consider substitutes for SYSTEM--e.g., > \"i686-linux\"")) > (newline) > (display (G_ " > -h, --help display this help and exit")) > (display (G_ " > -V, --version display version information and exit")) > (newline) > (show-bug-report-information)) > > (define %options > (list (option '(#\h "help") #f #f > (lambda args > (show-help) > (exit 0))) > (option '(#\V "version") #f #f > (lambda args > (show-version-and-exit "guix challenge"))) > > (option '("substitute-urls") #t #f > (lambda (opt name arg result . rest) > (apply values > (alist-cons 'substitute-urls > (string-tokenize arg) > (alist-delete 'substitute-urls > result)) > rest))) > (option '(#\s "system") #t #f > (lambda (opt name arg result) > (alist-cons 'system arg result))))) > > (define %default-options > `((substitute-urls . ,%default-substitute-urls))) > > > ;;; > ;;; Entry point. > ;;; > > (define (guix-weather . args) > (with-error-handling > (let* ((opts (parse-command-line args %options > (list %default-options))) > (urls (assoc-ref opts 'substitute-urls)) > (systems (match (filter-map (match-lambda > (('system . system) system) > (_ #f)) > opts) > (() (list (%current-system))) > (systems systems))) > (packages (all-packages)) > (items (with-store store > (parameterize ((%graft? #f)) > (concatenate > (run-with-store store > (mapm %store-monad > (lambda (system) > (package-outputs packages system)) > systems))))))) > (for-each (lambda (server) > (report-server-coverage server items)) > urls)))) > > ;;; Local Variables: > ;;; eval: (put 'let/time 'scheme-indent-function 1) > ;;; End: > > --089e0822423cef6cd00554f700b2 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
2017-07-21 17:13 GMT+02:00 Ludovic Court=C3=A8s <ludo@gnu.org= >:
<= blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px= #ccc solid;padding-left:1ex">Hello Guix!

Lately we=E2=80=99ve had a lot of nar URLs return 404, mostly for server-si= de
issues (setup issue on hydra.gnu.org that broke =E2=80=98guix publish=E2=80= =99 cache
management, and a =E2=80=98guix publish=E2=80=99 cache eviction policy that= =E2=80=99s too
aggressive.)

The attached tool allows you to query the status a substitute server
(and, as a side effect, triggers a nar regeneration if the server uses
=E2=80=98guix publish --cache=E2=80=99).=C2=A0 So it goes like this:

--8<---------------cut here---------------start------------->8--= -
$ ./pre-inst-env guix weather --substitute-urls=3Dhttps://hydra.gnu.org
computing 5,864 package derivations for x86_64-linux...
looking for 6,121 store items on
https://hydra.gnu.org...
updating list of substitutes from 'https://hydra.gnu.org'... 100.0%=
http= s://hydra.gnu.org
=C2=A0 81.2% substitutes available (4,970 out of 6,121)
=C2=A0 17,852.6 MiB of nars (compressed)
=C2=A0 46,415.5 MiB on disk (uncompressed)
=C2=A0 0.050 seconds per request (306.0 seconds in total)
=C2=A0 20.0 requests per second
--8<---------------cut here---------------end--------------->8--= -

Here it=E2=80=99s telling us that hydra.gnu.org has 81% of the substitutes f= or
x86_64 of the current public packages (those shown by =E2=80=9Cguix package=
-A=E2=80=9D).

We can add multiple -s flags, thought that quickly takes ages,
especially on that box.

Thoughts?

Ludo=E2=80=99.


This message has bee= n sitting here for 2 days without receiving any comment. How is that ?
<= br>
This is very interesting but I have a few remarks
<= div>
First: having never being involved with binaries publish= ing I don't know what you mean with
"if the server uses
=E2=80=98guix publish --cache=E2=80=99"
=C2=A0
or wit= h

"We can add multiple -s flags"

= Having said that, I think it would be interesting to have the percentage of= missing binaries for a specific operation rathher than for the whole serve= r

For example, if I want to reconfigure my system or if I= want to create a VM image, how many binaries are missing in order to do th= at ?

But even like this, I think it's usef= ul

Thanks !



;;; GNU Guix --- Functional package management for GNU
;;; Copyright =C2=A9 2017 Ludovic Court=C3=A8s <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at ;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.=C2=A0 If not, see <http://www.gnu.org/licens= es/>.

(define-module (guix scripts weather)
=C2=A0 #:use-module (guix ui)
=C2=A0 #:use-module (guix scripts)
=C2=A0 #:use-module (guix packages)
=C2=A0 #:use-module (guix derivations)
=C2=A0 #:use-module (guix monads)
=C2=A0 #:use-module (guix store)
=C2=A0 #:use-module (guix grafts)
=C2=A0 #:use-module (guix build syscalls)
=C2=A0 #:use-module (guix scripts substitute)
=C2=A0 #:use-module (gnu packages)
=C2=A0 #:use-module (srfi srfi-1)
=C2=A0 #:use-module (srfi srfi-19)
=C2=A0 #:use-module (srfi srfi-37)
=C2=A0 #:use-module (ice-9 match)
=C2=A0 #:use-module (ice-9 format)
=C2=A0 #:export (guix-weather))


(define (all-packages)
=C2=A0 "Return the list of public packages we are going to query."= ;
=C2=A0 (fold-packages (lambda (package result)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(match= (package-replacement package)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0((? package? replacement)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 (cons* replacement package result))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0(#f
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 (cons package result))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'()))

(define* (package-outputs packages
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 #:optional (system (%current-system)))
=C2=A0 "Return the list of outputs of all of PACKAGES for the given SY= STEM."
=C2=A0 (define update-progress!
=C2=A0 =C2=A0 (let ((total (length packages))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (done=C2=A0 0)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (width (max 10 (- (terminal-columns) 10)= )))
=C2=A0 =C2=A0 =C2=A0 (lambda ()
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (set! done (+ 1 done))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let* ((ratio (/ done total 1.))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(done=C2=A0 (inexact= ->exact (round (* width ratio))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(left=C2=A0 (- width= done)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (format (current-error-port) "~5,1f= % [~a~a]\r"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (* ratio 100= .)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (make-string= done #\#)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (make-string= left #\space))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (>=3D done total)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (newline (current-error-port))) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (force-output (current-error-port))))))<= br>
=C2=A0 (format (current-error-port)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (G_ "computing ~h package derivatio= ns for ~a...~%")
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (length packages) system)

=C2=A0 (foldm %store-monad
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(lambda (package result)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(mlet %store-monad ((drv (package-= >derivation package system
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0#:graft? #f)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(update-progress!)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(match (derivation->outp= ut-paths drv)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(((names . items) ..= .)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (return (append ite= ms result))))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'()
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0packages))

(cond-expand
=C2=A0 (guile-2.2
=C2=A0 =C2=A0;; Guile 2.2.2 has a bug whereby 'time-monotonic' obje= cts have seconds and
=C2=A0 =C2=A0;; nanoseconds swapped (fixed in Guile commit 886ac3e).=C2=A0 = Work around it.
=C2=A0 =C2=A0(define time-monotonic time-tai))
=C2=A0 (else #t))

(define (call-with-time thunk kont)
=C2=A0 "Call THUNK and pass KONT the elapsed time followed by THUNK= 9;s return
values."
=C2=A0 (let* ((start=C2=A0 (current-time time-monotonic))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(result (call-with-values thunk list)) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(end=C2=A0 =C2=A0 (current-time time-mono= tonic)))
=C2=A0 =C2=A0 (apply kont (time-difference end start) result)))

(define-syntax-rule (let/time ((time result exp)) body ...)
=C2=A0 (call-with-time (lambda () exp) (lambda (time result) body ...)))
(define (report-server-coverage server items)
=C2=A0 "Report the subset of ITEMS available as substitutes on SERVER.= "
=C2=A0 (define MiB (* (expt 2 20) 1.))

=C2=A0 (format #t (G_ "looking for ~h store items on ~a...~%") =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (length items) server)

=C2=A0 (let/time ((time narinfos (lookup-narinfos server items)))
=C2=A0 =C2=A0 (format #t "~a~%" server)
=C2=A0 =C2=A0 (let ((obtained=C2=A0 (length narinfos))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (requested (length items))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (sizes=C2=A0 =C2=A0 =C2=A0(filter-map na= rinfo-file-size narinfos))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (time=C2=A0 =C2=A0 =C2=A0 (+ (time-secon= d time)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (/ (time-nanosecond time) 1e9))))
=C2=A0 =C2=A0 =C2=A0 (format #t (G_ "=C2=A0 ~2,1f% substitutes availab= le (~h out of ~h)~%")
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (* 100. (/ obtained reques= ted 1.))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 obtained requested)
=C2=A0 =C2=A0 =C2=A0 (let ((total (/ (reduce + 0 sizes) MiB)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (match (length sizes)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((? zero?)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(format #t (G_=C2=A0 "unknown= substitute sizes~%")))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (len
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(if (=3D len obtained)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(format #t (G_ "= ;=C2=A0 ~,1h MiB of nars (compressed)~%") total)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(format #t (G_ "= ;=C2=A0 at least ~,1h MiB of nars (compressed)~%")
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0total)))))
=C2=A0 =C2=A0 =C2=A0 (format #t (G_ "=C2=A0 ~,1h MiB on disk (uncompre= ssed)~%")
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (/ (reduce + 0 (map narinf= o-size narinfos)) MiB))
=C2=A0 =C2=A0 =C2=A0 (format #t (G_ "=C2=A0 ~,3h seconds per request (= ~,1h seconds in total)~%")
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (/ time requested 1.) time= )
=C2=A0 =C2=A0 =C2=A0 (format #t (G_ "=C2=A0 ~,1h requests per second~%= ")
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (/ requested time 1.)))))<= br>

;;;
;;; Command-line options.
;;;

(define (show-help)
=C2=A0 (display (G_ "Usage: guix weather [OPTIONS]
Report the availability of substitutes.\n"))
=C2=A0 (display (G_ "
=C2=A0 =C2=A0 =C2=A0 --substitute-urls=3DURLS
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0check for available substitutes at URLS"))
=C2=A0 (display (G_ "
=C2=A0 -s, --system=3DSYSTEM=C2=A0 =C2=A0 consider substitutes for SYSTEM--= e.g., \"i686-linux\""))
=C2=A0 (newline)
=C2=A0 (display (G_ "
=C2=A0 -h, --help=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0display th= is help and exit"))
=C2=A0 (display (G_ "
=C2=A0 -V, --version=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 display version info= rmation and exit"))
=C2=A0 (newline)
=C2=A0 (show-bug-report-information))

(define %options
=C2=A0 (list=C2=A0 (option '(#\h "help") #f #f
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(lambda args<= br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(show-= help)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(exit = 0)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(option '(#\V "version") #f= #f
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(lambda args<= br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(show-= version-and-exit "guix challenge")))

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(option '("substitute-urls"= ) #t #f
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(lambda (opt = name arg result . rest)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(apply= values
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 (alist-cons 'substitute-urls
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (string-tokeniz= e arg)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (alist-delete &= #39;substitute-urls result))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 rest)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(option '(#\s "system") #t = #f
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(lambda (opt = name arg result)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(alist= -cons 'system arg result)))))

(define %default-options
=C2=A0 `((substitute-urls . ,%default-substitute-urls)))


;;;
;;; Entry point.
;;;

(define (guix-weather . args)
=C2=A0 (with-error-handling
=C2=A0 =C2=A0 (let* ((opts=C2=A0 =C2=A0 =C2=A0(parse-command-line args %opt= ions
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(l= ist %default-options)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(urls=C2=A0 =C2=A0 =C2=A0(assoc-re= f opts 'substitute-urls))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(systems=C2=A0 (match (filter-map = (match-lambda
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= ('system . system) system)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= _ #f))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 opts) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(() (list (%current-system)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(systems systems)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(packages (all-packages))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(items=C2=A0 =C2=A0 (with-store st= ore
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(parameterize ((%graft? #f))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(concatenate
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 (run-with-store store
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (mapm %store-monad
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda (system)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (package-outputs packa= ges system))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 systems)))))))
=C2=A0 =C2=A0 =C2=A0 (for-each (lambda (server)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (report-serv= er-coverage server items))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 urls))))

;;; Local Variables:
;;; eval: (put 'let/time 'scheme-indent-function 1)
;;; End:


--089e0822423cef6cd00554f700b2--