summaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
Diffstat (limited to 'guix')
-rw-r--r--guix/build-system/emacs.scm3
-rw-r--r--guix/build/download.scm2
-rw-r--r--guix/build/dub-build-system.scm9
-rw-r--r--guix/build/emacs-build-system.scm92
-rw-r--r--guix/build/emacs-utils.scm11
-rw-r--r--guix/build/go-build-system.scm10
-rw-r--r--guix/build/ruby-build-system.scm184
-rw-r--r--guix/build/union.scm2
-rw-r--r--guix/import/utils.scm12
-rw-r--r--guix/licenses.scm6
-rw-r--r--guix/packages.scm8
-rw-r--r--guix/scripts/offload.scm72
-rw-r--r--guix/scripts/pack.scm21
-rw-r--r--guix/scripts/publish.scm16
-rw-r--r--guix/scripts/system.scm10
-rw-r--r--guix/ssh.scm133
-rw-r--r--guix/ui.scm11
17 files changed, 425 insertions, 177 deletions
diff --git a/guix/build-system/emacs.scm b/guix/build-system/emacs.scm
index 02296829c6..d9f1a8d289 100644
--- a/guix/build-system/emacs.scm
+++ b/guix/build-system/emacs.scm
@@ -82,7 +82,8 @@
(define* (emacs-build store name inputs
#:key source
- (tests? #t)
+ (tests? #f)
+ (parallel-tests? #t)
(test-target "test")
(configure-flags ''())
(phases '(@ (guix build emacs-build-system)
diff --git a/guix/build/download.scm b/guix/build/download.scm
index 609a100538..1b630a9d6d 100644
--- a/guix/build/download.scm
+++ b/guix/build/download.scm
@@ -770,7 +770,7 @@ otherwise simply ignore them."
#:reporter (progress-reporter/file
(uri-abbreviation uri) size))
(newline)))
- #t)))
+ file)))
((ftp)
(false-if-exception* (ftp-fetch uri file
#:timeout timeout)))
diff --git a/guix/build/dub-build-system.scm b/guix/build/dub-build-system.scm
index 432d51f6a7..ed86635708 100644
--- a/guix/build/dub-build-system.scm
+++ b/guix/build/dub-build-system.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2016 David Craven <david@craven.ch>
;;; Copyright © 2017 Danny Milosavljevic <dannym@scratchpost.org>
+;;; Copyright © 2018 Tobias Geerinckx-Rice <me@tobias.gr>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -69,14 +70,14 @@
(zero? (system* "dub" "add-path" vendor-dir))))
(define (grep string file-name)
- "Find the first occurence of STRING in the file named FILE-NAME.
- Return the position of this occurence, or #f if none was found."
+ "Find the first occurrence of STRING in the file named FILE-NAME.
+ Return the position of this occurrence, or #f if none was found."
(string-contains (call-with-input-file file-name get-string-all)
string))
(define (grep* string file-name)
- "Find the first occurence of STRING in the file named FILE-NAME.
- Return the position of this occurence, or #f if none was found.
+ "Find the first occurrence of STRING in the file named FILE-NAME.
+ Return the position of this occurrence, or #f if none was found.
If the file named FILE-NAME doesn't exist, return #f."
(catch 'system-error
(lambda ()
diff --git a/guix/build/emacs-build-system.scm b/guix/build/emacs-build-system.scm
index bd0d2e0266..b779847424 100644
--- a/guix/build/emacs-build-system.scm
+++ b/guix/build/emacs-build-system.scm
@@ -2,6 +2,7 @@
;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
;;; Copyright © 2016 David Thompson <davet@gnu.org>
;;; Copyright © 2016 Alex Kost <alezost@gmail.com>
+;;; Copyright © 2018 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -42,7 +43,8 @@
;; 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 %install-suffix "/share/emacs/site-lisp/guix.d")
+(define %legacy-install-suffix "/share/emacs/site-lisp")
+(define %install-suffix (string-append %legacy-install-suffix "/guix.d"))
;; These are the default inclusion/exclusion regexps for the install phase.
(define %default-include '("^[^/]*\\.el$" "^[^/]*\\.info$" "^doc/.*\\.info$"))
@@ -72,38 +74,63 @@ archive, a directory, or an Emacs Lisp file."
#t)
(gnu:unpack #:source source)))
+(define* (set-emacs-load-path #:key inputs #:allow-other-keys)
+ "Set the EMACSLOADPATH environment variable so that dependencies are found."
+ (let* ((input-elisp-dirs (emacs-inputs-el-directories
+ (emacs-inputs-directories inputs)))
+ (emacs-load-path-value (string-join
+ input-elisp-dirs ":" 'suffix)))
+ (setenv "EMACSLOADPATH" emacs-load-path-value)
+ (format #t "environment variable `EMACSLOADPATH' set to ~a\n"
+ emacs-load-path-value)))
+
(define* (build #:key outputs inputs #:allow-other-keys)
"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))
- (deps-dirs (emacs-inputs-directories inputs)))
+ (el-dir (string-append out %install-suffix "/" elpa-name-ver)))
(setenv "SHELL" "sh")
(parameterize ((%emacs emacs))
- (emacs-byte-compile-directory el-dir
- (emacs-inputs-el-directories deps-dirs)))))
+ (emacs-byte-compile-directory el-dir))))
(define* (patch-el-files #:key outputs #:allow-other-keys)
"Substitute the absolute \"/bin/\" directory with the right location in the
store in '.el' files."
+
+ (define (file-contains-nul-char? file)
+ (call-with-input-file file
+ (lambda (in)
+ (let loop ((line (read-line in 'concat)))
+ (cond
+ ((eof-object? line) #f)
+ ((string-index line #\nul) #t)
+ (else (loop (read-line in 'concat))))))
+ #: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))
- (substitute-cmd (lambda ()
- (substitute* (find-files "." "\\.el$")
- (("\"/bin/([^.]\\S*)\"" _ cmd-name)
- (let ((cmd (which cmd-name)))
- (unless cmd
- (error
- "patch-el-files: unable to locate " cmd-name))
- (string-append "\"" cmd "\"")))))))
+
+ ;; (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.
+ (el-files (remove file-contains-nul-char?
+ (find-files (getcwd) "\\.el$"))))
+ (define (substitute-program-names)
+ (substitute* el-files
+ (("\"/bin/([^.]\\S*)\"" _ cmd-name)
+ (let ((cmd (which cmd-name)))
+ (unless cmd
+ (error "patch-el-files: unable to locate " cmd-name))
+ (string-append "\"" cmd "\"")))))
+
(with-directory-excursion el-dir
- ;; Some old '.el' files (e.g., tex-buf.el in AUCTeX) are still encoded
- ;; with the "ISO-8859-1" locale.
- (unless (false-if-exception (substitute-cmd))
+ ;; Some old '.el' files (e.g., tex-buf.el in AUCTeX) are still
+ ;; ISO-8859-1-encoded.
+ (unless (false-if-exception (substitute-program-names))
(with-fluids ((%default-port-encoding "ISO-8859-1"))
- (substitute-cmd))))
+ (substitute-program-names))))
#t))
(define* (install #:key outputs
@@ -199,18 +226,27 @@ store in '.el' files."
(match inputs
(((names . directories) ...) directories))))
+(define (emacs-input->el-directory emacs-input)
+ "Return the correct Elisp directory location of EMACS-INPUT or #f if none."
+ (let ((legacy-elisp-dir (string-append emacs-input %legacy-install-suffix))
+ (guix-elisp-dir (string-append
+ emacs-input %install-suffix "/"
+ (store-directory->elpa-name-version emacs-input))))
+ (cond
+ ((file-exists? guix-elisp-dir) guix-elisp-dir)
+ ((file-exists? legacy-elisp-dir) legacy-elisp-dir)
+ (else (format #t "warning: could not locate elisp directory under `~a'\n"
+ emacs-input)
+ #f))))
+
(define (emacs-inputs-el-directories dirs)
"Build the list of Emacs Lisp directories from the Emacs package directory
DIRS."
- (append-map (lambda (d)
- (list (string-append d "/share/emacs/site-lisp")
- (string-append d %install-suffix "/"
- (store-directory->elpa-name-version d))))
- dirs))
+ (filter-map emacs-input->el-directory dirs))
(define (package-name-version->elpa-name-version name-ver)
"Convert the Guix package NAME-VER to the corresponding ELPA name-version
-format. Essnetially drop the prefix used in Guix."
+format. Essentially drop the prefix used in Guix."
(if (emacs-package? name-ver) ; checks for "emacs-" prefix
(string-drop name-ver (string-length "emacs-"))
name-ver))
@@ -224,12 +260,14 @@ second hyphen. This corresponds to 'name-version' as used in ELPA packages."
(define %standard-phases
(modify-phases gnu:%standard-phases
+ (add-after 'set-paths 'set-emacs-load-path set-emacs-load-path)
(replace 'unpack unpack)
(delete 'configure)
- (delete 'check)
- (delete 'install)
- (replace 'build build)
- (add-before 'build 'install install)
+ ;; Move the build phase after install: the .el files are byte compiled
+ ;; directly in the store.
+ (delete 'build)
+ (replace 'install install)
+ (add-after 'install 'build build)
(add-after 'install 'make-autoloads make-autoloads)
(add-after 'make-autoloads 'patch-el-files patch-el-files)
(add-after 'make-autoloads 'move-doc move-doc)))
diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm
index fd06aad7ac..8389ca582f 100644
--- a/guix/build/emacs-utils.scm
+++ b/guix/build/emacs-utils.scm
@@ -58,14 +58,9 @@
(update-directory-autoloads ,directory))))
(emacs-batch-eval expr)))
-(define* (emacs-byte-compile-directory dir #:optional (dependency-dirs '()))
- "Byte compile all files in DIR and its sub-directories. Before compiling
-the files, add DIR and all directories in DEPENDENCY-DIRS to 'load-path'."
- (let ((expr `(progn
- (add-to-list 'load-path ,dir)
- (when ',dependency-dirs
- (setq load-path (append ',dependency-dirs load-path)))
- (byte-recompile-directory (file-name-as-directory ,dir) 0))))
+(define* (emacs-byte-compile-directory dir)
+ "Byte compile all files in DIR and its sub-directories."
+ (let ((expr `(byte-recompile-directory (file-name-as-directory ,dir) 0)))
(emacs-batch-eval expr)))
(define-syntax emacs-substitute-sexps
diff --git a/guix/build/go-build-system.scm b/guix/build/go-build-system.scm
index eaad9d8751..3114067aa9 100644
--- a/guix/build/go-build-system.scm
+++ b/guix/build/go-build-system.scm
@@ -37,7 +37,7 @@
;; process for Go libraries, so we use `go install`, which preserves the
;; results. [0]
-;; Go software is developed and built within a particular filesystem hierarchy
+;; Go software is developed and built within a particular file system hierarchy
;; structure called a 'workspace' [1]. This workspace is found by Go
;; via the GOPATH environment variable. Typically, all Go source code
;; and compiled objects are kept in a single workspace, but it is
@@ -48,7 +48,7 @@
;; an 'import path'. The import path is based on the URL of the
;; software's source. Since most source code is provided over the
;; internet, the import path is typically a combination of the remote
-;; URL and the source repository's filesystem structure. For example,
+;; URL and the source repository's file system structure. For example,
;; the Go port of the common `du` command is hosted on github.com, at
;; <https://github.com/calmh/du>. Thus, the import path is
;; <github.com/calmh/du>. [3]
@@ -58,12 +58,12 @@
;; the go-build-system.
;;
;; Modules of modular Go libraries are named uniquely with their
-;; filesystem paths. For example, the supplemental but "standardized"
+;; file system paths. For example, the supplemental but "standardized"
;; libraries developed by the Go upstream developers are available at
;; <https://golang.org/x/{net,text,crypto, et cetera}>. The Go IPv4
;; library's import path is <golang.org/x/net/ipv4>. The source of
;; such modular libraries must be unpacked at the top-level of the
-;; filesystem structure of the library. So the IPv4 library should be
+;; file system structure of the library. So the IPv4 library should be
;; unpacked to <golang.org/x/net>. This is handled in the
;; go-build-system with the optional #:unpack-path key.
;;
@@ -72,7 +72,7 @@
;; that all modules of modular libraries cannot be built with a single
;; command. Each module must be built individually. This complicates
;; certain cases, and these issues are currently resolved by creating a
-;; filesystem union of the required modules of such libraries. I think
+;; file system union of the required modules of such libraries. I think
;; this could be improved in future revisions of the go-build-system.
;;
;; [0] `go build`:
diff --git a/guix/build/ruby-build-system.scm b/guix/build/ruby-build-system.scm
index c2d2766279..09ae2390a5 100644
--- a/guix/build/ruby-build-system.scm
+++ b/guix/build/ruby-build-system.scm
@@ -21,14 +21,15 @@
(define-module (guix build ruby-build-system)
#:use-module ((guix build gnu-build-system) #:prefix gnu:)
#:use-module (guix build utils)
+ #:use-module (ice-9 ftw)
#:use-module (ice-9 match)
#:use-module (ice-9 popen)
+ #:use-module (ice-9 rdelim)
#:use-module (ice-9 regex)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-26)
#:export (%standard-phases
- ruby-build
- gem-home))
+ ruby-build))
;; Commentary:
;;
@@ -129,43 +130,179 @@ GEM-FLAGS are passed to the 'gem' invokation, if present."
(assoc-ref inputs "ruby"))
1))
(out (assoc-ref outputs "out"))
- (gem-home (string-append out "/lib/ruby/gems/" ruby-version ".0"))
+ (vendor-dir (string-append out "/lib/ruby/vendor_ruby"))
(gem-file (first-matching-file "\\.gem$"))
(gem-file-basename (basename gem-file))
(gem-name (substring gem-file-basename
0
- (- (string-length gem-file-basename) 4)))
- (gem-directory (string-append gem-home "/gems/" gem-name)))
- (setenv "GEM_HOME" gem-home)
- (mkdir-p gem-home)
- (and (apply system* "gem" "install" gem-file
- "--local" "--ignore-dependencies"
- ;; Executables should go into /bin, not /lib/ruby/gems.
- "--bindir" (string-append out "/bin")
- gem-flags)
+ (- (string-length gem-file-basename) 4))))
+ (setenv "GEM_VENDOR" vendor-dir)
+ (and (let ((install-succeeded?
+ (zero?
+ (apply system* "gem" "install" gem-file
+ "--local" "--ignore-dependencies" "--vendor"
+ ;; Executables should go into /bin, not
+ ;; /lib/ruby/gems.
+ "--bindir" (string-append out "/bin")
+ gem-flags))))
+ (or install-succeeded?
+ (begin
+ (simple-format #t "installation failed\n")
+ (let ((failed-output-dir (string-append (getcwd) "/out")))
+ (mkdir failed-output-dir)
+ (copy-recursively out failed-output-dir))
+ #f)))
(begin
;; Remove the cached gem file as this is unnecessary and contains
;; timestamped files rendering builds not reproducible.
- (let ((cached-gem (string-append gem-home "/cache/" gem-file)))
+ (let ((cached-gem (string-append vendor-dir "/cache/" gem-file)))
(log-file-deletion cached-gem)
(delete-file cached-gem))
;; For gems with native extensions, several Makefile-related files
;; are created that contain timestamps or other elements making
;; them not reproducible. They are unnecessary so we remove them.
- (if (file-exists? (string-append gem-directory "/ext"))
+ (if (file-exists? (string-append vendor-dir "/ext"))
(begin
(for-each (lambda (file)
(log-file-deletion file)
(delete-file file))
(append
- (find-files (string-append gem-home "/doc")
+ (find-files (string-append vendor-dir "/doc")
"page-Makefile.ri")
- (find-files (string-append gem-home "/extensions")
+ (find-files (string-append vendor-dir "/extensions")
"gem_make.out")
- (find-files (string-append gem-directory "/ext")
+ (find-files (string-append vendor-dir "/ext")
"Makefile")))))
#t))))
+(define* (wrap-ruby-program prog #:key (gem-clear-paths #t) #:rest vars)
+ "Make a wrapper for PROG. VARS should look like this:
+
+ '(VARIABLE DELIMITER POSITION LIST-OF-DIRECTORIES)
+
+where DELIMITER is optional. ':' will be used if DELIMITER is not given.
+
+For example, this command:
+
+ (wrap-ruby-program \"foo\"
+ '(\"PATH\" \":\" = (\"/gnu/.../bar/bin\"))
+ '(\"CERT_PATH\" suffix (\"/gnu/.../baz/certs\"
+ \"/qux/certs\")))
+
+will copy 'foo' to '.real/fool' and create the file 'foo' with the following
+contents:
+
+ #!location/of/bin/ruby
+ ENV['PATH'] = \"/gnu/.../bar/bin\"
+ ENV['CERT_PATH'] = (ENV.key?('CERT_PATH') ? (ENV['CERT_PATH'] + ':') : '') + '/gnu/.../baz/certs:/qux/certs'
+ load location/of/.real/foo
+
+This is useful for scripts that expect particular programs to be in $PATH, for
+programs that expect particular gems to be in the GEM_PATH.
+
+This is preferable to wrap-program, which uses a bash script, as this prevents
+ruby scripts from being executed with @command{ruby -S ...}.
+
+If PROG has previously been wrapped by 'wrap-ruby-program', the wrapper is
+extended with definitions for VARS."
+ (define wrapped-file
+ (string-append (dirname prog) "/.real/" (basename prog)))
+
+ (define already-wrapped?
+ (file-exists? wrapped-file))
+
+ (define (last-line port)
+ ;; Return the last line read from PORT and leave PORT's cursor right
+ ;; before it.
+ (let loop ((previous-line-offset 0)
+ (previous-line "")
+ (position (seek port 0 SEEK_CUR)))
+ (match (read-line port 'concat)
+ ((? eof-object?)
+ (seek port previous-line-offset SEEK_SET)
+ previous-line)
+ ((? string? line)
+ (loop position line (+ (string-length line) position))))))
+
+ (define (export-variable lst)
+ ;; Return a string that exports an environment variable.
+ (match lst
+ ((var sep '= rest)
+ (format #f "ENV['~a'] = '~a'"
+ var (string-join rest sep)))
+ ((var sep 'prefix rest)
+ (format #f "ENV['~a'] = '~a' + (ENV.key?('~a') ? ('~a' + ENV['~a']) : '')"
+ var (string-join rest sep) var sep var))
+ ((var sep 'suffix rest)
+ (format #f "ENV['~a'] = (ENV.key?('~a') ? (ENV['~a'] + '~a') : '') + '~a'"
+ var var var sep (string-join rest sep)))
+ ((var '= rest)
+ (format #f "ENV['~a'] = '~a'"
+ var (string-join rest ":")))
+ ((var 'prefix rest)
+ (format #f "ENV['~a'] = '~a' + (ENV.key?('~a') ? (':' + ENV['~a']) : '')"
+ var (string-join rest ":") var var))
+ ((var 'suffix rest)
+ (format #f "ENV['~a'] = (ENV.key?('~a') ? (ENV['~a'] + ':') : '') + '~a'"
+ var var var (string-join rest ":")))))
+
+ (if already-wrapped?
+
+ ;; PROG is already a wrapper: add the new "export VAR=VALUE" lines just
+ ;; before the last line.
+ (let* ((port (open-file prog "r+"))
+ (last (last-line port)))
+ (for-each (lambda (var)
+ (display (export-variable var) port)
+ (newline port))
+ vars)
+ (display last port)
+ (close-port port))
+
+ ;; PROG is not wrapped yet: create a shell script that sets VARS.
+ (let ((prog-tmp (string-append wrapped-file "-tmp")))
+ (mkdir-p (dirname prog-tmp))
+ (link prog wrapped-file)
+
+ (call-with-output-file prog-tmp
+ (lambda (port)
+ (format port
+ "#!~a~%~a~%~a~%load '~a'~%"
+ (which "ruby")
+ (string-join (map export-variable vars) "\n")
+ ;; This ensures that if the GEM_PATH has been changed,
+ ;; then that change will be noticed.
+ (if gem-clear-paths "Gem.clear_paths" "")
+ (canonicalize-path wrapped-file))))
+
+ (chmod prog-tmp #o755)
+ (rename-file prog-tmp prog))))
+
+(define* (wrap #:key inputs outputs #:allow-other-keys)
+ (define (list-of-files dir)
+ (map (cut string-append dir "/" <>)
+ (or (scandir dir (lambda (f)
+ (let ((s (stat (string-append dir "/" f))))
+ (eq? 'regular (stat:type s)))))
+ '())))
+
+ (define bindirs
+ (append-map (match-lambda
+ ((_ . dir)
+ (list (string-append dir "/bin")
+ (string-append dir "/sbin"))))
+ outputs))
+
+ (let* ((out (assoc-ref outputs "out"))
+ (var `("GEM_PATH" prefix
+ (,(string-append out "/lib/ruby/vendor_ruby")
+ ,(getenv "GEM_PATH")))))
+ (for-each (lambda (dir)
+ (let ((files (list-of-files dir)))
+ (for-each (cut wrap-ruby-program <> var)
+ files)))
+ bindirs)))
+
(define (log-file-deletion file)
(display (string-append "deleting '" file "' for reproducibility\n")))
@@ -177,18 +314,9 @@ GEM-FLAGS are passed to the 'gem' invokation, if present."
(add-after 'extract-gemspec 'replace-git-ls-files replace-git-ls-files)
(replace 'build build)
(replace 'check check)
- (replace 'install install)))
+ (replace 'install install)
+ (add-after 'install 'wrap wrap)))
(define* (ruby-build #:key inputs (phases %standard-phases)
#:allow-other-keys #:rest args)
(apply gnu:gnu-build #:inputs inputs #:phases phases args))
-
-(define (gem-home store-path ruby-version)
- "Return a string to the gem home directory in the store given a STORE-PATH
-and the RUBY-VERSION used to build that ruby package"
- (string-append
- store-path
- "/lib/ruby/gems/"
- (regexp-substitute #f
- (string-match "^[0-9]+\\.[0-9]+" ruby-version)
- 0 ".0")))
diff --git a/guix/build/union.scm b/guix/build/union.scm
index 256123c566..d46b750035 100644
--- a/guix/build/union.scm
+++ b/guix/build/union.scm
@@ -93,7 +93,7 @@ make sure the caller can modify them later."
(cond ((null? dirs)
;; The inputs are all files.
(format (current-error-port)
- "warning: collision encountered: ~{~a ~}~%"
+ "~%warning: collision encountered:~%~{~a~%~}"
files)
(let ((file (first files)))
diff --git a/guix/import/utils.scm b/guix/import/utils.scm
index d4cef6b503..efc6169077 100644
--- a/guix/import/utils.scm
+++ b/guix/import/utils.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2018 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016 Jelle Licht <jlicht@fsfe.org>
;;; Copyright © 2016 David Craven <david@craven.ch>
;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
@@ -330,10 +330,12 @@ the expected fields of an <origin> object."
(description
(assoc-ref meta "description"))
(license
- (let ((l (assoc-ref meta "license")))
- (or (module-ref (resolve-interface '(guix licenses) #:prefix 'license:)
- (spdx-string->license l))
- (license:fsdg-compatible l))))))
+ (match (assoc-ref meta "license")
+ (#f #f)
+ (l
+ (or (module-ref (resolve-interface '(guix licenses) #:prefix 'license:)
+ (spdx-string->license l))
+ (license:fsdg-compatible l)))))))
(define* (read-lines #:optional (port (current-input-port)))
"Read lines from PORT and return them as a list."
diff --git a/guix/licenses.scm b/guix/licenses.scm
index 269d97c723..700fa7f03a 100644
--- a/guix/licenses.scm
+++ b/guix/licenses.scm
@@ -87,6 +87,7 @@
tcl/tk
unlicense
vim
+ w3c
x11 x11-style
zpl2.1
zlib
@@ -578,6 +579,11 @@ at URI, which may be a file:// URI pointing the package's tree."
"https://unlicense.org/"
"https://www.gnu.org/licenses/license-list.html#Unlicense"))
+(define w3c
+ (license "W3C Software Notice and License"
+ "https://directory.fsf.org/wiki/License:W3C_31Dec2002"
+ "https://www.gnu.org/licenses/license-list.en.html#W3C"))
+
(define wtfpl2
(license "WTFPL 2"
"http://www.wtfpl.net"
diff --git a/guix/packages.scm b/guix/packages.scm
index 9571565e17..b5c0b60440 100644
--- a/guix/packages.scm
+++ b/guix/packages.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2014, 2015, 2017 Mark H Weaver <mhw@netris.org>
;;; Copyright © 2015 Eric Bavier <bavier@member.fsf.org>
;;; Copyright © 2016 Alex Kost <alezost@gmail.com>
@@ -620,6 +620,9 @@ itself.
This is implemented as a breadth-first traversal such that INPUTS is
preserved, and only duplicate propagated inputs are removed."
(define (seen? seen item outputs)
+ ;; FIXME: We're using pointer identity here, which is extremely sensitive
+ ;; to memoization in package-producing procedures; see
+ ;; <https://bugs.gnu.org/30155>.
(match (vhash-assq item seen)
((_ . o) (equal? o outputs))
(_ #f)))
@@ -786,7 +789,8 @@ when CUT? returns true for a given package."
(location (package-location p))
(inputs (map rewrite (package-inputs p)))
(native-inputs (map rewrite (package-native-inputs p)))
- (propagated-inputs (map rewrite (package-propagated-inputs p)))))))
+ (propagated-inputs (map rewrite (package-propagated-inputs p)))
+ (replacement (and=> (package-replacement p) proc))))))
replace)
diff --git a/guix/scripts/offload.scm b/guix/scripts/offload.scm
index 7e114fa2c9..56d6de6308 100644
--- a/guix/scripts/offload.scm
+++ b/guix/scripts/offload.scm
@@ -358,25 +358,18 @@ MACHINE."
(parameterize ((current-build-output-port (build-log-port)))
(build-derivations store (list drv))))
- (retrieve-files* outputs store)
- (format (current-error-port) "done with offloaded '~a'~%"
- (derivation-file-name drv)))
+ (retrieve-files* outputs store
-(define (retrieve-files* files remote)
- "Retrieve FILES from REMOTE and import them using 'restore-file-set'."
- (let-values (((port count)
- (file-retrieval-port files remote)))
- (format #t (N_ "retrieving ~a store item from '~a'...~%"
- "retrieving ~a store items from '~a'...~%" count)
- count (remote-store-host remote))
+ ;; We cannot use the 'import-paths' RPC here because we
+ ;; already hold the locks for FILES.
+ #:import
+ (lambda (port)
+ (restore-file-set port
+ #:log-port (current-error-port)
+ #:lock? #f)))
- ;; We cannot use the 'import-paths' RPC here because we already
- ;; hold the locks for FILES.
- (let ((result (restore-file-set port
- #:log-port (current-error-port)
- #:lock? #f)))
- (close-port port)
- result)))
+ (format (current-error-port) "done with offloaded '~a'~%"
+ (derivation-file-name drv)))
;;;
@@ -407,7 +400,7 @@ allowed on MACHINE. Return +∞ if MACHINE is unreachable."
+inf.0 ;MACHINE does not respond, so assume it is infinitely loaded
(match (string-tokenize line)
((one five fifteen . x)
- (let* ((raw (string->number five))
+ (let* ((raw (string->number one))
(jobs (build-machine-parallel-builds machine))
(normalized (/ raw jobs)))
(format (current-error-port) "load on machine '~a' is ~s\
@@ -549,8 +542,7 @@ slot (which must later be released with 'release-build-slot'), or #f and #f."
"Bail out if NODE is not running Guile."
(match (node-guile-version node)
(#f
- (leave (G_ "Guile could not be started on '~a'~%")
- name))
+ (report-guile-error name))
((? string? version)
;; Note: The version string already contains the word "Guile".
(info (G_ "'~a' is running ~a~%")
@@ -558,18 +550,34 @@ slot (which must later be released with 'release-build-slot'), or #f and #f."
(define (assert-node-has-guix node name)
"Bail out if NODE lacks the (guix) module, or if its daemon is not running."
- (match (node-eval node
- '(begin
- (use-modules (guix))
- (with-store store
- (add-text-to-store store "test"
- "Hello, build machine!"))))
- ((? string? str)
- (info (G_ "Guix is usable on '~a' (test returned ~s)~%")
- name str))
- (x
- (leave (G_ "failed to use Guix module on '~a' (test returned ~s)~%")
- name x))))
+ (catch 'node-repl-error
+ (lambda ()
+ (match (node-eval node
+ '(begin
+ (use-modules (guix))
+ (and add-text-to-store 'alright)))
+ ('alright #t)
+ (_ (report-module-error name))))
+ (lambda (key . args)
+ (report-module-error name)))
+
+ (catch 'node-repl-error
+ (lambda ()
+ (match (node-eval node
+ '(begin
+ (use-modules (guix))
+ (with-store store
+ (add-text-to-store store "test"
+ "Hello, build machine!"))))
+ ((? string? str)
+ (info (G_ "Guix is usable on '~a' (test returned ~s)~%")
+ name str))
+ (x
+ (leave (G_ "failed to talk to guix-daemon on '~a' (test returned ~s)~%")
+ name x))))
+ (lambda (key . args)
+ (leave (G_ "remove evaluation on '~a' failed:~{ ~s~}~%")
+ args))))
(define %random-state
(delay
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index a22258d5a6..59dd117edb 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -2,6 +2,7 @@
;;; Copyright © 2015, 2017 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Efraim Flashner <efraim@flashner.co.il>
;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2018 Konrad Hinsen <konrad.hinsen@fastmail.net>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -292,6 +293,9 @@ the image."
(option '(#\e "expression") #t #f
(lambda (opt name arg result)
(alist-cons 'expression arg result)))
+ (option '(#\m "manifest") #t #f
+ (lambda (opt name arg result)
+ (alist-cons 'manifest arg result)))
(option '(#\s "system") #t #f
(lambda (opt name arg result)
(alist-cons 'system arg
@@ -345,6 +349,8 @@ Create a bundle of PACKAGE.\n"))
(display (G_ "
-S, --symlink=SPEC create symlinks to the profile according to SPEC"))
(display (G_ "
+ -m, --manifest=FILE create a pack with the manifest from FILE"))
+ (display (G_ "
--localstatedir include /var/guix in the resulting pack"))
(newline)
(display (G_ "
@@ -375,10 +381,21 @@ Create a bundle of PACKAGE.\n"))
(read/eval-package-expression exp))
(x #f)))
+ (define (manifest-from-args opts)
+ (let ((packages (filter-map maybe-package-argument opts))
+ (manifest-file (assoc-ref opts 'manifest)))
+ (cond
+ ((and manifest-file (not (null? packages)))
+ (leave (G_ "both a manifest and a package list were given~%")))
+ (manifest-file
+ (let ((user-module (make-user-module '((guix profiles) (gnu)))))
+ (load* manifest-file user-module)))
+ (else (packages->manifest packages)))))
+
(with-error-handling
(parameterize ((%graft? (assoc-ref opts 'graft?)))
(let* ((dry-run? (assoc-ref opts 'dry-run?))
- (packages (filter-map maybe-package-argument opts))
+ (manifest (manifest-from-args opts))
(pack-format (assoc-ref opts 'format))
(name (string-append (symbol->string pack-format)
"-pack"))
@@ -397,7 +414,7 @@ Create a bundle of PACKAGE.\n"))
(run-with-store store
(mlet* %store-monad ((profile (profile-derivation
- (packages->manifest packages)
+ manifest
#:target target))
(drv (build-image name profile
#:target
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 1673fb9f33..b5dfdab32f 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -672,10 +672,10 @@ example: \"/foo/bar\" yields '(\"foo\" \"bar\")."
exp ...)
(const #f)))
-(define (nar-response-port response)
+(define (nar-response-port response compression)
"Return a port on which to write the body of RESPONSE, the response of a
/nar request, according to COMPRESSION."
- (match (assoc-ref (response-headers response) 'x-nar-compression)
+ (match compression
(($ <compression> 'gzip level)
;; Note: We cannot used chunked encoding here because
;; 'make-gzip-output-port' wants a file port.
@@ -697,11 +697,13 @@ blocking."
(call-with-new-thread
(lambda ()
(set-thread-name "publish nar")
- (let* ((response (write-response (sans-content-length response)
- client))
- (port (begin
- (force-output client)
- (nar-response-port response))))
+ (let* ((compression (assoc-ref (response-headers response)
+ 'x-nar-compression))
+ (response (write-response (sans-content-length response)
+ client))
+ (port (begin
+ (force-output client)
+ (nar-response-port response compression))))
;; XXX: Given our ugly workaround for <http://bugs.gnu.org/21093> in
;; 'render-nar', BODY here is just the file name of the store item.
;; We call 'write-file' from here because we know that's the only
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index ebcf3e4f3b..999ffb010b 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016 Alex Kost <alezost@gmail.com>
;;; Copyright © 2016, 2017 Chris Marusich <cmmarusich@gmail.com>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
@@ -331,7 +331,9 @@ bring the system down."
(let ((to-load-names (map shepherd-service-canonical-name to-load))
(to-start (filter shepherd-service-auto-start? to-load)))
(info (G_ "loading new services:~{ ~a~}...~%") to-load-names)
- (mlet %store-monad ((files (mapm %store-monad shepherd-service-file
+ (mlet %store-monad ((files (mapm %store-monad
+ (compose lower-object
+ shepherd-service-file)
to-load)))
;; Here we assume that FILES are exactly those that were computed
;; as part of the derivation that built OS, which is normally the
@@ -709,8 +711,8 @@ and TARGET arguments."
"Perform ACTION for OS. INSTALL-BOOTLOADER? specifies whether to install
bootloader; BOOTLOADER-TAGET is the target for the bootloader; TARGET is the
target root directory; IMAGE-SIZE is the size of the image to be built, for
-the 'vm-image' and 'disk-image' actions. The root filesystem is created as a
-FILE-SYSTEM-TYPE filesystem. FULL-BOOT? is used for the 'vm' action; it
+the 'vm-image' and 'disk-image' actions. The root file system is created as a
+FILE-SYSTEM-TYPE file system. FULL-BOOT? is used for the 'vm' action; it
determines whether to boot directly to the kernel or to the bootloader.
When DERIVATIONS-ONLY? is true, print the derivation file name(s) without
diff --git a/guix/ssh.scm b/guix/ssh.scm
index cb560c0e9c..9e90216a2d 100644
--- a/guix/ssh.scm
+++ b/guix/ssh.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2016, 2017 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -28,7 +28,9 @@
#:use-module (ssh session)
#:use-module (ssh dist)
#:use-module (ssh dist node)
+ #:use-module (srfi srfi-1)
#:use-module (srfi srfi-11)
+ #:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
#:use-module (ice-9 match)
@@ -38,9 +40,11 @@
connect-to-remote-daemon
send-files
retrieve-files
+ retrieve-files*
remote-store-host
- file-retrieval-port))
+ report-guile-error
+ report-module-error))
;;; Commentary:
;;;
@@ -102,42 +106,45 @@ Throw an error on failure."
;; hack.
`(begin
(use-modules (ice-9 match) (rnrs io ports)
- (rnrs bytevectors) (system foreign))
+ (rnrs bytevectors))
- (define read!
- ;; XXX: We would use 'get-bytevector-some' but it always returns a
- ;; single byte in Guile <= 2.2.3---see <https://bugs.gnu.org/30066>.
- ;; This procedure works around it.
- (let ((proc (pointer->procedure int
- (dynamic-func "read" (dynamic-link))
- (list int '* size_t))))
- (lambda (port bv)
- (proc (fileno port) (bytevector->pointer bv)
- (bytevector-length bv)))))
-
- (let ((sock (socket AF_UNIX SOCK_STREAM 0))
- (stdin (current-input-port))
- (stdout (current-output-port))
- (buffer (make-bytevector 65536)))
- (setvbuf stdin _IONBF)
+ (let ((sock (socket AF_UNIX SOCK_STREAM 0))
+ (stdin (current-input-port))
+ (stdout (current-output-port))
+ (select* (lambda (read write except)
+ ;; This is a workaround for
+ ;; <https://bugs.gnu.org/30365> in Guile < 2.2.4:
+ ;; since 'select' sometimes returns non-empty sets for
+ ;; no good reason, call 'select' a second time with a
+ ;; zero timeout to filter out incorrect replies.
+ (match (select read write except)
+ ((read write except)
+ (select read write except 0))))))
(setvbuf stdout _IONBF)
+
+ ;; Use buffered ports so that 'get-bytevector-some' returns up to the
+ ;; whole buffer like read(2) would--see <https://bugs.gnu.org/30066>.
+ (setvbuf stdin _IOFBF 65536)
+ (setvbuf sock _IOFBF 65536)
+
(connect sock AF_UNIX ,socket-name)
(let loop ()
- (match (select (list stdin sock) '() '())
+ (match (select* (list stdin sock) '() '())
((reads () ())
(when (memq stdin reads)
- (match (read! stdin buffer)
- ((? zero?) ;EOF
+ (match (get-bytevector-some stdin)
+ ((? eof-object?)
(primitive-exit 0))
- (count
- (put-bytevector sock buffer 0 count))))
+ (bv
+ (put-bytevector sock bv)
+ (force-output sock))))
(when (memq sock reads)
- (match (read! sock buffer)
- ((? zero?) ;EOF
+ (match (get-bytevector-some sock)
+ ((? eof-object?)
(primitive-exit 0))
- (count
- (put-bytevector stdout buffer 0 count))))
+ (bv
+ (put-bytevector stdout bv))))
(loop))
(_
(primitive-exit 1)))))))
@@ -235,6 +242,10 @@ be read. When RECURSIVE? is true, the closure of FILES is exported."
(write `(invalid-items ,invalid))
(exit 1))
+ ;; TODO: When RECURSIVE? is true, we could send the list of store
+ ;; items in the closure so that the other end can filter out
+ ;; those it already has.
+
(write '(exporting)) ;we're ready
(force-output)
@@ -339,10 +350,11 @@ to the length of FILES.)"
(&message
(message (format #f fmt args ...))))))))
-(define* (retrieve-files local files remote
- #:key recursive? (log-port (current-error-port)))
- "Retrieve FILES from REMOTE and import them using the 'import-paths' RPC on
-LOCAL. When RECURSIVE? is true, retrieve the closure of FILES."
+(define* (retrieve-files* files remote
+ #:key recursive? (log-port (current-error-port))
+ (import (const #f)))
+ "Pass IMPORT an input port from which to read the sequence of FILES coming
+from REMOTE. When RECURSIVE? is true, retrieve the closure of FILES."
(let-values (((port count)
(file-retrieval-port files remote
#:recursive? recursive?)))
@@ -352,25 +364,16 @@ LOCAL. When RECURSIVE? is true, retrieve the closure of FILES."
"retrieving ~a store items from '~a'...~%" count)
count (remote-store-host remote))
- (let ((result (import-paths local port)))
- (close-port port)
- result))
+ (dynamic-wind
+ (const #t)
+ (lambda ()
+ (import port))
+ (lambda ()
+ (close-port port))))
((? eof-object?)
- (raise-error (G_ "failed to start Guile on remote host '~A': exit code ~A")
- (remote-store-host remote)
- (channel-get-exit-status port)
- (=> (G_ "Make sure @command{guile} can be found in
-@code{$PATH} on the remote host. Run @command{ssh ~A guile --version} to
-check.")
- (remote-store-host remote))))
+ (report-guile-error (remote-store-host remote)))
(('module-error . _)
- ;; TRANSLATORS: Leave "Guile" untranslated.
- (raise-error (G_ "Guile modules not found on remote host '~A'")
- (remote-store-host remote)
- (=> (G_ "Make sure @code{GUILE_LOAD_PATH} includes Guix'
-own module directory. Run @command{ssh ~A env | grep GUILE_LOAD_PATH} to
-check.")
- (remote-store-host remote))))
+ (report-module-error (remote-store-host remote)))
(('connection-error file code . _)
(raise-error (G_ "failed to connect to '~A' on remote host '~A': ~a")
file (remote-store-host remote) (strerror code)))
@@ -386,4 +389,36 @@ check.")
(raise-error (G_ "failed to retrieve store items from '~a'")
(remote-store-host remote))))))
+(define* (retrieve-files local files remote
+ #:key recursive? (log-port (current-error-port)))
+ "Retrieve FILES from REMOTE and import them using the 'import-paths' RPC on
+LOCAL. When RECURSIVE? is true, retrieve the closure of FILES."
+ (retrieve-files* (remove (cut valid-path? local <>) files)
+ remote
+ #:recursive? recursive?
+ #:log-port log-port
+ #:import (lambda (port)
+ (import-paths local port))))
+
+
+;;;
+;;; Error reporting.
+;;;
+
+(define (report-guile-error host)
+ (raise-error (G_ "failed to start Guile on remote host '~A'") host
+ (=> (G_ "Make sure @command{guile} can be found in
+@code{$PATH} on the remote host. Run @command{ssh ~A guile --version} to
+check.")
+ host)))
+
+(define (report-module-error host)
+ "Report an error about missing Guix modules on HOST."
+ ;; TRANSLATORS: Leave "Guile" untranslated.
+ (raise-error (G_ "Guile modules not found on remote host '~A'") host
+ (=> (G_ "Make sure @code{GUILE_LOAD_PATH} includes Guix'
+own module directory. Run @command{ssh ~A env | grep GUILE_LOAD_PATH} to
+check.")
+ host)))
+
;;; ssh.scm ends here
diff --git a/guix/ui.scm b/guix/ui.scm
index 895179744b..fb2380b68a 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -195,7 +195,16 @@ messages."
(catch #t
(lambda ()
;; XXX: Force a recompilation to avoid ABI issues.
- ;; (set! %fresh-auto-compile #t)
+ ;;
+ ;; In 2.2.3, the bogus answer to <https://bugs.gnu.org/29226> was to
+ ;; ignore all available .go, not just those from ~/.cache, which in turn
+ ;; meant that we had to rebuild *everything*. Since this is too costly,
+ ;; we have to turn auto '%fresh-auto-compile' with that version, at the
+ ;; risk of getting ABI breakage in the user's config file. See
+ ;; <https://bugs.gnu.org/29881>.
+ (unless (string=? (version) "2.2.3")
+ (set! %fresh-auto-compile #t))
+
(set! %load-should-auto-compile #t)
(save-module-excursion