summaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
Diffstat (limited to 'guix')
-rw-r--r--guix/build-system/linux-module.scm3
-rw-r--r--guix/build-system/qt.scm295
-rw-r--r--guix/build/emacs-build-system.scm39
-rw-r--r--guix/build/qt-build-system.scm109
-rw-r--r--guix/build/syscalls.scm4
-rw-r--r--guix/gexp.scm7
-rw-r--r--guix/import/opam.scm16
-rw-r--r--guix/lint.scm5
-rw-r--r--guix/scripts/offload.scm30
-rw-r--r--guix/scripts/package.scm6
-rw-r--r--guix/scripts/pull.scm73
-rwxr-xr-xguix/scripts/substitute.scm16
-rw-r--r--guix/scripts/system.scm15
-rw-r--r--guix/ssh.scm69
-rw-r--r--guix/ui.scm26
15 files changed, 609 insertions, 104 deletions
diff --git a/guix/build-system/linux-module.scm b/guix/build-system/linux-module.scm
index 6084d22210..dde2423434 100644
--- a/guix/build-system/linux-module.scm
+++ b/guix/build-system/linux-module.scm
@@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2019 Danny Milosavljevic <dannym@scratchpost.org>
+;;; Copyright © 2019 Tobias Geerinckx-Rice <me@tobias.gr>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -120,6 +121,7 @@
(define* (linux-module-build store name inputs
#:key
(search-paths '())
+ (make-flags '())
(tests? #t)
(phases '(@ (guix build linux-module-build-system)
%standard-phases))
@@ -146,6 +148,7 @@
search-paths)
#:phases ,phases
#:system ,system
+ #:make-flags ,make-flags
#:tests? ,tests?
#:outputs %outputs
#:inputs %build-inputs)))
diff --git a/guix/build-system/qt.scm b/guix/build-system/qt.scm
new file mode 100644
index 0000000000..b776845377
--- /dev/null
+++ b/guix/build-system/qt.scm
@@ -0,0 +1,295 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013 Cyril Roelandt <tipecaml@gmail.com>
+;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2019 Hartmut Goebel <h.goebel@crazy-compilers.com>
+;;;
+;;; 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 <http://www.gnu.org/licenses/>.
+
+(define-module (guix build-system qt)
+ #:use-module (guix store)
+ #:use-module (guix utils)
+ #:use-module (guix derivations)
+ #:use-module (guix search-paths)
+ #:use-module (guix build-system)
+ #:use-module (guix build-system cmake)
+ #:use-module (guix build-system gnu)
+ #:use-module (guix packages)
+ #:use-module (ice-9 match)
+ #:export (%qt-build-system-modules
+ qt-build
+ qt-build-system))
+
+;; Commentary:
+;;
+;; This build system is an extension of the 'cmake-build-system'. It
+;; accommodates the needs of Qt and KDE applications by adding a phase run
+;; after the 'install' phase:
+;;
+;; 'qt-wrap' phase:
+;;
+;; This phase looks for Qt5 plugin paths, QML paths and some XDG paths as well
+;; as the corresponding environment variables. If any of these is found in
+;; the output or if respective environment variables are set, then all
+;; programs in the output's "bin", "sbin", "libexec and "lib/libexec"
+;; directories are wrapped in scripts defining the necessary environment
+;; variables.
+;;
+;; Code:
+
+(define %qt-build-system-modules
+ ;; Build-side modules imported and used by default.
+ `((guix build qt-build-system)
+ ,@%cmake-build-system-modules))
+
+(define (default-cmake)
+ "Return the default CMake package."
+
+ ;; Do not use `@' to avoid introducing circular dependencies.
+ (let ((module (resolve-interface '(gnu packages cmake))))
+ (module-ref module 'cmake-minimal)))
+
+;; This barely is a copy from (guix build-system cmake), only adjusted to use
+;; the variables defined here.
+(define* (lower name
+ #:key source inputs native-inputs outputs system target
+ (cmake (default-cmake))
+ #:allow-other-keys
+ #:rest arguments)
+ "Return a bag for NAME."
+ (define private-keywords
+ `(#:source #:cmake #:inputs #:native-inputs #:outputs
+ ,@(if target '() '(#:target))))
+
+ (bag
+ (name name)
+ (system system)
+ (target target)
+ (build-inputs `(,@(if source
+ `(("source" ,source))
+ '())
+ ,@`(("cmake" ,cmake))
+ ,@native-inputs
+ ,@(if target
+ ;; Use the standard cross inputs of
+ ;; 'gnu-build-system'.
+ (standard-cross-packages target 'host)
+ '())
+ ;; Keep the standard inputs of 'gnu-build-system'.
+ ,@(standard-packages)))
+ (host-inputs inputs)
+
+ ;; The cross-libc is really a target package, but for bootstrapping
+ ;; reasons, we can't put it in 'host-inputs'. Namely, 'cross-gcc' is a
+ ;; native package, so it would end up using a "native" variant of
+ ;; 'cross-libc' (built with 'gnu-build'), whereas all the other packages
+ ;; would use a target variant (built with 'gnu-cross-build'.)
+ (target-inputs (if target
+ (standard-cross-packages target 'target)
+ '()))
+ (outputs outputs)
+ (build (if target qt-cross-build qt-build))
+ (arguments (strip-keyword-arguments private-keywords arguments))))
+
+
+(define* (qt-build store name inputs
+ #:key (guile #f)
+ (outputs '("out")) (configure-flags ''())
+ (search-paths '())
+ (make-flags ''())
+ (out-of-source? #t)
+ (build-type "RelWithDebInfo")
+ (tests? #t)
+ (test-target "test")
+ (parallel-build? #t) (parallel-tests? #f)
+ (validate-runpath? #t)
+ (patch-shebangs? #t)
+ (strip-binaries? #t)
+ (strip-flags ''("--strip-debug"))
+ (strip-directories ''("lib" "lib64" "libexec"
+ "bin" "sbin"))
+ (phases '(@ (guix build qt-build-system)
+ %standard-phases))
+ (qt-wrap-excluded-outputs ''())
+ (system (%current-system))
+ (imported-modules %qt-build-system-modules)
+ (modules '((guix build cmake-build-system)
+ (guix build utils))))
+ "Build SOURCE using CMAKE, and with INPUTS. This assumes that SOURCE
+provides a 'CMakeLists.txt' file as its build system."
+ (define builder
+ `(begin
+ (use-modules ,@modules)
+ (cmake-build #:source ,(match (assoc-ref inputs "source")
+ (((? derivation? source))
+ (derivation->output-path source))
+ ((source)
+ source)
+ (source
+ source))
+ #:system ,system
+ #:outputs %outputs
+ #:inputs %build-inputs
+ #:search-paths ',(map search-path-specification->sexp
+ search-paths)
+ #:phases ,phases
+ #:qt-wrap-excluded-outputs ,qt-wrap-excluded-outputs
+ #:configure-flags ,configure-flags
+ #:make-flags ,make-flags
+ #:out-of-source? ,out-of-source?
+ #:build-type ,build-type
+ #:tests? ,tests?
+ #:test-target ,test-target
+ #:parallel-build? ,parallel-build?
+ #:parallel-tests? ,parallel-tests?
+ #:validate-runpath? ,validate-runpath?
+ #:patch-shebangs? ,patch-shebangs?
+ #:strip-binaries? ,strip-binaries?
+ #:strip-flags ,strip-flags
+ #:strip-directories ,strip-directories)))
+
+ (define guile-for-build
+ (match guile
+ ((? package?)
+ (package-derivation store guile system #:graft? #f))
+ (#f ; the default
+ (let* ((distro (resolve-interface '(gnu packages commencement)))
+ (guile (module-ref distro 'guile-final)))
+ (package-derivation store guile system #:graft? #f)))))
+
+ (build-expression->derivation store name builder
+ #:system system
+ #:inputs inputs
+ #:modules imported-modules
+ #:outputs outputs
+ #:guile-for-build guile-for-build))
+
+
+;;;
+;;; Cross-compilation.
+;;;
+
+(define* (qt-cross-build store name
+ #:key
+ target native-drvs target-drvs
+ (guile #f)
+ (outputs '("out"))
+ (configure-flags ''())
+ (search-paths '())
+ (native-search-paths '())
+ (make-flags ''())
+ (out-of-source? #t)
+ (build-type "RelWithDebInfo")
+ (tests? #f) ; nothing can be done
+ (test-target "test")
+ (parallel-build? #t) (parallel-tests? #f)
+ (validate-runpath? #t)
+ (patch-shebangs? #t)
+ (strip-binaries? #t)
+ (strip-flags ''("--strip-debug"
+ "--enable-deterministic-archives"))
+ (strip-directories ''("lib" "lib64" "libexec"
+ "bin" "sbin"))
+ (phases '(@ (guix build qt-build-system)
+ %standard-phases))
+ (system (%current-system))
+ (build (nix-system->gnu-triplet system))
+ (imported-modules %qt-build-system-modules)
+ (modules '((guix build cmake-build-system)
+ (guix build utils))))
+ "Cross-build NAME using CMAKE for TARGET, where TARGET is a GNU triplet and
+with INPUTS. This assumes that SOURCE provides a 'CMakeLists.txt' file as its
+build system."
+ (define builder
+ `(begin
+ (use-modules ,@modules)
+ (let ()
+ (define %build-host-inputs
+ ',(map (match-lambda
+ ((name (? derivation? drv) sub ...)
+ `(,name . ,(apply derivation->output-path drv sub)))
+ ((name path)
+ `(,name . ,path)))
+ native-drvs))
+
+ (define %build-target-inputs
+ ',(map (match-lambda
+ ((name (? derivation? drv) sub ...)
+ `(,name . ,(apply derivation->output-path drv sub)))
+ ((name (? package? pkg) sub ...)
+ (let ((drv (package-cross-derivation store pkg
+ target system)))
+ `(,name . ,(apply derivation->output-path drv sub))))
+ ((name path)
+ `(,name . ,path)))
+ target-drvs))
+
+ (cmake-build #:source ,(match (assoc-ref native-drvs "source")
+ (((? derivation? source))
+ (derivation->output-path source))
+ ((source)
+ source)
+ (source
+ source))
+ #:system ,system
+ #:build ,build
+ #:target ,target
+ #:outputs %outputs
+ #:inputs %build-target-inputs
+ #:native-inputs %build-host-inputs
+ #:search-paths ',(map search-path-specification->sexp
+ search-paths)
+ #:native-search-paths ',(map
+ search-path-specification->sexp
+ native-search-paths)
+ #:phases ,phases
+ #:configure-flags ,configure-flags
+ #:make-flags ,make-flags
+ #:out-of-source? ,out-of-source?
+ #:build-type ,build-type
+ #:tests? ,tests?
+ #:test-target ,test-target
+ #:parallel-build? ,parallel-build?
+ #:parallel-tests? ,parallel-tests?
+ #:validate-runpath? ,validate-runpath?
+ #:patch-shebangs? ,patch-shebangs?
+ #:strip-binaries? ,strip-binaries?
+ #:strip-flags ,strip-flags
+ #:strip-directories ,strip-directories))))
+
+ (define guile-for-build
+ (match guile
+ ((? package?)
+ (package-derivation store guile system #:graft? #f))
+ (#f ; the default
+ (let* ((distro (resolve-interface '(gnu packages commencement)))
+ (guile (module-ref distro 'guile-final)))
+ (package-derivation store guile system #:graft? #f)))))
+
+ (build-expression->derivation store name builder
+ #:system system
+ #:inputs (append native-drvs target-drvs)
+ #:outputs outputs
+ #:modules imported-modules
+ #:guile-for-build guile-for-build))
+
+(define qt-build-system
+ (build-system
+ (name 'qt)
+ (description
+ "The CMake build system augmented with definition of suitable environment
+variables for Qt and KDE in program wrappers.")
+ (lower lower)))
diff --git a/guix/build/emacs-build-system.scm b/guix/build/emacs-build-system.scm
index f0c41812f1..e2b792d3dc 100644
--- a/guix/build/emacs-build-system.scm
+++ b/guix/build/emacs-build-system.scm
@@ -40,11 +40,10 @@
;;
;; Code:
-;; Directory suffix where we install ELPA packages. We avoid ".../elpa" as
-;; Emacs expects to find the ELPA repository 'archive-contents' file and the
-;; archive signature.
-(define %legacy-install-suffix "/share/emacs/site-lisp")
-(define %install-suffix (string-append %legacy-install-suffix "/guix.d"))
+;;; All the packages are installed directly under site-lisp, which means that
+;;; having that directory in the EMACSLOADPATH is enough to have them found by
+;;; Emacs.
+(define %install-dir "/share/emacs/site-lisp")
;; These are the default inclusion/exclusion regexps for the install phase.
(define %default-include '("^[^/]*\\.el$" "^[^/]*\\.info$" "^doc/.*\\.info$"))
@@ -87,11 +86,10 @@ environment variable\n" source-directory)))
"Compile .el files."
(let* ((emacs (string-append (assoc-ref inputs "emacs") "/bin/emacs"))
(out (assoc-ref outputs "out"))
- (elpa-name-ver (store-directory->elpa-name-version out))
- (el-dir (string-append out %install-suffix "/" elpa-name-ver)))
+ (site-lisp (string-append out %install-dir)))
(setenv "SHELL" "sh")
(parameterize ((%emacs emacs))
- (emacs-byte-compile-directory el-dir))))
+ (emacs-byte-compile-directory site-lisp))))
(define* (patch-el-files #:key outputs #:allow-other-keys)
"Substitute the absolute \"/bin/\" directory with the right location in the
@@ -108,9 +106,7 @@ store in '.el' files."
#:binary #t))
(let* ((out (assoc-ref outputs "out"))
- (elpa-name-ver (store-directory->elpa-name-version out))
- (el-dir (string-append out %install-suffix "/" elpa-name-ver))
-
+ (site-lisp (string-append out %install-dir))
;; (ice-9 regex) uses libc's regexp routines, which cannot deal with
;; strings containing NULs. Filter out such files. TODO: Remove
;; this workaround when <https://bugs.gnu.org/30116> is fixed.
@@ -124,7 +120,7 @@ store in '.el' files."
(error "patch-el-files: unable to locate " cmd-name))
(string-append "\"" cmd "\"")))))
- (with-directory-excursion el-dir
+ (with-directory-excursion site-lisp
;; Some old '.el' files (e.g., tex-buf.el in AUCTeX) are still
;; ISO-8859-1-encoded.
(unless (false-if-exception (substitute-program-names))
@@ -175,15 +171,14 @@ parallel. PARALLEL-TESTS? is ignored when using a non-make TEST-COMMAND."
(not (any (cut match-stripped-file "excluded" <>) exclude)))))
(let* ((out (assoc-ref outputs "out"))
- (elpa-name-ver (store-directory->elpa-name-version out))
- (target-directory (string-append out %install-suffix "/" elpa-name-ver))
+ (site-lisp (string-append out %install-dir))
(files-to-install (find-files source install-file?)))
(cond
((not (null? files-to-install))
(for-each
(lambda (file)
(let* ((stripped-file (string-drop file (string-length source)))
- (target-file (string-append target-directory stripped-file)))
+ (target-file (string-append site-lisp stripped-file)))
(format #t "`~a' -> `~a'~%" file target-file)
(install-file file (dirname target-file))))
files-to-install)
@@ -197,14 +192,12 @@ parallel. PARALLEL-TESTS? is ignored when using a non-make TEST-COMMAND."
(define* (move-doc #:key outputs #:allow-other-keys)
"Move info files from the ELPA package directory to the info directory."
(let* ((out (assoc-ref outputs "out"))
- (elpa-name-ver (store-directory->elpa-name-version out))
- (el-dir (string-append out %install-suffix "/" elpa-name-ver))
- (name-ver (strip-store-file-name out))
+ (site-lisp (string-append out %install-dir))
(info-dir (string-append out "/share/info/"))
- (info-files (find-files el-dir "\\.info$")))
+ (info-files (find-files site-lisp "\\.info$")))
(unless (null? info-files)
(mkdir-p info-dir)
- (with-directory-excursion el-dir
+ (with-directory-excursion site-lisp
(when (file-exists? "dir") (delete-file "dir"))
(for-each (lambda (f)
(copy-file f (string-append info-dir "/" (basename f)))
@@ -216,11 +209,11 @@ parallel. PARALLEL-TESTS? is ignored when using a non-make TEST-COMMAND."
"Generate the autoloads file."
(let* ((emacs (string-append (assoc-ref inputs "emacs") "/bin/emacs"))
(out (assoc-ref outputs "out"))
+ (site-lisp (string-append out %install-dir))
(elpa-name-ver (store-directory->elpa-name-version out))
- (elpa-name (package-name->name+version elpa-name-ver))
- (el-dir (string-append out %install-suffix "/" elpa-name-ver)))
+ (elpa-name (package-name->name+version elpa-name-ver)))
(parameterize ((%emacs emacs))
- (emacs-generate-autoloads elpa-name el-dir))))
+ (emacs-generate-autoloads elpa-name site-lisp))))
(define (emacs-package? name)
"Check if NAME correspond to the name of an Emacs package."
diff --git a/guix/build/qt-build-system.scm b/guix/build/qt-build-system.scm
new file mode 100644
index 0000000000..46fcad7848
--- /dev/null
+++ b/guix/build/qt-build-system.scm
@@ -0,0 +1,109 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2014 Federico Beffa <beffa@fbengineering.ch>
+;;; Copyright © 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2018 Mark H Weaver <mhw@netris.org>
+;;; Copyright © 2019 Hartmut Goebel <h.goebel@crazy-compilers.com>
+;;;
+;;; 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 <http://www.gnu.org/licenses/>.
+
+(define-module (guix build qt-build-system)
+ #:use-module ((guix build cmake-build-system) #:prefix cmake:)
+ #:use-module (guix build utils)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 regex)
+ #:use-module (ice-9 ftw)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+ #:export (%standard-phases
+ qt-build))
+
+;; Commentary:
+;;
+;; Builder-side code of the standard Qt build procedure.
+;;
+;; Code:
+
+(define (variables-for-wrapping base-directories)
+
+ (define (collect-sub-dirs base-directories subdirectory)
+ (filter-map
+ (lambda (dir)
+ (let ((directory (string-append dir subdirectory)))
+ (if (directory-exists? directory) directory #f)))
+ base-directories))
+
+ (filter
+ (lambda (var-to-wrap) (not (null? (last var-to-wrap))))
+ (map
+ (lambda (var-spec)
+ `(,(first var-spec) = ,(collect-sub-dirs base-directories (last var-spec))))
+ (list
+ ;; these shall match the search-path-specification for Qt and KDE
+ ;; libraries
+ '("XDG_DATA_DIRS" "/share")
+ '("XDG_CONFIG_DIRS" "/etc/xdg")
+ '("QT_PLUGIN_PATH" "/lib/qt5/plugins")
+ '("QML2_IMPORT_PATH" "/lib/qt5/qml")))))
+
+(define* (wrap-all-programs #:key inputs outputs
+ (qt-wrap-excluded-outputs '())
+ #:allow-other-keys)
+ "Implement phase \"qt-wrap\": look for GSettings schemas and
+gtk+-v.0 libraries and create wrappers with suitably set environment variables
+if found.
+
+Wrapping is not applied to outputs whose name is listed in
+QT-WRAP-EXCLUDED-OUTPUTS. This is useful when an output is known not
+to contain any Qt binaries, and where wrapping would gratuitously
+add a dependency of that output on Qt."
+ (define (find-files-to-wrap directory)
+ (append-map
+ (lambda (dir)
+ (if (directory-exists? dir) (find-files dir ".*") (list)))
+ (list (string-append directory "/bin")
+ (string-append directory "/sbin")
+ (string-append directory "/libexec")
+ (string-append directory "/lib/libexec"))))
+
+ (define input-directories
+ ;; FIXME: Filter out unwanted inputs, e.g. cmake
+ (match inputs
+ (((_ . dir) ...)
+ dir)))
+
+ (define handle-output
+ (match-lambda
+ ((output . directory)
+ (unless (member output qt-wrap-excluded-outputs)
+ (let ((bin-list (find-files-to-wrap directory))
+ (vars-to-wrap (variables-for-wrapping
+ (append (list output)
+ input-directories))))
+ (when (not (null? vars-to-wrap))
+ (for-each (cut apply wrap-program <> vars-to-wrap)
+ bin-list)))))))
+
+ (for-each handle-output outputs)
+ #t)
+
+(define %standard-phases
+ (modify-phases cmake:%standard-phases
+ (add-after 'install 'qt-wrap wrap-all-programs)))
+
+(define* (qt-build #:key inputs (phases %standard-phases)
+ #:allow-other-keys #:rest args)
+ "Build the given package, applying all of PHASES in order."
+ (apply cmake:cmake-build #:inputs inputs #:phases phases args))
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index a5a9c92a42..ce7999b433 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -1127,7 +1127,9 @@ exception if it's already taken."
(lambda (key . args)
(match key
('flock-error
- (handler args))
+ (apply handler args)
+ ;; No open port to the lock, so return #f.
+ #f)
('system-error
;; When using the statically-linked Guile in the initrd,
;; 'fcntl-flock' returns ENOSYS unconditionally. Ignore
diff --git a/guix/gexp.scm b/guix/gexp.scm
index b640c079e4..a96592ac76 100644
--- a/guix/gexp.scm
+++ b/guix/gexp.scm
@@ -320,9 +320,16 @@ It is implemented as a macro to capture the current source directory where it
appears."
(syntax-case s ()
((_ file rest ...)
+ (string? (syntax->datum #'file))
+ ;; FILE is a literal, so resolve it relative to the source directory.
#'(%local-file file
(delay (absolute-file-name file (current-source-directory)))
rest ...))
+ ((_ file rest ...)
+ ;; Resolve FILE relative to the current directory.
+ #'(%local-file file
+ (delay (absolute-file-name file (getcwd)))
+ rest ...))
((_)
#'(syntax-error "missing file name"))
(id
diff --git a/guix/import/opam.scm b/guix/import/opam.scm
index 7f089a5cf3..e258c4197f 100644
--- a/guix/import/opam.scm
+++ b/guix/import/opam.scm
@@ -49,7 +49,7 @@
(define-peg-pattern COLON none ":")
;; A string character is any character that is not a quote, or a quote preceded by a backslash.
(define-peg-pattern STRCHR body
- (or " " "!" (and (ignore "\\") "\"")
+ (or " " "!" "\n" (and (ignore "\\") "\"")
(and (ignore "\\") "\\") (range #\# #\頋)))
(define-peg-pattern operator all (or "=" "!" "<" ">"))
@@ -249,10 +249,7 @@ path to the repository."
(url-dict (metadata-ref opam-content "url"))
(source-url (metadata-ref url-dict "src"))
(requirements (metadata-ref opam-content "depends"))
- (dependencies (filter
- (lambda (name)
- (not (member name '("dune" "jbuilder"))))
- (dependency-list->names requirements)))
+ (dependencies (dependency-list->names requirements))
(native-dependencies (depends->native-inputs requirements))
(inputs (dependency-list->inputs (depends->inputs requirements)))
(native-inputs (dependency-list->inputs
@@ -264,8 +261,8 @@ path to the repository."
native-dependencies))))
;; If one of these are required at build time, it means we
;; can use the much nicer dune-build-system.
- (let ((use-dune? (or (member "dune" native-dependencies)
- (member "jbuilder" native-dependencies))))
+ (let ((use-dune? (or (member "dune" (append dependencies native-dependencies))
+ (member "jbuilder" (append dependencies native-dependencies)))))
(call-with-temporary-output-file
(lambda (temp port)
(and (url-fetch source-url temp)
@@ -297,7 +294,10 @@ path to the repository."
(synopsis ,(metadata-ref opam-content "synopsis"))
(description ,(metadata-ref opam-content "description"))
(license #f))
- dependencies)))))))
+ (filter
+ (lambda (name)
+ (not (member name '("dune" "jbuilder"))))
+ dependencies))))))))
(define (opam-recursive-import package-name)
(recursive-import package-name #f
diff --git a/guix/lint.scm b/guix/lint.scm
index 629604e0e9..cd2ea571ed 100644
--- a/guix/lint.scm
+++ b/guix/lint.scm
@@ -1122,7 +1122,10 @@ Heritage")
((key . args)
(if (eq? key skip-key)
'()
- (apply throw key args)))))))
+ (with-networking-fail-safe
+ (G_ "while connecting to Software Heritage")
+ '()
+ (apply throw key args))))))))
;;;
diff --git a/guix/scripts/offload.scm b/guix/scripts/offload.scm
index 18473684eb..e81b6c25f2 100644
--- a/guix/scripts/offload.scm
+++ b/guix/scripts/offload.scm
@@ -149,19 +149,6 @@ ignoring it~%")
(leave (G_ "failed to load machine file '~a': ~s~%")
file args))))))
-(define (host-key->type+key host-key)
- "Destructure HOST-KEY, an OpenSSH host key string, and return two values:
-its key type as a symbol, and the actual base64-encoded string."
- (define (type->symbol type)
- (and (string-prefix? "ssh-" type)
- (string->symbol (string-drop type 4))))
-
- (match (string-tokenize host-key)
- ((type key x)
- (values (type->symbol type) key))
- ((type key)
- (values (type->symbol type) key))))
-
(define (private-key-from-file* file)
"Like 'private-key-from-file', but raise an error that 'with-error-handling'
can interpret meaningfully."
@@ -203,21 +190,8 @@ private key from '~a': ~a")
(build-machine-compression-level machine))))
(match (connect! session)
('ok
- ;; Authenticate the server. XXX: Guile-SSH 0.10.1 doesn't know about
- ;; ed25519 keys and 'get-key-type' returns #f in that case.
- (let-values (((server) (get-server-public-key session))
- ((type key) (host-key->type+key
- (build-machine-host-key machine))))
- (unless (and (or (not (get-key-type server))
- (eq? (get-key-type server) type))
- (string=? (public-key->string server) key))
- ;; Key mismatch: something's wrong. XXX: It could be that the server
- ;; provided its Ed25519 key when we where expecting its RSA key.
- (leave (G_ "server at '~a' returned host key '~a' of type '~a' \
-instead of '~a' of type '~a'~%")
- (build-machine-name machine)
- (public-key->string server) (get-key-type server)
- key type)))
+ ;; Make sure the server's key is what we expect.
+ (authenticate-server* session (build-machine-host-key machine))
(let ((auth (userauth-public-key! session private)))
(unless (eq? 'success auth)
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 97436feee7..92c6e34194 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -866,11 +866,7 @@ processed, #f otherwise."
;; First, acquire a lock on the profile, to ensure only one guix process
;; is modifying it at a time.
- (with-file-lock/no-wait (string-append profile ".lock")
- (lambda (key . args)
- (leave (G_ "profile ~a is locked by another process~%")
- profile))
-
+ (with-profile-lock profile
;; Then, process roll-backs, generation removals, etc.
(for-each (match-lambda
((key . arg)
diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm
index a74776bd7b..19410ad141 100644
--- a/guix/scripts/pull.scm
+++ b/guix/scripts/pull.scm
@@ -54,6 +54,7 @@
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
#:use-module (srfi srfi-37)
+ #:use-module (web uri)
#:use-module (ice-9 match)
#:use-module (ice-9 vlist)
#:use-module (ice-9 format)
@@ -184,6 +185,42 @@ Download and deploy the latest version of Guix.\n"))
%standard-build-options))
+(define %vcs-web-views
+ ;; Hard-coded list of host names and corresponding web view URL templates.
+ ;; TODO: Allow '.guix-channel' files to specify a URL template.
+ (let ((labhub-url (lambda (repository-url commit)
+ (string-append
+ (if (string-suffix? ".git" repository-url)
+ (string-drop-right repository-url 4)
+ repository-url)
+ "/commit/" commit))))
+ `(("git.savannah.gnu.org"
+ ,(lambda (repository-url commit)
+ (string-append (string-replace-substring repository-url
+ "/git/" "/cgit/")
+ "/commit/?id=" commit)))
+ ("notabug.org" ,labhub-url)
+ ("framagit.org" ,labhub-url)
+ ("gitlab.com" ,labhub-url)
+ ("gitlab.inria.fr" ,labhub-url)
+ ("github.com" ,labhub-url))))
+
+(define* (channel-commit-hyperlink channel
+ #:optional
+ (commit (channel-commit channel)))
+ "Return a hyperlink for COMMIT in CHANNEL, using COMMIT as the hyperlink's
+text. The hyperlink links to a web view of COMMIT, when available."
+ (let* ((url (channel-url channel))
+ (uri (string->uri url))
+ (host (and uri (uri-host uri))))
+ (if host
+ (match (assoc host %vcs-web-views)
+ (#f
+ commit)
+ ((_ template)
+ (hyperlink (template url commit) commit)))
+ commit)))
+
(define* (display-profile-news profile #:key concise?
current-is-newer?)
"Display what's up in PROFILE--new packages, and all that. If
@@ -247,15 +284,20 @@ purposes."
;; When Texinfo markup is invalid, display it as-is.
(const title)))))))
-(define (display-news-entry entry language port)
- "Display ENTRY, a <channel-news-entry>, in LANGUAGE, a language code, to
-PORT."
+(define (display-news-entry entry channel language port)
+ "Display ENTRY, a <channel-news-entry> from CHANNEL, in LANGUAGE, a language
+code, to PORT."
(define body
(channel-news-entry-body entry))
+ (define commit
+ (channel-news-entry-commit entry))
+
(display-news-entry-title entry language port)
(format port (dim (G_ " commit ~a~%"))
- (channel-news-entry-commit entry))
+ (if (supports-hyperlinks?)
+ (channel-commit-hyperlink channel commit)
+ commit))
(newline port)
(let ((body (or (assoc-ref body language)
(assoc-ref body (%default-message-language))
@@ -293,7 +335,7 @@ to display."
(channel-name channel))
(for-each (if concise?
(cut display-news-entry-title <> language port)
- (cut display-news-entry <> language port))
+ (cut display-news-entry <> channel language port))
entries)
(newline port)
#t))))))
@@ -528,10 +570,17 @@ way and displaying details about the channel's source code."
('branch branch)
('commit commit)
_ ...))
- (format #t (G_ " repository URL: ~a~%") url)
- (when branch
- (format #t (G_ " branch: ~a~%") branch))
- (format #t (G_ " commit: ~a~%") commit))
+ (let ((channel (channel (name 'nameless)
+ (url url)
+ (branch branch)
+ (commit commit))))
+ (format #t (G_ " repository URL: ~a~%") url)
+ (when branch
+ (format #t (G_ " branch: ~a~%") branch))
+ (format #t (G_ " commit: ~a~%")
+ (if (supports-hyperlinks?)
+ (channel-commit-hyperlink channel commit)
+ commit))))
(_ #f)))
;; Show most recently installed packages last.
@@ -817,11 +866,7 @@ Use '~/.config/guix/channels.scm' instead."))
(if (assoc-ref opts 'bootstrap?)
%bootstrap-guile
(canonical-package guile-2.2)))))
- (with-file-lock/no-wait (string-append profile ".lock")
- (lambda (key . args)
- (leave (G_ "profile ~a is locked by another process~%")
- profile))
-
+ (with-profile-lock profile
(run-with-store store
(build-and-install instances profile
#:dry-run?
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index 421561a4ea..b6034a75d2 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -322,22 +322,6 @@ must contain the original contents of a narinfo file."
(and=> signature narinfo-signature->canonical-sexp))
str)))
-(define* (assert-valid-signature narinfo signature hash
- #:optional (acl (current-acl)))
- "Bail out if SIGNATURE, a canonical sexp representing the signature of
-NARINFO, doesn't match HASH, a bytevector containing the hash of NARINFO."
- (let ((uri (uri->string (first (narinfo-uris narinfo)))))
- (signature-case (signature hash acl)
- (valid-signature #t)
- (invalid-signature
- (leave (G_ "invalid signature for '~a'~%") uri))
- (hash-mismatch
- (leave (G_ "hash mismatch for '~a'~%") uri))
- (unauthorized-key
- (leave (G_ "'~a' is signed with an unauthorized key~%") uri))
- (corrupt-signature
- (leave (G_ "signature on '~a' is corrupt~%") uri)))))
-
(define* (read-narinfo port #:optional url
#:key size)
"Read a narinfo from PORT. If URL is true, it must be a string used to
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index e49c9d36b9..5f0dce2093 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -2,7 +2,7 @@
;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016 Alex Kost <alezost@gmail.com>
;;; Copyright © 2016, 2017, 2018 Chris Marusich <cmmarusich@gmail.com>
-;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
+;;; Copyright © 2017, 2019 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2019 Christopher Baines <mail@cbaines.net>
;;;
@@ -932,6 +932,8 @@ Some ACTIONS support additional ARGS.\n"))
(display (G_ "
--skip-checks skip file system and initrd module safety checks"))
(display (G_ "
+ --target=TRIPLET cross-build for TRIPLET--e.g., \"armel-linux-gnu\""))
+ (display (G_ "
-v, --verbosity=LEVEL use the given verbosity LEVEL"))
(newline)
(display (G_ "
@@ -1004,6 +1006,10 @@ Some ACTIONS support additional ARGS.\n"))
(lambda (opt name arg result)
(alist-cons 'system arg
(alist-delete 'system result eq?))))
+ (option '("target") #t #f
+ (lambda (opt name arg result)
+ (alist-cons 'target arg
+ (alist-delete 'target result eq?))))
(option '(#\r "root") #t #f
(lambda (opt name arg result)
(alist-cons 'gc-root arg result)))
@@ -1012,6 +1018,7 @@ Some ACTIONS support additional ARGS.\n"))
(define %default-options
;; Alist of default option values.
`((system . ,(%current-system))
+ (target . #f)
(substitutes? . #t)
(offload? . #t)
(print-build-trace? . #t)
@@ -1045,6 +1052,7 @@ resulting from command-line parsing."
((x . _) x)))
(expr (assoc-ref opts 'expression))
(system (assoc-ref opts 'system))
+ (target (assoc-ref opts 'target))
(os (ensure-operating-system
(or file expr)
(cond
@@ -1061,7 +1069,7 @@ resulting from command-line parsing."
(dry? (assoc-ref opts 'dry-run?))
(bootloader? (assoc-ref opts 'install-bootloader?))
- (target (match args
+ (target-file (match args
((first second) second)
(_ #f)))
(bootloader-target
@@ -1103,9 +1111,10 @@ resulting from command-line parsing."
(_ #f))
opts)
#:install-bootloader? bootloader?
- #:target target
+ #:target target-file
#:bootloader-target bootloader-target
#:gc-root (assoc-ref opts 'gc-root)))))
+ #:target target
#:system system))
(warn-about-disk-space)))
diff --git a/guix/ssh.scm b/guix/ssh.scm
index 5fd3c280e8..291ce20b61 100644
--- a/guix/ssh.scm
+++ b/guix/ssh.scm
@@ -37,6 +37,8 @@
#:use-module (ice-9 format)
#:use-module (ice-9 binary-ports)
#:export (open-ssh-session
+ authenticate-server*
+
remote-inferior
remote-daemon-channel
connect-to-remote-daemon
@@ -60,15 +62,56 @@
(define %compression
"zlib@openssh.com,zlib")
+(define (host-key->type+key host-key)
+ "Destructure HOST-KEY, an OpenSSH host key string, and return two values:
+its key type as a symbol, and the actual base64-encoded string."
+ (define (type->symbol type)
+ (and (string-prefix? "ssh-" type)
+ (string->symbol (string-drop type 4))))
+
+ (match (string-tokenize host-key)
+ ((type key x)
+ (values (type->symbol type) key))
+ ((type key)
+ (values (type->symbol type) key))))
+
+(define (authenticate-server* session key)
+ "Make sure the server for SESSION has the given KEY, where KEY is a string
+such as \"ssh-ed25519 AAAAC3Nz… root@example.org\". Raise an exception if the
+actual key does not match."
+ (let-values (((server) (get-server-public-key session))
+ ((type key) (host-key->type+key key)))
+ (unless (and (or (not (get-key-type server))
+ (eq? (get-key-type server) type))
+ (string=? (public-key->string server) key))
+ ;; Key mismatch: something's wrong. XXX: It could be that the server
+ ;; provided its Ed25519 key when we where expecting its RSA key. XXX:
+ ;; Guile-SSH 0.10.1 doesn't know about ed25519 keys and 'get-key-type'
+ ;; returns #f in that case.
+ (raise (condition
+ (&message
+ (message (format #f (G_ "server at '~a' returned host key \
+'~a' of type '~a' instead of '~a' of type '~a'~%")
+ (session-get session 'host)
+ (public-key->string server)
+ (get-key-type server)
+ key type))))))))
+
(define* (open-ssh-session host #:key user port identity
+ host-key
(compression %compression)
(timeout 3600))
"Open an SSH session for HOST and return it. IDENTITY specifies the file
name of a private key to use for authenticating with the host. When USER,
PORT, or IDENTITY are #f, use default values or whatever '~/.ssh/config'
-specifies; otherwise use them. Install TIMEOUT as the maximum time in seconds
-after which a read or write operation on a channel of the returned session is
-considered as failing.
+specifies; otherwise use them.
+
+When HOST-KEY is true, it must be a string like \"ssh-ed25519 AAAAC3Nz…
+root@example.org\"; the server is authenticated and an error is raised if its
+host key is different from HOST-KEY.
+
+Install TIMEOUT as the maximum time in seconds after which a read or write
+operation on a channel of the returned session is considered as failing.
Throw an error on failure."
(let ((session (make-session #:user user
@@ -78,6 +121,11 @@ Throw an error on failure."
#:timeout 10 ;seconds
;; #:log-verbosity 'protocol
+ ;; Prevent libssh from reading
+ ;; ~/.ssh/known_hosts when the caller provides
+ ;; a HOST-KEY to match against.
+ #:knownhosts (and host-key "/dev/null")
+
;; We need lightweight compression when
;; exchanging full archives.
#:compression compression
@@ -88,6 +136,21 @@ Throw an error on failure."
(match (connect! session)
('ok
+ (if host-key
+ ;; Make sure the server's key is what we expect.
+ (authenticate-server* session host-key)
+
+ ;; Authenticate against ~/.ssh/known_hosts.
+ (match (authenticate-server session)
+ ('ok #f)
+ (reason
+ (raise (condition
+ (&message
+ (message (format #f (G_ "failed to authenticate \
+server at '~a': ~a")
+ (session-get session 'host)
+ reason))))))))
+
;; Use public key authentication, via the SSH agent if it's available.
(match (userauth-public-key/auto! session)
('success
diff --git a/guix/ui.scm b/guix/ui.scm
index e31db33d3b..540671f3dd 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -47,8 +47,8 @@
#:use-module ((guix licenses)
#:select (license? license-name license-uri))
#:use-module ((guix build syscalls)
- #:select (free-disk-space terminal-columns
- terminal-rows))
+ #:select (free-disk-space terminal-columns terminal-rows
+ with-file-lock/no-wait))
#:use-module ((guix build utils)
;; XXX: All we need are the bindings related to
;; '&invoke-error'. However, to work around the bug described
@@ -111,6 +111,7 @@
package-specification->name+version+output
supports-hyperlinks?
+ hyperlink
file-hyperlink
location->hyperlink
@@ -118,6 +119,7 @@
package-relevance
display-search-results
+ with-profile-lock
string->generations
string->duration
matching-generations
@@ -1662,6 +1664,26 @@ DURATION-RELATION with the current time."
(display-diff profile gen1 gen2))
+(define (profile-lock-handler profile errno . _)
+ "Handle failure to acquire PROFILE's lock."
+ ;; NFS mounts can return ENOLCK. When that happens, there's not much that
+ ;; can be done, so warn the user and keep going.
+ (if (= errno ENOLCK)
+ (warning (G_ "cannot lock profile ~a: ~a~%")
+ profile (strerror errno))
+ (leave (G_ "profile ~a is locked by another process~%")
+ profile)))
+
+(define profile-lock-file
+ (cut string-append <> ".lock"))
+
+(define-syntax-rule (with-profile-lock profile exp ...)
+ "Grab PROFILE's lock and evaluate EXP... Call 'leave' if the lock is
+already taken."
+ (with-file-lock/no-wait (profile-lock-file profile)
+ (cut profile-lock-handler profile <...>)
+ exp ...))
+
(define (display-profile-content profile number)
"Display the packages in PROFILE, generation NUMBER, in a human-readable
way."