diff options
Diffstat (limited to 'guix')
-rw-r--r-- | guix/build-system/emacs.scm | 3 | ||||
-rw-r--r-- | guix/build/download.scm | 2 | ||||
-rw-r--r-- | guix/build/dub-build-system.scm | 9 | ||||
-rw-r--r-- | guix/build/emacs-build-system.scm | 92 | ||||
-rw-r--r-- | guix/build/emacs-utils.scm | 11 | ||||
-rw-r--r-- | guix/build/go-build-system.scm | 10 | ||||
-rw-r--r-- | guix/build/ruby-build-system.scm | 184 | ||||
-rw-r--r-- | guix/build/union.scm | 2 | ||||
-rw-r--r-- | guix/import/utils.scm | 12 | ||||
-rw-r--r-- | guix/licenses.scm | 6 | ||||
-rw-r--r-- | guix/packages.scm | 8 | ||||
-rw-r--r-- | guix/scripts/offload.scm | 72 | ||||
-rw-r--r-- | guix/scripts/pack.scm | 21 | ||||
-rw-r--r-- | guix/scripts/publish.scm | 16 | ||||
-rw-r--r-- | guix/scripts/system.scm | 10 | ||||
-rw-r--r-- | guix/ssh.scm | 133 | ||||
-rw-r--r-- | guix/ui.scm | 11 |
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 |