summaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
Diffstat (limited to 'guix')
-rw-r--r--guix/build/haskell-build-system.scm5
-rw-r--r--guix/build/profiles.scm2
-rw-r--r--guix/gexp.scm10
-rw-r--r--guix/gnu-maintenance.scm26
-rw-r--r--guix/import/cabal.scm70
-rw-r--r--guix/import/gem.scm48
-rw-r--r--guix/import/opam.scm193
-rw-r--r--guix/profiles.scm26
-rw-r--r--guix/scripts/environment.scm210
-rw-r--r--guix/scripts/import.scm2
-rw-r--r--guix/scripts/import/gem.scm27
-rw-r--r--guix/scripts/import/opam.scm92
-rw-r--r--guix/store.scm15
-rw-r--r--guix/ui.scm2
14 files changed, 545 insertions, 183 deletions
diff --git a/guix/build/haskell-build-system.scm b/guix/build/haskell-build-system.scm
index 268d59c1be..26519ce5a6 100644
--- a/guix/build/haskell-build-system.scm
+++ b/guix/build/haskell-build-system.scm
@@ -66,7 +66,7 @@
(format #t "running \"runhaskell Setup.hs\" with command ~s \
and parameters ~s~%"
command params)
- (zero? (apply system* "runhaskell" setup-file command params)))
+ (apply invoke "runhaskell" setup-file command params))
(error "no Setup.hs nor Setup.lhs found"))))
(define* (configure #:key outputs inputs tests? (configure-flags '())
@@ -114,7 +114,8 @@ and parameters ~s~%"
(setenv "CONFIG_SHELL" "sh"))
(run-setuphs "configure" params)
- (setenv "GHC_PACKAGE_PATH" ghc-path)))
+ (setenv "GHC_PACKAGE_PATH" ghc-path)
+ #t))
(define* (build #:rest empty)
"Build a given Haskell package."
diff --git a/guix/build/profiles.scm b/guix/build/profiles.scm
index 819688a913..df785c85a7 100644
--- a/guix/build/profiles.scm
+++ b/guix/build/profiles.scm
@@ -89,7 +89,7 @@ definitions for all the SEARCH-PATHS."
# When GUIX_PROFILE is undefined, the various environment variables refer
# to this specific profile generation.
\n" port)
- (let ((variables (evaluate-search-paths (cons $PATH search-paths)
+ (let ((variables (evaluate-search-paths search-paths
(list output))))
(for-each (write-environment-variable-definition port)
(map (abstract-profile output) variables))))))
diff --git a/guix/gexp.scm b/guix/gexp.scm
index 153b29bd42..cc3613f6f6 100644
--- a/guix/gexp.scm
+++ b/guix/gexp.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Clément Lassieur <clement@lassieur.org>
+;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -23,6 +24,7 @@
#:use-module (guix derivations)
#:use-module (guix grafts)
#:use-module (guix utils)
+ #:use-module (rnrs bytevectors)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-9 gnu)
@@ -334,7 +336,7 @@ appears."
(%plain-file name content references)
plain-file?
(name plain-file-name) ;string
- (content plain-file-content) ;string
+ (content plain-file-content) ;string or bytevector
(references plain-file-references)) ;list (currently unused)
(define (plain-file name content)
@@ -349,8 +351,10 @@ This is the declarative counterpart of 'text-file'."
(define-gexp-compiler (plain-file-compiler (file <plain-file>) system target)
;; "Compile" FILE by adding it to the store.
(match file
- (($ <plain-file> name content references)
- (text-file name content references))))
+ (($ <plain-file> name (and (? string?) content) references)
+ (text-file name content references))
+ (($ <plain-file> name (and (? bytevector?) content) references)
+ (binary-file name content references))))
(define-record-type <computed-file>
(%computed-file name gexp guile options)
diff --git a/guix/gnu-maintenance.scm b/guix/gnu-maintenance.scm
index c2a7a33b6a..3634f4bb27 100644
--- a/guix/gnu-maintenance.scm
+++ b/guix/gnu-maintenance.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2012, 2013 Nikita Karetnikov <nikita@karetnikov.org>
;;;
;;; This file is part of GNU Guix.
@@ -82,13 +82,14 @@
(define %package-list-url
(string->uri
- (string-append %gnumaint-base-url "gnupackages.txt")))
+ (string-append %gnumaint-base-url "rec/gnupackages.rec")))
(define %package-description-url
;; This file contains package descriptions in recutils format.
- ;; See <https://lists.gnu.org/archive/html/guix-devel/2013-10/msg00071.html>.
+ ;; See <https://lists.gnu.org/archive/html/guix-devel/2013-10/msg00071.html>
+ ;; and <https://lists.gnu.org/archive/html/guix-devel/2018-06/msg00362.html>.
(string->uri
- (string-append %gnumaint-base-url "pkgblurbs.txt")))
+ (string-append %gnumaint-base-url "rec/pkgblurbs.rec")))
(define-record-type* <gnu-package-descriptor>
gnu-package-descriptor
@@ -121,7 +122,12 @@ to fetch the list of GNU packages over HTTP."
(if (null? alist)
(reverse result)
(loop (recutils->alist port)
- (cons alist result)))))
+
+ ;; Ignore things like "%rec" (info "(recutils) Record
+ ;; Descriptors").
+ (if (assoc-ref alist "package")
+ (cons alist result)
+ result)))))
(define official-description
(let ((db (read-records (fetch %package-description-url #:text? #t))))
@@ -148,12 +154,12 @@ to fetch the list of GNU packages over HTTP."
(alist->record `(("description" . ,(official-description name))
,@alist)
make-gnu-package-descriptor
- (list "package" "mundane-name" "copyright-holder"
+ (list "package" "mundane_name" "copyright_holder"
"savannah" "fsd" "language" "logo"
- "doc-category" "doc-summary" "description"
- "doc-url"
- "download-url")
- '("doc-url" "language"))))
+ "doc_category" "doc_summary" "description"
+ "doc_url"
+ "download_url")
+ '("doc_url" "language"))))
(let* ((port (fetch %package-list-url #:text? #t))
(lst (read-records port)))
(close-port port)
diff --git a/guix/import/cabal.scm b/guix/import/cabal.scm
index 09130e4498..4cd09cac29 100644
--- a/guix/import/cabal.scm
+++ b/guix/import/cabal.scm
@@ -139,8 +139,8 @@ to the stack."
"Generate a parser for Cabal files."
(lalr-parser
;; --- token definitions
- (CCURLY VCCURLY OPAREN CPAREN TEST ID VERSION RELATION TRUE FALSE
- (right: IF FLAG EXEC TEST-SUITE SOURCE-REPO BENCHMARK LIB OCURLY)
+ (CCURLY VCCURLY OPAREN CPAREN TEST ID VERSION RELATION TRUE FALSE -ANY -NONE
+ (right: IF FLAG EXEC TEST-SUITE CUSTOM-SETUP SOURCE-REPO BENCHMARK LIB OCURLY)
(left: OR)
(left: PROPERTY AND)
(right: ELSE NOT))
@@ -150,6 +150,7 @@ to the stack."
(sections source-repo) : (append $1 (list $2))
(sections executables) : (append $1 $2)
(sections test-suites) : (append $1 $2)
+ (sections custom-setup) : (append $1 $2)
(sections benchmarks) : (append $1 $2)
(sections lib-sec) : (append $1 (list $2))
() : '())
@@ -172,6 +173,7 @@ to the stack."
(ts-sec) : (list $1))
(ts-sec (TEST-SUITE OCURLY exprs CCURLY) : `(section test-suite ,$1 ,$3)
(TEST-SUITE open exprs close) : `(section test-suite ,$1 ,$3))
+ (custom-setup (CUSTOM-SETUP exprs) : (list `(section custom-setup ,$1 ,$2)))
(benchmarks (benchmarks bm-sec) : (append $1 (list $2))
(bm-sec) : (list $1))
(bm-sec (BENCHMARK OCURLY exprs CCURLY) : `(section benchmark ,$1 ,$3)
@@ -211,6 +213,10 @@ to the stack."
(FALSE) : 'false
(TEST OPAREN ID RELATION VERSION CPAREN)
: `(,$1 ,(string-append $3 " " $4 " " $5))
+ (TEST OPAREN ID -ANY CPAREN)
+ : `(,$1 ,(string-append $3 " -any"))
+ (TEST OPAREN ID -NONE CPAREN)
+ : `(,$1 ,(string-append $3 " -none"))
(TEST OPAREN ID RELATION VERSION AND RELATION VERSION CPAREN)
: `(and (,$1 ,(string-append $3 " " $4 " " $5))
(,$1 ,(string-append $3 " " $7 " " $8)))
@@ -349,6 +355,9 @@ matching a string against the created regexp."
(define is-test-suite (make-rx-matcher "^test-suite +([a-z0-9_-]+)"
regexp/icase))
+(define is-custom-setup (make-rx-matcher "^(custom-setup)"
+ regexp/icase))
+
(define is-benchmark (make-rx-matcher "^benchmark +([a-z0-9_-]+)"
regexp/icase))
@@ -362,13 +371,17 @@ matching a string against the created regexp."
(define (is-false s) (string-ci=? s "false"))
+(define (is-any s) (string-ci=? s "-any"))
+
+(define (is-none s) (string-ci=? s "-none"))
+
(define (is-and s) (string=? s "&&"))
(define (is-or s) (string=? s "||"))
(define (is-id s port)
(let ((cabal-reserved-words
- '("if" "else" "library" "flag" "executable" "test-suite"
+ '("if" "else" "library" "flag" "executable" "test-suite" "custom-setup"
"source-repository" "benchmark"))
(spaces (read-while (cut char-set-contains? char-set:blank <>) port))
(c (peek-char port)))
@@ -392,8 +405,11 @@ matching a string against the created regexp."
(define (lex-version loc port)
(make-lexical-token 'VERSION loc
- (read-while char-numeric? port
- (cut char=? #\. <>) char-numeric?)))
+ (read-while (lambda (x)
+ (or (char-numeric? x)
+ (char=? x #\*)
+ (char=? x #\.)))
+ port)))
(define* (read-while is? port #:optional
(is-if-followed-by? (lambda (c) #f))
@@ -435,6 +451,8 @@ string with the read characters."
(define (lex-test-suite ts-rx-res loc) (lex-rx-res ts-rx-res 'TEST-SUITE loc))
+(define (lex-custom-setup ts-rx-res loc) (lex-rx-res ts-rx-res 'CUSTOM-SETUP loc))
+
(define (lex-benchmark bm-rx-res loc) (lex-rx-res bm-rx-res 'BENCHMARK loc))
(define (lex-lib loc) (make-lexical-token 'LIB loc #f))
@@ -447,6 +465,10 @@ string with the read characters."
(define (lex-false loc) (make-lexical-token 'FALSE loc #f))
+(define (lex-any loc) (make-lexical-token '-ANY loc #f))
+
+(define (lex-none loc) (make-lexical-token '-NONE loc #f))
+
(define (lex-and loc) (make-lexical-token 'AND loc #f))
(define (lex-or loc) (make-lexical-token 'OR loc #f))
@@ -514,6 +536,8 @@ LOC is the current port location."
((is-test w port) (lex-test w loc))
((is-true w) (lex-true loc))
((is-false w) (lex-false loc))
+ ((is-any w) (lex-any loc))
+ ((is-none w) (lex-none loc))
((is-and w) (lex-and loc))
((is-or w) (lex-or loc))
((is-id w port) (lex-id w loc))
@@ -529,6 +553,7 @@ the current port location."
((is-src-repo s) => (cut lex-src-repo <> loc))
((is-exec s) => (cut lex-exec <> loc))
((is-test-suite s) => (cut lex-test-suite <> loc))
+ ((is-custom-setup s) => (cut lex-custom-setup <> loc))
((is-benchmark s) => (cut lex-benchmark <> loc))
((is-lib s) (lex-lib loc))
((is-else s) (lex-else loc))
@@ -658,6 +683,12 @@ If #f use the function 'port-filename' to obtain it."
(name cabal-test-suite-name)
(dependencies cabal-test-suite-dependencies)) ; list of <cabal-dependency>
+(define-record-type <cabal-custom-setup>
+ (make-cabal-custom-setup name dependencies)
+ cabal-custom-setup?
+ (name cabal-custom-setuo-name)
+ (dependencies cabal-custom-setup-dependencies)) ; list of <cabal-dependency>
+
(define (cabal-flags->alist flag-list)
"Retrun an alist associating the flag name to its default value from a
list of <cabal-flag> objects."
@@ -694,13 +725,20 @@ the ordering operation and the version."
(let* ((with-ver-matcher-fn (make-rx-matcher
"([a-zA-Z0-9_-]+) *([<>=]+) *([0-9.]+) *"))
(without-ver-matcher-fn (make-rx-matcher "([a-zA-Z0-9_-]+)"))
+ (without-ver-matcher-fn-2 (make-rx-matcher "([a-zA-Z0-9_-]+) (-any|-none)"))
(name (or (and=> (with-ver-matcher-fn spec)
(cut match:substring <> 1))
+ (and=> (without-ver-matcher-fn-2 spec)
+ (cut match:substring <> 1))
(match:substring (without-ver-matcher-fn spec) 1)))
- (operator (and=> (with-ver-matcher-fn spec)
- (cut match:substring <> 2)))
- (version (and=> (with-ver-matcher-fn spec)
- (cut match:substring <> 3))))
+ (operator (or (and=> (with-ver-matcher-fn spec)
+ (cut match:substring <> 2))
+ (and=> (without-ver-matcher-fn-2 spec)
+ (cut match:substring <> 2))))
+ (version (or (and=> (with-ver-matcher-fn spec)
+ (cut match:substring <> 3))
+ (and=> (without-ver-matcher-fn-2 spec)
+ (cut match:substring <> 2)))))
(values name operator version)))
(define (impl haskell)
@@ -716,6 +754,8 @@ the ordering operation and the version."
((string= spec-op ">") (version>? comp-ver spec-ver))
((string= spec-op "<=") (not (version>? comp-ver spec-ver)))
((string= spec-op "<") (not (version>=? comp-ver spec-ver)))
+ ((string= spec-op "-any") #t)
+ ((string= spec-op "-none") #f)
(else
(raise (condition
(&message (message "Failed to evaluate 'impl' test."))))))
@@ -728,7 +768,6 @@ the ordering operation and the version."
(let ((value (or (assoc-ref env name)
(assoc-ref (cabal-flags->alist (cabal-flags)) name))))
(if (eq? value 'false) #f #t)))
-
(define (eval sexp)
(match sexp
(() '())
@@ -755,6 +794,8 @@ the ordering operation and the version."
;; no need to evaluate flag parameters
(('section 'flag name parameters)
(list 'section 'flag name parameters))
+ (('section 'custom-setup parameters)
+ (list 'section 'custom-setup parameters))
;; library does not have a name parameter
(('section 'library parameters)
(list 'section 'library (eval parameters)))
@@ -795,12 +836,15 @@ See the manual for limitations.")))))))
(define (make-cabal-section sexp section-type)
"Given an SEXP as produced by 'read-cabal', produce a list of objects
pertaining to SECTION-TYPE sections. SECTION-TYPE must be one of:
-'executable, 'flag, 'test-suite, 'source-repository or 'library."
+'executable, 'flag, 'test-suite, 'custom-setup, 'source-repository or
+'library."
(filter-map (cut match <>
(('section (? (cut equal? <> section-type)) name parameters)
(case section-type
((test-suite) (make-cabal-test-suite
name (dependencies parameters)))
+ ((custom-setup) (make-cabal-custom-setup
+ name (dependencies parameters "setup-depends")))
((executable) (make-cabal-executable
name (dependencies parameters)))
((source-repository) (make-cabal-source-repository
@@ -843,10 +887,10 @@ to be added between the values found in different key/value pairs."
(define dependency-name-version-rx
(make-regexp "([a-zA-Z0-9_-]+) *(.*)"))
-(define (dependencies key-values-list)
+(define* (dependencies key-values-list #:optional (key "build-depends"))
"Return a list of 'cabal-dependency' objects for the dependencies found in
KEY-VALUES-LIST."
- (let ((deps (string-tokenize (lookup-join key-values-list "build-depends" ",")
+ (let ((deps (string-tokenize (lookup-join key-values-list key ",")
(char-set-complement (char-set #\,)))))
(map (lambda (d)
(let ((rx-result (regexp-exec dependency-name-version-rx d)))
diff --git a/guix/import/gem.scm b/guix/import/gem.scm
index 646163fb7b..ea576b5e4a 100644
--- a/guix/import/gem.scm
+++ b/guix/import/gem.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2015 David Thompson <davet@gnu.org>
;;; Copyright © 2016 Ben Woodcroft <donttrustben@gmail.com>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -33,7 +34,8 @@
#:use-module (guix base32)
#:use-module (guix build-system ruby)
#:export (gem->guix-package
- %gem-updater))
+ %gem-updater
+ gem-recursive-import))
(define (rubygems-fetch name)
"Return an alist representation of the RubyGems metadata for the package NAME,
@@ -115,29 +117,30 @@ VERSION, HASH, HOME-PAGE, DESCRIPTION, DEPENDENCIES, and LICENSES."
((license) (license->symbol license))
(_ `(list ,@(map license->symbol licenses)))))))
-(define* (gem->guix-package package-name #:optional version)
+(define* (gem->guix-package package-name #:optional (repo 'rubygems) version)
"Fetch the metadata for PACKAGE-NAME from rubygems.org, and return the
`package' s-expression corresponding to that package, or #f on failure."
(let ((package (rubygems-fetch package-name)))
(and package
- (let ((name (assoc-ref package "name"))
- (version (assoc-ref package "version"))
- (hash (assoc-ref package "sha"))
- (synopsis (assoc-ref package "info")) ; nothing better to use
- (description (beautify-description
- (assoc-ref package "info")))
- (home-page (assoc-ref package "homepage_uri"))
- (dependencies (map (lambda (dep)
- (let ((name (assoc-ref dep "name")))
- (if (string=? name "bundler")
- "bundler" ; special case, no prefix
- (ruby-package-name name))))
- (assoc-ref* package "dependencies"
- "runtime")))
- (licenses (map string->license
- (assoc-ref package "licenses"))))
- (make-gem-sexp name version hash home-page synopsis
- description dependencies licenses)))))
+ (let* ((name (assoc-ref package "name"))
+ (version (assoc-ref package "version"))
+ (hash (assoc-ref package "sha"))
+ (synopsis (assoc-ref package "info")) ; nothing better to use
+ (description (beautify-description
+ (assoc-ref package "info")))
+ (home-page (assoc-ref package "homepage_uri"))
+ (dependencies-names (map (lambda (dep) (assoc-ref dep "name"))
+ (assoc-ref* package "dependencies" "runtime")))
+ (dependencies (map (lambda (dep)
+ (if (string=? dep "bundler")
+ "bundler" ; special case, no prefix
+ (ruby-package-name dep)))
+ dependencies-names))
+ (licenses (map string->license
+ (assoc-ref package "licenses"))))
+ (values (make-gem-sexp name version hash home-page synopsis
+ description dependencies licenses)
+ dependencies-names)))))
(define (guix-package->gem-name package)
"Given a PACKAGE built from rubygems.org, return the name of the
@@ -192,3 +195,8 @@ package on RubyGems."
(description "Updater for RubyGem packages")
(pred gem-package?)
(latest latest-release)))
+
+(define* (gem-recursive-import package-name #:optional version)
+ (recursive-import package-name '()
+ #:repo->guix-package gem->guix-package
+ #:guix-name ruby-package-name))
diff --git a/guix/import/opam.scm b/guix/import/opam.scm
new file mode 100644
index 0000000000..f252bdc31a
--- /dev/null
+++ b/guix/import/opam.scm
@@ -0,0 +1,193 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2018 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 import opam)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 vlist)
+ #:use-module ((ice-9 rdelim) #:select (read-line))
+ #:use-module (srfi srfi-1)
+ #:use-module (web uri)
+ #:use-module (guix http-client)
+ #:use-module (guix utils)
+ #:use-module (guix import utils)
+ #:use-module ((guix licenses) #:prefix license:)
+ #:export (opam->guix-package))
+
+(define (opam-urls)
+ "Fetch the urls.txt file from the opam repository and returns the list of
+URLs it contains."
+ (let ((port (http-fetch/cached (string->uri "https://opam.ocaml.org/urls.txt"))))
+ (let loop ((result '()))
+ (let ((line (read-line port)))
+ (if (eof-object? line)
+ (begin
+ (close port)
+ result)
+ (loop (cons line result)))))))
+
+(define (vhash-ref hashtable key default)
+ (match (vhash-assoc key hashtable)
+ (#f default)
+ ((_ . x) x)))
+
+(define (hashtable-update hashtable line)
+ "Parse @var{line} to get the name and version of the package and adds them
+to the hashtable."
+ (let* ((line (string-split line #\ )))
+ (match line
+ ((url foo ...)
+ (if (equal? url "repo")
+ hashtable
+ (match (string-split url #\/)
+ ((type name1 versionstr foo ...)
+ (if (equal? type "packages")
+ (match (string-split versionstr #\.)
+ ((name2 versions ...)
+ (let ((version (string-join versions ".")))
+ (if (equal? name1 name2)
+ (let ((curr (vhash-ref hashtable name1 '())))
+ (vhash-cons name1 (cons version curr) hashtable))
+ hashtable)))
+ (_ hashtable))
+ hashtable))
+ (_ hashtable))))
+ (_ hashtable))))
+
+(define (urls->hashtable urls)
+ "Transform urls.txt in a hashtable whose keys are package names and values
+the list of available versions."
+ (let ((hashtable vlist-null))
+ (let loop ((urls urls) (hashtable hashtable))
+ (match urls
+ (() hashtable)
+ ((url rest ...) (loop rest (hashtable-update hashtable url)))))))
+
+(define (latest-version versions)
+ "Find the most recent version from a list of versions."
+ (match versions
+ ((first rest ...)
+ (let loop ((versions rest) (m first))
+ (match versions
+ (() m)
+ ((first rest ...)
+ (loop rest (if (version>? m first) m first))))))))
+
+(define (fetch-package-url uri)
+ "Fetch and parse the url file. Return the URL the package can be downloaded
+from."
+ (let ((port (http-fetch uri)))
+ (let loop ((result #f))
+ (let ((line (read-line port)))
+ (if (eof-object? line)
+ (begin
+ (close port)
+ result)
+ (let* ((line (string-split line #\ )))
+ (match line
+ ((key value rest ...)
+ (if (member key '("archive:" "http:"))
+ (loop (string-trim-both value #\"))
+ (loop result))))))))))
+
+(define (fetch-package-metadata uri)
+ "Fetch and parse the opam file. Return an association list containing the
+homepage, the license and the list of inputs."
+ (let ((port (http-fetch uri)))
+ (let loop ((result '()) (dependencies? #f))
+ (let ((line (read-line port)))
+ (if (eof-object? line)
+ (begin
+ (close port)
+ result)
+ (let* ((line (string-split line #\ )))
+ (match line
+ ((key value ...)
+ (let ((dependencies?
+ (if dependencies?
+ (not (equal? key "]"))
+ (equal? key "depends:")))
+ (val (string-trim-both (string-join value "") #\")))
+ (cond
+ ((equal? key "homepage:")
+ (loop (cons `("homepage" . ,val) result) dependencies?))
+ ((equal? key "license:")
+ (loop (cons `("license" . ,val) result) dependencies?))
+ ((and dependencies? (not (equal? val "[")))
+ (match (string-split val #\{)
+ ((val rest ...)
+ (let ((curr (assoc-ref result "inputs"))
+ (new (string-trim-both
+ val (list->char-set '(#\] #\[ #\")))))
+ (loop (cons `("inputs" . ,(cons new (if curr curr '()))) result)
+ (if (string-contains val "]") #f dependencies?))))))
+ (else (loop result dependencies?))))))))))))
+
+(define (string->license str)
+ (cond
+ ((equal? str "MIT") '(license:expat))
+ ((equal? str "GPL2") '(license:gpl2))
+ ((equal? str "LGPLv2") '(license:lgpl2))
+ (else `())))
+
+(define (ocaml-name->guix-name name)
+ (cond
+ ((equal? name "ocamlfind") "ocaml-findlib")
+ ((string-prefix? "ocaml" name) name)
+ ((string-prefix? "conf-" name) (substring name 5))
+ (else (string-append "ocaml-" name))))
+
+(define (dependencies->inputs dependencies)
+ "Transform the list of dependencies in a list of inputs."
+ (if (not dependencies)
+ '()
+ (map (lambda (input)
+ (list input (list 'unquote (string->symbol input))))
+ (map ocaml-name->guix-name dependencies))))
+
+(define (opam->guix-package name)
+ (let* ((hashtable (urls->hashtable (opam-urls)))
+ (versions (vhash-ref hashtable name #f)))
+ (unless (eq? versions #f)
+ (let* ((version (latest-version versions))
+ (package-url (string-append "https://opam.ocaml.org/packages/" name
+ "/" name "." version "/"))
+ (url-url (string-append package-url "url"))
+ (opam-url (string-append package-url "opam"))
+ (source-url (fetch-package-url url-url))
+ (metadata (fetch-package-metadata opam-url))
+ (dependencies (assoc-ref metadata "inputs"))
+ (inputs (dependencies->inputs dependencies)))
+ (call-with-temporary-output-file
+ (lambda (temp port)
+ (and (url-fetch source-url temp)
+ `(package
+ (name ,(ocaml-name->guix-name name))
+ (version ,version)
+ (source
+ (origin
+ (method url-fetch)
+ (uri ,source-url)
+ (sha256 (base32 ,(guix-hash-url temp)))))
+ (build-system ocaml-build-system)
+ ,@(if (null? inputs)
+ '()
+ `((inputs ,(list 'quasiquote inputs))))
+ (home-page ,(assoc-ref metadata "homepage"))
+ (synopsis "")
+ (description "")
+ (license ,@(string->license (assoc-ref metadata "license")))))))))))
diff --git a/guix/profiles.scm b/guix/profiles.scm
index e6b77e8d38..d2a794b187 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -91,6 +91,7 @@
manifest-lookup
manifest-installed?
manifest-matching-entries
+ manifest-search-paths
manifest-transaction
manifest-transaction?
@@ -109,6 +110,7 @@
ca-certificate-bundle
%default-profile-hooks
profile-derivation
+ profile-search-paths
generation-number
generation-numbers
@@ -545,6 +547,14 @@ no match.."
(filter matches? (manifest-entries manifest)))
+(define (manifest-search-paths manifest)
+ "Return the list of search path specifications that apply to MANIFEST,
+including the search path specification for $PATH."
+ (delete-duplicates
+ (cons $PATH
+ (append-map manifest-entry-search-paths
+ (manifest-entries manifest)))))
+
;;;
;;; Manifest transactions.
@@ -1367,8 +1377,7 @@ are cross-built for TARGET."
(map sexp->search-path-specification
(delete-duplicates
'#$(map search-path-specification->sexp
- (append-map manifest-entry-search-paths
- (manifest-entries manifest))))))
+ (manifest-search-paths manifest)))))
(build-profile #$output '#$inputs
#:symlink #$(if relative-symlinks?
@@ -1392,6 +1401,19 @@ are cross-built for TARGET."
;; to have no substitute to offer.
#:substitutable? #f)))
+(define* (profile-search-paths profile
+ #:optional (manifest (profile-manifest profile))
+ #:key (getenv (const #f)))
+ "Read the manifest of PROFILE and evaluate the values of search path
+environment variables required by PROFILE; return a list of
+specification/value pairs. If MANIFEST is not #f, it is assumed to be the
+manifest of PROFILE, which avoids rereading it.
+
+Use GETENV to determine the current settings and report only settings not
+already effective."
+ (evaluate-search-paths (manifest-search-paths manifest)
+ (list profile) getenv))
+
(define (profile-regexp profile)
"Return a regular expression that matches PROFILE's name and number."
(make-regexp (string-append "^" (regexp-quote (basename profile))
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index f8a9702b30..1c04800e42 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -1,6 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014, 2015, 2018 David Thompson <davet@gnu.org>
-;;; Copyright © 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Mike Gerwitz <mtg@gnu.org>
;;;
;;; This file is part of GNU Guix.
@@ -49,11 +49,6 @@
#:use-module (srfi srfi-98)
#:export (guix-environment))
-(define (evaluate-profile-search-paths profile search-paths)
- "Evaluate SEARCH-PATHS, a list of search-path specifications, for the
-directories in PROFILE, the store path of a profile."
- (evaluate-search-paths search-paths (list profile)))
-
;; Protect some env vars from purification. Borrowed from nix-shell.
(define %precious-variables
'("HOME" "USER" "LOGNAME" "DISPLAY" "TERM" "TZ" "PAGER"))
@@ -70,8 +65,8 @@ as 'HOME' and 'USER' are left untouched."
(((names . _) ...)
names)))))
-(define (create-environment profile paths pure?)
- "Set the environment variables specified by PATHS for PROFILE. When PURE?
+(define* (create-environment profile manifest #:key pure?)
+ "Set the environment variables specified by MANIFEST for PROFILE. When PURE?
is #t, unset the variables in the current environment. Otherwise, augment
existing environment variables with additional search paths."
(when pure? (purify-environment))
@@ -84,53 +79,41 @@ existing environment variables with additional search paths."
(string-append value separator current)
value)
value)))))
- (evaluate-profile-search-paths profile paths))
+ (profile-search-paths profile manifest))
;; Give users a way to know that they're in 'guix environment', so they can
;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users can
;; conveniently access its contents.
(setenv "GUIX_ENVIRONMENT" profile))
-(define (show-search-paths profile search-paths pure?)
- "Display SEARCH-PATHS applied to PROFILE. When PURE? is #t, do not augment
-existing environment variables with additional search paths."
+(define* (show-search-paths profile manifest #:key pure?)
+ "Display the search paths of MANIFEST applied to PROFILE. When PURE? is #t,
+do not augment existing environment variables with additional search paths."
(for-each (match-lambda
((search-path . value)
(display
(search-path-definition search-path value
#:kind (if pure? 'exact 'prefix)))
(newline)))
- (evaluate-profile-search-paths profile search-paths)))
+ (profile-search-paths profile manifest)))
-(define (strip-input-name input)
- "Remove the name element from the tuple INPUT."
+(define (input->manifest-entry input)
+ "Return a manifest entry for INPUT, or #f if INPUT does not correspond to a
+package."
(match input
- ((_ package) package)
- ((_ package output)
- (list package output))))
-
-(define (package+propagated-inputs package output)
- "Return the union of PACKAGE's OUTPUT and its transitive propagated inputs."
- (cons (list package output)
- (map strip-input-name
- (package-transitive-propagated-inputs package))))
-
-(define (package-or-package+output? expr)
- "Return #t if EXPR is a package or a 2 element list consisting of a package
-and an output string."
- (match expr
- ((or (? package?) ; bare package object
- ((? package?) (? string?))) ; package+output tuple
- #t)
- (_ #f)))
+ ((_ (? package? package))
+ (package->manifest-entry package))
+ ((_ (? package? package) output)
+ (package->manifest-entry package output))
+ (_
+ #f)))
(define (package-environment-inputs package)
- "Return a list of the transitive input packages for PACKAGE."
+ "Return a list of manifest entries corresponding to the transitive input
+packages for PACKAGE."
;; Remove non-package inputs such as origin records.
- (filter package-or-package+output?
- (map strip-input-name
- (bag-transitive-inputs
- (package->bag package)))))
+ (filter-map input->manifest-entry
+ (bag-transitive-inputs (package->bag package))))
(define (show-help)
(display (G_ "Usage: guix environment [OPTION]... PACKAGE... [-- COMMAND...]
@@ -287,55 +270,50 @@ COMMAND or an interactive shell in that environment.\n"))
(_ memo)))
'() alist))
-(define (compact lst)
- "Remove all #f elements from LST."
- (filter identity lst))
-
(define (options/resolve-packages opts)
- "Return OPTS with package specification strings replaced by actual
-packages."
- (define (package->output package mode)
- (match package
- ((? package?)
- (list mode package "out"))
- (((? package? package) (? string? output))
- (list mode package output))))
+ "Return OPTS with package specification strings replaced by manifest entries
+for the corresponding packages."
+ (define (manifest-entry=? e1 e2)
+ (and (eq? (manifest-entry-item e1) (manifest-entry-item e2))
+ (string=? (manifest-entry-output e1)
+ (manifest-entry-output e2))))
(define (packages->outputs packages mode)
(match packages
- ((? package-or-package+output? package) ; single package
- (list (package->output package mode)))
- (((? package-or-package+output?) ...) ; many packages
- (map (cut package->output <> mode) packages))))
-
- (define (manifest->outputs manifest)
- (map (lambda (entry)
- (cons 'ad-hoc-package ; manifests are implicitly ad-hoc
- (if (package? (manifest-entry-item entry))
- (list (manifest-entry-item entry)
- (manifest-entry-output entry))
- ;; Direct store paths have no output.
- (list (manifest-entry-item entry)))))
- (manifest-entries manifest)))
-
- (compact
- (append-map (match-lambda
- (('package mode (? string? spec))
- (let-values (((package output)
- (specification->package+output spec)))
- (list (list mode package output))))
- (('expression mode str)
- ;; Add all the outputs of the package STR evaluates to.
- (packages->outputs (read/eval str) mode))
- (('load mode file)
- ;; Add all the outputs of the package defined in FILE.
- (let ((module (make-user-module '())))
- (packages->outputs (load* file module) mode)))
- (('manifest . file)
- (let ((module (make-user-module '((guix profiles) (gnu)))))
- (manifest->outputs (load* file module))))
- (_ '(#f)))
- opts)))
+ ((? package? package)
+ (if (eq? mode 'ad-hoc-package)
+ (list (package->manifest-entry package))
+ (package-environment-inputs package)))
+ (((? package? package) (? string? output))
+ (if (eq? mode 'ad-hoc-package)
+ (list (package->manifest-entry package output))
+ (package-environment-inputs package)))
+ ((lst ...)
+ (append-map (cut packages->outputs <> mode) lst))))
+
+ (manifest
+ (delete-duplicates
+ (append-map (match-lambda
+ (('package 'ad-hoc-package (? string? spec))
+ (let-values (((package output)
+ (specification->package+output spec)))
+ (list (package->manifest-entry package output))))
+ (('package 'package (? string? spec))
+ (package-environment-inputs
+ (specification->package+output spec)))
+ (('expression mode str)
+ ;; Add all the outputs of the package STR evaluates to.
+ (packages->outputs (read/eval str) mode))
+ (('load mode file)
+ ;; Add all the outputs of the package defined in FILE.
+ (let ((module (make-user-module '())))
+ (packages->outputs (load* file module) mode)))
+ (('manifest . file)
+ (let ((module (make-user-module '((guix profiles) (gnu)))))
+ (manifest-entries (load* file module))))
+ (_ '()))
+ opts)
+ manifest-entry=?)))
(define* (build-environment derivations opts)
"Build the DERIVATIONS required by the environment using the build options
@@ -350,11 +328,10 @@ in OPTS."
(return #f)
(built-derivations derivations)))))
-(define (inputs->profile-derivation inputs system bootstrap?)
- "Return the derivation for a profile consisting of INPUTS for SYSTEM.
-BOOTSTRAP? specifies whether to use the bootstrap Guile to build the
-profile."
- (profile-derivation (packages->manifest inputs)
+(define (manifest->derivation manifest system bootstrap?)
+ "Return the derivation for a profile of MANIFEST.
+BOOTSTRAP? specifies whether to use the bootstrap Guile to build the profile."
+ (profile-derivation manifest
#:system system
;; Packages can have conflicting inputs, or explicit
@@ -397,32 +374,34 @@ and suitable for 'exit'."
(define exit/status (compose exit status->exit-code))
(define primitive-exit/status (compose primitive-exit status->exit-code))
-(define (launch-environment command inputs paths pure?)
+(define* (launch-environment command profile manifest
+ #:key pure?)
"Run COMMAND in a new environment containing INPUTS, using the native search
paths defined by the list PATHS. When PURE?, pre-existing environment
variables are cleared before setting the new ones."
;; Properly handle SIGINT, so pressing C-c in an interactive terminal
;; application works.
(sigaction SIGINT SIG_DFL)
- (create-environment inputs paths pure?)
+ (create-environment profile manifest #:pure? pure?)
(match command
((program . args)
(apply execlp program program args))))
-(define (launch-environment/fork command inputs paths pure?)
- "Run COMMAND in a new process with an environment containing INPUTS, using
-the native search paths defined by the list PATHS. When PURE?, pre-existing
-environment variables are cleared before setting the new ones."
+(define* (launch-environment/fork command profile manifest #:key pure?)
+ "Run COMMAND in a new process with an environment containing PROFILE, with
+the search paths specified by MANIFEST. When PURE?, pre-existing environment
+variables are cleared before setting the new ones."
(match (primitive-fork)
- (0 (launch-environment command inputs paths pure?))
+ (0 (launch-environment command profile manifest
+ #:pure? pure?))
(pid (match (waitpid pid)
((_ . status) status)))))
(define* (launch-environment/container #:key command bash user user-mappings
- profile paths link-profile? network?)
+ profile manifest link-profile? network?)
"Run COMMAND within a container that features the software in PROFILE.
-Environment variables are set according to PATHS, a list of native search
-paths. The global shell is BASH, a file name for a GNU Bash binary in the
+Environment variables are set according to the search paths of MANIFEST.
+The global shell is BASH, a file name for a GNU Bash binary in the
store. When NETWORK?, access to the host system network is permitted.
USER-MAPPINGS, a list of file system mappings, contains the user-specified
host file systems to mount inside the container. If USER is not #f, each
@@ -514,7 +493,7 @@ will be used for the passwd entry. LINK-PROFILE? creates a symbolic link from
(primitive-exit/status
;; A container's environment is already purified, so no need to
;; request it be purified again.
- (launch-environment command profile paths #f)))
+ (launch-environment command profile manifest #:pure? #f)))
#:namespaces (if network?
(delq 'net %namespaces) ; share host network
%namespaces)))))))
@@ -671,25 +650,8 @@ message if any test fails."
;; within the container.
'("/bin/sh")
(list %default-shell))))
- (packages (options/resolve-packages opts))
- (mappings (pick-all opts 'file-system-mapping))
- (inputs (delete-duplicates
- (append-map (match-lambda
- (('ad-hoc-package package output)
- (package+propagated-inputs package
- output))
- (('package package _)
- (package-environment-inputs package)))
- packages)))
- (paths (delete-duplicates
- (cons $PATH
- (append-map (match-lambda
- ((or ((? package? p) _ ...)
- (? package? p))
- (package-native-search-paths p))
- (_ '()))
- inputs))
- eq?)))
+ (manifest (options/resolve-packages opts))
+ (mappings (pick-all opts 'file-system-mapping)))
(when container? (assert-container-features))
@@ -714,8 +676,8 @@ message if any test fails."
(mlet* %store-monad ((bash (environment-bash container?
bootstrap?
system))
- (prof-drv (inputs->profile-derivation
- inputs system bootstrap?))
+ (prof-drv (manifest->derivation
+ manifest system bootstrap?))
(profile -> (derivation->output-path prof-drv))
(gc-root -> (assoc-ref opts 'gc-root)))
@@ -734,7 +696,7 @@ message if any test fails."
((assoc-ref opts 'dry-run?)
(return #t))
((assoc-ref opts 'search-paths)
- (show-search-paths profile paths pure?)
+ (show-search-paths profile manifest #:pure? pure?)
(return #t))
(container?
(let ((bash-binary
@@ -747,11 +709,11 @@ message if any test fails."
#:user user
#:user-mappings mappings
#:profile profile
- #:paths paths
+ #:manifest manifest
#:link-profile? link-prof?
#:network? network?)))
(else
(return
(exit/status
- (launch-environment/fork command profile
- paths pure?)))))))))))))
+ (launch-environment/fork command profile manifest
+ #:pure? pure?)))))))))))))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index f8cb85700d..0b326e1049 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -75,7 +75,7 @@ rather than \\n."
;;;
(define importers '("gnu" "nix" "pypi" "cpan" "hackage" "stackage" "elpa" "gem"
- "cran" "crate" "texlive" "json"))
+ "cran" "crate" "texlive" "json" "opam"))
(define (resolve-importer name)
(let ((module (resolve-interface
diff --git a/guix/scripts/import/gem.scm b/guix/scripts/import/gem.scm
index 349a0a072a..b6d9ccaae4 100644
--- a/guix/scripts/import/gem.scm
+++ b/guix/scripts/import/gem.scm
@@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -25,6 +26,7 @@
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-11)
#:use-module (srfi srfi-37)
+ #:use-module (srfi srfi-41)
#:use-module (ice-9 match)
#:use-module (ice-9 format)
#:export (guix-import-gem))
@@ -44,6 +46,9 @@ Import and convert the RubyGems package for PACKAGE-NAME.\n"))
-h, --help display this help and exit"))
(display (G_ "
-V, --version display version information and exit"))
+ (display (G_ "
+ -r, --recursive generate package expressions for all Gem packages\
+ that are not yet in Guix"))
(newline)
(show-bug-report-information))
@@ -56,6 +61,9 @@ Import and convert the RubyGems package for PACKAGE-NAME.\n"))
(option '(#\V "version") #f #f
(lambda args
(show-version-and-exit "guix import pypi")))
+ (option '(#\r "recursive") #f #f
+ (lambda (opt name arg result)
+ (alist-cons 'recursive #t result)))
%standard-import-options))
@@ -81,11 +89,20 @@ Import and convert the RubyGems package for PACKAGE-NAME.\n"))
(reverse opts))))
(match args
((package-name)
- (let ((sexp (gem->guix-package package-name)))
- (unless sexp
- (leave (G_ "failed to download meta-data for package '~a'~%")
- package-name))
- sexp))
+ (if (assoc-ref opts 'recursive)
+ (map (match-lambda
+ ((and ('package ('name name) . rest) pkg)
+ `(define-public ,(string->symbol name)
+ ,pkg))
+ (_ #f))
+ (reverse
+ (stream->list
+ (gem-recursive-import package-name 'rubygems))))
+ (let ((sexp (gem->guix-package package-name)))
+ (unless sexp
+ (leave (G_ "failed to download meta-data for package '~a'~%")
+ package-name))
+ sexp)))
(()
(leave (G_ "too few arguments~%")))
((many ...)
diff --git a/guix/scripts/import/opam.scm b/guix/scripts/import/opam.scm
new file mode 100644
index 0000000000..b549878742
--- /dev/null
+++ b/guix/scripts/import/opam.scm
@@ -0,0 +1,92 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2018 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 scripts import opam)
+ #:use-module (guix ui)
+ #:use-module (guix utils)
+ #:use-module (guix scripts)
+ #:use-module (guix import opam)
+ #:use-module (guix scripts import)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-11)
+ #:use-module (srfi srfi-37)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 format)
+ #:export (guix-import-opam))
+
+
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+ '())
+
+(define (show-help)
+ (display (G_ "Usage: guix import opam PACKAGE-NAME
+Import and convert the opam package for PACKAGE-NAME.\n"))
+ (display (G_ "
+ -h, --help display this help and exit"))
+ (display (G_ "
+ -V, --version display version information and exit"))
+ (newline)
+ (show-bug-report-information))
+
+(define %options
+ ;; Specification of the command-line options.
+ (cons* (option '(#\h "help") #f #f
+ (lambda args
+ (show-help)
+ (exit 0)))
+ (option '(#\V "version") #f #f
+ (lambda args
+ (show-version-and-exit "guix import opam")))
+ %standard-import-options))
+
+
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-opam . args)
+ (define (parse-options)
+ ;; Return the alist of option values.
+ (args-fold* args %options
+ (lambda (opt name arg result)
+ (leave (G_ "~A: unrecognized option~%") name))
+ (lambda (arg result)
+ (alist-cons 'argument arg result))
+ %default-options))
+
+ (let* ((opts (parse-options))
+ (args (filter-map (match-lambda
+ (('argument . value)
+ value)
+ (_ #f))
+ (reverse opts))))
+ (match args
+ ((package-name)
+ (let ((sexp (opam->guix-package package-name)))
+ (unless sexp
+ (leave (G_ "failed to download meta-data for package '~a'~%")
+ package-name))
+ sexp))
+ (()
+ (leave (G_ "too few arguments~%")))
+ ((many ...)
+ (leave (G_ "too many arguments~%"))))))
diff --git a/guix/store.scm b/guix/store.scm
index bac42f2738..cc5c24a77d 100644
--- a/guix/store.scm
+++ b/guix/store.scm
@@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -77,6 +78,7 @@
add-data-to-store
add-text-to-store
add-to-store
+ binary-file
build-things
build
query-failed-paths
@@ -1362,7 +1364,18 @@ taking the store as its first argument."
;; Store monad operators.
;;
-(define* (text-file name text
+(define* (binary-file name
+ data ;bytevector
+ #:optional (references '()))
+ "Return as a monadic value the absolute file name in the store of the file
+containing DATA, a bytevector. REFERENCES is a list of store items that the
+resulting text file refers to; it defaults to the empty list."
+ (lambda (store)
+ (values (add-data-to-store store name data references)
+ store)))
+
+(define* (text-file name
+ text ;string
#:optional (references '()))
"Return as a monadic value the absolute file name in the store of the file
containing TEXT, a string. REFERENCES is a list of store items that the
diff --git a/guix/ui.scm b/guix/ui.scm
index 6a5feaa953..29c0b2b9ce 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -1428,7 +1428,7 @@ DURATION-RELATION with the current time."
(format #t "~a~%" header)))))
(define (display-profile-content-diff profile gen1 gen2)
- "Display the changed packages in PROFILE GEN2 compared to generation GEN2."
+ "Display the changed packages in PROFILE GEN2 compared to generation GEN1."
(define (equal-entry? first second)
(string= (manifest-entry-item first) (manifest-entry-item second)))