git: Display a progress bar while fetching a repo.

Fixes <https://bugs.gnu.org/39260>.

This uses the API of the yet-to-be-released Guile-Git 0.4.0.  Using an
older version is still possible, but progress report is disabled.

* guix/git.scm (show-progress, make-default-fetch-options): New
procedures.
(clone*, update-cached-checkout): Use it instead of
'make-fetch-options'.
This commit is contained in:
Ludovic Courtès 2020-10-12 22:33:05 +02:00
parent 59bb1ae3a9
commit 298f9d29d6
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5

View file

@ -31,7 +31,9 @@
#:use-module (guix gexp) #:use-module (guix gexp)
#:use-module (guix sets) #:use-module (guix sets)
#:use-module ((guix diagnostics) #:select (leave)) #:use-module ((guix diagnostics) #:select (leave))
#:use-module (guix progress)
#:use-module (rnrs bytevectors) #:use-module (rnrs bytevectors)
#:use-module (ice-9 format)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:use-module (srfi srfi-1) #:use-module (srfi srfi-1)
#:use-module (srfi srfi-11) #:use-module (srfi srfi-11)
@ -117,6 +119,59 @@ the 'SSL_CERT_FILE' and 'SSL_CERT_DIR' environment variables."
(string-append "R:" url) (string-append "R:" url)
url)))))) url))))))
(define (show-progress progress)
"Display a progress bar as we fetch Git code. PROGRESS is an
<indexer-progress> record from (git)."
(define total
(indexer-progress-total-objects progress))
(define hundredth
(match (quotient (indexer-progress-total-objects progress) 100)
(0 1)
(x x)))
(define-values (done label)
(if (< (indexer-progress-received-objects progress) total)
(values (indexer-progress-received-objects progress)
(G_ "receiving objects"))
(values (indexer-progress-indexed-objects progress)
(G_ "indexing objects"))))
(define %
(* 100. (/ done total)))
(when (and (< % 100) (zero? (modulo done hundredth)))
(erase-current-line (current-error-port))
(let ((width (max (- (current-terminal-columns)
(string-length label) 7)
3)))
(format (current-error-port) "~a ~3,d% ~a"
label (inexact->exact (round %))
(progress-bar % width)))
(force-output (current-error-port)))
(when (= % 100.)
;; We're done, erase the line.
(erase-current-line (current-error-port))
(force-output (current-error-port)))
;; Return true to indicate that we should go on.
#t)
(define (make-default-fetch-options)
"Return the default fetch options."
(let ((auth-method (%make-auth-ssh-agent)))
;; The #:transfer-progress option appeared in Guile-Git 0.4.0. Omit it
;; when using an older version.
(catch 'wrong-number-of-args
(lambda ()
(make-fetch-options auth-method
#:transfer-progress
(and (isatty? (current-error-port))
show-progress)))
(lambda args
(make-fetch-options auth-method)))))
(define (clone* url directory) (define (clone* url directory)
"Clone git repository at URL into DIRECTORY. Upon failure, "Clone git repository at URL into DIRECTORY. Upon failure,
make sure no empty directory is left behind." make sure no empty directory is left behind."
@ -127,7 +182,7 @@ make sure no empty directory is left behind."
(let ((auth-method (%make-auth-ssh-agent))) (let ((auth-method (%make-auth-ssh-agent)))
(clone url directory (clone url directory
(make-clone-options (make-clone-options
#:fetch-options (make-fetch-options auth-method))))) #:fetch-options (make-default-fetch-options)))))
(lambda _ (lambda _
(false-if-exception (rmdir directory))))) (false-if-exception (rmdir directory)))))
@ -300,7 +355,7 @@ it unchanged."
(not (reference-available? repository ref))) (not (reference-available? repository ref)))
(let ((auth-method (%make-auth-ssh-agent))) (let ((auth-method (%make-auth-ssh-agent)))
(remote-fetch (remote-lookup repository "origin") (remote-fetch (remote-lookup repository "origin")
#:fetch-options (make-fetch-options auth-method)))) #:fetch-options (make-default-fetch-options))))
(when recursive? (when recursive?
(update-submodules repository #:log-port log-port)) (update-submodules repository #:log-port log-port))