summaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
Diffstat (limited to 'guix')
-rw-r--r--guix/build/download.scm16
-rw-r--r--guix/gexp.scm15
-rw-r--r--guix/git.scm136
-rw-r--r--guix/import/opam.scm46
-rw-r--r--guix/monads.scm15
-rw-r--r--guix/profiles.scm34
-rw-r--r--guix/scripts/build.scm3
-rw-r--r--guix/scripts/pull.scm26
-rw-r--r--guix/status.scm8
-rw-r--r--guix/ui.scm8
10 files changed, 237 insertions, 70 deletions
diff --git a/guix/build/download.scm b/guix/build/download.scm
index c08221b3b2..a64e0f0bd3 100644
--- a/guix/build/download.scm
+++ b/guix/build/download.scm
@@ -157,7 +157,8 @@ out if the connection could not be established in less than TIMEOUT seconds."
;; XXX: Use this hack instead of #:autoload to avoid compilation errors.
;; See <http://bugs.gnu.org/12202>.
(module-autoload! (current-module)
- '(gnutls) '(make-session connection-end/client))
+ '(gnutls)
+ '(gnutls-version make-session connection-end/client))
(define %tls-ports
;; Mapping of session record ports to the underlying file port.
@@ -268,7 +269,18 @@ host name without trailing dot."
;; "(gnutls) Priority Strings"); see <http://bugs.gnu.org/23311>.
;; Explicitly disable SSLv3, which is insecure:
;; <https://tools.ietf.org/html/rfc7568>.
- (set-session-priorities! session "NORMAL:%COMPAT:-VERS-SSL3.0")
+ ;;
+ ;; FIXME: Since we currently fail to handle TLS 1.3 (with GnuTLS 3.6.5),
+ ;; remove it; see <https://bugs.gnu.org/34102>.
+ (set-session-priorities! session
+ (string-append
+ "NORMAL:%COMPAT:-VERS-SSL3.0"
+
+ ;; The "VERS-TLS1.3" priority string is not
+ ;; supported by GnuTLS 3.5.
+ (if (string-prefix? "3.5." (gnutls-version))
+ ""
+ ":-VERS-TLS1.3")))
(set-session-credentials! session
(if (and verify-certificate? ca-certs)
diff --git a/guix/gexp.scm b/guix/gexp.scm
index f7c064297b..5b5b064b59 100644
--- a/guix/gexp.scm
+++ b/guix/gexp.scm
@@ -920,7 +920,18 @@ and in the current monad setting (system type, etc.)"
(simple-format #f "~a:~a" line column)))
"<unknown location>")))
-(define-syntax-parameter current-imported-modules
+(define-syntax-rule (define-syntax-parameter-once name proc)
+ ;; Like 'define-syntax-parameter' but ensure the top-level binding for NAME
+ ;; does not get redefined. This works around a race condition in a
+ ;; multi-threaded context with Guile <= 2.2.4: <https://bugs.gnu.org/27476>.
+ (eval-when (load eval expand compile)
+ (define name
+ (if (module-locally-bound? (current-module) 'name)
+ (module-ref (current-module) 'name)
+ (make-syntax-transformer 'name 'syntax-parameter
+ (list proc))))))
+
+(define-syntax-parameter-once current-imported-modules
;; Current list of imported modules.
(identifier-syntax '()))
@@ -931,7 +942,7 @@ environment."
(identifier-syntax modules)))
body ...))
-(define-syntax-parameter current-imported-extensions
+(define-syntax-parameter-once current-imported-extensions
;; Current list of extensions.
(identifier-syntax '()))
diff --git a/guix/git.scm b/guix/git.scm
index 0666f0c0a9..0e3ce37e26 100644
--- a/guix/git.scm
+++ b/guix/git.scm
@@ -1,6 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
-;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2018, 2019 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -35,6 +35,8 @@
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
#:export (%repository-cache-directory
+ honor-system-x509-certificates!
+
update-cached-checkout
latest-repository-commit
@@ -43,25 +45,70 @@
git-checkout-url
git-checkout-branch))
+;; XXX: Use this hack instead of #:autoload to avoid compilation errors.
+;; See <http://bugs.gnu.org/12202>.
+(module-autoload! (current-module)
+ '(git submodule) '(repository-submodules))
+
(define %repository-cache-directory
(make-parameter (string-append (cache-directory #:ensure? #f)
"/checkouts")))
+(define (honor-system-x509-certificates!)
+ "Use the system's X.509 certificates for Git checkouts over HTTPS. Honor
+the 'SSL_CERT_FILE' and 'SSL_CERT_DIR' environment variables."
+ ;; On distros such as CentOS 7, /etc/ssl/certs contains only a couple of
+ ;; files (instead of all the certificates) among which "ca-bundle.crt". On
+ ;; other distros /etc/ssl/certs usually contains the whole set of
+ ;; certificates along with "ca-certificates.crt". Try to choose the right
+ ;; one.
+ (let ((file (letrec-syntax ((choose
+ (syntax-rules ()
+ ((_ file rest ...)
+ (let ((f file))
+ (if (and f (file-exists? f))
+ f
+ (choose rest ...))))
+ ((_)
+ #f))))
+ (choose (getenv "SSL_CERT_FILE")
+ "/etc/ssl/certs/ca-certificates.crt"
+ "/etc/ssl/certs/ca-bundle.crt")))
+ (directory (or (getenv "SSL_CERT_DIR") "/etc/ssl/certs")))
+ (and (or file
+ (and=> (stat directory #f)
+ (lambda (st)
+ (> (stat:nlink st) 2))))
+ (begin
+ (set-tls-certificate-locations! directory file)
+ #t))))
+
+(define %certificates-initialized?
+ ;; Whether 'honor-system-x509-certificates!' has already been called.
+ #f)
+
(define-syntax-rule (with-libgit2 thunk ...)
(begin
;; XXX: The right thing to do would be to call (libgit2-shutdown) here,
;; but pointer finalizers used in guile-git may be called after shutdown,
;; resulting in a segfault. Hence, let's skip shutdown call for now.
(libgit2-init!)
+ (unless %certificates-initialized?
+ (honor-system-x509-certificates!)
+ (set! %certificates-initialized? #t))
thunk ...))
(define* (url-cache-directory url
#:optional (cache-directory
- (%repository-cache-directory)))
+ (%repository-cache-directory))
+ #:key recursive?)
"Return the directory associated to URL in %repository-cache-directory."
(string-append
cache-directory "/"
- (bytevector->base32-string (sha256 (string->utf8 url)))))
+ (bytevector->base32-string
+ (sha256 (string->utf8 (if recursive?
+ (string-append "R:" url)
+ url))))))
(define (clone* url directory)
"Clone git repository at URL into DIRECTORY. Upon failure,
@@ -119,18 +166,62 @@ OID (roughly the commit hash) corresponding to REF."
(reset repository obj RESET_HARD)
(object-id obj))
+(define (call-with-repository directory proc)
+ (let ((repository #f))
+ (dynamic-wind
+ (lambda ()
+ (set! repository (repository-open directory)))
+ (lambda ()
+ (proc repository))
+ (lambda ()
+ (repository-close! repository)))))
+
+(define-syntax-rule (with-repository directory repository exp ...)
+ "Open the repository at DIRECTORY and bind REPOSITORY to it within the
+dynamic extent of EXP."
+ (call-with-repository directory
+ (lambda (repository) exp ...)))
+
+(define* (update-submodules repository
+ #:key (log-port (current-error-port)))
+ "Update the submodules of REPOSITORY, a Git repository object."
+ ;; Guile-Git < 0.2.0 did not have (git submodule).
+ (if (false-if-exception (resolve-interface '(git submodule)))
+ (for-each (lambda (name)
+ (let ((submodule (submodule-lookup repository name)))
+ (format log-port (G_ "updating submodule '~a'...~%")
+ name)
+ (submodule-update submodule)
+
+ ;; Recurse in SUBMODULE.
+ (let ((directory (string-append
+ (repository-working-directory repository)
+ "/" (submodule-path submodule))))
+ (with-repository directory repository
+ (update-submodules repository
+ #:log-port log-port)))))
+ (repository-submodules repository))
+ (format (current-error-port)
+ (G_ "Support for submodules is missing; \
+please upgrade Guile-Git.~%"))))
+
(define* (update-cached-checkout url
#:key
(ref '(branch . "master"))
+ recursive?
+ (log-port (%make-void-port "w"))
(cache-directory
(url-cache-directory
- url (%repository-cache-directory))))
+ url (%repository-cache-directory)
+ #:recursive? recursive?)))
"Update the cached checkout of URL to REF in CACHE-DIRECTORY. Return two
values: the cache directory name, and the SHA1 commit (a string) corresponding
to REF.
REF is pair whose key is [branch | commit | tag] and value the associated
-data, respectively [<branch name> | <sha1> | <tag name>]."
+data, respectively [<branch name> | <sha1> | <tag name>].
+
+When RECURSIVE? is true, check out submodules as well, if any."
(define canonical-ref
;; We used to require callers to specify "origin/" for each branch, which
;; made little sense since the cache should be transparent to them. So
@@ -150,6 +241,8 @@ data, respectively [<branch name> | <sha1> | <tag name>]."
;; Only fetch remote if it has not been cloned just before.
(when cache-exists?
(remote-fetch (remote-lookup repository "origin")))
+ (when recursive?
+ (update-submodules repository #:log-port log-port))
(let ((oid (switch-to-ref repository canonical-ref)))
;; Reclaim file descriptors and memory mappings associated with
@@ -162,6 +255,7 @@ data, respectively [<branch name> | <sha1> | <tag name>]."
(define* (latest-repository-commit store url
#:key
+ recursive?
(log-port (%make-void-port "w"))
(cache-directory
(%repository-cache-directory))
@@ -172,21 +266,33 @@ reference to be checkout, once the repository is fetched, is specified by REF.
REF is pair whose key is [branch | commit | tag] and value the associated
data, respectively [<branch name> | <sha1> | <tag name>].
+When RECURSIVE? is true, check out submodules as well, if any.
+
Git repositories are kept in the cache directory specified by
%repository-cache-directory parameter.
Log progress and checkout info to LOG-PORT."
(define (dot-git? file stat)
(and (string=? (basename file) ".git")
- (eq? 'directory (stat:type stat))))
+ (or (eq? 'directory (stat:type stat))
+
+ ;; Submodule checkouts end up with a '.git' regular file that
+ ;; contains metadata about where their actual '.git' directory
+ ;; lives.
+ (and recursive?
+ (eq? 'regular (stat:type stat))))))
(format log-port "updating checkout of '~a'...~%" url)
(let*-values
(((checkout commit)
(update-cached-checkout url
+ #:recursive? recursive?
#:ref ref
#:cache-directory
- (url-cache-directory url cache-directory)))
+ (url-cache-directory url cache-directory
+ #:recursive?
+ recursive?)
+ #:log-port log-port))
((name)
(url+commit->name url commit)))
(format log-port "retrieved commit ~a~%" commit)
@@ -205,9 +311,10 @@ Log progress and checkout info to LOG-PORT."
git-checkout?
(url git-checkout-url)
(branch git-checkout-branch (default "master"))
- (commit git-checkout-commit (default #f)))
+ (commit git-checkout-commit (default #f))
+ (recursive? git-checkout-recursive? (default #f)))
-(define* (latest-repository-commit* url #:key ref log-port)
+(define* (latest-repository-commit* url #:key ref recursive? log-port)
;; Monadic variant of 'latest-repository-commit'.
(lambda (store)
;; The caller--e.g., (guix scripts build)--may not handle 'git-error' so
@@ -216,7 +323,9 @@ Log progress and checkout info to LOG-PORT."
(catch 'git-error
(lambda ()
(values (latest-repository-commit store url
- #:ref ref #:log-port log-port)
+ #:ref ref
+ #:recursive? recursive?
+ #:log-port log-port)
store))
(lambda (key error . _)
(raise (condition
@@ -238,9 +347,14 @@ Log progress and checkout info to LOG-PORT."
;; "Compile" CHECKOUT by updating the local checkout and adding it to the
;; store.
(match checkout
- (($ <git-checkout> url branch commit)
+ (($ <git-checkout> url branch commit recursive?)
(latest-repository-commit* url
#:ref (if commit
`(commit . ,commit)
`(branch . ,branch))
+ #:recursive? recursive?
#:log-port (current-error-port)))))
+
+;; Local Variables:
+;; eval: (put 'with-repository 'scheme-indent-function 2)
+;; End:
diff --git a/guix/import/opam.scm b/guix/import/opam.scm
index c254db5f2c..7b2e832e92 100644
--- a/guix/import/opam.scm
+++ b/guix/import/opam.scm
@@ -1,4 +1,3 @@
-;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2018 Julien Lepiller <julien@lepiller.eu>
;;;
;;; This file is part of GNU Guix.
@@ -90,8 +89,8 @@
(define-peg-pattern condition-lower all (and (ignore "<") (* SP) condition-string))
(define-peg-pattern condition-and all (and condition-form2 (* SP) (? (ignore "&")) (* SP) condition-form))
(define-peg-pattern condition-or all (and condition-form2 (* SP) (ignore "|") (* SP) condition-form))
-(define-peg-pattern condition-eq all (and condition-content (* SP) (ignore "=") (* SP) condition-content))
-(define-peg-pattern condition-neq all (and condition-content (* SP) (ignore (and "!" "=")) (* SP) condition-content))
+(define-peg-pattern condition-eq all (and (? condition-content) (* SP) (ignore "=") (* SP) condition-content))
+(define-peg-pattern condition-neq all (and (? condition-content) (* SP) (ignore (and "!" "=")) (* SP) condition-content))
(define-peg-pattern condition-content body (or condition-string condition-var))
(define-peg-pattern condition-content2 body (and condition-content (* SP) (not-followed-by (or "&" "=" "!"))))
(define-peg-pattern condition-string all (and QUOTE (* STRCHR) QUOTE))
@@ -117,7 +116,11 @@ path to the repository."
(lambda (dir)
(string-join (cdr (string-split dir #\.)) "."))
versions)))
- (latest-version versions))
+ ;; Workaround for janestreet re-versionning
+ (let ((v-versions (filter (lambda (version) (string-prefix? "v" version)) versions)))
+ (if (null? v-versions)
+ (latest-version versions)
+ (string-append "v" (latest-version (map (lambda (version) (substring version 1)) v-versions))))))
(begin
(format #t (G_ "Package not found in opam repository: ~a~%") package)
#f))))
@@ -127,12 +130,17 @@ path to the repository."
(lambda _
(peg:tree (match-pattern records (get-string-all (current-input-port)))))))
+(define (substitute-char str what with)
+ (string-join (string-split str what) with))
+
(define (ocaml-name->guix-name name)
- (cond
- ((equal? name "ocamlfind") "ocaml-findlib")
- ((string-prefix? "ocaml" name) name)
- ((string-prefix? "conf-" name) (substring name 5))
- (else (string-append "ocaml-" name))))
+ (substitute-char
+ (cond
+ ((equal? name "ocamlfind") "ocaml-findlib")
+ ((string-prefix? "ocaml" name) name)
+ ((string-prefix? "conf-" name) (substring name 5))
+ (else (string-append "ocaml-" name)))
+ #\_ "-"))
(define (metadata-ref file lookup)
(fold (lambda (record acc)
@@ -234,7 +242,9 @@ path to the repository."
(values
`(package
(name ,(ocaml-name->guix-name name))
- (version ,version)
+ (version ,(if (string-prefix? "v" version)
+ (substring version 1)
+ version))
(source
(origin
(method url-fetch)
@@ -247,6 +257,10 @@ path to the repository."
,@(if (null? native-inputs)
'()
`((native-inputs ,(list 'quasiquote native-inputs))))
+ ,@(if (equal? name (guix-name->opam-name (ocaml-name->guix-name name)))
+ '()
+ `((properties
+ ,(list 'quasiquote `((upstream-name . ,name))))))
(home-page ,(metadata-ref opam-content "homepage"))
(synopsis ,(metadata-ref opam-content "synopsis"))
(description ,(metadata-ref opam-content "description"))
@@ -259,6 +273,11 @@ path to the repository."
(opam->guix-package name))
#:guix-name ocaml-name->guix-name))
+(define (guix-name->opam-name name)
+ (if (string-prefix? "ocaml-" name)
+ (substring name 6)
+ name))
+
(define (guix-package->opam-name package)
"Given an OCaml PACKAGE built from OPAM, return the name of the
package in OPAM."
@@ -266,10 +285,9 @@ package in OPAM."
(package-properties package)
'upstream-name))
(name (package-name package)))
- (cond
- (upstream-name upstream-name)
- ((string-prefix? "ocaml-" name) (substring name 6))
- (else name))))
+ (if upstream-name
+ upstream-name
+ (guix-name->opam-name name))))
(define (opam-package? package)
"Return true if PACKAGE is an OCaml package from OPAM"
diff --git a/guix/monads.scm b/guix/monads.scm
index 6ae616aca9..6924471345 100644
--- a/guix/monads.scm
+++ b/guix/monads.scm
@@ -274,12 +274,23 @@ more optimizations."
(_
#'generic-name))))))))))
-(define-syntax-parameter >>=
+(define-syntax-rule (define-syntax-parameter-once name proc)
+ ;; Like 'define-syntax-parameter' but ensure the top-level binding for NAME
+ ;; does not get redefined. This works around a race condition in a
+ ;; multi-threaded context with Guile <= 2.2.4: <https://bugs.gnu.org/27476>.
+ (eval-when (load eval expand compile)
+ (define name
+ (if (module-locally-bound? (current-module) 'name)
+ (module-ref (current-module) 'name)
+ (make-syntax-transformer 'name 'syntax-parameter
+ (list proc))))))
+
+(define-syntax-parameter-once >>=
;; The name 'bind' is already taken, so we choose this (obscure) symbol.
(lambda (s)
(syntax-violation '>>= ">>= (bind) used outside of 'with-monad'" s)))
-(define-syntax-parameter return
+(define-syntax-parameter-once return
(lambda (s)
(syntax-violation 'return "return used outside of 'with-monad'" s)))
diff --git a/guix/profiles.scm b/guix/profiles.scm
index efe5ecb9dc..6564526aee 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -63,6 +63,10 @@
&missing-generation-error
missing-generation-error?
missing-generation-error-generation
+ &unmatched-pattern-error
+ unmatched-pattern-error?
+ unmatched-pattern-error-pattern
+ unmatched-pattern-error-manifest
manifest make-manifest
manifest?
@@ -156,6 +160,11 @@
(entry profile-collision-error-entry) ;<manifest-entry>
(conflict profile-collision-error-conflict)) ;<manifest-entry>
+(define-condition-type &unmatched-pattern-error &error
+ unmatched-pattern-error?
+ (pattern unmatched-pattern-error-pattern) ;<manifest-pattern>
+ (manifest unmatched-pattern-error-manifest)) ;<manifest>
+
(define-condition-type &missing-generation-error &profile-error
missing-generation-error?
(generation missing-generation-error-generation))
@@ -559,16 +568,21 @@ no match.."
(->bool (manifest-lookup manifest pattern)))
(define (manifest-matching-entries manifest patterns)
- "Return all the entries of MANIFEST that match one of the PATTERNS."
- (define predicates
- (map entry-predicate patterns))
-
- (define (matches? entry)
- (any (lambda (pred)
- (pred entry))
- predicates))
-
- (filter matches? (manifest-entries manifest)))
+ "Return all the entries of MANIFEST that match one of the PATTERNS. Raise
+an '&unmatched-pattern-error' if none of the entries of MANIFEST matches one
+of PATTERNS."
+ (fold-right (lambda (pattern matches)
+ (match (filter (entry-predicate pattern)
+ (manifest-entries manifest))
+ (()
+ (raise (condition
+ (&unmatched-pattern-error
+ (pattern pattern)
+ (manifest manifest)))))
+ (lst
+ (append lst matches))))
+ '()
+ patterns))
(define (manifest-search-paths manifest)
"Return the list of search path specifications that apply to MANIFEST,
diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm
index 5a158799ae..fb7e04904d 100644
--- a/guix/scripts/build.scm
+++ b/guix/scripts/build.scm
@@ -308,7 +308,8 @@ strings like \"guile-next=stable-3.0\" meaning that packages are built using
(package
(inherit old)
(version (string-append "git." branch))
- (source (git-checkout (url url) (branch branch)))))
+ (source (git-checkout (url url) (branch branch)
+ (recursive? #t)))))
(let* ((replacements (evaluate-git-replacement-specs replacement-specs
replace))
diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm
index 683ab3f059..3320200c07 100644
--- a/guix/scripts/pull.scm
+++ b/guix/scripts/pull.scm
@@ -216,30 +216,8 @@ true, display what would be built without actually building it."
(define (honor-x509-certificates store)
"Use the right X.509 certificates for Git checkouts over HTTPS."
- ;; On distros such as CentOS 7, /etc/ssl/certs contains only a couple of
- ;; files (instead of all the certificates) among which "ca-bundle.crt". On
- ;; other distros /etc/ssl/certs usually contains the whole set of
- ;; certificates along with "ca-certificates.crt". Try to choose the right
- ;; one.
- (let ((file (letrec-syntax ((choose
- (syntax-rules ()
- ((_ file rest ...)
- (let ((f file))
- (if (and f (file-exists? f))
- f
- (choose rest ...))))
- ((_)
- #f))))
- (choose (getenv "SSL_CERT_FILE")
- "/etc/ssl/certs/ca-certificates.crt"
- "/etc/ssl/certs/ca-bundle.crt")))
- (directory (or (getenv "SSL_CERT_DIR") "/etc/ssl/certs")))
- (if (or file
- (and=> (stat directory #f)
- (lambda (st)
- (> (stat:nlink st) 2))))
- (set-tls-certificate-locations! directory file)
- (honor-lets-encrypt-certificates! store))))
+ (unless (honor-system-x509-certificates!)
+ (honor-lets-encrypt-certificates! store)))
(define (report-git-error error)
"Report the given Guile-Git error."
diff --git a/guix/status.scm b/guix/status.scm
index 984f329964..cd5027ef17 100644
--- a/guix/status.scm
+++ b/guix/status.scm
@@ -498,14 +498,12 @@ addition to build events."
(spin! #f port))))))
(define erase-current-line*
- (if (isatty?* port)
- (lambda (port)
+ (if (and (not print-log?) (isatty?* port))
+ (lambda ()
(erase-current-line port)
(force-output port))
(const #t)))
- (unless print-log?
- (erase-current-line* port)) ;clear the spinner or progress bar
(match event
(('build-started drv . _)
(let ((properties (derivation-properties
@@ -530,6 +528,7 @@ addition to build events."
(format port (info (G_ "building ~a...")) drv))))
(newline port))
(('build-succeeded drv . _)
+ (erase-current-line*) ;erase spinner or progress bar
(when (or print-log? (not (extended-build-trace-supported?)))
(format port (success (G_ "successfully built ~a")) drv)
(newline port))
@@ -542,6 +541,7 @@ addition to build events."
(length ongoing))
(map build-derivation ongoing)))))
(('build-failed drv . _)
+ (erase-current-line*) ;erase spinner or progress bar
(format port (failure (G_ "build of ~a failed")) drv)
(newline port)
(match (derivation-log-file drv)
diff --git a/guix/ui.scm b/guix/ui.scm
index 9eab4ba3f7..f0465519b6 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -643,6 +643,14 @@ or remove one of them from the profile.")
(leave (G_ "generation ~a of profile '~a' does not exist~%")
(missing-generation-error-generation c)
(profile-error-profile c)))
+ ((unmatched-pattern-error? c)
+ (let ((pattern (unmatched-pattern-error-pattern c)))
+ (leave (G_ "package '~a~@[@~a~]~@[:~a~]' not found in profile~%")
+ (manifest-pattern-name pattern)
+ (manifest-pattern-version pattern)
+ (match (manifest-pattern-output pattern)
+ ("out" #f)
+ (output output)))))
((profile-collision-error? c)
(let ((entry (profile-collision-error-entry c))
(conflict (profile-collision-error-conflict c)))