From d7ee90fe906aacb7f0bb1513195a1457970fd19d Mon Sep 17 00:00:00 2001 From: Ricardo Wurmus Date: Sat, 16 Jun 2018 12:20:32 +0200 Subject: build-system/ant: Unconditionally return #t in build phases. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/build/ant-build-system.scm (unpack, build, strip-jar-timestamps, check, install): Use invoke. Signed-off-by: Gábor Boskovits --- guix/build/ant-build-system.scm | 76 ++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 38 deletions(-) (limited to 'guix') diff --git a/guix/build/ant-build-system.scm b/guix/build/ant-build-system.scm index d081a2b313..3ed12b9f4e 100644 --- a/guix/build/ant-build-system.scm +++ b/guix/build/ant-build-system.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2016 Ricardo Wurmus +;;; Copyright © 2016, 2018 Ricardo Wurmus ;;; ;;; This file is part of GNU Guix. ;;; @@ -150,7 +150,8 @@ to the default GNU unpack strategy." (begin (mkdir "src") (with-directory-excursion "src" - (zero? (system* "jar" "-xf" source)))) + (invoke "jar" "-xf" source)) + #t) ;; Use GNU unpack strategy for things that aren't jar archives. ((assq-ref gnu:%standard-phases 'unpack) #:source source))) @@ -171,7 +172,7 @@ to the default GNU unpack strategy." (define* (build #:key (make-flags '()) (build-target "jar") #:allow-other-keys) - (zero? (apply system* `("ant" ,build-target ,@make-flags)))) + (apply invoke `("ant" ,build-target ,@make-flags))) (define* (generate-jar-indices #:key outputs #:allow-other-keys) "Generate file \"META-INF/INDEX.LIST\". This file does not use word wraps @@ -194,50 +195,49 @@ repack them. This is necessary to ensure that archives are reproducible." (format #t "repacking ~a\n" jar) (let* ((dir (mkdtemp! "jar-contents.XXXXXX")) (manifest (string-append dir "/META-INF/MANIFEST.MF"))) - (and (with-directory-excursion dir - (zero? (system* "jar" "xf" jar))) - (delete-file jar) - ;; XXX: copied from (gnu build install) - (for-each (lambda (file) - (let ((s (lstat file))) - (unless (eq? (stat:type s) 'symlink) - (utime file 0 0 0 0)))) - (find-files dir #:directories? #t)) + (with-directory-excursion dir + (invoke "jar" "xf" jar)) + (delete-file jar) + ;; XXX: copied from (gnu build install) + (for-each (lambda (file) + (let ((s (lstat file))) + (unless (eq? (stat:type s) 'symlink) + (utime file 0 0 0 0)))) + (find-files dir #:directories? #t)) - ;; The jar tool will always set the timestamp on the manifest file - ;; and the containing directory to the current time, even when we - ;; reuse an existing manifest file. To avoid this we use "zip" - ;; instead of "jar". It is important that the manifest appears - ;; first. - (with-directory-excursion dir - (let* ((files (find-files "." ".*" #:directories? #t)) - ;; To ensure that the reference scanner can detect all - ;; store references in the jars we disable compression - ;; with the "-0" option. - (command (if (file-exists? manifest) - `("zip" "-0" "-X" ,jar ,manifest ,@files) - `("zip" "-0" "-X" ,jar ,@files)))) - (unless (zero? (apply system* command)) - (error "'zip' failed")))) - (utime jar 0 0) - #t))) + ;; The jar tool will always set the timestamp on the manifest file + ;; and the containing directory to the current time, even when we + ;; reuse an existing manifest file. To avoid this we use "zip" + ;; instead of "jar". It is important that the manifest appears + ;; first. + (with-directory-excursion dir + (let* ((files (find-files "." ".*" #:directories? #t)) + ;; To ensure that the reference scanner can detect all + ;; store references in the jars we disable compression + ;; with the "-0" option. + (command (if (file-exists? manifest) + `("zip" "-0" "-X" ,jar ,manifest ,@files) + `("zip" "-0" "-X" ,jar ,@files)))) + (apply invoke command))) + (utime jar 0 0) + #t)) - (every (match-lambda - ((output . directory) - (every repack-archive (find-files directory "\\.jar$")))) - outputs)) + (for-each (match-lambda + ((output . directory) + (for-each repack-archive (find-files directory "\\.jar$")))) + outputs) + #t) (define* (check #:key target (make-flags '()) (tests? (not target)) (test-target "check") #:allow-other-keys) (if tests? - (zero? (apply system* `("ant" ,test-target ,@make-flags))) - (begin - (format #t "test suite not run~%") - #t))) + (apply invoke `("ant" ,test-target ,@make-flags)) + (format #t "test suite not run~%")) + #t) (define* (install #:key (make-flags '()) #:allow-other-keys) - (zero? (apply system* `("ant" "install" ,@make-flags)))) + (apply invoke `("ant" "install" ,@make-flags))) (define %standard-phases (modify-phases gnu:%standard-phases -- cgit v1.2.3 From 90ea1006a86518e523c510eee1214fd81e71da74 Mon Sep 17 00:00:00 2001 From: Gábor Boskovits Date: Tue, 12 Jun 2018 13:52:40 +0200 Subject: guix: ant-build-system: Use manifest task to create manifest. * guix/build/ant-build-system.scm (default-build.xml): Use manifest task to create manifest file instead of a custom echo task. --- guix/build/ant-build-system.scm | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'guix') diff --git a/guix/build/ant-build-system.scm b/guix/build/ant-build-system.scm index 3ed12b9f4e..87c782d853 100644 --- a/guix/build/ant-build-system.scm +++ b/guix/build/ant-build-system.scm @@ -68,14 +68,11 @@ (target (@ (name "manifest")) (mkdir (@ (dir "${manifest.dir}"))) - (echo (@ (file "${manifest.file}") - (message ,(string-append - (if main-class - (string-append - "Main-Class: " main-class - "${line.separator}") - "") - ""))))) + (manifest (@ (file "${manifest.file}")) + ,(if main-class + `(attribute (@ (name "Main-Class") + (value ,main-class))) + ""))) (target (@ (name "compile")) (mkdir (@ (dir "${classes.dir}"))) -- cgit v1.2.3 From 0e6cce2e01c1ff89e373cc77578853de11a7e8eb Mon Sep 17 00:00:00 2001 From: Mark H Weaver Date: Mon, 25 Jun 2018 18:53:49 -0400 Subject: meson-build-system: Return #t from all phases. * guix/build/meson-build-system.scm (configure, build, check, install): (fix-runpath): Use 'invoke' and return #t from all phases. --- guix/build/meson-build-system.scm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'guix') diff --git a/guix/build/meson-build-system.scm b/guix/build/meson-build-system.scm index e7690a4c37..e4aae8212f 100644 --- a/guix/build/meson-build-system.scm +++ b/guix/build/meson-build-system.scm @@ -58,15 +58,14 @@ (mkdir build-dir) (chdir build-dir) - (zero? (apply system* "meson" args)))) + (apply invoke "meson" args))) (define* (build #:key parallel-build? #:allow-other-keys) "Build a given meson package." - (zero? (apply system* "ninja" - (if parallel-build? - `("-j" ,(number->string (parallel-job-count))) - '("-j" "1"))))) + (invoke "ninja" "-j" (if parallel-build? + (number->string (parallel-job-count)) + "1"))) (define* (check #:key test-target parallel-tests? tests? #:allow-other-keys) @@ -75,13 +74,13 @@ (number->string (parallel-job-count)) "1")) (if tests? - (zero? (system* "ninja" test-target)) + (invoke "ninja" test-target) (begin (format #t "test suite not run~%") #t))) (define* (install #:rest args) - (zero? (system* "ninja" "install"))) + (invoke "ninja" "install")) (define* (fix-runpath #:key (elf-directories '("lib" "lib64" "libexec" "bin" "sbin")) @@ -135,7 +134,7 @@ for example libraries only needed for the tests." (find-files dir elf-pred)) existing-elf-dirs)))) (for-each (lambda (elf-file) - (system* "patchelf" "--shrink-rpath" elf-file) + (invoke "patchelf" "--shrink-rpath" elf-file) (handle-file elf-file elf-list)) elf-list))))) (for-each handle-output outputs) -- cgit v1.2.3 From 2c8ac3641a673328d19677f8c8f2ebf690ad3c0e Mon Sep 17 00:00:00 2001 From: Mark H Weaver Date: Thu, 28 Jun 2018 03:52:08 -0400 Subject: gnu: java: Return #t from all phases and snippets. * guix/build/java-utils.scm (ant-build-javadoc): Use invoke; return #t. * guix/build/ant-build-system.scm (generate-jar-indices): Return #t and remove vestigal plumbing. * gnu/packages/java.scm (classpath-bootstrap, ant-bootstrap, classpath-devel) (icedtea-6, icedtea-7, java-plexus-sec-dispatcher, ant/java8, clojure) (java-classpathx-servletapi, java-swt, java-qdox-1.12, java-hamcrest-core) (java-plexus-archiver, java-plexus-sec-dispatcher, java-modello-plugins-xml) (java-asm, java-commons-collections, java-commons-bsf, java-slf4j-api) (java-slf4j-api, java-slf4j-simple, java-stringtemplate-3) (java-stringtemplate, antlr3, antlr3-3.3, antlr3-3.1, java-ops4j-base-lang) (java-ops4j-pax-tinybundles, java-ops4j-pax-exam-core-spi) (java-fasterxml-jackson-core, java-fasterxml-jackson-databind) (java-fasterxml-jackson-modules-base-jaxb, java-ecj-3, java-ecj-3.5) (java-fasterxml-jackson-dataformat-yaml, java-woodstox-core) (java-fasterxml-jackson-dataformat-xml, java-testng, java-jnacl) (java-bouncycastle, java-powermock-core, java-powermock-modules-junit4) (java-jansi-native, java-jansi, java-commons-httpclient, java-commons-vfs) (java-apache-ivy, java-janino, java-logback-core): Return #t from all phases and snippets, use invoke where appropriate, and remove vestigial plumbing. --- gnu/packages/java.scm | 359 ++++++++++++++++++++++------------------ guix/build/ant-build-system.scm | 9 +- guix/build/java-utils.scm | 2 +- 3 files changed, 202 insertions(+), 168 deletions(-) (limited to 'guix') diff --git a/gnu/packages/java.scm b/gnu/packages/java.scm index e28ddc4bce..043696ca98 100644 --- a/gnu/packages/java.scm +++ b/gnu/packages/java.scm @@ -718,34 +718,32 @@ machine."))) (modify-phases %standard-phases (replace 'unpack (lambda* (#:key source inputs #:allow-other-keys) - (and (zero? (system* "tar" "xvf" source)) - (begin - (chdir (string-append "icedtea6-" ,version)) - (mkdir "openjdk") - (copy-recursively (assoc-ref inputs "openjdk-src") "openjdk") - ;; The convenient OpenJDK source bundle is no longer - ;; available for download, so we have to take the sources - ;; from the Mercurial repositories and change the Makefile - ;; to avoid tests for the OpenJDK zip archive. - (with-directory-excursion "openjdk" - (for-each (lambda (part) - (mkdir part) - (copy-recursively - (assoc-ref inputs - (string-append part "-src")) - part)) - '("jdk" "hotspot" "corba" - "langtools" "jaxp" "jaxws"))) - (substitute* "Makefile.in" - (("echo \"ERROR: No up-to-date OpenJDK zip available\"; exit -1;") - "echo \"trust me\";") - ;; The contents of the bootstrap directory must be - ;; writeable but when copying from the store they are - ;; not. - (("mkdir -p lib/rt" line) - (string-append line "; chmod -R u+w $(BOOT_DIR)"))) - (zero? (system* "chmod" "-R" "u+w" "openjdk")) - #t)))) + (invoke "tar" "xvf" source) + (chdir (string-append "icedtea6-" ,version)) + (mkdir "openjdk") + (copy-recursively (assoc-ref inputs "openjdk-src") "openjdk") + ;; The convenient OpenJDK source bundle is no longer + ;; available for download, so we have to take the sources + ;; from the Mercurial repositories and change the Makefile + ;; to avoid tests for the OpenJDK zip archive. + (with-directory-excursion "openjdk" + (for-each (lambda (part) + (mkdir part) + (copy-recursively + (assoc-ref inputs + (string-append part "-src")) + part)) + '("jdk" "hotspot" "corba" + "langtools" "jaxp" "jaxws"))) + (substitute* "Makefile.in" + (("echo \"ERROR: No up-to-date OpenJDK zip available\"; exit -1;") + "echo \"trust me\";") + ;; The contents of the bootstrap directory must be + ;; writeable but when copying from the store they are + ;; not. + (("mkdir -p lib/rt" line) + (string-append line "; chmod -R u+w $(BOOT_DIR)"))) + (invoke "chmod" "-R" "u+w" "openjdk"))) (add-after 'unpack 'use-classpath (lambda* (#:key inputs #:allow-other-keys) (let ((jvmlib (assoc-ref inputs "classpath")) @@ -1081,23 +1079,22 @@ bootstrapping purposes.") (let ((dir (or dir (string-drop-right name 5)))) (mkdir dir) - (zero? (system* "tar" "xvf" - (assoc-ref inputs name) - "-C" dir - "--strip-components=1")))))) + (invoke "tar" "xvf" + (assoc-ref inputs name) + "-C" dir + "--strip-components=1"))))) (mkdir target) - (and - (zero? (system* "tar" "xvf" source - "-C" target "--strip-components=1")) - (chdir target) - (unpack "openjdk-src" "openjdk.src") - (with-directory-excursion "openjdk.src" - (for-each unpack - (filter (cut string-suffix? "-drop" <>) - (map (match-lambda - ((name . _) name)) - inputs)))) - #t)))) + (invoke "tar" "xvf" source + "-C" target "--strip-components=1") + (chdir target) + (unpack "openjdk-src" "openjdk.src") + (with-directory-excursion "openjdk.src" + (for-each unpack + (filter (cut string-suffix? "-drop" <>) + (map (match-lambda + ((name . _) name)) + inputs)))) + #t))) (add-after 'unpack 'fix-x11-extension-include-path (lambda* (#:key inputs #:allow-other-keys) (substitute* "openjdk.src/jdk/make/sun/awt/mawt.gmk" @@ -1322,17 +1319,18 @@ bootstrapping purposes.") (let ((line (read-line port))) (cond ((eof-object? line) #t) - ((regexp-exec error-pattern line) #f) + ((regexp-exec error-pattern line) + (error "test failed")) (else (loop))))))) (run-test (lambda (test) - (system* "make" test) + (invoke "make" test) (call-with-input-file (string-append "test/" test ".log") checker)))) - (or #t ; skip tests - (and (run-test "check-hotspot") - (run-test "check-langtools") - (run-test "check-jdk")))))) + (when #f ; skip tests + (run-test "check-hotspot") + (run-test "check-langtools") + (run-test "check-jdk"))))) (replace 'install (lambda* (#:key outputs #:allow-other-keys) (let ((doc (string-append (assoc-ref outputs "doc") @@ -1695,9 +1693,9 @@ new Date();")) ;; result in the tests to be run. (substitute* "build.xml" (("depends=\"jars,test-jar\"") "depends=\"jars\"")) - (zero? (system* "bash" "bootstrap.sh" - (string-append "-Ddist.dir=" - (assoc-ref outputs "out")))))))))) + (invoke "bash" "bootstrap.sh" + (string-append "-Ddist.dir=" + (assoc-ref outputs "out"))))))))) (native-inputs `(("jdk" ,icedtea-8 "jdk") ("zip" ,zip) @@ -1827,14 +1825,13 @@ new Date();")) (lambda (name) (mkdir-p name) (with-directory-excursion name - (or (zero? (system* "tar" - ;; Use xz for repacked tarball. - "--xz" - "--extract" - "--verbose" - "--file" (assoc-ref inputs name) - "--strip-components=1")) - (error "failed to unpack tarball" name))) + (invoke "tar" + ;; Use xz for repacked tarball. + "--xz" + "--extract" + "--verbose" + "--file" (assoc-ref inputs name) + "--strip-components=1")) (copy-recursively (string-append name "/src/main/clojure/") "src/clj/")) '("core-specs-alpha-src" @@ -1847,7 +1844,7 @@ new Date();")) ;; The javadoc target is not built by default. (add-after 'build 'build-doc (lambda _ - (zero? (system* "ant" "javadoc")))) + (invoke "ant" "javadoc"))) ;; Needed since no install target is provided. (replace 'install (lambda* (#:key outputs #:allow-other-keys) @@ -2009,7 +2006,8 @@ debugging, etc.") (lambda (in out) (display "Manifest-Version: 1.0 Main-Class: org.eclipse.jdt.internal.compiler.batch.Main\n" - out))))) + out))) + #t)) (replace 'install (install-jars "."))))) (home-page "https://eclipse.org") (synopsis "Eclipse Java development tools core batch compiler") @@ -2042,7 +2040,8 @@ Main-Class: org.eclipse.jdt.internal.compiler.batch.Main\n" (lambda (in out) (dump-port in out) (display "Main-Class: org.eclipse.jdt.internal.compiler.batch.Main\n" - out))))) + out))) + #t)) (replace 'install (install-jars "."))))) (native-inputs `(("unzip" ,unzip))))) @@ -2509,7 +2508,7 @@ HDF5 files, building on the libraries provided by the HDF Group.") (modify-phases %standard-phases (replace 'install (lambda* (#:key make-flags #:allow-other-keys) - (zero? (apply system* `("ant" "dist" ,@make-flags)))))))) + (apply invoke `("ant" "dist" ,@make-flags))))))) (home-page "https://www.gnu.org/software/classpathx/") (synopsis "Java servlet API implementation") (description "This is the GNU servlet API distribution, part of the @@ -2551,11 +2550,11 @@ API and version 2.1 of the Java ServerPages API.") (modify-phases %standard-phases (replace 'unpack (lambda* (#:key source #:allow-other-keys) - (and (mkdir "swt") - (zero? (system* "unzip" source "-d" "swt")) - (chdir "swt") - (mkdir "src") - (zero? (system* "unzip" "src.zip" "-d" "src"))))) + (mkdir "swt") + (invoke "unzip" source "-d" "swt") + (chdir "swt") + (mkdir "src") + (invoke "unzip" "src.zip" "-d" "src"))) ;; The classpath contains invalid icecat jars. Since we don't need ;; anything other than the JDK on the classpath, we can simply unset ;; it. @@ -2570,7 +2569,7 @@ API and version 2.1 of the Java ServerPages API.") (mkdir-p lib) (setenv "OUTPUT_DIR" lib) (with-directory-excursion "src" - (zero? (system* "bash" "build.sh")))))) + (invoke "bash" "build.sh"))))) (add-after 'install 'install-native (lambda* (#:key outputs #:allow-other-keys) (let ((lib (string-append (assoc-ref outputs "out") "/lib"))) @@ -2656,7 +2655,7 @@ decompression and random access decompression have been fully implemented.") (lambda* (#:key source #:allow-other-keys) (mkdir "src") (with-directory-excursion "src" - (zero? (system* "jar" "-xf" source))))) + (invoke "jar" "-xf" source)))) ;; At this point we don't have junit, so we must remove the API ;; tests. (add-after 'unpack 'delete-tests @@ -2767,7 +2766,8 @@ private Method[] getSortedMethods() { return _allMethods; } -private Method[] allMethods = getSortedMethods();"))))) +private Method[] allMethods = getSortedMethods();"))) + #t)) (add-before 'build 'do-not-use-bundled-qdox (lambda* (#:key inputs #:allow-other-keys) (substitute* "build.xml" @@ -3058,7 +3058,8 @@ reusing it in maven.") (lambda _ ;; Requires an older version of plexus container (delete-file - "src/test/java/org/codehaus/plexus/archiver/DuplicateFilesTest.java"))) + "src/test/java/org/codehaus/plexus/archiver/DuplicateFilesTest.java") + #t)) (add-before 'build 'copy-resources (lambda _ (mkdir-p "build/classes/META-INF/plexus") @@ -3251,15 +3252,15 @@ Compiler component."))) (add-before 'build 'generate-models (lambda* (#:key inputs #:allow-other-keys) (define (modello-single-mode file version mode) - (zero? (system* "java" - "org.codehaus.modello.ModelloCli" - file mode "src/main/java" version - "false" "true"))) + (invoke "java" + "org.codehaus.modello.ModelloCli" + file mode "src/main/java" version + "false" "true")) (let ((file "src/main/mdo/settings-security.mdo")) - (and (modello-single-mode file "1.0.0" "java") (modello-single-mode file "1.0.0" "xpp3-reader") - (modello-single-mode file "1.0.0" "xpp3-writer"))))) + (modello-single-mode file "1.0.0" "xpp3-writer")) + #t)) (add-before 'build 'generate-components.xml (lambda _ (mkdir-p "build/classes/META-INF/plexus") @@ -3288,10 +3289,12 @@ Compiler component."))) \n \n \n -\n"))))) +\n"))) + #t)) (add-before 'check 'fix-paths (lambda _ - (copy-recursively "src/test/resources" "target")))))) + (copy-recursively "src/test/resources" "target") + #t))))) (inputs `(("java-plexus-cipher" ,java-plexus-cipher))) (native-inputs @@ -3514,7 +3517,8 @@ XSD and documentation.") (with-directory-excursion "modello-plugins/modello-plugin-xml/src/test" (substitute* "java/org/codehaus/modello/plugins/xml/XmlModelloPluginTest.java" - (("src/test") "modello-plugins/modello-plugin-xml/src/test")))))))) + (("src/test") "modello-plugins/modello-plugin-xml/src/test"))) + #t))))) (inputs `(("java-modello-core" ,java-modello-core) ("java-modello-plugins-java" ,java-modello-plugins-java) @@ -3609,9 +3613,9 @@ on the XPP3 API (XML Pull Parser)."))) ;; We cannot use the "jar" target because it depends on a couple ;; of unpackaged, complicated tools. (mkdir "dist") - (zero? (system* "jar" - "-cf" (string-append "dist/asm-" ,version ".jar") - "-C" "output/build/tmp" ".")))) + (invoke "jar" + "-cf" (string-append "dist/asm-" ,version ".jar") + "-C" "output/build/tmp" "."))) (replace 'install (install-jars "dist"))))) (native-inputs @@ -4099,7 +4103,8 @@ are many features, including: (mkdir-p "build/conf") (call-with-output-file "build/conf/MANIFEST.MF" (lambda (file) - (format file "Manifest-Version: 1.0\n"))))) + (format file "Manifest-Version: 1.0\n"))) + #t)) (replace 'install (install-jars "build")))))))) @@ -4345,7 +4350,8 @@ in the @code{java.lang} package. The following classes are included: (property (@ (name "tests.dir") (value "src/org/apache/bsf/test"))) (property (@ (name "build.tests") (value "build/test-classes"))) (property (@ (name "build.dest") (value "build/classes")))) - port))))) + port))) + #t)) (replace 'install (install-jars "build"))))) (native-inputs `(("java-junit" ,java-junit))) @@ -5792,8 +5798,8 @@ more efficient storage-wise than an uncompressed bitmap (as implemented in the ;; pom.xml ignores these files in the jar creation process. If we don't, ;; we get the error "This code should have never made it into slf4j-api.jar" (delete-file-recursively "build/classes/org/slf4j/impl") - (zero? (system* "jar" "-cf" "build/jar/slf4j-api.jar" "-C" - "build/classes" ".")))) + (invoke "jar" "-cf" "build/jar/slf4j-api.jar" "-C" + "build/classes" "."))) (add-before 'check 'dont-test-abstract-classes (lambda _ ;; abstract classes are not meant to be run with junit @@ -5801,7 +5807,8 @@ more efficient storage-wise than an uncompressed bitmap (as implemented in the (("") (string-append "" "")))))))) + ".java\" />"))) + #t))))) (inputs `(("java-junit" ,java-junit) ("java-hamcrest-core" ,java-hamcrest-core))) @@ -5842,10 +5849,9 @@ time.") (setenv "CLASSPATH" (string-append (getcwd) ":" (getenv "CLASSPATH"))) ;; ... and build test helper classes here: - (zero? - (apply system* - `("javac" "-d" "." - ,@(find-files "slf4j-api/src/test" ".*\\.java"))))))))) + (apply invoke + `("javac" "-d" "." + ,@(find-files "slf4j-api/src/test" ".*\\.java")))))))) (inputs `(("java-junit" ,java-junit) ("java-hamcrest-core" ,java-hamcrest-core) @@ -5944,11 +5950,12 @@ tree walking, and translation.") (add-before 'build 'generate-grammar (lambda _ (with-directory-excursion "src/org/antlr/stringtemplate/language/" - (every (lambda (file) - (format #t "~a\n" file) - (zero? (system* "antlr" file))) - '("template.g" "angle.bracket.template.g" "action.g" - "eval.g" "group.g" "interface.g")))))))) + (for-each (lambda (file) + (format #t "~a\n" file) + (invoke "antlr" file)) + '("template.g" "angle.bracket.template.g" "action.g" + "eval.g" "group.g" "interface.g"))) + #t))))) (native-inputs `(("antlr" ,antlr2) ("java-junit" ,java-junit))) @@ -6006,10 +6013,11 @@ StringTemplate also powers ANTLR.") (add-before 'build 'generate-grammar (lambda _ (with-directory-excursion "src/org/stringtemplate/v4/compiler/" - (every (lambda (file) - (format #t "~a\n" file) - (zero? (system* "antlr3" file))) - '("STParser.g" "Group.g" "CodeGenerator.g")))))))) + (for-each (lambda (file) + (format #t "~a\n" file) + (invoke "antlr3" file)) + '("STParser.g" "Group.g" "CodeGenerator.g"))) + #t))))) (inputs `(("antlr3" ,antlr3-bootstrap) ("antlr2" ,antlr2) @@ -6076,14 +6084,15 @@ StringTemplate also powers ANTLR.") "/lib") ".*\\.jar")) " org.antlr.Tool $*")))) - (chmod (string-append bin "/antlr3") #o755)))) + (chmod (string-append bin "/antlr3") #o755)) + #t)) (add-before 'build 'generate-grammar (lambda _ (chdir "tool/src/main/antlr3/org/antlr/grammar/v3/") (for-each (lambda (file) (display file) (newline) - (system* "antlr3" file)) + (invoke "antlr3" file)) '("ANTLR.g" "ANTLRTreePrinter.g" "ActionAnalysis.g" "AssignTokenTypesWalker.g" "ActionTranslator.g" "TreeToNFAConverter.g" @@ -6094,14 +6103,15 @@ StringTemplate also powers ANTLR.") (substitute* "ANTLRv3Parser.java" (("public Object getTree") "public CommonTree getTree")) (chdir "../../../../../java") - (system* "antlr" "-o" "org/antlr/tool" - "org/antlr/tool/serialize.g") + (invoke "antlr" "-o" "org/antlr/tool" + "org/antlr/tool/serialize.g") (substitute* "org/antlr/tool/LeftRecursiveRuleAnalyzer.java" (("import org.antlr.grammar.v3.\\*;") "import org.antlr.grammar.v3.*; import org.antlr.grammar.v3.ANTLRTreePrinter;")) (substitute* "org/antlr/tool/ErrorManager.java" (("case NO_SUCH_ATTRIBUTE_PASS_THROUGH:") "")) - (chdir "../../../.."))) + (chdir "../../../..") + #t)) (add-before 'build 'fix-build-xml (lambda _ (substitute* "build.xml" @@ -6112,7 +6122,8 @@ import org.antlr.grammar.v3.ANTLRTreePrinter;")) - -") "")) - (zero? (system* "java" "-cp" (string-append (getenv "CLASSPATH") - ":build/classes" - ":build/test-classes") - "-Dtest.resources.dir=src/test/resources" - "org.testng.TestNG" "src/test/resources/testng.xml"))))))) + (invoke "java" "-cp" (string-append (getenv "CLASSPATH") + ":build/classes" + ":build/test-classes") + "-Dtest.resources.dir=src/test/resources" + "org.testng.TestNG" "src/test/resources/testng.xml")))))) (propagated-inputs `(("junit" ,java-junit) ("java-jsr305" ,java-jsr305) @@ -8177,8 +8206,7 @@ to use.") ":build/classes" ":build/test-classes") "org.testng.TestNG" "-testclass" - "build/test-classes/com/neilalexander/jnacl/NaClTest.class") - #t))))) + "build/test-classes/com/neilalexander/jnacl/NaClTest.class")))))) (native-inputs `(("java-testng" ,java-testng) ("java-fest-util" ,java-fest-util) @@ -8361,8 +8389,7 @@ algorithms and xxHash hashing algorithm.") (replace 'build (lambda _ (invoke "ant" "-f" "ant/jdk15+.xml" "build-provider") - (invoke "ant" "-f" "ant/jdk15+.xml" "build") - #t)) + (invoke "ant" "-f" "ant/jdk15+.xml" "build"))) ;; FIXME: the tests freeze. ;; (replace 'check ;; (lambda _ @@ -8540,7 +8567,8 @@ done to the IDE or continuous integration servers which simplifies adoption.") (add-before 'build 'copy-resources (lambda _ (copy-recursively "powermock-core/src/main/resources" - "build/classes")))))) + "build/classes") + #t))))) (inputs `(("reflect" ,java-powermock-reflect) ("javassist" ,java-jboss-javassist))) @@ -8597,7 +8625,8 @@ done to the IDE or continuous integration servers which simplifies adoption.") ;; Our junit version is 4.12-SNAPSHOT (substitute* (find-files "powermock-modules/powermock-module-junit4" "PowerMockJUnit4MethodValidator.java") - (("4.12") "4.12-SNAPSHOT"))))))) + (("4.12") "4.12-SNAPSHOT")) + #t))))) (inputs `(("core" ,java-powermock-core) ("reflect" ,java-powermock-reflect) @@ -9062,8 +9091,7 @@ that is part of the SWT Tools project.") (string-append "-I" (assoc-ref inputs "jdk") "/include/linux") "-fPIC" "-O2") - (invoke "gcc" "-o" "libjansi.so" "-shared" "jansi_ttyname.o") - #t))) + (invoke "gcc" "-o" "libjansi.so" "-shared" "jansi_ttyname.o")))) (add-before 'build 'install-native (lambda _ (let ((dir (string-append "build/classes/META-INF/native/" @@ -9108,7 +9136,7 @@ console output.") (modify-phases %standard-phases (add-after 'check 'clear-term (lambda _ - (zero? (system* "echo" "-e" "\\e[0m"))))))) + (invoke "echo" "-e" "\\e[0m")))))) (inputs `(("java-jansi-native" ,java-jansi-native))) (native-inputs @@ -9572,7 +9600,8 @@ graphs, and pie charts.") '("src/java/org/apache/commons/httpclient/HttpContentTooLargeException.java" "src/examples/TrivialApp.java" "src/examples/ClientApp.java" "src/test/org/apache/commons/httpclient/TestHttps.java" - "src/test/org/apache/commons/httpclient/TestURIUtil2.java")))) + "src/test/org/apache/commons/httpclient/TestURIUtil2.java")) + #t)) (replace 'install (lambda* (#:key outputs #:allow-other-keys) (invoke "ant" "dist" @@ -9622,7 +9651,8 @@ authentication, HTTP state management, and HTTP connection management.") (lambda _ (for-each delete-file-recursively '("commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/webdav" - "commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/hdfs"))))))) + "commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/hdfs")) + #t))))) (inputs `(("java-commons-collections4" ,java-commons-collections4) ("java-commons-compress" ,java-commons-compress) @@ -9933,7 +9963,8 @@ jsch-agent-proxy with JSch."))) (find-files "." ".*.properties") (find-files "." ".*.xsd") (find-files "." ".*.xsl") - (find-files "." ".*.xml")))))) + (find-files "." ".*.xml")))) + #t)) (add-before 'build 'fix-vfs (lambda _ (substitute* @@ -9948,8 +9979,7 @@ jsch-agent-proxy with JSch."))) (add-before 'install 'repack (lambda _ (invoke "jar" "-cmf" "build/classes/META-INF/MANIFEST.MF" "build/jar/ivy.jar" - "-C" "build/classes" ".") - #t)) + "-C" "build/classes" "."))) (add-after 'install 'install-bin (lambda* (#:key outputs #:allow-other-keys) (let* ((bin (string-append (assoc-ref outputs "out") "/bin")) @@ -10162,7 +10192,8 @@ and @code{ISimpleCompiler} interfaces.") (modify-phases %standard-phases (add-before 'configure 'chdir (lambda _ - (chdir "janino")))))) + (chdir "janino") + #t))))) (inputs `(("java-commons-compiler" ,java-commons-compiler))) (native-inputs @@ -10187,7 +10218,9 @@ static code analysis or code manipulation."))) "1x6ga74yfgm94cfx98gybakbrlilx8i2gn6dx13l40kasmys06mi")) (modules '((guix build utils))) (snippet - '(delete-file-recursively "logback-access/lib")))) + '(begin + (delete-file-recursively "logback-access/lib") + #t)))) (build-system ant-build-system) (arguments `(#:jar-name "logback.jar" diff --git a/guix/build/ant-build-system.scm b/guix/build/ant-build-system.scm index 87c782d853..d79b4d503b 100644 --- a/guix/build/ant-build-system.scm +++ b/guix/build/ant-build-system.scm @@ -179,10 +179,11 @@ grafting works - and so that the garbage collector doesn't collect dependencies of this jar file." (define (generate-index jar) (invoke "jar" "-i" jar)) - (every (match-lambda - ((output . directory) - (every generate-index (find-files directory "\\.jar$")))) - outputs)) + (for-each (match-lambda + ((output . directory) + (for-each generate-index (find-files directory "\\.jar$")))) + outputs) + #t) (define* (strip-jar-timestamps #:key outputs #:allow-other-keys) diff --git a/guix/build/java-utils.scm b/guix/build/java-utils.scm index 402d377bf8..128be1edeb 100644 --- a/guix/build/java-utils.scm +++ b/guix/build/java-utils.scm @@ -31,7 +31,7 @@ (define* (ant-build-javadoc #:key (target "javadoc") (make-flags '()) #:allow-other-keys) - (zero? (apply system* `("ant" ,target ,@make-flags)))) + (apply invoke `("ant" ,target ,@make-flags))) (define* (install-jars jar-directory) "Install jar files from JAR-DIRECTORY to the default target directory. This -- cgit v1.2.3 From fd1395c4982dd8cf7fe9843317d1ebb1e5d78bee Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 29 Jun 2018 12:17:41 +0200 Subject: ui: Increase relevance score for exact matches. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously "guix package -s python" would have 'python2-zope-interface' as its first result (relevance: 10), followed by many other python-* packages with the same score, while 'python' itself would come later (relevance: 7). This change makes 'python' the first result (relevance: 27). Reported by Gábor Boskovits. * guix/ui.scm (relevance)[score]: Use 'fold-matches' instead of 'match:count' to counter the number of maches. Give more weight to exact matches. --- guix/ui.scm | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'guix') diff --git a/guix/ui.scm b/guix/ui.scm index ec709450d8..6996b7f1c4 100644 --- a/guix/ui.scm +++ b/guix/ui.scm @@ -1222,11 +1222,14 @@ field in the final score. A score of zero means that OBJ does not match any of REGEXPS. The higher the score, the more relevant OBJ is to REGEXPS." (define (score str) - (let ((counts (filter-map (lambda (regexp) - (match (regexp-exec regexp str) - (#f #f) - (m (match:count m)))) - regexps))) + (let ((counts (map (lambda (regexp) + (match (fold-matches regexp str '() cons) + (() 0) + ((m) (if (string=? (match:substring m) str) + 5 ;exact match + 1)) + (lst (length lst)))) + regexps))) ;; Compute a score that's proportional to the number of regexps matched ;; and to the number of matches for each regexp. (* (length counts) (reduce + 0 counts)))) -- cgit v1.2.3 From cb4b508cd68df89bfbd5255a0c5569f8318ad50f Mon Sep 17 00:00:00 2001 From: Marius Bakke Date: Mon, 2 Jul 2018 12:07:58 +0200 Subject: build-system/meson: Really skip the 'fix-runpath' phase on armhf. This follows up commit d5b5a15a4046362377f1a45d466b43bb6e93d4f which doesn't work because %current-system etc expands before the actual build. Fixes . * guix/build-system/meson.scm (meson-build)[builder]: Compare against the already existing "system" variable rather than (%current-system). --- guix/build-system/meson.scm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'guix') diff --git a/guix/build-system/meson.scm b/guix/build-system/meson.scm index 529a2b8b0f..e894e1472d 100644 --- a/guix/build-system/meson.scm +++ b/guix/build-system/meson.scm @@ -148,8 +148,7 @@ has a 'meson.build' file." #:search-paths ',(map search-path-specification->sexp search-paths) #:phases - (if (string-prefix? "arm" ,(or (%current-target-system) - (%current-system))) + (if (string-prefix? "arm" ,system) (modify-phases build-phases (delete 'fix-runpath)) build-phases) #:configure-flags ,configure-flags -- cgit v1.2.3 From 3059a35afe3f0ff2561870e0a0fb21e03fc3247a Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 2 Jul 2018 14:47:35 +0200 Subject: utils: Disable memoization for 'location'. This was getting 25% hits, which did not quite justify the overhead. * guix/utils.scm (location): Remove 'mlambda'. --- guix/utils.scm | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'guix') diff --git a/guix/utils.scm b/guix/utils.scm index a5de9605e7..9fbb95d31c 100644 --- a/guix/utils.scm +++ b/guix/utils.scm @@ -773,11 +773,10 @@ be determined." (line location-line) ; 1-indexed line (column location-column)) ; 0-indexed column -(define location - (mlambda (file line column) - "Return the object for the given FILE, LINE, and COLUMN." - (and line column file - (make-location file line column)))) +(define (location file line column) + "Return the object for the given FILE, LINE, and COLUMN." + (and line column file + (make-location file line column))) (define (source-properties->location loc) "Return a location object based on the info in LOC, an alist as returned -- cgit v1.2.3 From 223fa5b327b0892cf45d22e4a9fbfb06164e409d Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 2 Jul 2018 14:49:14 +0200 Subject: utils: Micro-optimize 'source-properties->location'. * guix/utils.scm (source-properties->location): Destructure LOC with 'match', adding a fast path without 'assq-ref' calls. --- guix/utils.scm | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'guix') diff --git a/guix/utils.scm b/guix/utils.scm index 9fbb95d31c..f934b6ed13 100644 --- a/guix/utils.scm +++ b/guix/utils.scm @@ -782,12 +782,19 @@ be determined." "Return a location object based on the info in LOC, an alist as returned by Guile's `source-properties', `frame-source', `current-source-location', etc." - (let ((file (assq-ref loc 'filename)) - (line (assq-ref loc 'line)) - (col (assq-ref loc 'column))) - ;; In accordance with the GCS, start line and column numbers at 1. Note - ;; that unlike LINE and `port-column', COL is actually 1-indexed here... - (location file (and line (+ line 1)) col))) + ;; In accordance with the GCS, start line and column numbers at 1. Note + ;; that unlike LINE and `port-column', COL is actually 1-indexed here... + (match loc + ((('line . line) ('column . col) ('filename . file)) ;common case + (and file line col + (make-location file (+ line 1) col))) + (#f + #f) + (_ + (let ((file (assq-ref loc 'filename)) + (line (assq-ref loc 'line)) + (col (assq-ref loc 'column))) + (location file (and line (+ line 1)) col))))) (define (location->source-properties loc) "Return the source property association list based on the info in LOC, -- cgit v1.2.3 From 8970a886e640d584de16b2bc5973c7ef293fa74a Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 2 Jul 2018 14:50:36 +0200 Subject: self: Use #:guile-for-build in the shebang of the 'guix' executable. * guix/self.scm (guix-command): Add #:guile and pass it to 'program-file'. (whole-package): Add #:guile and pass it to 'guix-command'. (compiled-guix): Pass #:guile to 'guix-command' and 'whole-package'. --- guix/self.scm | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'guix') diff --git a/guix/self.scm b/guix/self.scm index 89c5428039..240bb89cd5 100644 --- a/guix/self.scm +++ b/guix/self.scm @@ -343,7 +343,7 @@ DOMAIN, a gettext domain." (define* (guix-command modules #:optional compiled-modules #:key source (dependencies '()) - (guile-version (effective-version))) + guile (guile-version (effective-version))) "Return the 'guix' command such that it adds MODULES and DEPENDENCIES in its load path." (program-file "guix-command" @@ -383,15 +383,17 @@ load path." ;; XXX: It would be more convenient to change it to: ;; (exit (apply guix-main (command-line))) - (apply guix-main (command-line)))))) + (apply guix-main (command-line)))) + #:guile guile)) (define* (whole-package name modules dependencies #:key (guile-version (effective-version)) compiled-modules - info daemon + info daemon guile (command (guix-command modules #:dependencies dependencies + #:guile guile #:guile-version guile-version))) "Return the whole Guix package NAME that uses MODULES, a derivation of all the modules, and DEPENDENCIES, a list of packages depended on. COMMAND is the @@ -630,10 +632,12 @@ assumed to be part of MODULES." (command (guix-command modules compiled #:source source #:dependencies dependencies + #:guile guile-for-build #:guile-version guile-version))) (whole-package name modules dependencies #:compiled-modules compiled #:command command + #:guile guile-for-build ;; Include 'guix-daemon'. XXX: Here we inject an ;; older snapshot of guix-daemon, but that's a good -- cgit v1.2.3 From 084f64cb032b6ab4ce326b088d230bd1ead53ee2 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 2 Jul 2018 14:51:42 +0200 Subject: self: Build with Guile 2.2.4. * guix/self.scm (guile-for-build): In the "2.2" case, choose GUILE-2.2.4. --- guix/self.scm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/self.scm b/guix/self.scm index 240bb89cd5..c9c7138e65 100644 --- a/guix/self.scm +++ b/guix/self.scm @@ -907,8 +907,10 @@ running Guile." (module-ref (resolve-interface '(gnu packages guile)) 'guile-2.2.2)) ("2.2" + ;; Use the latest version, which has fixes for + ;; and VM stack-marking issues. (canonical-package (module-ref (resolve-interface '(gnu packages guile)) - 'guile-2.2/fixed))) + 'guile-2.2.4))) ("2.0" (module-ref (resolve-interface '(gnu packages guile)) 'guile-2.0)))) -- cgit v1.2.3 From 24420f5ffabfbdbe913a5765e5c00e17de18fb4c Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 2 Jul 2018 22:15:35 +0200 Subject: packages: Optimize 'package-transitive-supported-systems'. This version is 13% faster than the one above when timing: (fold-packages (lambda (p x) (package-transitive-supported-systems p)) '()) * guix/packages.scm (package-transitive-supported-systems): Make 'systems' a set instead of calling 'lset-intersection' repeatedly. --- guix/packages.scm | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'guix') diff --git a/guix/packages.scm b/guix/packages.scm index c762fa7c39..cd7d3b895c 100644 --- a/guix/packages.scm +++ b/guix/packages.scm @@ -766,15 +766,16 @@ in INPUTS and their transitive propagated inputs." (mlambdaq (package) "Return the intersection of the systems supported by PACKAGE and those supported by its dependencies." - (fold (lambda (input systems) - (match input - ((label (? package? p) . _) - (lset-intersection - string=? systems (package-transitive-supported-systems p))) - (_ - systems))) - (package-supported-systems package) - (bag-direct-inputs (package->bag package))))) + (set->list + (fold (lambda (input systems) + (match input + ((label (? package? p) . _) + (fold set-insert systems + (package-transitive-supported-systems p))) + (_ + systems))) + (list->set (package-supported-systems package)) + (bag-direct-inputs (package->bag package)))))) (define* (supported-package? package #:optional (system (%current-system))) "Return true if PACKAGE is supported on SYSTEM--i.e., if PACKAGE and all its -- cgit v1.2.3 From 0744a9f0029b2f78cc86b193214004b4501fa847 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 2 Jul 2018 23:50:38 +0200 Subject: store: Add 'query-path-info*'. * guix/scripts/size.scm (query-path-info*): Move to... * guix/store.scm (query-path-info*): ... here. --- guix/scripts/size.scm | 11 +---------- guix/store.scm | 10 ++++++++++ 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'guix') diff --git a/guix/scripts/size.scm b/guix/scripts/size.scm index b7b53e43fb..344be40883 100644 --- a/guix/scripts/size.scm +++ b/guix/scripts/size.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2015, 2016, 2017 Ludovic Courtès +;;; Copyright © 2015, 2016, 2017, 2018 Ludovic Courtès ;;; ;;; This file is part of GNU Guix. ;;; @@ -53,15 +53,6 @@ (define substitutable-path-info* (store-lift substitutable-path-info)) -(define (query-path-info* item) - "Monadic version of 'query-path-info' that returns #f when ITEM is not in -the store." - (lambda (store) - (guard (c ((nix-protocol-error? c) - ;; ITEM is not in the store; return #f. - (values #f store))) - (values (query-path-info store item) store)))) - (define (file-size item) "Return the size in bytes of ITEM, resorting to information from substitutes if ITEM is not in the store." diff --git a/guix/store.scm b/guix/store.scm index 3bf56573bf..bac42f2738 100644 --- a/guix/store.scm +++ b/guix/store.scm @@ -107,6 +107,7 @@ references references/substitutes references* + query-path-info* requisites referrers optimize-store @@ -1398,6 +1399,15 @@ where FILE is the entry's absolute file name and STAT is the result of (define references* (store-lift references)) +(define (query-path-info* item) + "Monadic version of 'query-path-info' that returns #f when ITEM is not in +the store." + (lambda (store) + (guard (c ((nix-protocol-error? c) + ;; ITEM is not in the store; return #f. + (values #f store))) + (values (query-path-info store item) store)))) + (define-inlinable (current-system) ;; Consult the %CURRENT-SYSTEM fluid at bind time. This is equivalent to ;; (lift0 %current-system %store-monad), but inlinable, thus avoiding -- cgit v1.2.3 From 8120b23e51d8a21056cf982c6740234b8f858633 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 2 Jul 2018 23:51:20 +0200 Subject: ui: Make 'check-available-space' public. * guix/ui.scm (check-available-space): Add optional 'directory' parameter, defaulting to (%store-prefix). Honor it. Make public. --- guix/ui.scm | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'guix') diff --git a/guix/ui.scm b/guix/ui.scm index 6996b7f1c4..c1101eb4bb 100644 --- a/guix/ui.scm +++ b/guix/ui.scm @@ -87,6 +87,7 @@ leave-on-EPIPE read/eval read/eval-package-expression + check-available-space location->string fill-paragraph %text-width @@ -795,16 +796,17 @@ error." (derivation->output-path derivation out-name))) (derivation-outputs derivation)))) -(define (check-available-space need) - "Make sure at least NEED bytes are available in the store. Otherwise emit a +(define* (check-available-space need + #:optional (directory (%store-prefix))) + "Make sure at least NEED bytes are available in DIRECTORY. Otherwise emit a warning." (let ((free (catch 'system-error (lambda () - (free-disk-space (%store-prefix))) + (free-disk-space directory)) (const #f)))) (when (and free (>= need free)) (warning (G_ "at least ~,1h MB needed but only ~,1h MB available in ~a~%") - (/ need 1e6) (/ free 1e6) (%store-prefix))))) + (/ need 1e6) (/ free 1e6) directory)))) (define* (show-what-to-build store drv #:key dry-run? (use-substitutes? #t) -- cgit v1.2.3 From 71bf6cb700965cfe5b8f3661315017b022d0aca1 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 2 Jul 2018 23:59:52 +0200 Subject: guix system: init: Check the available space before copying. * guix/scripts/system.scm (copy-closure): Call 'query-path-info*' on TO-COPY and REFS. Compute the total size. Call 'check-available-space'. --- guix/scripts/system.scm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm index 14aedceac1..92e92237b6 100644 --- a/guix/scripts/system.scm +++ b/guix/scripts/system.scm @@ -148,12 +148,18 @@ REFERENCES as its set of references." "Copy ITEM and all its dependencies to the store under root directory TARGET, and register them." (mlet* %store-monad ((to-copy (topologically-sorted* (list item))) - (refs (mapm %store-monad references* to-copy))) + (refs (mapm %store-monad references* to-copy)) + (info (mapm %store-monad query-path-info* + (delete-duplicates + (append to-copy (concatenate refs))))) + (size -> (reduce + 0 (map path-info-nar-size info)))) (define progress-bar (progress-reporter/bar (length to-copy) (format #f (G_ "copying to '~a'...") target))) + (check-available-space size target) + (call-with-progress-reporter progress-bar (lambda (report) (let ((void (%make-void-port "w"))) -- cgit v1.2.3 From af2f8ae5f14d272d341148764d256792d8ef06aa Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Tue, 3 Jul 2018 00:01:20 +0200 Subject: deduplication: Fix incorrect use of 'throw'. * guix/store/deduplication.scm (get-temp-link): In handler, fix call to 'throw'. --- guix/store/deduplication.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/store/deduplication.scm b/guix/store/deduplication.scm index d3139eb904..b1cd8873ae 100644 --- a/guix/store/deduplication.scm +++ b/guix/store/deduplication.scm @@ -88,7 +88,7 @@ LINK-PREFIX." (lambda args (if (= (system-error-errno args) EEXIST) (try (tempname-in link-prefix)) - (throw 'system-error args)))))) + (apply throw args)))))) ;; There are 3 main kinds of errors we can get from hardlinking: "Too many ;; things link to this" (EMLINK), "this link already exists" (EEXIST), and -- cgit v1.2.3 From 3dbf331942f11ee888ccbf849cacdd3a0ab971cd Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Tue, 3 Jul 2018 00:26:59 +0200 Subject: deduplication: Place link files under /gnu/store/.links. Previously they'd always be placed next to TO-REPLACE, which would lead to EPERM in some cases. * guix/store/deduplication.scm (replace-with-link): Add #:swap-directory parameter and honor it. Add call to 'make-file-writable'. Catch 'system-error' around 'rename-file'. (deduplicate): Pass #:swap-directory and remove uses of 'false-if-system-error'. * tests/store-deduplication.scm ("deduplicate"): Add 'chmod' call. --- guix/store/deduplication.scm | 28 +++++++++++++++++++--------- tests/store-deduplication.scm | 4 ++++ 2 files changed, 23 insertions(+), 9 deletions(-) (limited to 'guix') diff --git a/guix/store/deduplication.scm b/guix/store/deduplication.scm index b1cd8873ae..b97719d4bf 100644 --- a/guix/store/deduplication.scm +++ b/guix/store/deduplication.scm @@ -94,11 +94,21 @@ LINK-PREFIX." ;; things link to this" (EMLINK), "this link already exists" (EEXIST), and ;; "can't fit more stuff in this directory" (ENOSPC). -(define (replace-with-link target to-replace) - "Atomically replace the file TO-REPLACE with a link to TARGET. Note: TARGET -and TO-REPLACE must be on the same file system." - (let ((temp-link (get-temp-link target (dirname to-replace)))) - (rename-file temp-link to-replace))) +(define* (replace-with-link target to-replace + #:key (swap-directory (dirname target))) + "Atomically replace the file TO-REPLACE with a link to TARGET. Use +SWAP-DIRECTORY as the directory to store temporary hard links. + +Note: TARGET, TO-REPLACE, and SWAP-DIRECTORY must be on the same file system." + (let ((temp-link (get-temp-link target swap-directory))) + (make-file-writable (dirname to-replace)) + (catch 'system-error + (lambda () + (rename-file temp-link to-replace)) + (lambda args + (delete-file temp-link) + (unless (= EMLINK (system-error-errno args)) + (apply throw args)))))) (define-syntax-rule (false-if-system-error (errors ...) exp ...) "Given ERRORS, a list of system error codes to ignore, evaluates EXP... and @@ -131,8 +141,8 @@ under STORE." #:store store)))) (scandir path)) (if (file-exists? link-file) - (false-if-system-error (EMLINK) - (replace-with-link link-file path)) + (replace-with-link link-file path + #:swap-directory links-directory) (catch 'system-error (lambda () (link path link-file)) @@ -141,8 +151,8 @@ under STORE." (cond ((= errno EEXIST) ;; Someone else put an entry for PATH in ;; LINKS-DIRECTORY before we could. Let's use it. - (false-if-system-error (EMLINK) - (replace-with-link path link-file))) + (replace-with-link path link-file + #:swap-directory links-directory)) ((= errno ENOSPC) ;; There's not enough room in the directory index for ;; more entries in .links, but that's fine: we can diff --git a/tests/store-deduplication.scm b/tests/store-deduplication.scm index 2361723199..4ca2ec0f61 100644 --- a/tests/store-deduplication.scm +++ b/tests/store-deduplication.scm @@ -47,6 +47,10 @@ (lambda (port) (put-bytevector port data)))) identical) + ;; Make the parent of IDENTICAL read-only. This should not prevent + ;; deduplication for inserting its hard link. + (chmod (dirname (second identical)) #o544) + (call-with-output-file unique (lambda (port) (put-bytevector port (string->utf8 "This is unique.")))) -- cgit v1.2.3 From ae6fa00af02399e2ffadccc81bd7718cc7c26f10 Mon Sep 17 00:00:00 2001 From: Oleg Pykhalov Date: Sat, 30 Jun 2018 10:51:45 +0300 Subject: import: elpa: Check if 'fetch-elpa-package' rest argument is null. * guix/import/elpa.scm (fetch-elpa-package): Check if 'rest' is null. --- guix/import/elpa.scm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/import/elpa.scm b/guix/import/elpa.scm index 65e0be45ab..c37afaf8e6 100644 --- a/guix/import/elpa.scm +++ b/guix/import/elpa.scm @@ -187,7 +187,9 @@ include VERSION." (url (package-source-url kind name ver repo))) (make-elpa-package name ver (ensure-list reqs) synopsis kind - (package-home-page (first rest)) + (package-home-page (match rest + (() #f) + ((one) one))) (fetch-package-description kind name repo) url))) (_ #f)))) -- cgit v1.2.3 From a5b34d9d24cababcaa9d5e93813ccb3196e11a95 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Tue, 3 Jul 2018 10:17:09 +0200 Subject: deduplication: Remove 'false-if-system-error', now unused. * guix/store/deduplication.scm (false-if-system-error): Remove. --- guix/store/deduplication.scm | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'guix') diff --git a/guix/store/deduplication.scm b/guix/store/deduplication.scm index b97719d4bf..6ff4a50de5 100644 --- a/guix/store/deduplication.scm +++ b/guix/store/deduplication.scm @@ -110,17 +110,6 @@ Note: TARGET, TO-REPLACE, and SWAP-DIRECTORY must be on the same file system." (unless (= EMLINK (system-error-errno args)) (apply throw args)))))) -(define-syntax-rule (false-if-system-error (errors ...) exp ...) - "Given ERRORS, a list of system error codes to ignore, evaluates EXP... and -return #f if any of the system error codes in the given list are thrown." - (catch 'system-error - (lambda () - exp ...) - (lambda args - (if (member (system-error-errno args) (list errors ...)) - #f - (apply throw args))))) - (define* (deduplicate path hash #:key (store %store-directory)) "Check if a store item with sha256 hash HASH already exists. If so, replace PATH with a hardlink to the already-existing one. If not, register -- cgit v1.2.3 From 25c7ff6a3ecbaa1e93b38d35c8cbff40b7f4edb8 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Tue, 3 Jul 2018 10:52:55 +0200 Subject: syscalls: Define AT_SYMLINK_NOFOLLOW et al. * guix/build/syscalls.scm (AT_FDCWD, AT_SYMLINK_NOFOLLOW, AT_REMOVEDIR) (AT_SYMLINK_FOLLOW, AT_NO_AUTOMOUNT, AT_EMPTY_PATH): New variables. * tests/syscalls.scm ("utime with AT_SYMLINK_NOFOLLOW"): New test. --- guix/build/syscalls.scm | 17 +++++++++++++++++ tests/syscalls.scm | 13 +++++++++++++ 2 files changed, 30 insertions(+) (limited to 'guix') diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm index 25726b885e..74cb675fcf 100644 --- a/guix/build/syscalls.scm +++ b/guix/build/syscalls.scm @@ -46,6 +46,14 @@ MNT_DETACH MNT_EXPIRE UMOUNT_NOFOLLOW + + AT_FDCWD + AT_SYMLINK_NOFOLLOW + AT_REMOVEDIR + AT_SYMLINK_FOLLOW + AT_NO_AUTOMOUNT + AT_EMPTY_PATH + restart-on-EINTR mount-points swapon @@ -667,6 +675,15 @@ mounted at FILE." (* (file-system-block-size fs) (file-system-blocks-available fs)))) +;; Flags for the *at command, notably the 'utime' procedure of libguile. +;; From . +(define AT_FDCWD -100) +(define AT_SYMLINK_NOFOLLOW #x100) +(define AT_REMOVEDIR #x200) +(define AT_SYMLINK_FOLLOW #x400) +(define AT_NO_AUTOMOUNT #x800) +(define AT_EMPTY_PATH #x1000) + ;;; ;;; Containers. diff --git a/tests/syscalls.scm b/tests/syscalls.scm index 0d07280b99..3e267c9f01 100644 --- a/tests/syscalls.scm +++ b/tests/syscalls.scm @@ -60,6 +60,19 @@ (any (cute member <> (mount-points)) '("/" "/proc" "/sys" "/dev"))) +(false-if-exception (delete-file temp-file)) +(test-equal "utime with AT_SYMLINK_NOFOLLOW" + '(0 0) + (begin + ;; Test libguile's utime with AT_SYMLINK_NOFOLLOW, which libguile does not + ;; define as of Guile 2.2.4. + (symlink "/nowhere" temp-file) + (utime temp-file 0 0 0 0 AT_SYMLINK_NOFOLLOW) + (let ((st (lstat temp-file))) + (delete-file temp-file) + ;; Note: 'utimensat' does not change 'ctime'. + (list (stat:mtime st) (stat:atime st))))) + (test-assert "swapon, ENOENT/EPERM" (catch 'system-error (lambda () -- cgit v1.2.3 From e5e5119855b0269e8e6507b90c7f4d7df5118fc8 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Tue, 3 Jul 2018 11:02:22 +0200 Subject: database: 'reset-timestamps' now correctly handles symlinks. * guix/store/database.scm (reset-timestamps): Use 'utime' with AT_SYMLINK_NOFOLLOW for symlinks. --- guix/store/database.scm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'guix') diff --git a/guix/store/database.scm b/guix/store/database.scm index 05b2ba6c3f..8f35b63e37 100644 --- a/guix/store/database.scm +++ b/guix/store/database.scm @@ -209,9 +209,7 @@ it's a directory. While at it, canonicalize file permissions." (type type)))))) (scandir* parent)))) ((symlink) - ;; FIXME: Implement bindings for 'futime' to reset the timestamps on - ;; symlinks. - #f) + (utime file 0 0 0 0 AT_SYMLINK_NOFOLLOW)) (else (chmod file (if (executable-file? file) #o555 #o444)) (utime file 0 0 0 0))))) -- cgit v1.2.3 From 90b144d22d001a832a8fb345a7d71e9c657c0c86 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Tue, 3 Jul 2018 11:02:54 +0200 Subject: ui: Report file names in 'system-error' exceptions from 'delete-file'. * guix/ui.scm (delete-file): New error-reporting wrapper. --- guix/ui.scm | 3 +++ 1 file changed, 3 insertions(+) (limited to 'guix') diff --git a/guix/ui.scm b/guix/ui.scm index c1101eb4bb..66c9233b44 100644 --- a/guix/ui.scm +++ b/guix/ui.scm @@ -520,6 +520,9 @@ FILE." (set! canonicalize-path (error-reporting-wrapper canonicalize-path (file) file)) +(set! delete-file + (error-reporting-wrapper delete-file (file) file)) + (define (make-regexp* regexp . flags) "Like 'make-regexp' but error out if REGEXP is invalid, reporting the error -- cgit v1.2.3 From f3f1d0a5578b4ad6d85494283eedfaa62b28fe2c Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Tue, 3 Jul 2018 11:24:32 +0200 Subject: guix system: Make 'init' idempotent again. This fixes a regression introduced in df2f6400b1fbc282ef4d6dd7124ea1c17adc23c2: since the new 'register-path' (actually 'reset-timestamps') would make files read-only, 'delete-file-recursively' would fail to delete them. Thus, re-running 'guix system init' on an already-populated store would fail with a 'delete-file' EPERM. * guix/scripts/system.scm (copy-item): Use 'lstat' instead of 'file-exists?'. Call 'make-file-writable' on each directory below DEST. --- guix/scripts/system.scm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm index 92e92237b6..69bd05b516 100644 --- a/guix/scripts/system.scm +++ b/guix/scripts/system.scm @@ -126,7 +126,11 @@ REFERENCES as its set of references." ;; Remove DEST if it exists to make sure that (1) we do not fail badly ;; while trying to overwrite it (see ), and ;; (2) we end up with the right contents. - (when (file-exists? dest) + (when (false-if-exception (lstat dest)) + (for-each make-file-writable + (find-files dest (lambda (file stat) + (eq? 'directory (stat:type stat))) + #:directories? #t)) (delete-file-recursively dest)) (copy-recursively item dest -- cgit v1.2.3 From 86eee976f5ef21fa132de9827ad09a026bfdfd63 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Tue, 3 Jul 2018 13:49:28 +0200 Subject: Revert "packages: Optimize 'package-transitive-supported-systems'." This reverts commit 24420f5ffabfbdbe913a5765e5c00e17de18fb4c. This broke 'package-transitive-supported-systems', which would return the union of supported systems instead of the intersection. --- guix/packages.scm | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'guix') diff --git a/guix/packages.scm b/guix/packages.scm index cd7d3b895c..c762fa7c39 100644 --- a/guix/packages.scm +++ b/guix/packages.scm @@ -766,16 +766,15 @@ in INPUTS and their transitive propagated inputs." (mlambdaq (package) "Return the intersection of the systems supported by PACKAGE and those supported by its dependencies." - (set->list - (fold (lambda (input systems) - (match input - ((label (? package? p) . _) - (fold set-insert systems - (package-transitive-supported-systems p))) - (_ - systems))) - (list->set (package-supported-systems package)) - (bag-direct-inputs (package->bag package)))))) + (fold (lambda (input systems) + (match input + ((label (? package? p) . _) + (lset-intersection + string=? systems (package-transitive-supported-systems p))) + (_ + systems))) + (package-supported-systems package) + (bag-direct-inputs (package->bag package))))) (define* (supported-package? package #:optional (system (%current-system))) "Return true if PACKAGE is supported on SYSTEM--i.e., if PACKAGE and all its -- cgit v1.2.3 From 5b0c648a7c5ac3d827bb6fc61b3b2037a2d4b62c Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Wed, 4 Jul 2018 10:52:59 +0200 Subject: profiles: 'info-dir-file' hook now produces 'dir.LANG' files. Previously, entries for 'guix.fr.info' would end up in 'dir', above the 'guix.info' entries; consequently, running 'info guix' would actually open 'guix.fr.info', which was confusing for non-French readers. * guix/profiles.scm (info-dir-file)[glibc-utf8-locales]: New variable. [build](info-file-language): New procedure. (install-info): Use it, to create 'dir.LANG' files. Set GUIX_LOCPATH. --- guix/profiles.scm | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'guix') diff --git a/guix/profiles.scm b/guix/profiles.scm index ebd7da2a24..e6b77e8d38 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -703,6 +703,8 @@ MANIFEST." (module-ref (resolve-interface '(gnu packages texinfo)) 'texinfo)) (define gzip ;lazy reference (module-ref (resolve-interface '(gnu packages compression)) 'gzip)) + (define glibc-utf8-locales ;lazy reference + (module-ref (resolve-interface '(gnu packages base)) 'glibc-utf8-locales)) (define build (with-imported-modules '((guix build utils)) @@ -720,11 +722,31 @@ MANIFEST." (map (cut string-append infodir "/" <>) (or (scandir infodir info-file?) '())))) + (define (info-file-language file) + (let* ((base (if (string-suffix? ".gz" file) + (basename file ".info.gz") + (basename file ".info"))) + (dot (string-rindex base #\.))) + (if dot + (string-drop base (+ 1 dot)) + "en"))) + (define (install-info info) - (setenv "PATH" (string-append #+gzip "/bin")) ;for info.gz files - (zero? - (system* (string-append #+texinfo "/bin/install-info") "--silent" - info (string-append #$output "/share/info/dir")))) + (let ((language (info-file-language info))) + ;; We need to choose a valid locale for $LANGUAGE to be honored. + (setenv "LC_ALL" "en_US.utf8") + (setenv "LANGUAGE" language) + (zero? + (system* #+(file-append texinfo "/bin/install-info") + "--silent" info + (apply string-append #$output "/share/info/dir" + (if (string=? "en" language) + '("") + `("." ,language))))))) + + (setenv "PATH" (string-append #+gzip "/bin")) ;for info.gz files + (setenv "GUIX_LOCPATH" + #+(file-append glibc-utf8-locales "/lib/locale")) (mkdir-p (string-append #$output "/share/info")) (exit (every install-info -- cgit v1.2.3 From 5adb2df0a2584d49f1fde7671c81ba54f7e43d51 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Thu, 5 Jul 2018 13:35:21 +0200 Subject: pack: Use guile-for-build for the target system. Until now, running "guix pack -s i686-linux" on an x86_64-linux machine, for instance, would use an x86_64 guile for module derivations. This was OK until now, but would break when passing "--localstatedir" due to the introduction of guile-sqlite3: we'd be using the i686 guile-sqlite3 along with the x86_64 guile. * guix/scripts/pack.scm (guix-pack): Pass the 'system option from OPTS to 'package-derivation'. --- guix/scripts/pack.scm | 1 + 1 file changed, 1 insertion(+) (limited to 'guix') diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm index 7f087a3a3c..6d5d745bc8 100644 --- a/guix/scripts/pack.scm +++ b/guix/scripts/pack.scm @@ -722,6 +722,7 @@ Create a bundle of PACKAGE.\n")) (if (assoc-ref opts 'bootstrap?) %bootstrap-guile (canonical-package guile-2.2)) + (assoc-ref opts 'system) #:graft? (assoc-ref opts 'graft?)))) (let* ((dry-run? (assoc-ref opts 'dry-run?)) (relocatable? (assoc-ref opts 'relocatable?)) -- cgit v1.2.3 From 7a369f6d2f3509d39f5f702aa2ced44d8d3636af Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Sat, 7 Jul 2018 01:18:21 -0400 Subject: weather: Fix pasto in --version output. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/scripts/weather.scm (%options): Correct the command name passed to show-version-and-exit. Signed-off-by: Ludovic Courtès --- guix/scripts/weather.scm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/scripts/weather.scm b/guix/scripts/weather.scm index d7c2fbea10..98b7338fb9 100644 --- a/guix/scripts/weather.scm +++ b/guix/scripts/weather.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2017, 2018 Ludovic Courtès ;;; Copyright © 2017 Ricardo Wurmus +;;; Copyright © 2018 Kyle Meyer ;;; ;;; This file is part of GNU Guix. ;;; @@ -269,7 +270,7 @@ Report the availability of substitutes.\n")) (exit 0))) (option '(#\V "version") #f #f (lambda args - (show-version-and-exit "guix challenge"))) + (show-version-and-exit "guix weather"))) (option '("substitute-urls") #t #f (lambda (opt name arg result . rest) -- cgit v1.2.3 From 7ede577a5f90a459b731eeb025af450ff891603c Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Sat, 7 Jul 2018 00:41:34 -0400 Subject: scripts: Add missing -V option to commands that document it. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/scripts/container.scm (guix-container): * guix/scripts/import.scm (guix-import): * guix/scripts/substitute.scm (guix-substitute): Add -V as the short option for --version to match show-help's description. Signed-off-by: Ludovic Courtès --- guix/scripts/container.scm | 3 ++- guix/scripts/import.scm | 3 ++- guix/scripts/substitute.scm | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'guix') diff --git a/guix/scripts/container.scm b/guix/scripts/container.scm index 10aed2be75..8041d64b6b 100644 --- a/guix/scripts/container.scm +++ b/guix/scripts/container.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2015 David Thompson +;;; Copyright © 2018 Kyle Meyer ;;; ;;; This file is part of GNU Guix. ;;; @@ -54,7 +55,7 @@ Build and manipulate Linux containers.\n")) ((or ("-h") ("--help")) (show-help) (exit 0)) - (("--version") + ((or ("-V") ("--version")) (show-version-and-exit "guix container")) ((action args ...) (if (member action %actions) diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm index 67bc7a7553..f8cb85700d 100644 --- a/guix/scripts/import.scm +++ b/guix/scripts/import.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2012, 2013, 2014 Ludovic Courtès ;;; Copyright © 2014 David Thompson +;;; Copyright © 2018 Kyle Meyer ;;; ;;; This file is part of GNU Guix. ;;; @@ -104,7 +105,7 @@ Run IMPORTER with ARGS.\n")) ((or ("-h") ("--help")) (show-help) (exit 0)) - (("--version") + ((or ("-V") ("--version")) (show-version-and-exit "guix import")) ((importer args ...) (if (member importer importers) diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm index d0beacc8ea..7634bb37f6 100755 --- a/guix/scripts/substitute.scm +++ b/guix/scripts/substitute.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès ;;; Copyright © 2014 Nikita Karetnikov +;;; Copyright © 2018 Kyle Meyer ;;; ;;; This file is part of GNU Guix. ;;; @@ -1108,7 +1109,7 @@ default value." (process-substitution store-path destination #:cache-urls (substitute-urls) #:acl (current-acl)))) - (("--version") + ((or ("-V") ("--version")) (show-version-and-exit "guix substitute")) (("--help") (show-help)) -- cgit v1.2.3 From 85c3fbf5de29bf7c08e445bab9b985a7b84b6406 Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Sat, 7 Jul 2018 00:41:35 -0400 Subject: ui: Add -V as short option for --version. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/ui.scm (run-guix): Add -V as the short option for --version for consistency with most commands. Signed-off-by: Ludovic Courtès --- guix/ui.scm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/ui.scm b/guix/ui.scm index 66c9233b44..6a5feaa953 100644 --- a/guix/ui.scm +++ b/guix/ui.scm @@ -9,6 +9,7 @@ ;;; Copyright © 2015, 2016 Mathieu Lirzin ;;; Copyright © 2016 Roel Janssen ;;; Copyright © 2016 Benz Schenk +;;; Copyright © 2018 Kyle Meyer ;;; ;;; This file is part of GNU Guix. ;;; @@ -1598,7 +1599,7 @@ and signal handling has already been set up." (show-guix-usage)) ((or ("-h") ("--help")) (show-guix-help)) - (("--version") + ((or ("-V") ("--version")) (show-version-and-exit "guix")) (((? option? o) args ...) (format (current-error-port) -- cgit v1.2.3 From b24443bff9f9f3f36353eea2ef35e6dc3745a417 Mon Sep 17 00:00:00 2001 From: Julien Lepiller Date: Wed, 6 Jun 2018 19:14:39 +0200 Subject: guix: Add opam importer. * guix/scripts/import.scm (importers): Add opam. * guix/scripts/import/opam.scm: New file. * guix/import/opam.scm: New file. * tests/opam.scm: New file. * Makefile.am: Add them. * doc/guix.texi (Invoking guix import): Document it. --- Makefile.am | 3 + doc/guix.texi | 6 ++ guix/import/opam.scm | 193 +++++++++++++++++++++++++++++++++++++++++++ guix/scripts/import.scm | 2 +- guix/scripts/import/opam.scm | 92 +++++++++++++++++++++ tests/opam.scm | 118 ++++++++++++++++++++++++++ 6 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 guix/import/opam.scm create mode 100644 guix/scripts/import/opam.scm create mode 100644 tests/opam.scm (limited to 'guix') diff --git a/Makefile.am b/Makefile.am index 5dc04de35c..618d1653e4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -231,11 +231,13 @@ MODULES += \ guix/import/github.scm \ guix/import/gnome.scm \ guix/import/json.scm \ + guix/import/opam.scm \ guix/import/pypi.scm \ guix/import/stackage.scm \ guix/scripts/import/crate.scm \ guix/scripts/import/gem.scm \ guix/scripts/import/json.scm \ + guix/scripts/import/opam.scm \ guix/scripts/import/pypi.scm \ guix/scripts/import/stackage.scm \ guix/scripts/weather.scm @@ -382,6 +384,7 @@ if HAVE_GUILE_JSON SCM_TESTS += \ tests/pypi.scm \ + tests/opam.scm \ tests/cpan.scm \ tests/gem.scm \ tests/crate.scm diff --git a/doc/guix.texi b/doc/guix.texi index 7ce364b0af..a8e53a5308 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -6661,6 +6661,12 @@ in Guix. @cindex crate Import metadata from the crates.io Rust package repository @uref{https://crates.io, crates.io}. + +@item opam +@cindex OPAM +@cindex OCaml +Import metadata from the @uref{https://opam.ocaml.org/, OPAM} package +repository used by the OCaml community. @end table The structure of the @command{guix import} code is modular. It would be 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 +;;; +;;; 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 . + +(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/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/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 +;;; +;;; 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 . + +(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/tests/opam.scm b/tests/opam.scm new file mode 100644 index 0000000000..26832174a8 --- /dev/null +++ b/tests/opam.scm @@ -0,0 +1,118 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2018 Julien Lepiller +;;; +;;; 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 . + +(define-module (test-opam) + #:use-module (guix import opam) + #:use-module (guix base32) + #:use-module (guix hash) + #:use-module (guix tests) + #:use-module ((guix build utils) #:select (delete-file-recursively mkdir-p which)) + #:use-module (srfi srfi-64) + #:use-module (web uri) + #:use-module (ice-9 match)) + +(define test-url-file + "http: \"https://example.org/foo-1.0.0.tar.gz\" +checksum: \"ac8920f39a8100b94820659bc2c20817\"") + +(define test-source-hash + "") + +(define test-urls + "repo ac8920f39a8100b94820659bc2c20817 0o644 +packages/foo/foo.1.0.0/url ac8920f39a8100b94820659bc2c20817 0o644 +packages/foo/foo.1.0.0/opam ac8920f39a8100b94820659bc2c20817 0o644 +packages/foo/foo.1.0.0/descr ac8920f39a8100b94820659bc2c20817 0o644") + +(define test-opam-file +"opam-version: 1.2 +maintainer: \"Alice Doe\" +authors: \"Alice Doe, John Doe\" +homepage: \"https://example.org/\" +bug-reports: \"https://example.org/bugs\" +license: \"MIT\" +dev-repo: \"https://example.org/git\" +build: [ + \"ocaml\" \"pkg/pkg.ml\" \"build\" \"--pinned\" \"%{pinned}%\" +] +build-test: [ + \"ocaml\" \"pkg/pkg.ml\" \"build\" \"--pinned\" \"%{pinned}%\" \"--tests\" \"true\" +] +depends: [ + \"alcotest\" {test & >= \"0.7.2\"} + \"ocamlbuild\" {build & >= \"0.9.2\"} +]") + +(test-begin "opam") + +(test-assert "opam->guix-package" + ;; Replace network resources with sample data. + (mock ((guix import utils) url-fetch + (lambda (url file-name) + (match url + ("https://example.org/foo-1.0.0.tar.gz" + (begin + (mkdir-p "foo-1.0.0") + (system* "tar" "czvf" file-name "foo-1.0.0/") + (delete-file-recursively "foo-1.0.0") + (set! test-source-hash + (call-with-input-file file-name port-sha256)))) + (_ (error "Unexpected URL: " url))))) + (mock ((guix http-client) http-fetch/cached + (lambda (url . rest) + (match (uri->string url) + ("https://opam.ocaml.org/urls.txt" + (values (open-input-string test-urls) + (string-length test-urls))) + (_ (error "Unexpected URL: " url))))) + (mock ((guix http-client) http-fetch + (lambda (url . rest) + (match url + ("https://opam.ocaml.org/packages/foo/foo.1.0.0/url" + (values (open-input-string test-url-file) + (string-length test-url-file))) + ("https://opam.ocaml.org/packages/foo/foo.1.0.0/opam" + (values (open-input-string test-opam-file) + (string-length test-opam-file))) + (_ (error "Unexpected URL: " url))))) + (match (opam->guix-package "foo") + (('package + ('name "ocaml-foo") + ('version "1.0.0") + ('source ('origin + ('method 'url-fetch) + ('uri "https://example.org/foo-1.0.0.tar.gz") + ('sha256 + ('base32 + (? string? hash))))) + ('build-system 'ocaml-build-system) + ('inputs + ('quasiquote + (("ocamlbuild" ('unquote 'ocamlbuild)) + ("ocaml-alcotest" ('unquote 'ocaml-alcotest))))) + ('home-page "https://example.org/") + ('synopsis "") + ('description "") + ('license 'license:expat)) + (string=? (bytevector->nix-base32-string + test-source-hash) + hash)) + (x + (pk 'fail x #f))))))) + +(test-end "opam") -- cgit v1.2.3 From f03df3ee75d1209fb9782999bd04378c58e9f0f1 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 9 Jul 2018 10:44:36 +0200 Subject: profiles: Factorize 'manifest-search-paths'. * guix/profiles.scm (manifest-search-paths): New procedure. (profile-derivation)[builder]: Use it. * guix/build/profiles.scm (build-etc/profile): Remove $PATH. --- guix/build/profiles.scm | 2 +- guix/profiles.scm | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'guix') 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/profiles.scm b/guix/profiles.scm index e6b77e8d38..88228f1558 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? @@ -545,6 +546,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 +1376,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? -- cgit v1.2.3 From 10f0a40c16bb572ab7b45f32e39b7761e519ba32 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 9 Jul 2018 13:00:46 +0200 Subject: environment: Simplify code by using manifests internally. * guix/scripts/environment.scm (strip-input-name) (package+propagated-inputs, package-or-package+output?) (compact): Remove. (inputs->profile-derivation): Rename to... (manifest->derivation): ... this. Replace 'inputs' parameter with 'manifest'. (input->manifest-entry): New procedure. (package-environment-inputs): Rewrite to return a list of manifest entries. (options/resolve-packages): Rewrite to return a manifest. (guix-environment): Remove 'inputs'. Define 'paths' in terms of 'manifest-search-paths'. --- guix/scripts/environment.scm | 158 +++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 96 deletions(-) (limited to 'guix') diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index f8a9702b30..9a69e3b269 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 -;;; Copyright © 2015, 2016, 2017 Ludovic Courtès +;;; Copyright © 2015, 2016, 2017, 2018 Ludovic Courtès ;;; Copyright © 2018 Mike Gerwitz ;;; ;;; This file is part of GNU Guix. @@ -102,35 +102,23 @@ existing environment variables with additional search paths." (newline))) (evaluate-profile-search-paths profile search-paths))) -(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 +275,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 +333,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 @@ -671,25 +653,9 @@ message if any test fails." ;; within the container. '("/bin/sh") (list %default-shell)))) - (packages (options/resolve-packages opts)) + (manifest (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?))) + (paths (manifest-search-paths manifest))) (when container? (assert-container-features)) @@ -714,8 +680,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))) -- cgit v1.2.3 From 78d55b703d155d36520e1c93dc08a6502c56bd55 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 9 Jul 2018 13:22:29 +0200 Subject: profiles: Introduce 'profile-search-paths' and use it. * guix/profiles.scm (profile-search-paths): New procedure. * guix/scripts/environment.scm (evaluate-search-paths): Remove. (create-environment): Replace 'paths' with 'manifest'. Use 'profile-search-paths' instead of 'evaluate-search-paths'. (show-search-paths): Likewise. (launch-environment): Replace 'paths' with 'manifest'. Make 'pure?' a keyword parameter. (launch-environment/fork, launch-environment/container): Likewise. (guix-environment): Remove 'paths' variable. Adjust callers of the above procedures accordingly. --- guix/profiles.scm | 14 ++++++++++++ guix/scripts/environment.scm | 54 ++++++++++++++++++++------------------------ 2 files changed, 39 insertions(+), 29 deletions(-) (limited to 'guix') diff --git a/guix/profiles.scm b/guix/profiles.scm index 88228f1558..d2a794b187 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -110,6 +110,7 @@ ca-certificate-bundle %default-profile-hooks profile-derivation + profile-search-paths generation-number generation-numbers @@ -1400,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 9a69e3b269..1c04800e42 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -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,23 +79,23 @@ 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 (input->manifest-entry input) "Return a manifest entry for INPUT, or #f if INPUT does not correspond to a @@ -379,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 @@ -496,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))))))) @@ -654,8 +651,7 @@ message if any test fails." '("/bin/sh") (list %default-shell)))) (manifest (options/resolve-packages opts)) - (mappings (pick-all opts 'file-system-mapping)) - (paths (manifest-search-paths manifest))) + (mappings (pick-all opts 'file-system-mapping))) (when container? (assert-container-features)) @@ -700,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 @@ -713,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?))))))))))))) -- cgit v1.2.3 From dc013aff819ad2a95c50f3ba7d66c1297a7b1585 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Wed, 11 Jul 2018 00:53:04 +0200 Subject: ui: Fix typo. * guix/ui.scm (display-profile-content-diff): Fix typo in docstring. --- guix/ui.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'guix') 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))) -- cgit v1.2.3 From a59b0fa2d7af644482a015cebfe1487e3736c223 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 11 Jul 2018 02:32:58 +0200 Subject: build-system/haskell: Make phases fail on error. * guix/build/haskell-build-system.scm (configure): Make it fail on error. (run-setuphs): Make it fail on error. --- guix/build/haskell-build-system.scm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'guix') 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." -- cgit v1.2.3 From 88388766f778d344699e7a8a0a4d970c403007e3 Mon Sep 17 00:00:00 2001 From: Oleg Pykhalov Date: Tue, 3 Jul 2018 23:28:42 +0300 Subject: import: gem: Add recursive import. * doc/guix.texi (Invoking guix import): Document gem recursive import. * guix/import/gem.scm (gem->guix-package): Return package and dependencies values. (gem-recursive-import): New procedure. * guix/scripts/import/gem.scm (show-help, %options): Add recursive option. (guix-import-gem): Use 'gem-recursive-import'. * tests/gem.scm (test-json): Rename to 'test-foo-json'. ("gem->guix-package"): Use 'test-foo-json'. (test-bar-json, test-bundler-json): New variables. ("gem-recursive-import"): New test. --- doc/guix.texi | 8 ++++ guix/import/gem.scm | 48 ++++++++++++-------- guix/scripts/import/gem.scm | 27 +++++++++-- tests/gem.scm | 108 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 163 insertions(+), 28 deletions(-) (limited to 'guix') diff --git a/doc/guix.texi b/doc/guix.texi index a8e53a5308..8026bea356 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -6380,6 +6380,14 @@ The command below imports metadata for the @code{rails} Ruby package: guix import gem rails @end example +@table @code +@item --recursive +@itemx -r +Traverse the dependency graph of the given upstream package recursively +and generate package expressions for all those packages that are not yet +in Guix. +@end table + @item cpan @cindex CPAN Import metadata from @uref{https://www.metacpan.org/, MetaCPAN}@footnote{This 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 ;;; Copyright © 2016 Ben Woodcroft +;;; Copyright © 2018 Oleg Pykhalov ;;; ;;; 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/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 +;;; Copyright © 2018 Oleg Pykhalov ;;; ;;; 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/tests/gem.scm b/tests/gem.scm index a39e8ba514..4220170ff0 100644 --- a/tests/gem.scm +++ b/tests/gem.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2015 David Thompson ;;; Copyright © 2016 Ricardo Wurmus +;;; Copyright © 2018 Oleg Pykhalov ;;; ;;; This file is part of GNU Guix. ;;; @@ -23,10 +24,11 @@ #:use-module (guix hash) #:use-module (guix tests) #:use-module ((guix build utils) #:select (delete-file-recursively)) + #:use-module (srfi srfi-41) #:use-module (srfi srfi-64) #:use-module (ice-9 match)) -(define test-json +(define test-foo-json "{ \"name\": \"foo\", \"version\": \"1.0.0\", @@ -42,6 +44,34 @@ \"licenses\": [\"MIT\", \"Apache 2.0\"] }") +(define test-bar-json + "{ + \"name\": \"bar\", + \"version\": \"1.0.0\", + \"sha\": \"f3676eafca9987cb5fe263df1edf2538bf6dafc712b30e17be3543a9680547a8\", + \"info\": \"Another cool gem\", + \"homepage_uri\": \"https://example.com\", + \"dependencies\": { + \"runtime\": [ + { \"name\": \"bundler\" }, + ] + }, + \"licenses\": [\"MIT\", \"Apache 2.0\"] +}") + +(define test-bundler-json + "{ + \"name\": \"bundler\", + \"version\": \"1.14.2\", + \"sha\": \"3bb53e03db0a8008161eb4c816ccd317120d3c415ba6fee6f90bbc7f7eec8690\", + \"info\": \"Ruby gem bundler\", + \"homepage_uri\": \"https://bundler.io/\", + \"dependencies\": { + \"runtime\": [] + }, + \"licenses\": [\"MIT\"] +}") + (test-begin "gem") (test-assert "gem->guix-package" @@ -50,8 +80,8 @@ (lambda (url . rest) (match url ("https://rubygems.org/api/v1/gems/foo.json" - (values (open-input-string test-json) - (string-length test-json))) + (values (open-input-string test-foo-json) + (string-length test-foo-json))) (_ (error "Unexpected URL: " url))))) (match (gem->guix-package "foo") (('package @@ -76,4 +106,76 @@ (x (pk 'fail x #f))))) +(test-assert "gem-recursive-import" + ;; Replace network resources with sample data. + (mock ((guix http-client) http-fetch + (lambda (url . rest) + (match url + ("https://rubygems.org/api/v1/gems/foo.json" + (values (open-input-string test-foo-json) + (string-length test-foo-json))) + ("https://rubygems.org/api/v1/gems/bar.json" + (values (open-input-string test-bar-json) + (string-length test-bar-json))) + ("https://rubygems.org/api/v1/gems/bundler.json" + (values (open-input-string test-bundler-json) + (string-length test-bundler-json))) + (_ (error "Unexpected URL: " url))))) + (match (stream->list (gem-recursive-import "foo")) + ((('package + ('name "ruby-foo") + ('version "1.0.0") + ('source + ('origin + ('method 'url-fetch) + ('uri ('rubygems-uri "foo" 'version)) + ('sha256 + ('base32 + "1a270mlajhrmpqbhxcqjqypnvgrq4pgixpv3w9gwp1wrrapnwrzk")))) + ('build-system 'ruby-build-system) + ('propagated-inputs + ('quasiquote + (("bundler" ('unquote 'bundler)) + ("ruby-bar" ('unquote 'ruby-bar))))) + ('synopsis "A cool gem") + ('description "This package provides a cool gem") + ('home-page "https://example.com") + ('license ('list 'license:expat 'license:asl2.0))) + ('package + ('name "ruby-bundler") + ('version "1.14.2") + ('source + ('origin + ('method 'url-fetch) + ('uri ('rubygems-uri "bundler" 'version)) + ('sha256 + ('base32 + "1446xiz7zg0bz7kgx9jv84y0s4hpsg61dj5l3qb0i00avc1kxd9v")))) + ('build-system 'ruby-build-system) + ('synopsis "Ruby gem bundler") + ('description "Ruby gem bundler") + ('home-page "https://bundler.io/") + ('license 'license:expat)) + ('package + ('name "ruby-bar") + ('version "1.0.0") + ('source + ('origin + ('method 'url-fetch) + ('uri ('rubygems-uri "bar" 'version)) + ('sha256 + ('base32 + "1a270mlajhrmpqbhxcqjqypnvgrq4pgixpv3w9gwp1wrrapnwrzk")))) + ('build-system 'ruby-build-system) + ('propagated-inputs + ('quasiquote + (('"bundler" ('unquote 'bundler))))) + ('synopsis "Another cool gem") + ('description "Another cool gem") + ('home-page "https://example.com") + ('license ('list 'license:expat 'license:asl2.0)))) + #t) + (x + (pk 'fail x #f))))) + (test-end "gem") -- cgit v1.2.3 From daf76c7cd54df428abc28d490747c7f83a844df0 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Wed, 11 Jul 2018 14:28:23 +0200 Subject: gnu-maintenance: Get GNU metadata from rec files. Suggested by Mike Gerwitz . * guix/gnu-maintenance.scm (%package-list-url): Use the .rec file. (%package-description-url): Likewise. (official-gnu-packages)[read-records]: Skip record descriptors. Rename fields to use underscores instead of hyphens. --- guix/gnu-maintenance.scm | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'guix') 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 +;;; Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès ;;; Copyright © 2012, 2013 Nikita Karetnikov ;;; ;;; 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 . + ;; See + ;; and . (string->uri - (string-append %gnumaint-base-url "pkgblurbs.txt"))) + (string-append %gnumaint-base-url "rec/pkgblurbs.rec"))) (define-record-type* 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) -- cgit v1.2.3 From f3a422511f793fb6c6cfeec2bb8735965a03294a Mon Sep 17 00:00:00 2001 From: Jan Nieuwenhuizen Date: Tue, 10 Jul 2018 19:00:48 +0200 Subject: store: Add `binary-file'. * guix/store.scm (binary-file): New function. * doc/guix.texi (The Store Monad): Describe binary-file. --- doc/guix.texi | 8 +++++++- guix/store.scm | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'guix') diff --git a/doc/guix.texi b/doc/guix.texi index 8026bea356..6900717059 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -27,7 +27,7 @@ Copyright @copyright{} 2016, 2017, 2018 Chris Marusich@* Copyright @copyright{} 2016, 2017, 2018 Efraim Flashner@* Copyright @copyright{} 2016 John Darrington@* Copyright @copyright{} 2016, 2017 Nils Gillmann@* -Copyright @copyright{} 2016, 2017 Jan Nieuwenhuizen@* +Copyright @copyright{} 2016, 2017, 2018 Jan Nieuwenhuizen@* Copyright @copyright{} 2016 Julien Lepiller@* Copyright @copyright{} 2016 Alex ter Weele@* Copyright @copyright{} 2017, 2018 Clément Lassieur@* @@ -4916,6 +4916,12 @@ containing @var{text}, a string. @var{references} is a list of store items that resulting text file refers to; it defaults to the empty list. @end deffn +@deffn {Monadic Procedure} binary-file @var{name} @var{data} [@var{references}] +Return as a monadic value the absolute file name in the store of the file +containing @var{data}, a bytevector. @var{references} is a list of store +items that the resulting binary file refers to; it defaults to the empty list. +@end deffn + @deffn {Monadic Procedure} interned-file @var{file} [@var{name}] @ [#:recursive? #t] [#:select? (const #t)] Return the name of @var{file} once interned in the store. Use 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 +;;; Copyright © 2018 Jan Nieuwenhuizen ;;; ;;; 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 -- cgit v1.2.3 From e8e1f295f15fa56660a2c460d422795b1a31bed8 Mon Sep 17 00:00:00 2001 From: Jan Nieuwenhuizen Date: Tue, 10 Jul 2018 19:06:32 +0200 Subject: gexp: Allow bytevector as content of `plain-file'. This allows for using a package source directly from git, doing something like (define (command->bytevector command) (let ((port (apply open-pipe* OPEN_READ command))) (let ((output (get-bytevector-all port))) (close-port port) output))) (define-public hello-git (package (name "hello") (version "git") (source (let* ((commit "stable-2.0") (content (command->bytevector `("git" "archive" "--format" "tar" "--prefix" ,(string-append commit "/") ,commit))) (file-name (string-append "hello-" commit))) (plain-file file-name content))) ... )) * guix/gexp.scm (): Also allow bytevector content. (plain-file-compiler): Handle bytevector content. * doc/guix.texi (G-Expressions): Describe plain-file now also taking bytevectors. --- doc/guix.texi | 2 +- guix/gexp.scm | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'guix') diff --git a/doc/guix.texi b/doc/guix.texi index 6900717059..8b286e9d8e 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -5355,7 +5355,7 @@ procedure (@pxref{The Store Monad, @code{interned-file}}). @deffn {Scheme Procedure} plain-file @var{name} @var{content} Return an object representing a text file called @var{name} with the given -@var{content} (a string) to be added to the store. +@var{content} (a string or a bytevector) to be added to the store. This is the declarative counterpart of @code{text-file}. @end deffn 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 ;;; Copyright © 2018 Clément Lassieur +;;; Copyright © 2018 Jan Nieuwenhuizen ;;; ;;; 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 ) system target) ;; "Compile" FILE by adding it to the store. (match file - (($ name content references) - (text-file name content references)))) + (($ name (and (? string?) content) references) + (text-file name content references)) + (($ name (and (? bytevector?) content) references) + (binary-file name content references)))) (define-record-type (%computed-file name gexp guile options) -- cgit v1.2.3 From 314b63e0b4372681aec165113ae2a0349eaaa357 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 11 Jul 2018 11:02:51 +0200 Subject: import: hackage: Support "custom-setup" field. Fixes . * guix/import/cabal.scm (make-cabal-parser): Modify. (is-custom-setup): New variable. (lex-custom-setup): New procedure. (is-id): Modify. (lex-version): Modify. (): New record type. (eval-cabal): Modify. (dependencies): Add parameter. --- guix/import/cabal.scm | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'guix') diff --git a/guix/import/cabal.scm b/guix/import/cabal.scm index 09130e4498..1775c38791 100644 --- a/guix/import/cabal.scm +++ b/guix/import/cabal.scm @@ -140,7 +140,7 @@ to the stack." (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) + (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) @@ -349,6 +351,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)) @@ -368,7 +373,7 @@ matching a string against the created regexp." (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 +397,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 +443,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)) @@ -529,6 +539,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 +669,12 @@ If #f use the function 'port-filename' to obtain it." (name cabal-test-suite-name) (dependencies cabal-test-suite-dependencies)) ; list of +(define-record-type + (make-cabal-custom-setup name dependencies) + cabal-custom-setup? + (name cabal-custom-setuo-name) + (dependencies cabal-custom-setup-dependencies)) ; list of + (define (cabal-flags->alist flag-list) "Retrun an alist associating the flag name to its default value from a list of objects." @@ -728,7 +745,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 +771,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 +813,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 +864,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))) -- cgit v1.2.3 From ecba50bb79a49b317c4b1e718f4732b36438227f Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 11 Jul 2018 17:07:01 +0200 Subject: import: hackage: Support "-any" and "-none" version comparison operators. * guix/import/cabal.scm (make-cabal-parser): Modify. (is-any): New variable. (is-none): New variable. (lex-any): New procedure. (lex-none): New procedure. (lex-word): Modify. (eval-cabal): Modify. --- guix/import/cabal.scm | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'guix') diff --git a/guix/import/cabal.scm b/guix/import/cabal.scm index 1775c38791..cd0a2953c6 100644 --- a/guix/import/cabal.scm +++ b/guix/import/cabal.scm @@ -139,7 +139,7 @@ to the stack." "Generate a parser for Cabal files." (lalr-parser ;; --- token definitions - (CCURLY VCCURLY OPAREN CPAREN TEST ID VERSION RELATION TRUE FALSE + (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) @@ -213,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))) @@ -367,6 +371,10 @@ 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 "||")) @@ -457,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)) @@ -524,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)) @@ -711,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) -- cgit v1.2.3 From e39a44f34010e4439fc3fc4925b3f26b7ca6d719 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Thu, 12 Jul 2018 14:17:08 +0200 Subject: import: hackage: Evaluate "-any" and "-none" version comparison operators. * guix/import/cabal.scm (eval-cabal): Modify. * tests/hackage.scm (test-cabal-4): New variable and test. (test-cabal-5): New variable and test. (test-cabal-6): New variable and test. --- guix/import/cabal.scm | 2 ++ tests/hackage.scm | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) (limited to 'guix') diff --git a/guix/import/cabal.scm b/guix/import/cabal.scm index cd0a2953c6..4cd09cac29 100644 --- a/guix/import/cabal.scm +++ b/guix/import/cabal.scm @@ -754,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.")))))) diff --git a/tests/hackage.scm b/tests/hackage.scm index a4de8be91e..e17851a213 100644 --- a/tests/hackage.scm +++ b/tests/hackage.scm @@ -69,6 +69,65 @@ library mtl >= 2.0 && < 3 ") +;; Check "-any", "-none" when name is different. +(define test-cabal-4 + "name: foo +version: 1.0.0 +homepage: http://test.org +synopsis: synopsis +description: description +license: BSD3 +library + if impl(ghcjs -any) + Build-depends: ghc-a + if impl(ghc>=7.2&&<7.6) + Build-depends: ghc-b + if impl(ghc == 7.8) + Build-depends: + HTTP >= 4000.2.5 && < 4000.3, + mtl >= 2.0 && < 3 +") + +;; Check "-any", "-none". +(define test-cabal-5 + "name: foo +version: 1.0.0 +homepage: http://test.org +synopsis: synopsis +description: description +license: BSD3 +library + if impl(ghc == 7.8) + Build-depends: + HTTP >= 4000.2.5 && < 4000.3, + if impl(ghc -any) + Build-depends: mtl >= 2.0 && < 3 + if impl(ghc>=7.2&&<7.6) + Build-depends: ghc-b +") + +;; Check "custom-setup". +(define test-cabal-6 + "name: foo +build-type: Custom +version: 1.0.0 +homepage: http://test.org +synopsis: synopsis +description: description +license: BSD3 +custom-setup + setup-depends: base >= 4.7 && < 5, + Cabal >= 1.24, + haskell-gi == 0.21.* +library + if impl(ghc>=7.2&&<7.6) + Build-depends: ghc-b + if impl(ghc == 7.8) + Build-depends: + HTTP >= 4000.2.5 && < 4000.3, + mtl >= 2.0 && < 3 +") + ;; A fragment of a real Cabal file with minor modification to check precedence ;; of 'and' over 'or', missing final newline, spaces between keywords and ;; parentheses and between key and column. @@ -139,6 +198,18 @@ library (eval-test-with-cabal test-cabal-3 #:cabal-environment '(("impl" . "ghc-7.8")))) +(test-assert "hackage->guix-package test 4" + (eval-test-with-cabal test-cabal-4 + #:cabal-environment '(("impl" . "ghc-7.8")))) + +(test-assert "hackage->guix-package test 5" + (eval-test-with-cabal test-cabal-5 + #:cabal-environment '(("impl" . "ghc-7.8")))) + +(test-assert "hackage->guix-package test 6" + (eval-test-with-cabal test-cabal-6 + #:cabal-environment '(("impl" . "ghc-7.8")))) + (test-assert "read-cabal test 1" (match (call-with-input-string test-read-cabal-1 read-cabal) ((("name" ("test-me")) -- cgit v1.2.3 From e29067d22e89743b9d2c7a68987d7b892a3d304a Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Fri, 13 Jul 2018 14:24:27 +0200 Subject: import: hackage: Fix typo. * guix/import/cabal.scm (cabal-custom-setuo-name): Rename to... (cabal-custom-setup-name): ...this. --- guix/import/cabal.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/import/cabal.scm b/guix/import/cabal.scm index 4cd09cac29..4b2bfd4a25 100644 --- a/guix/import/cabal.scm +++ b/guix/import/cabal.scm @@ -686,7 +686,7 @@ If #f use the function 'port-filename' to obtain it." (define-record-type (make-cabal-custom-setup name dependencies) cabal-custom-setup? - (name cabal-custom-setuo-name) + (name cabal-custom-setup-name) (dependencies cabal-custom-setup-dependencies)) ; list of (define (cabal-flags->alist flag-list) -- cgit v1.2.3 From ffc3fcade3f7d2c7d26b2fe5245902e6407f9c93 Mon Sep 17 00:00:00 2001 From: Oleg Pykhalov Date: Sun, 8 Jul 2018 13:15:41 +0300 Subject: git: Call 'url-cache-directory' outside 'update-cached-checkout'. * guix/git.scm (update-cached-checkout): Call 'url-cache-directory' in 'cache-directory' key argument. (latest-repository-commit): Call 'url-cache-directory'. --- guix/git.scm | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'guix') diff --git a/guix/git.scm b/guix/git.scm index 9e89cc0062..193e2df111 100644 --- a/guix/git.scm +++ b/guix/git.scm @@ -114,7 +114,8 @@ OID (roughly the commit hash) corresponding to REF." #:key (ref '(branch . "origin/master")) (cache-directory - (%repository-cache-directory))) + (url-cache-directory + url (%repository-cache-directory)))) "Update the cached checkout of URL to REF in CACHE-DIRECTORY. Return two values: the cache directory name, and the SHA1 commit (a string) corresponding to REF. @@ -122,11 +123,10 @@ to REF. REF is pair whose key is [branch | commit | tag] and value the associated data, respectively [ | | ]." (with-libgit2 - (let* ((cache-dir (url-cache-directory url cache-directory)) - (cache-exists? (openable-repository? cache-dir)) + (let* ((cache-exists? (openable-repository? cache-directory)) (repository (if cache-exists? - (repository-open cache-dir) - (clone* url cache-dir)))) + (repository-open cache-directory) + (clone* url cache-directory)))) ;; Only fetch remote if it has not been cloned just before. (when cache-exists? (remote-fetch (remote-lookup repository "origin"))) @@ -138,7 +138,7 @@ data, respectively [ | | ]." 'repository-close!) (repository-close! repository)) - (values cache-dir (oid->string oid)))))) + (values cache-directory (oid->string oid)))))) (define* (latest-repository-commit store url #:key @@ -157,12 +157,14 @@ Git repositories are kept in the cache directory specified by (and (string=? (basename file) ".git") (eq? 'directory (stat:type stat)))) - (let*-values (((checkout commit) - (update-cached-checkout url - #:ref ref - #:cache-directory cache-directory)) - ((name) - (url+commit->name url commit))) + (let*-values + (((checkout commit) + (update-cached-checkout url + #:ref ref + #:cache-directory + (url-cache-directory url cache-directory))) + ((name) + (url+commit->name url commit))) (values (add-to-store store name #t "sha256" checkout #:select? (negate dot-git?)) commit))) -- cgit v1.2.3 From bc6e291ef0b3c71c07e50d88d7764e5dd334e8b1 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 13 Jul 2018 14:33:11 +0200 Subject: guix package: Use relative symlinks to generations. Reported by Roel Janssen at . * guix/profiles.scm (switch-to-generation): Use (basename generation) as the symlink target. * guix/scripts/package.scm (build-and-use-profile): Likewise, use (basename name) as the symlink target. * tests/guix-package.sh: Adjust --roll-back test accordingly. Add explicitly test with '-p foo/prof'. --- guix/profiles.scm | 2 +- guix/scripts/package.scm | 2 +- tests/guix-package.sh | 12 +++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'guix') diff --git a/guix/profiles.scm b/guix/profiles.scm index d2a794b187..f34f4fcff6 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -1521,7 +1521,7 @@ the generation that was current before switching." (profile profile) (generation number))))) (else - (switch-symlinks profile generation) + (switch-symlinks profile (basename generation)) current)))) (define (switch-to-previous-generation profile) diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm index 29829f52c8..b38a55d01c 100644 --- a/guix/scripts/package.scm +++ b/guix/scripts/package.scm @@ -190,7 +190,7 @@ do not treat collisions in MANIFEST as an error." (let* ((entries (manifest-entries manifest)) (count (length entries))) (switch-symlinks name prof) - (switch-symlinks profile name) + (switch-symlinks profile (basename name)) (unless (string=? profile %current-profile) (register-gc-root store name)) (format #t (N_ "~a package in profile~%" diff --git a/tests/guix-package.sh b/tests/guix-package.sh index 3b3fa35cd8..cef3b3452e 100644 --- a/tests/guix-package.sh +++ b/tests/guix-package.sh @@ -185,6 +185,16 @@ grep -E 'emacs[[:blank:]]+42\.5\.9rc7[[:blank:]]+.*-emacs-42.5.9rc7' \ rm "$emacs_tarball" "$tmpfile" rmdir "$module_dir" +# Profiles with a relative file name. Make sure we don't create dangling +# symlinks--see bug report at +# . +mkdir -p "$module_dir/foo" +( cd "$module_dir" ; \ + guix package --bootstrap -i guile-bootstrap -p foo/prof ) +test -f "$module_dir/foo/prof/bin/guile" +rm "$module_dir/foo"/* +rmdir "$module_dir/foo" +rmdir "$module_dir" # # Try with the default profile. @@ -215,7 +225,7 @@ do guix package --bootstrap --roll-back ! test -f "$HOME/.guix-profile/bin" ! test -f "$HOME/.guix-profile/lib" - test "`readlink "$default_profile"`" = "$default_profile-0-link" + test "`readlink "$default_profile"`" = "`basename $default_profile-0-link`" done # Check whether '-p ~/.guix-profile' makes any difference. -- cgit v1.2.3 From 2ca299caf64489f4e1e665ec1158fb0309b0b565 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Tue, 10 Jul 2018 14:18:36 +0200 Subject: Add (guix inferior) and (guix scripts repl). * guix/inferior.scm, guix/scripts/repl.scm, tests/inferior.scm: New files. * Makefile.am (MODULES): Add 'guix/scripts/repl.scm' and 'guix/inferior.scm'. (SCM_TESTS): Add 'tests/inferior.scm'. * doc/guix.texi (Invoking guix repl): New node. --- Makefile.am | 3 + doc/guix.texi | 53 ++++++++++++++ guix/inferior.scm | 197 +++++++++++++++++++++++++++++++++++++++++++++++++ guix/scripts/repl.scm | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/inferior.scm | 69 +++++++++++++++++ 5 files changed, 521 insertions(+) create mode 100644 guix/inferior.scm create mode 100644 guix/scripts/repl.scm create mode 100644 tests/inferior.scm (limited to 'guix') diff --git a/Makefile.am b/Makefile.am index 618d1653e4..134ab0f142 100644 --- a/Makefile.am +++ b/Makefile.am @@ -85,6 +85,7 @@ MODULES = \ guix/nar.scm \ guix/derivations.scm \ guix/grafts.scm \ + guix/inferior.scm \ guix/gnu-maintenance.scm \ guix/self.scm \ guix/upstream.scm \ @@ -200,6 +201,7 @@ MODULES = \ guix/scripts/substitute.scm \ guix/scripts/authenticate.scm \ guix/scripts/refresh.scm \ + guix/scripts/repl.scm \ guix/scripts/system.scm \ guix/scripts/system/search.scm \ guix/scripts/lint.scm \ @@ -357,6 +359,7 @@ SCM_TESTS = \ tests/profiles.scm \ tests/search-paths.scm \ tests/syscalls.scm \ + tests/inferior.scm \ tests/gremlin.scm \ tests/bournish.scm \ tests/lint.scm \ diff --git a/doc/guix.texi b/doc/guix.texi index eaec4c422b..7a5ddefd4e 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -166,6 +166,7 @@ Programming Interface * Derivations:: Low-level interface to package derivations. * The Store Monad:: Purely functional interface to the store. * G-Expressions:: Manipulating build expressions. +* Invoking guix repl:: Fiddling with Guix interactively. Defining Packages @@ -3267,6 +3268,7 @@ package definitions. * Derivations:: Low-level interface to package derivations. * The Store Monad:: Purely functional interface to the store. * G-Expressions:: Manipulating build expressions. +* Invoking guix repl:: Fiddling with Guix interactively. @end menu @node Defining Packages @@ -5544,6 +5546,57 @@ corresponding to @var{obj} for @var{system}, cross-compiling for has an associated gexp compiler, such as a @code{}. @end deffn +@node Invoking guix repl +@section Invoking @command{guix repl} + +@cindex REPL, read-eval-print loop +The @command{guix repl} command spawns a Guile @dfn{read-eval-print loop} +(REPL) for interactive programming (@pxref{Using Guile Interactively,,, guile, +GNU Guile Reference Manual}). Compared to just launching the @command{guile} +command, @command{guix repl} guarantees that all the Guix modules and all its +dependencies are available in the search path. You can use it this way: + +@example +$ guix repl +scheme@@(guile-user)> ,use (gnu packages base) +scheme@@(guile-user)> coreutils +$1 = # +@end example + +@cindex inferiors +In addition, @command{guix repl} implements a simple machine-readable REPL +protocol for use by @code{(guix inferior)}, a facility to interact with +@dfn{inferiors}, separate processes running a potentially different revision +of Guix. + +The available options are as follows: + +@table @code +@item --type=@var{type} +@itemx -t @var{type} +Start a REPL of the given @var{TYPE}, which can be one of the following: + +@table @code +@item guile +This is default, and it spawns a standard full-featured Guile REPL. +@item machine +Spawn a REPL that uses the machine-readable protocol. This is the protocol +that the @code{(guix inferior)} module speaks. +@end table + +@item --listen=@var{endpoint} +By default, @command{guix repl} reads from standard input and writes to +standard output. When this option is passed, it will instead listen for +connections on @var{endpoint}. Here are examples of valid options: + +@table @code +@item --listen=tcp:37146 +Accept connections on localhost on port 37146. + +@item --listen=unix:/tmp/socket +Accept connections on the Unix-domain socket @file{/tmp/socket}. +@end table +@end table @c ********************************************************************* @node Utilities diff --git a/guix/inferior.scm b/guix/inferior.scm new file mode 100644 index 0000000000..629c2c4313 --- /dev/null +++ b/guix/inferior.scm @@ -0,0 +1,197 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2018 Ludovic Courtès +;;; +;;; 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 . + +(define-module (guix inferior) + #:use-module (srfi srfi-9) + #:use-module (srfi srfi-9 gnu) + #:use-module (ice-9 match) + #:use-module (ice-9 popen) + #:export (inferior? + open-inferior + close-inferior + inferior-eval + inferior-object? + + inferior-package? + inferior-package-name + inferior-package-version + + inferior-packages + inferior-package-synopsis + inferior-package-description)) + +;;; Commentary: +;;; +;;; This module provides a way to spawn Guix "inferior" processes and to talk +;;; to them. It allows us, from one instance of Guix, to interact with +;;; another instance of Guix coming from a different commit. +;;; +;;; Code: + +;; Inferior Guix process. +(define-record-type + (inferior pid socket version) + inferior? + (pid inferior-pid) + (socket inferior-socket) + (version inferior-version)) ;REPL protocol version + +(define (inferior-pipe directory command) + "Return an input/output pipe on the Guix instance in DIRECTORY. This runs +'DIRECTORY/COMMAND repl' if it exists, or falls back to some other method if +it's an old Guix." + (let ((pipe (with-error-to-port (%make-void-port "w") + (lambda () + (open-pipe* OPEN_BOTH + (string-append directory "/" command) + "repl" "-t" "machine"))))) + (if (eof-object? (peek-char pipe)) + (begin + (close-pipe pipe) + + ;; Older versions of Guix didn't have a 'guix repl' command, so + ;; emulate it. + (open-pipe* OPEN_BOTH "guile" + "-L" (string-append directory "/share/guile/site/" + (effective-version)) + "-C" (string-append directory "/share/guile/site/" + (effective-version)) + "-C" (string-append directory "/lib/guile/" + (effective-version) "/site-ccache") + "-c" + (object->string + `(begin + (primitive-load ,(search-path %load-path + "guix/scripts/repl.scm")) + ((@ (guix scripts repl) machine-repl)))))) + pipe))) + +(define* (open-inferior directory #:key (command "bin/guix")) + "Open the inferior Guix in DIRECTORY, running 'DIRECTORY/COMMAND repl' or +equivalent. Return #f if the inferior could not be launched." + (define pipe + (inferior-pipe directory command)) + + (setvbuf pipe _IOLBF) + (match (read pipe) + (('repl-version 0 rest ...) + (let ((result (inferior 'pipe pipe (cons 0 rest)))) + (inferior-eval '(use-modules (guix)) result) + (inferior-eval '(use-modules (gnu)) result) + (inferior-eval '(define %package-table (make-hash-table)) + result) + result)) + (_ + #f))) + +(define (close-inferior inferior) + "Close INFERIOR." + (close-pipe (inferior-socket inferior))) + +;; Non-self-quoting object of the inferior. +(define-record-type + (inferior-object address appearance) + inferior-object? + (address inferior-object-address) + (appearance inferior-object-appearance)) + +(define (write-inferior-object object port) + (match object + (($ _ appearance) + (format port "#" appearance)))) + +(set-record-type-printer! write-inferior-object) + +(define (inferior-eval exp inferior) + "Evaluate EXP in INFERIOR." + (define sexp->object + (match-lambda + (('value value) + value) + (('non-self-quoting address string) + (inferior-object address string)))) + + (write exp (inferior-socket inferior)) + (newline (inferior-socket inferior)) + (match (read (inferior-socket inferior)) + (('values objects ...) + (apply values (map sexp->object objects))) + (('exception key objects ...) + (apply throw key (map sexp->object objects))))) + + +;;; +;;; Inferior packages. +;;; + +(define-record-type + (inferior-package inferior name version id) + inferior-package? + (inferior inferior-package-inferior) + (name inferior-package-name) + (version inferior-package-version) + (id inferior-package-id)) + +(define (write-inferior-package package port) + (match package + (($ _ name version) + (format port "#" + name version + (number->string (object-address package) 16))))) + +(set-record-type-printer! write-inferior-package) + +(define (inferior-packages inferior) + "Return the list of packages known to INFERIOR." + (let ((result (inferior-eval + '(fold-packages (lambda (package result) + (let ((id (object-address package))) + (hashv-set! %package-table id package) + (cons (list (package-name package) + (package-version package) + id) + result))) + '()) + inferior))) + (map (match-lambda + ((name version id) + (inferior-package inferior name version id))) + result))) + +(define (inferior-package-field package getter) + "Return the field of PACKAGE, an inferior package, accessed with GETTER." + (let ((inferior (inferior-package-inferior package)) + (id (inferior-package-id package))) + (inferior-eval `(,getter (hashv-ref %package-table ,id)) + inferior))) + +(define* (inferior-package-synopsis package #:key (translate? #t)) + "Return the Texinfo synopsis of PACKAGE, an inferior package. When +TRANSLATE? is true, translate it to the current locale's language." + (inferior-package-field package + (if translate? + '(compose (@ (guix ui) P_) package-synopsis) + 'package-synopsis))) + +(define* (inferior-package-description package #:key (translate? #t)) + "Return the Texinfo description of PACKAGE, an inferior package. When +TRANSLATE? is true, translate it to the current locale's language." + (inferior-package-field package + (if translate? + '(compose (@ (guix ui) P_) package-description) + 'package-description))) diff --git a/guix/scripts/repl.scm b/guix/scripts/repl.scm new file mode 100644 index 0000000000..b157833a49 --- /dev/null +++ b/guix/scripts/repl.scm @@ -0,0 +1,199 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2018 Ludovic Courtès +;;; +;;; 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 . + +(define-module (guix scripts repl) + #:use-module (guix ui) + #:use-module (guix scripts) + #:use-module (guix utils) + #:use-module (guix packages) + #:use-module (gnu packages) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-37) + #:use-module (ice-9 match) + #:use-module (rnrs bytevectors) + #:autoload (system repl repl) (start-repl) + #:autoload (system repl server) + (make-tcp-server-socket make-unix-domain-server-socket) + #:export (machine-repl + guix-repl)) + +;;; Commentary: +;;; +;;; This command provides a Guile REPL + +(define %default-options + `((type . guile))) + +(define %options + (list (option '(#\h "help") #f #f + (lambda args + (show-help) + (exit 0))) + (option '(#\V "version") #f #f + (lambda args + (show-version-and-exit "guix repl"))) + (option '(#\t "type") #t #f + (lambda (opt name arg result) + (alist-cons 'type (string->symbol arg) result))) + (option '("listen") #t #f + (lambda (opt name arg result) + (alist-cons 'listen arg result))))) + + +(define (show-help) + (display (G_ "Usage: guix repl [OPTIONS...] +Start a Guile REPL in the Guix execution environment.\n")) + (display (G_ " + -t, --type=TYPE start a REPL of the given TYPE")) + (newline) + (display (G_ " + -h, --help display this help and exit")) + (display (G_ " + -V, --version display version information and exit")) + (newline) + (show-bug-report-information)) + +(define (self-quoting? x) + "Return #t if X is self-quoting." + (letrec-syntax ((one-of (syntax-rules () + ((_) #f) + ((_ pred rest ...) + (or (pred x) + (one-of rest ...)))))) + (one-of symbol? string? pair? null? vector? + bytevector? number? boolean?))) + +(define user-module + ;; Module where we execute user code. + (let ((module (resolve-module '(guix-user) #f #f #:ensure #t))) + (beautify-user-module! module) + module)) + +(define* (machine-repl #:optional + (input (current-input-port)) + (output (current-output-port))) + "Run a machine-usable REPL over ports INPUT and OUTPUT. + +The protocol of this REPL is meant to be machine-readable and provides proper +support to represent multiple-value returns, exceptions, objects that lack a +read syntax, and so on. As such it is more convenient and robust than parsing +Guile's REPL prompt." + (define (value->sexp value) + (if (self-quoting? value) + `(value ,value) + `(non-self-quoting ,(object-address value) + ,(object->string value)))) + + (write `(repl-version 0 0) output) + (newline output) + (force-output output) + + (let loop () + (match (read input) + ((? eof-object?) #t) + (exp + (catch #t + (lambda () + (let ((results (call-with-values + (lambda () + + (primitive-eval exp)) + list))) + (write `(values ,@(map value->sexp results)) + output) + (newline output) + (force-output output))) + (lambda (key . args) + (write `(exception ,key ,@(map value->sexp args))) + (newline output) + (force-output output))) + (loop))))) + +(define (call-with-connection spec thunk) + "Dynamically-bind the current input and output ports according to SPEC and +call THUNK." + (if (not spec) + (thunk) + + ;; Note: the "PROTO:" prefix in SPEC is here so that we can eventually + ;; parse things like "fd:123" in a non-ambiguous way. + (match (string-index spec #\:) + (#f + (leave (G_ "~A: invalid listen specification~%") spec)) + (index + (let ((protocol (string-take spec index)) + (address (string-drop spec (+ index 1)))) + (define socket + (match protocol + ("tcp" + (make-tcp-server-socket #:port (string->number address))) + ("unix" + (make-unix-domain-server-socket #:path address)) + (_ + (leave (G_ "~A: unsupported protocol family~%") + protocol)))) + + (listen socket 10) + (let loop () + (match (accept socket) + ((connection . address) + (if (= AF_UNIX (sockaddr:fam address)) + (info (G_ "accepted connection~%")) + (info (G_ "accepted connection from ~a~%") + (inet-ntop (sockaddr:fam address) + (sockaddr:addr address)))) + (dynamic-wind + (const #t) + (lambda () + (parameterize ((current-input-port connection) + (current-output-port connection)) + (thunk))) + (lambda () + (false-if-exception (close-port connection)) + (info (G_ "connection closed~%")))))) + (loop))))))) + + +(define (guix-repl . args) + (define opts + ;; Return the list of package names. + (args-fold* args %options + (lambda (opt name arg result) + (leave (G_ "~A: unrecognized option~%") name)) + (lambda (arg result) + (leave (G_ "~A: extraneous argument~%") arg)) + %default-options)) + + (with-error-handling + (let ((type (assoc-ref opts 'type))) + (call-with-connection (assoc-ref opts 'listen) + (lambda () + (case type + ((guile) + (save-module-excursion + (lambda () + (set-current-module user-module) + (start-repl)))) + ((machine) + (machine-repl)) + (else + (leave (G_ "~a: unknown type of REPL~%") type)))))))) + +;; Local Variables: +;; eval: (put 'call-with-connection 'scheme-indent-function 1) +;; End: diff --git a/tests/inferior.scm b/tests/inferior.scm new file mode 100644 index 0000000000..5e0f8ae66e --- /dev/null +++ b/tests/inferior.scm @@ -0,0 +1,69 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2018 Ludovic Courtès +;;; +;;; 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 . + +(define-module (test-inferior) + #:use-module (guix inferior) + #:use-module (guix packages) + #:use-module (gnu packages) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-64)) + +(define %top-srcdir + (dirname (search-path %load-path "guix.scm"))) + +(define %top-builddir + (dirname (search-path %load-compiled-path "guix.go"))) + + +(test-begin "inferior") + +(test-equal "open-inferior" + '(42 #t) + (let ((inferior (open-inferior %top-builddir + #:command "scripts/guix"))) + (and (inferior? inferior) + (let ((a (inferior-eval '(apply * '(6 7)) inferior)) + (b (inferior-eval '(@ (gnu packages base) coreutils) + inferior))) + (close-inferior inferior) + (list a (inferior-object? b)))))) + +(test-equal "inferior-packages" + (take (sort (fold-packages (lambda (package lst) + (alist-cons (package-name package) + (package-version package) + lst)) + '()) + (lambda (x y) + (string Date: Tue, 10 Jul 2018 16:06:32 +0200 Subject: pull: Use (guix inferior) to display new and upgraded packages. * guix/scripts/pull.scm (display-profile-content): Call 'display-generation'. (display-new/upgraded-packages, display-profile-content-diff): New procedures. (process-query)[list-generation]: Remove. [list-generations]: New procedure. Adjust accordingly. * doc/guix.texi (Invoking guix pull): Update example of '-l'. --- doc/guix.texi | 6 +++ guix/scripts/pull.scm | 109 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 104 insertions(+), 11 deletions(-) (limited to 'guix') diff --git a/doc/guix.texi b/doc/guix.texi index 7a5ddefd4e..c759ccb119 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -2786,12 +2786,18 @@ Generation 2 Jun 11 2018 11:02:49 repository URL: https://git.savannah.gnu.org/git/guix.git branch: origin/master commit: e0cc7f669bec22c37481dd03a7941c7d11a64f1d + 2 new packages: keepalived, libnfnetlink + 6 packages upgraded: emacs-nix-mode@@2.0.4, + guile2.0-guix@@0.14.0-12.77a1aac, guix@@0.14.0-12.77a1aac, + heimdal@@7.5.0, milkytracker@@1.02.00, nix@@2.0.4 Generation 3 Jun 13 2018 23:31:07 (current) guix 844cc1c repository URL: https://git.savannah.gnu.org/git/guix.git branch: origin/master commit: 844cc1c8f394f03b404c5bb3aee086922373490c + 28 new packages: emacs-helm-ls-git, emacs-helm-mu, @dots{} + 69 packages upgraded: borg@@1.1.6, cheese@@3.28.0, @dots{} @end example This @code{~/.config/guix/current} profile works like any other profile diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm index 7202e3cc16..aa77434334 100644 --- a/guix/scripts/pull.scm +++ b/guix/scripts/pull.scm @@ -28,7 +28,9 @@ #:use-module (guix profiles) #:use-module (guix gexp) #:use-module (guix grafts) + #:use-module (guix memoization) #:use-module (guix monads) + #:autoload (guix inferior) (open-inferior) #:use-module (guix scripts build) #:autoload (guix self) (whole-package) #:autoload (gnu packages ssh) (guile-ssh) @@ -45,9 +47,11 @@ #:use-module ((gnu packages certs) #:select (le-certs)) #:use-module (srfi srfi-1) #:use-module (srfi srfi-11) + #:use-module (srfi srfi-26) #:use-module (srfi srfi-35) #:use-module (srfi srfi-37) #:use-module (ice-9 match) + #:use-module (ice-9 vlist) #:export (guix-pull)) (module-autoload! (resolve-module '(guix scripts pull)) @@ -289,6 +293,7 @@ certificates~%")) (define (display-profile-content profile number) "Display the packages in PROFILE, generation NUMBER, in a human-readable way and displaying details about the channel's source code." + (display-generation profile number) (for-each (lambda (entry) (format #t " ~a ~a~%" (manifest-entry-name entry) @@ -310,6 +315,85 @@ way and displaying details about the channel's source code." (manifest-entries (profile-manifest (generation-file-name profile number)))))) +(define (indented-string str indent) + "Return STR with each newline preceded by IDENT spaces." + (define indent-string + (make-list indent #\space)) + + (list->string + (string-fold-right (lambda (chr result) + (if (eqv? chr #\newline) + (cons chr (append indent-string result)) + (cons chr result))) + '() + str))) + +(define profile-package-alist + (mlambda (profile) + "Return a name/version alist representing the packages in PROFILE." + (fold (lambda (package lst) + (alist-cons (inferior-package-name package) + (inferior-package-version package) + lst)) + '() + (let* ((inferior (open-inferior profile)) + (packages (inferior-packages inferior))) + (close-inferior inferior) + packages)))) + +(define (display-new/upgraded-packages alist1 alist2) + "Given the two package name/version alists ALIST1 and ALIST2, display the +list of new and upgraded packages going from ALIST1 to ALIST2." + (let* ((old (fold (match-lambda* + (((name . version) table) + (vhash-cons name version table))) + vlist-null + alist1)) + (new (remove (match-lambda + ((name . _) + (vhash-assoc name old))) + alist2)) + (upgraded (filter-map (match-lambda + ((name . new-version) + (match (vhash-fold* cons '() name old) + (() #f) + ((= (cut sort <> version>?) old-versions) + (and (version>? new-version + (first old-versions)) + (string-append name "@" + new-version)))))) + alist2))) + (match (length new) + (0 #t) + (count + (format #t (N_ " ~h new package: ~a~%" + " ~h new packages: ~a~%" count) + count + (indented-string + (fill-paragraph (string-join (sort (map first new) string (match-lambda (() (exit 1)) ((numbers ...) - (for-each (lambda (generation) - (list-generation display-profile-content generation)) - numbers))))))))) + (list-generations profile numbers))))))))) (define (guix-pull . args) -- cgit v1.2.3 From bca302c67af6969584e60bd1604ea196ecc48c4b Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 13 Jul 2018 16:59:15 +0200 Subject: pull: Display new/upgraded packages upon completion. * guix/scripts/pull.scm (display-profile-news): New procedure. (build-and-install): Call it. (display-new/upgraded-packages): Add #:heading and honor it. --- guix/scripts/pull.scm | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) (limited to 'guix') diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm index aa77434334..433502b5de 100644 --- a/guix/scripts/pull.scm +++ b/guix/scripts/pull.scm @@ -33,6 +33,7 @@ #:autoload (guix inferior) (open-inferior) #:use-module (guix scripts build) #:autoload (guix self) (whole-package) + #:use-module (gnu packages) #:autoload (gnu packages ssh) (guile-ssh) #:autoload (gnu packages tls) (gnutls) #:use-module ((guix scripts package) #:select (build-and-use-profile)) @@ -234,12 +235,32 @@ URL, BRANCH, and COMMIT as a property in the manifest entry." (branch ,branch) (commit ,commit)))))))))) +(define (display-profile-news profile) + "Display what's up in PROFILE--new packages, and all that." + (match (memv (generation-number profile) + (reverse (profile-generations profile))) + ((current previous _ ...) + (newline) + (let ((old (fold-packages (lambda (package result) + (alist-cons (package-name package) + (package-version package) + result)) + '())) + (new (profile-package-alist + (generation-file-name profile current)))) + (display-new/upgraded-packages old new + #:heading (G_ "New in this revision:\n")))) + (_ #t))) + (define* (build-and-install source config-dir #:key verbose? url branch commit) "Build the tool from SOURCE, and install it in CONFIG-DIR." (define update-profile (store-lift build-and-use-profile)) + (define profile + (string-append config-dir "/current")) + (mlet* %store-monad ((drv (build-from-source source #:commit commit #:verbose? verbose?)) @@ -247,8 +268,9 @@ URL, BRANCH, and COMMIT as a property in the manifest entry." #:url url #:branch branch #:commit commit))) - (update-profile (string-append config-dir "/current") - (manifest (list entry))))) + (mbegin %store-monad + (update-profile profile (manifest (list entry))) + (return (display-profile-news profile))))) (define (honor-lets-encrypt-certificates! store) "Tell Guile-Git to use the Let's Encrypt certificates." @@ -341,9 +363,11 @@ way and displaying details about the channel's source code." (close-inferior inferior) packages)))) -(define (display-new/upgraded-packages alist1 alist2) +(define* (display-new/upgraded-packages alist1 alist2 + #:key (heading "")) "Given the two package name/version alists ALIST1 and ALIST2, display the -list of new and upgraded packages going from ALIST1 to ALIST2." +list of new and upgraded packages going from ALIST1 to ALIST2. When ALIST1 +and ALIST2 differ, display HEADING upfront." (let* ((old (fold (match-lambda* (((name . version) table) (vhash-cons name version table))) @@ -363,6 +387,9 @@ list of new and upgraded packages going from ALIST1 to ALIST2." (string-append name "@" new-version)))))) alist2))) + (unless (and (null? new) (null? upgraded)) + (display heading)) + (match (length new) (0 #t) (count -- cgit v1.2.3 From 27f7cbc91d1963118e44b14d04fcc669c9618176 Mon Sep 17 00:00:00 2001 From: Leo Famulari Date: Wed, 11 Jul 2018 20:24:29 -0400 Subject: utils: Really clean up temporary directories. Fixes . * guix/utils.scm (call-with-temporary-directory): Use DELETE-FILE-RECURSIVELY instead of RMDIR. --- guix/utils.scm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'guix') diff --git a/guix/utils.scm b/guix/utils.scm index f934b6ed13..200bb69e03 100644 --- a/guix/utils.scm +++ b/guix/utils.scm @@ -33,10 +33,11 @@ #:use-module (srfi srfi-35) #:use-module (srfi srfi-39) #:use-module (ice-9 binary-ports) + #:use-module (ice-9 ftw) #:autoload (rnrs io ports) (make-custom-binary-input-port) #:use-module ((rnrs bytevectors) #:select (bytevector-u8-set!)) #:use-module (guix memoization) - #:use-module ((guix build utils) #:select (dump-port mkdir-p)) + #:use-module ((guix build utils) #:select (dump-port mkdir-p delete-file-recursively)) #:use-module ((guix build syscalls) #:select (mkdtemp! fdatasync)) #:use-module (ice-9 format) #:autoload (ice-9 popen) (open-pipe*) @@ -631,7 +632,7 @@ delete it when leaving the dynamic extent of this call." (lambda () (proc tmp-dir)) (lambda () - (false-if-exception (rmdir tmp-dir)))))) + (false-if-exception (delete-file-recursively tmp-dir)))))) (define (with-atomic-file-output file proc) "Call PROC with an output port for the file that is going to replace FILE. -- cgit v1.2.3 From 0d354666d35ea54b024f45a6b3d835e8879a5df5 Mon Sep 17 00:00:00 2001 From: Christopher Baines Date: Sat, 14 Jul 2018 11:52:14 +0100 Subject: ruby-build-system: Error or return #t from all phases. Previously, if the tests didn't pass, the check phase would evaluate to #f, but the package would be built sucessfully. This changes all the phases to raise exceptions if errors are encountered, and return #t otherwise. This involves using invoke rather than system*, so that exceptions are raised if the program exits with a status other than 0, and also returning #t at the end of functions. * gnu/build/ruby-build-system.scm (unpack): Use invoke rather than system*, and return #t at the end. (build, check): Use invoke rather than system*. (install): Remove the use of "and", and rewrite the error handling to raise an exception. (wrap): Return #t. --- guix/build/ruby-build-system.scm | 108 ++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 53 deletions(-) (limited to 'guix') diff --git a/guix/build/ruby-build-system.scm b/guix/build/ruby-build-system.scm index abef6937bc..a346e9fb8e 100644 --- a/guix/build/ruby-build-system.scm +++ b/guix/build/ruby-build-system.scm @@ -52,18 +52,19 @@ directory." (define* (unpack #:key source #:allow-other-keys) "Unpack the gem SOURCE and enter the resulting directory." (if (gem-archive? source) - (and (zero? (system* "gem" "unpack" source)) - ;; The unpacked gem directory is named the same as the archive, - ;; sans the ".gem" extension. It is renamed to simply "gem" in an - ;; effort to keep file names shorter to avoid UNIX-domain socket - ;; file names and shebangs that exceed the system's fixed maximum - ;; length when running test suites. - (let ((dir (match:substring (string-match "^(.*)\\.gem$" - (basename source)) - 1))) - (rename-file dir "gem") - (chdir "gem") - #t)) + (begin + (invoke "gem" "unpack" source) + ;; The unpacked gem directory is named the same as the archive, + ;; sans the ".gem" extension. It is renamed to simply "gem" in an + ;; effort to keep file names shorter to avoid UNIX-domain socket + ;; file names and shebangs that exceed the system's fixed maximum + ;; length when running test suites. + (let ((dir (match:substring (string-match "^(.*)\\.gem$" + (basename source)) + 1))) + (rename-file dir "gem") + (chdir "gem")) + #t) ;; Use GNU unpack strategy for things that aren't gem archives. (gnu:unpack #:source source))) @@ -104,7 +105,8 @@ generate the files list." (write-char (read-char pipe) out)))) #t) (lambda () - (close-pipe pipe))))))) + (close-pipe pipe))))) + #t)) (define* (build #:key source #:allow-other-keys) "Build a new gem using the gemspec from the SOURCE gem." @@ -112,13 +114,13 @@ generate the files list." ;; Build a new gem from the current working directory. This also allows any ;; dynamic patching done in previous phases to be present in the installed ;; gem. - (zero? (system* "gem" "build" (first-gemspec)))) + (invoke "gem" "build" (first-gemspec))) (define* (check #:key tests? test-target #:allow-other-keys) "Run the gem's test suite rake task TEST-TARGET. Skip the tests if TESTS? is #f." (if tests? - (zero? (system* "rake" test-target)) + (invoke "rake" test-target) #t)) (define* (install #:key inputs outputs (gem-flags '()) @@ -137,43 +139,42 @@ GEM-FLAGS are passed to the 'gem' invokation, if present." 0 (- (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 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 vendor-dir "/ext")) - (begin - (for-each (lambda (file) - (log-file-deletion file) - (delete-file file)) - (append - (find-files (string-append vendor-dir "/doc") - "page-Makefile.ri") - (find-files (string-append vendor-dir "/extensions") - "gem_make.out") - (find-files (string-append vendor-dir "/ext") - "Makefile"))))) - #t)))) + + (or (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)) + (begin + (let ((failed-output-dir (string-append (getcwd) "/out"))) + (mkdir failed-output-dir) + (copy-recursively out failed-output-dir)) + (error "installation failed"))) + + ;; Remove the cached gem file as this is unnecessary and contains + ;; timestamped files rendering builds not reproducible. + (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. + (when (file-exists? (string-append vendor-dir "/ext")) + (for-each (lambda (file) + (log-file-deletion file) + (delete-file file)) + (append + (find-files (string-append vendor-dir "/doc") + "page-Makefile.ri") + (find-files (string-append vendor-dir "/extensions") + "gem_make.out") + (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: @@ -301,7 +302,8 @@ extended with definitions for VARS." (let ((files (list-of-files dir))) (for-each (cut wrap-ruby-program <> var) files))) - bindirs))) + bindirs)) + #t) (define (log-file-deletion file) (display (string-append "deleting '" file "' for reproducibility\n"))) -- cgit v1.2.3 From b94b698d4ed4bc478c56e507d53e5284d4f63073 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sat, 14 Jul 2018 19:28:07 +0200 Subject: serialization: Add 'write-file-tree'. * guix/serialization.scm (write-contents-from-port): New procedure. (write-contents): Write in terms of 'write-contents-from-port'. (filter/sort-directory-entries, write-file-tree): New procedures. (write-file): Rewrite in terms of 'write-file-tree'. * tests/nar.scm ("write-file-tree + restore-file"): New test. --- guix/serialization.scm | 140 ++++++++++++++++++++++++++++++++++++++----------- tests/nar.scm | 62 +++++++++++++++++++++- 2 files changed, 169 insertions(+), 33 deletions(-) (limited to 'guix') diff --git a/guix/serialization.scm b/guix/serialization.scm index b41a0a09d1..129374f541 100644 --- a/guix/serialization.scm +++ b/guix/serialization.scm @@ -47,6 +47,7 @@ nar-read-error-token write-file + write-file-tree restore-file)) ;;; Comment: @@ -211,14 +212,19 @@ substitute invalid byte sequences with question marks. This is a (lambda () (close-port port)))))) - (write-string "contents" p) - (write-long-long size p) (call-with-binary-input-file file - ;; Use 'sendfile' when P is a file port. - (if (file-port? p) - (cut sendfile p <> size 0) - (cut dump <> p size))) - (write-padding size p)) + (lambda (input) + (write-contents-from-port input p size)))) + +(define (write-contents-from-port input output size) + "Write SIZE bytes from port INPUT to port OUTPUT." + (write-string "contents" output) + (write-long-long size output) + ;; Use 'sendfile' when both OUTPUT and INPUT are file ports. + (if (and (file-port? output) (file-port? input)) + (sendfile output input size 0) + (dump input output size)) + (write-padding size output)) (define (read-contents in out) "Read the contents of a file from the Nar at IN, write it to OUT, and return @@ -263,47 +269,113 @@ the size in bytes." sub-directories of FILE as needed. For each directory entry, call (SELECT? FILE STAT), where FILE is the entry's absolute file name and STAT is the result of 'lstat'; exclude entries for which SELECT? does not return true." + (write-file-tree file port + #:file-type+size + (lambda (file) + (let* ((stat (lstat file)) + (size (stat:size stat))) + (case (stat:type stat) + ((directory) + (values 'directory size)) + ((regular) + (values (if (zero? (logand (stat:mode stat) + #o100)) + 'regular + 'executable) + size)) + (else + (values (stat:type stat) size))))) ;bah! + #:file-port (cut open-file <> "r0b") + #:symlink-target readlink + + #:directory-entries + (lambda (directory) + ;; 'scandir' defaults to 'string-locale '("." ".."))) + string '("." "..")) lst) + string '("." ".."))) string +;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès ;;; ;;; This file is part of GNU Guix. ;;; @@ -152,6 +152,66 @@ (test-begin "nar") +(test-assert "write-file-tree + restore-file" + (let* ((file1 (search-path %load-path "guix.scm")) + (file2 (search-path %load-path "guix/base32.scm")) + (file3 "#!/bin/something") + (output (string-append %test-dir "/output"))) + (dynamic-wind + (lambda () #t) + (lambda () + (define-values (port get-bytevector) + (open-bytevector-output-port)) + (write-file-tree "root" port + #:file-type+size + (match-lambda + ("root" + (values 'directory 0)) + ("root/foo" + (values 'regular (stat:size (stat file1)))) + ("root/lnk" + (values 'symlink 0)) + ("root/dir" + (values 'directory 0)) + ("root/dir/bar" + (values 'regular (stat:size (stat file2)))) + ("root/dir/exe" + (values 'executable (string-length file3)))) + #:file-port + (match-lambda + ("root/foo" (open-input-file file1)) + ("root/dir/bar" (open-input-file file2)) + ("root/dir/exe" (open-input-string file3))) + #:symlink-target + (match-lambda + ("root/lnk" "foo")) + #:directory-entries + (match-lambda + ("root" '("foo" "dir" "lnk")) + ("root/dir" '("bar" "exe")))) + (close-port port) + + (rm-rf %test-dir) + (mkdir %test-dir) + (restore-file (open-bytevector-input-port (get-bytevector)) + output) + (and (file=? (string-append output "/foo") file1) + (string=? (readlink (string-append output "/lnk")) + "foo") + (file=? (string-append output "/dir/bar") file2) + (string=? (call-with-input-file (string-append output "/dir/exe") + get-string-all) + file3) + (> (logand (stat:mode (lstat (string-append output "/dir/exe"))) + #o100) + 0) + (equal? '("." ".." "bar" "exe") + (scandir (string-append output "/dir"))) + (equal? '("." ".." "dir" "foo" "lnk") + (scandir output)))) + (lambda () + (false-if-exception (rm-rf %test-dir)))))) + (test-assert "write-file supports non-file output ports" (let ((input (string-append (dirname (search-path %load-path "guix.scm")) "/guix")) -- cgit v1.2.3 From 7f11efbac7a13898bd925d2ef1e9d26cb0e22ade Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 16 Jul 2018 09:55:49 +0200 Subject: store: Add 'add-file-tree-to-store'. * guix/store.scm (%not-slash): New variable. (add-file-tree-to-store, interned-file-tree): New procedures. * tests/store.scm ("add-file-tree-to-store"): New test. --- guix/store.scm | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/store.scm | 46 ++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) (limited to 'guix') diff --git a/guix/store.scm b/guix/store.scm index cc5c24a77d..f41a1e2690 100644 --- a/guix/store.scm +++ b/guix/store.scm @@ -78,6 +78,7 @@ add-data-to-store add-text-to-store add-to-store + add-file-tree-to-store binary-file build-things build @@ -137,6 +138,7 @@ set-current-system text-file interned-file + interned-file-tree %store-prefix store-path @@ -951,6 +953,101 @@ where FILE is the entry's absolute file name and STAT is the result of (hash-set! cache args path) path)))))) +(define %not-slash + (char-set-complement (char-set #\/))) + +(define* (add-file-tree-to-store server tree + #:key + (hash-algo "sha256") + (recursive? #t)) + "Add the given TREE to the store on SERVER. TREE must be an entry such as: + + (\"my-tree\" directory + (\"a\" regular (data \"hello\")) + (\"b\" symlink \"a\") + (\"c\" directory + (\"d\" executable (file \"/bin/sh\")))) + +This is a generalized version of 'add-to-store'. It allows you to reproduce +an arbitrary directory layout in the store without creating a derivation." + + ;; Note: The format of TREE was chosen to allow trees to be compared with + ;; 'equal?', which in turn allows us to memoize things. + + (define root + ;; TREE is a single entry. + (list tree)) + + (define basename + (match tree + ((name . _) name))) + + (define (lookup file) + (let loop ((components (string-tokenize file %not-slash)) + (tree root)) + (match components + ((basename) + (assoc basename tree)) + ((head . rest) + (loop rest + (match (assoc-ref tree head) + (('directory . entries) entries))))))) + + (define (file-type+size file) + (match (lookup file) + ((_ (and type (or 'directory 'symlink)) . _) + (values type 0)) + ((_ type ('file file)) + (values type (stat:size (stat file)))) + ((_ type ('data (? string? data))) + (values type (string-length data))) + ((_ type ('data (? bytevector? data))) + (values type (bytevector-length data))))) + + (define (file-port file) + (match (lookup file) + ((_ (or 'regular 'executable) content) + (match content + (('file (? string? file)) + (open-file file "r0b")) + (('data (? string? str)) + (open-input-string str)) + (('data (? bytevector? bv)) + (open-bytevector-input-port bv)))))) + + (define (symlink-target file) + (match (lookup file) + ((_ 'symlink target) target))) + + (define (directory-entries directory) + (match (lookup directory) + ((_ 'directory (names . _) ...) names))) + + (define cache + (nix-server-add-to-store-cache server)) + + (or (hash-ref cache tree) + (begin + ;; We don't use the 'operation' macro so we can use 'write-file-tree' + ;; instead of 'write-file'. + (record-operation 'add-to-store/tree) + (let ((port (nix-server-socket server))) + (write-int (operation-id add-to-store) port) + (write-string basename port) + (write-int 1 port) ;obsolete, must be #t + (write-int (if recursive? 1 0) port) + (write-string hash-algo port) + (write-file-tree basename port + #:file-type+size file-type+size + #:file-port file-port + #:symlink-target symlink-target + #:directory-entries directory-entries) + (let loop ((done? (process-stderr server))) + (or done? (loop (process-stderr server)))) + (let ((result (read-store-path port))) + (hash-set! cache tree result) + result))))) + (define build-things (let ((build (operation (build-things (string-list things) (integer mode)) @@ -1402,6 +1499,9 @@ where FILE is the entry's absolute file name and STAT is the result of #:select? select?) store))) +(define interned-file-tree + (store-lift add-file-tree-to-store)) + (define build ;; Monadic variant of 'build-things'. (store-lift build-things)) diff --git a/tests/store.scm b/tests/store.scm index afecec940a..47fab0df18 100644 --- a/tests/store.scm +++ b/tests/store.scm @@ -210,6 +210,52 @@ (valid-path? store path) (file-exists? path))))) +(test-equal "add-file-tree-to-store" + `(42 + ("." directory #t) + ("./bar" directory #t) + ("./foo" directory #t) + ("./foo/a" regular "file a") + ("./foo/b" symlink "a") + ("./foo/c" directory #t) + ("./foo/c/p" regular "file p") + ("./foo/c/q" directory #t) + ("./foo/c/q/x" regular "#!/bin/sh\nexit 42") + ("./foo/c/q/y" symlink "..") + ("./foo/c/q/z" directory #t)) + (let* ((tree `("file-tree" directory + ("foo" directory + ("a" regular (data "file a")) + ("b" symlink "a") + ("c" directory + ("p" regular (data ,(string->utf8 "file p"))) + ("q" directory + ("x" executable + (data "#!/bin/sh\nexit 42")) + ("y" symlink "..") + ("z" directory)))) + ("bar" directory))) + (result (add-file-tree-to-store %store tree))) + (cons (status:exit-val (system* (string-append result "/foo/c/q/x"))) + (with-directory-excursion result + (map (lambda (file) + (let ((type (stat:type (lstat file)))) + `(,file ,type + ,(match type + ((or 'regular 'executable) + (call-with-input-file file + get-string-all)) + ('symlink (readlink file)) + ('directory #t))))) + (find-files "." #:directories? #t)))))) + +(test-equal "add-file-tree-to-store, flat" + "Hello, world!" + (let* ((tree `("flat-file" regular (data "Hello, world!"))) + (result (add-file-tree-to-store %store tree))) + (and (file-exists? result) + (call-with-input-file result get-string-all)))) + (test-assert "references" (let* ((t1 (add-text-to-store %store "random1" (random-text))) -- cgit v1.2.3 From 4d20d87b53930c68bab1b6d8865402260c351145 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 16 Jul 2018 10:14:00 +0200 Subject: gexp: Remove unnecessary 'mlet'. * guix/gexp.scm (imported-modules): Use 'let' instead of 'mlet'. --- guix/gexp.scm | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'guix') diff --git a/guix/gexp.scm b/guix/gexp.scm index cc3613f6f6..3414b81dc6 100644 --- a/guix/gexp.scm +++ b/guix/gexp.scm @@ -1098,18 +1098,14 @@ by an arrow followed by a file-like object. For example: In this example, the first two modules are taken from MODULE-PATH, and the last one is created from the given object." - (mlet %store-monad ((files - (mapm %store-monad - (match-lambda - (((module ...) '=> file) - (return - (cons (module->source-file-name module) - file))) - ((module ...) - (let ((f (module->source-file-name module))) - (return - (cons f (search-path* module-path f)))))) - modules))) + (let ((files (map (match-lambda + (((module ...) '=> file) + (cons (module->source-file-name module) + file)) + ((module ...) + (let ((f (module->source-file-name module))) + (cons f (search-path* module-path f))))) + modules))) (imported-files files #:name name #:system system #:guile guile #:deprecation-warnings deprecation-warnings))) -- cgit v1.2.3 From 8df2eca6b0915942ea087d7c5981514c532d47a2 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 16 Jul 2018 11:17:55 +0200 Subject: gexp: 'imported-files' no longer creates a derivation by default. * guix/gexp.scm (gexp->derivation): Add #:import-creates-derivation?. Pass #:derivation? to 'imported-modules' and 'compiled-modules'. In -L argument, check whether MODULES is a derivation. (%not-slash): New variable. (file-mapping->tree): New procedure. (imported-files): Rename to... (imported-files/derivation): ... this. (imported-files): New procedure. Rewrite in terms of 'interned-file-tree' when possible; add #:derivation? parameter. (imported-modules, compiled-modules): Add #:derivation? parameter and pass it to 'imported-files'. * guix/packages.scm (patch-and-repack): Pass #:import-creates-derivation? to 'gexp->derivation'. * tests/gexp.scm ("imported-files"): Adjust to no longer expect a derivation. --- guix/gexp.scm | 117 +++++++++++++++++++++++++++++++++++++++++++++++------- guix/packages.scm | 3 ++ tests/gexp.scm | 20 +++++----- 3 files changed, 115 insertions(+), 25 deletions(-) (limited to 'guix') diff --git a/guix/gexp.scm b/guix/gexp.scm index 3414b81dc6..19d90f5eee 100644 --- a/guix/gexp.scm +++ b/guix/gexp.scm @@ -601,6 +601,12 @@ names and file names suitable for the #:allowed-references argument to allowed-references disallowed-references leaked-env-vars local-build? (substitutable? #t) + + ;; TODO: This parameter is transitional; it's here + ;; to avoid a full rebuild. Remove it on the next + ;; rebuild cycle. + import-creates-derivation? + deprecation-warnings (script-name (string-append name "-builder"))) "Return a derivation NAME that runs EXP (a gexp) with GUILE-FOR-BUILD (a @@ -695,6 +701,8 @@ The other arguments are as for 'derivation'." extensions)) (modules (if (pair? %modules) (imported-modules %modules + #:derivation? + import-creates-derivation? #:system system #:module-path module-path #:guile guile-for-build @@ -703,6 +711,8 @@ The other arguments are as for 'derivation'." (return #f))) (compiled (if (pair? %modules) (compiled-modules %modules + #:derivation? + import-creates-derivation? #:system system #:module-path module-path #:extensions extensions @@ -735,7 +745,9 @@ The other arguments are as for 'derivation'." "/bin/guile") `("--no-auto-compile" ,@(if (pair? %modules) - `("-L" ,(derivation->output-path modules) + `("-L" ,(if (derivation? modules) + (derivation->output-path modules) + modules) "-C" ,(derivation->output-path compiled)) '()) ,@(append-map extension-flags exts) @@ -1013,6 +1025,49 @@ execution environment." ;;; Module handling. ;;; +(define %not-slash + (char-set-complement (char-set #\/))) + +(define (file-mapping->tree mapping) + "Convert MAPPING, an alist like: + + ((\"guix/build/utils.scm\" . \"…/utils.scm\")) + +to a tree suitable for 'interned-file-tree'." + (let ((mapping (map (match-lambda + ((destination . source) + (cons (string-tokenize destination + %not-slash) + source))) + mapping))) + (fold (lambda (pair result) + (match pair + ((destination . source) + (let loop ((destination destination) + (result result)) + (match destination + ((file) + (let* ((mode (stat:mode (stat source))) + (type (if (zero? (logand mode #o100)) + 'regular + 'executable))) + (alist-cons file + `(,type (file ,source)) + result))) + ((file rest ...) + (let ((directory (assoc-ref result file))) + (alist-cons file + `(directory + ,@(loop rest + (match directory + (('directory . entries) entries) + (#f '())))) + (if directory + (alist-delete file result) + result))))))))) + '() + mapping))) + (define %utils-module ;; This file provides 'mkdir-p', needed to implement 'imported-files' and ;; other primitives below. Note: We give the file name relative to this @@ -1021,18 +1076,18 @@ execution environment." (local-file "build/utils.scm" "build-utils.scm")) -(define* (imported-files files - #:key (name "file-import") - (system (%current-system)) - (guile (%guile-for-build)) - - ;; XXX: The only reason we have - ;; #:deprecation-warnings is because (guix build - ;; utils), which we use here, relies on _IO*, which - ;; is deprecated in 2.2. On the next full-rebuild - ;; cycle, we should disable such warnings - ;; unconditionally. - (deprecation-warnings #f)) +(define* (imported-files/derivation files + #:key (name "file-import") + (system (%current-system)) + (guile (%guile-for-build)) + + ;; XXX: The only reason we have + ;; #:deprecation-warnings is because (guix + ;; build utils), which we use here, relies + ;; on _IO*, which is deprecated in 2.2. On + ;; the next full-rebuild cycle, we should + ;; disable such warnings unconditionally. + (deprecation-warnings #f)) "Return a derivation that imports FILES into STORE. FILES must be a list of (FINAL-PATH . FILE) pairs. Each FILE is mapped to FINAL-PATH in the resulting store path. FILE can be either a file name, or a file-like object, @@ -1081,8 +1136,38 @@ as returned by 'local-file' for example." (else '()))))) +(define* (imported-files files + #:key (name "file-import") + + ;; TODO: Remove this parameter on the next rebuild + ;; cycle. + (derivation? #f) + + ;; The following parameters make sense when creating + ;; an actual derivation. + (system (%current-system)) + (guile (%guile-for-build)) + (deprecation-warnings #f)) + "Import FILES into the store and return the resulting derivation or store +file name (a derivation is created if and only if some elements of FILES are +file-like objects and not local file names.) FILES must be a list +of (FINAL-PATH . FILE) pairs. Each FILE is mapped to FINAL-PATH in the +resulting store path. FILE can be either a file name, or a file-like object, +as returned by 'local-file' for example." + (if (or derivation? + (any (match-lambda + ((_ . (? struct? source)) #t) + (_ #f)) + files)) + (imported-files/derivation files #:name name + #:system system #:guile guile + #:deprecation-warnings deprecation-warnings) + (interned-file-tree `(,name directory + ,@(file-mapping->tree files))))) + (define* (imported-modules modules #:key (name "module-import") + (derivation? #f) ;TODO: remove on next rebuild (system (%current-system)) (guile (%guile-for-build)) (module-path %load-path) @@ -1106,12 +1191,15 @@ last one is created from the given object." (let ((f (module->source-file-name module))) (cons f (search-path* module-path f))))) modules))) - (imported-files files #:name name #:system system + (imported-files files #:name name + #:derivation? derivation? + #:system system #:guile guile #:deprecation-warnings deprecation-warnings))) (define* (compiled-modules modules #:key (name "module-import-compiled") + (derivation? #f) ;TODO: remove on next rebuild (system (%current-system)) (guile (%guile-for-build)) (module-path %load-path) @@ -1131,6 +1219,7 @@ they can refer to each other." (not (equal? module-path %load-path)))) (mlet %store-monad ((modules (imported-modules modules + #:derivation? derivation? #:system system #:guile guile #:module-path diff --git a/guix/packages.scm b/guix/packages.scm index c762fa7c39..a220b9c476 100644 --- a/guix/packages.scm +++ b/guix/packages.scm @@ -646,6 +646,9 @@ specifies modules in scope when evaluating SNIPPET." (let ((name (tarxz-name original-file-name))) (gexp->derivation name build + ;; TODO: Remove this on the next rebuild cycle. + #:import-creates-derivation? #t + #:graft? #f #:system system #:deprecation-warnings #t ;to avoid a rebuild diff --git a/tests/gexp.scm b/tests/gexp.scm index 391a0f8be5..c89d0c4855 100644 --- a/tests/gexp.scm +++ b/tests/gexp.scm @@ -635,18 +635,16 @@ "guix/derivations.scm")) ("p/q" . ,(search-path %load-path "guix.scm")) ("p/z" . ,(search-path %load-path "guix/store.scm")))) - (drv (imported-files files))) + (dir (imported-files files))) (mbegin %store-monad - (built-derivations (list drv)) - (let ((dir (derivation->output-path drv))) - (return - (every (match-lambda - ((path . source) - (equal? (call-with-input-file (string-append dir "/" path) - get-bytevector-all) - (call-with-input-file source - get-bytevector-all)))) - files)))))) + (return + (every (match-lambda + ((path . source) + (equal? (call-with-input-file (string-append dir "/" path) + get-bytevector-all) + (call-with-input-file source + get-bytevector-all)))) + files))))) (test-assertm "imported-files with file-like objects" (mlet* %store-monad ((plain -> (plain-file "foo" "bar!")) -- cgit v1.2.3 From e529d46828c359b449fc570bdc293fc12534647c Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 16 Jul 2018 11:40:34 +0200 Subject: gexp: 'imported-files/derivation' can copy files instead of symlinking. * guix/gexp.scm (imported-files/derivation): Add #:symlink? and honor it. (imported-files): Pass #:symlink? to 'imported-files/derivation'. * tests/gexp.scm ("imported-files with file-like objects"): Add 'file=?' and use it instead of calling 'readlink'. --- guix/gexp.scm | 8 ++++++-- tests/gexp.scm | 11 +++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'guix') diff --git a/guix/gexp.scm b/guix/gexp.scm index 19d90f5eee..ffc976d61b 100644 --- a/guix/gexp.scm +++ b/guix/gexp.scm @@ -1078,6 +1078,7 @@ to a tree suitable for 'interned-file-tree'." (define* (imported-files/derivation files #:key (name "file-import") + (symlink? #f) (system (%current-system)) (guile (%guile-for-build)) @@ -1091,7 +1092,8 @@ to a tree suitable for 'interned-file-tree'." "Return a derivation that imports FILES into STORE. FILES must be a list of (FINAL-PATH . FILE) pairs. Each FILE is mapped to FINAL-PATH in the resulting store path. FILE can be either a file name, or a file-like object, -as returned by 'local-file' for example." +as returned by 'local-file' for example. If SYMLINK? is true, create symlinks +to the source files instead of copying them." (define file-pair (match-lambda ((final-path . (? string? file-name)) @@ -1114,7 +1116,8 @@ as returned by 'local-file' for example." (for-each (match-lambda ((final-path store-path) (mkdir-p (dirname final-path)) - (symlink store-path final-path))) + ((ungexp (if symlink? 'symlink 'copy-file)) + store-path final-path))) '(ungexp files))))) ;; TODO: Pass FILES as an environment variable so that BUILD remains @@ -1160,6 +1163,7 @@ as returned by 'local-file' for example." (_ #f)) files)) (imported-files/derivation files #:name name + #:symlink? derivation? #:system system #:guile guile #:deprecation-warnings deprecation-warnings) (interned-file-tree `(,name directory diff --git a/tests/gexp.scm b/tests/gexp.scm index c89d0c4855..b22e635805 100644 --- a/tests/gexp.scm +++ b/tests/gexp.scm @@ -652,16 +652,19 @@ (files -> `(("a/b/c" . ,q-scm) ("p/q" . ,plain))) (drv (imported-files files))) + (define (file=? file1 file2) + ;; Assume deduplication is in place. + (= (stat:ino (lstat file1)) + (stat:ino (lstat file2)))) + (mbegin %store-monad (built-derivations (list drv)) (mlet %store-monad ((dir -> (derivation->output-path drv)) (plain* (text-file "foo" "bar!")) (q-scm* (interned-file q-scm "c"))) (return - (and (string=? (readlink (string-append dir "/a/b/c")) - q-scm*) - (string=? (readlink (string-append dir "/p/q")) - plain*))))))) + (and (file=? (string-append dir "/a/b/c") q-scm*) + (file=? (string-append dir "/p/q") plain*))))))) (test-equal "gexp-modules & ungexp" '((bar) (foo)) -- cgit v1.2.3 From f5db54eaa51f4fdd9cec14254e413e17bfca4cca Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 16 Jul 2018 14:45:20 +0200 Subject: self: Use the new 'imported-files'. That way, the source of most nodes is now a content-addressed store item instead of a derivation. * guix/self.scm (): New record type. (file-mapping-compiler): New procedure. (scheme-node): Use 'file-mapping' instead of 'imported-files'. (imported-files): Remove. --- guix/self.scm | 57 +++++++++++++++++++++++---------------------------------- 1 file changed, 23 insertions(+), 34 deletions(-) (limited to 'guix') diff --git a/guix/self.scm b/guix/self.scm index c9c7138e65..5ad644b1df 100644 --- a/guix/self.scm +++ b/guix/self.scm @@ -112,6 +112,27 @@ GUILE-VERSION (\"2.0\" or \"2.2\"), or #f if none of the packages matches." (dependencies node-dependencies) ;list of nodes (compiled node-compiled)) ;node -> lowerable object +;; File mappings are essentially an alist as passed to 'imported-files'. +(define-record-type + (file-mapping name alist) + file-mapping? + (name file-mapping-name) + (alist file-mapping-alist)) + +(define-gexp-compiler (file-mapping-compiler (mapping ) + system target) + ;; Here we use 'imported-files', which can arrange to directly import all + ;; the files instead of creating a derivation, when possible. + (imported-files (map (match-lambda + ((destination (? local-file? file)) + (cons destination + (local-file-absolute-file-name file))) + ((destination source) + (cons destination source))) ;silliness + (file-mapping-alist mapping)) + #:name (file-mapping-name mapping) + #:system system)) + (define (node-fold proc init nodes) (let loop ((nodes nodes) (visited (setq)) @@ -166,8 +187,8 @@ must be present in the search path." (closure modules (node-modules/recursive dependencies)))) (module-files (map module->import modules)) - (source (imported-files (string-append name "-source") - (append module-files extra-files)))) + (source (file-mapping (string-append name "-source") + (append module-files extra-files)))) (node name modules source dependencies (compiled-modules name source (map car module-files) @@ -766,38 +787,6 @@ assumed to be part of MODULES." ;;; Building. ;;; -(define (imported-files name files) - ;; This is a non-monadic, simplified version of 'imported-files' from (guix - ;; gexp). - (define same-target? - (match-lambda* - (((file1 . _) (file2 . _)) - (string=? file1 file2)))) - - (define build - (with-imported-modules (source-module-closure - '((guix build utils))) - #~(begin - (use-modules (ice-9 match) - (guix build utils)) - - (mkdir (ungexp output)) (chdir (ungexp output)) - (for-each (match-lambda - ((final-path store-path) - (mkdir-p (dirname final-path)) - - ;; Note: We need regular files to be regular files, not - ;; symlinks, as this makes a difference for - ;; 'add-to-store'. - (copy-file store-path final-path))) - '#$(delete-duplicates files same-target?))))) - - ;; We're just copying files around, no need to substitute or offload it. - (computed-file name build - #:options '(#:local-build? #t - #:substitutable? #f - #:env-vars (("COLUMNS" . "200"))))) - (define* (compiled-modules name module-tree module-files #:optional (dependencies '()) -- cgit v1.2.3 From c71cd4a61fc8085ccb17169aad826d6f9ee1718b Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Thu, 19 Jul 2018 17:08:53 +0200 Subject: hash: sha256 port now implements 'port-position'. * guix/hash.scm (open-sha256-port)[position]: New variable. [get-position]: New procedure. Pass it to 'make-custom-binary-output-port'. * tests/hash.scm ("open-sha256-port, hello"): Test 'port-position'. --- guix/hash.scm | 7 ++++++- tests/hash.scm | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'guix') diff --git a/guix/hash.scm b/guix/hash.scm index 39834043e1..8d7ba21425 100644 --- a/guix/hash.scm +++ b/guix/hash.scm @@ -101,6 +101,7 @@ output port." (open-sha256-md)) (define digest #f) + (define position 0) (define (finalize!) (let ((ptr (md-read sha256-md 0))) @@ -114,14 +115,18 @@ output port." 0) (let ((ptr (bytevector->pointer bv offset))) (md-write sha256-md ptr len) + (set! position (+ position len)) len))) + (define (get-position) + position) + (define (close) (unless digest (finalize!))) (values (make-custom-binary-output-port "sha256" - write! #f #f + write! get-position #f close) (lambda () (unless digest diff --git a/tests/hash.scm b/tests/hash.scm index da87616eec..47dff3915b 100644 --- a/tests/hash.scm +++ b/tests/hash.scm @@ -64,12 +64,12 @@ (get))) (test-equal "open-sha256-port, hello" - %hello-sha256 + (list %hello-sha256 (string-length "hello world")) (let-values (((port get) (open-sha256-port))) (put-bytevector port (string->utf8 "hello world")) (force-output port) - (get))) + (list (get) (port-position port)))) (test-assert "port-sha256" (let* ((file (search-path %load-path "ice-9/psyntax.scm")) -- cgit v1.2.3 From 83099892e0cf0d9c59f5e1a0774331026e48baa8 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Thu, 19 Jul 2018 17:12:48 +0200 Subject: deduplication: Remove 'counting-wrapper-port'. * guix/store/deduplication.scm (counting-wrapper-port): Remove. (nar-sha256): Call 'port-position' directly on PORT. --- guix/store/deduplication.scm | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) (limited to 'guix') diff --git a/guix/store/deduplication.scm b/guix/store/deduplication.scm index 6ff4a50de5..8234819f14 100644 --- a/guix/store/deduplication.scm +++ b/guix/store/deduplication.scm @@ -31,37 +31,15 @@ #:export (nar-sha256 deduplicate)) -;; Would it be better to just make WRITE-FILE give size as well? I question -;; the general utility of this approach. -(define (counting-wrapper-port output-port) - "Some custom ports don't implement GET-POSITION at all. But if we want to -figure out how many bytes are being written, we will want to use that. So this -makes a wrapper around a port which implements GET-POSITION." - (let ((byte-count 0)) - (make-custom-binary-output-port "counting-wrapper" - (lambda (bytes offset count) - (set! byte-count - (+ byte-count count)) - (put-bytevector output-port bytes - offset count) - count) - (lambda () - byte-count) - #f - (lambda () - (close-port output-port))))) - (define (nar-sha256 file) "Gives the sha256 hash of a file and the size of the file in nar form." (let-values (((port get-hash) (open-sha256-port))) - (let ((wrapper (counting-wrapper-port port))) - (write-file file wrapper) - (force-output wrapper) - (force-output port) - (let ((hash (get-hash)) - (size (port-position wrapper))) - (close-port wrapper) - (values hash size))))) + (write-file file port) + (force-output port) + (let ((hash (get-hash)) + (size (port-position port))) + (close-port port) + (values hash size)))) (define (tempname-in directory) "Gives an unused temporary name under DIRECTORY. Not guaranteed to still be -- cgit v1.2.3 From 82549f2328c59525584b92565846217c288d8e85 Mon Sep 17 00:00:00 2001 From: Leo Famulari Date: Wed, 11 Jul 2018 21:08:27 -0400 Subject: build-system/go: Use invoke instead of system*. * guix/build/go-build-system.scm (unpack, build): Use invoke. (install-source): Unconditionally return #t. (check): Use invoke and unconditionally return #t. --- guix/build/go-build-system.scm | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'guix') diff --git a/guix/build/go-build-system.scm b/guix/build/go-build-system.scm index 7c833a616f..6be0167063 100644 --- a/guix/build/go-build-system.scm +++ b/guix/build/go-build-system.scm @@ -125,17 +125,17 @@ unset. When SOURCE is a directory, copy it instead of unpacking." (copy-recursively source dest #:keep-mtime? #t) #t) (if (string-suffix? ".zip" source) - (zero? (system* "unzip" "-d" dest source)) - (zero? (system* "tar" "-C" dest "-xvf" source)))))) + (invoke "unzip" "-d" dest source) + (invoke "tar" "-C" dest "-xvf" source))))) (define* (install-source #:key install-source? outputs #:allow-other-keys) "Install the source code to the output directory." (let* ((out (assoc-ref outputs "out")) (source "src") (dest (string-append out "/" source))) - (if install-source? - (copy-recursively source dest #:keep-mtime? #t) - #t))) + (when install-source? + (copy-recursively source dest #:keep-mtime? #t)) + #t)) (define (go-package? name) (string-prefix? "go-" name)) @@ -178,24 +178,26 @@ respectively." (define* (build #:key import-path #:allow-other-keys) "Build the package named by IMPORT-PATH." - (or - (zero? (system* "go" "install" - "-v" ; print the name of packages as they are compiled - "-x" ; print each command as it is invoked - ;; Respectively, strip the symbol table and debug - ;; information, and the DWARF symbol table. - "-ldflags=-s -w" - import-path)) - (begin + (with-throw-handler + #t + (lambda _ + (invoke "go" "install" + "-v" ; print the name of packages as they are compiled + "-x" ; print each command as it is invoked + ;; Respectively, strip the symbol table and debug + ;; information, and the DWARF symbol table. + "-ldflags=-s -w" + import-path)) + (lambda (key . args) (display (string-append "Building '" import-path "' failed.\n" "Here are the results of `go env`:\n")) - (system* "go" "env") - #f))) + (invoke "go" "env")))) (define* (check #:key tests? import-path #:allow-other-keys) "Run the tests for the package named by IMPORT-PATH." - (if tests? - (zero? (system* "go" "test" import-path)))) + (when tests? + (invoke "go" "test" import-path)) + #t) (define* (install #:key outputs #:allow-other-keys) "Install the compiled libraries. `go install` installs these files to -- cgit v1.2.3 From 4f89a8eec69491b925f084381ea4de37527c9310 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 20 Jul 2018 13:49:50 +0200 Subject: deduplication: Work around Guile bug in 'seek'. Fixes . Reported by Ricardo Wurmus . This mostly reverts 83099892e0cf0d9c59f5e1a0774331026e48baa8. * guix/store/deduplication.scm (counting-wrapper-port): New procedure. (nar-sha256): Use it. --- guix/store/deduplication.scm | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'guix') diff --git a/guix/store/deduplication.scm b/guix/store/deduplication.scm index 8234819f14..8c19d7309e 100644 --- a/guix/store/deduplication.scm +++ b/guix/store/deduplication.scm @@ -31,14 +31,38 @@ #:export (nar-sha256 deduplicate)) +;; XXX: This port is used as a workaround on Guile <= 2.2.4 where +;; 'port-position' throws to 'out-of-range' when the offset is great than or +;; equal to 2^32: . +(define (counting-wrapper-port output-port) + "Return two values: an output port that wraps OUTPUT-PORT, and a thunk to +retrieve the number of bytes written to OUTPUT-PORT." + (let ((byte-count 0)) + (values (make-custom-binary-output-port "counting-wrapper" + (lambda (bytes offset count) + (put-bytevector output-port bytes + offset count) + (set! byte-count + (+ byte-count count)) + count) + (lambda () + byte-count) + #f + (lambda () + (close-port output-port))) + (lambda () + byte-count)))) + (define (nar-sha256 file) "Gives the sha256 hash of a file and the size of the file in nar form." - (let-values (((port get-hash) (open-sha256-port))) - (write-file file port) + (let*-values (((port get-hash) (open-sha256-port)) + ((wrapper get-size) (counting-wrapper-port port))) + (write-file file wrapper) + (force-output wrapper) (force-output port) (let ((hash (get-hash)) - (size (port-position port))) - (close-port port) + (size (get-size))) + (close-port wrapper) (values hash size)))) (define (tempname-in directory) -- cgit v1.2.3 From e4752118691e41ae8307649d1abfd4739b3e4bfa Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 20 Jul 2018 14:49:34 +0200 Subject: database: Reset timestamps to one second after the Epoch. Previously, store items registered in the database by this code (for instance, store items retrieved by 'guix offload' and passed to 'restore-file-set') would have an mtime of 0 instead of 1. This would cause problems for things like .go files: Guile would consider them to be older than the corresponding .scm file, and consequently it would ignore them and possibly use another (incorrect) .go file. Reported by Ricardo Wurmus. * guix/store/database.scm (reset-timestamps): Pass 1, not 0, to 'utime'. * tests/store-database.scm ("register-path"): Check the mtime of FILE and REF. --- guix/store/database.scm | 8 +++++--- tests/store-database.scm | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'guix') diff --git a/guix/store/database.scm b/guix/store/database.scm index 8f35b63e37..0879a95d0b 100644 --- a/guix/store/database.scm +++ b/guix/store/database.scm @@ -190,12 +190,14 @@ Every store item in REFERENCES must already be registered." (define (reset-timestamps file) "Reset the modification time on FILE and on all the files it contains, if it's a directory. While at it, canonicalize file permissions." + ;; Note: We're resetting to one second after the Epoch like 'guix-daemon' + ;; has always done. (let loop ((file file) (type (stat:type (lstat file)))) (case type ((directory) (chmod file #o555) - (utime file 0 0 0 0) + (utime file 1 1 0 0) (let ((parent file)) (for-each (match-lambda (("." . _) #f) @@ -209,10 +211,10 @@ it's a directory. While at it, canonicalize file permissions." (type type)))))) (scandir* parent)))) ((symlink) - (utime file 0 0 0 0 AT_SYMLINK_NOFOLLOW)) + (utime file 1 1 0 0 AT_SYMLINK_NOFOLLOW)) (else (chmod file (if (executable-file? file) #o555 #o444)) - (utime file 0 0 0 0))))) + (utime file 1 1 0 0))))) (define* (register-path path #:key (references '()) deriver prefix diff --git a/tests/store-database.scm b/tests/store-database.scm index fcae66e2de..4d91884250 100644 --- a/tests/store-database.scm +++ b/tests/store-database.scm @@ -32,7 +32,8 @@ (test-begin "store-database") -(test-assert "register-path" +(test-equal "register-path" + '(1 1) (let ((file (string-append (%store-prefix) "/" (make-string 32 #\f) "-fake"))) (when (valid-path? %store file) @@ -50,7 +51,9 @@ (and (valid-path? %store file) (equal? (references %store file) (list ref)) (null? (valid-derivers %store file)) - (null? (referrers %store file)))))) + (null? (referrers %store file)) + (list (stat:mtime (lstat file)) + (stat:mtime (lstat ref))))))) (test-equal "new database" (list 1 2) -- cgit v1.2.3 From e9be2c5409f37173d70b202aa06752e3814ccdc2 Mon Sep 17 00:00:00 2001 From: Marius Bakke Date: Sun, 22 Jul 2018 18:01:35 +0200 Subject: Revert "guix: Compress and decompress xz archives in parallel." Threaded compression makes archives non-deterministic: the result depends on the number of threads used for compressing. See . This reverts commit 63102406f22412bb922de5549deb89d3594a38c0. --- guix/scripts/pack.scm | 5 ++--- guix/utils.scm | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'guix') diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm index 6d5d745bc8..729850839b 100644 --- a/guix/scripts/pack.scm +++ b/guix/scripts/pack.scm @@ -1,6 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2015, 2017, 2018 Ludovic Courtès -;;; Copyright © 2017 Efraim Flashner ;;; Copyright © 2017, 2018 Ricardo Wurmus ;;; Copyright © 2018 Konrad Hinsen ;;; Copyright © 2018 Chris Marusich @@ -69,7 +68,7 @@ (compressor "lzip" ".lz" #~(#+(file-append lzip "/bin/lzip") "-9")) (compressor "xz" ".xz" - #~(#+(file-append xz "/bin/xz") "-e -T0")) + #~(#+(file-append xz "/bin/xz") "-e")) (compressor "bzip2" ".bz2" #~(#+(file-append bzip2 "/bin/bzip2") "-9")) (compressor "none" "" #f))) @@ -77,7 +76,7 @@ ;; This one is only for use in this module, so don't put it in %compressors. (define bootstrap-xz (compressor "bootstrap-xz" ".xz" - #~(#+(file-append %bootstrap-coreutils&co "/bin/xz") "-e -T0"))) + #~(#+(file-append %bootstrap-coreutils&co "/bin/xz") "-e"))) (define (lookup-compressor name) "Return the compressor object called NAME. Error out if it could not be diff --git a/guix/utils.scm b/guix/utils.scm index 200bb69e03..9bad06d52f 100644 --- a/guix/utils.scm +++ b/guix/utils.scm @@ -5,7 +5,6 @@ ;;; Copyright © 2014 Ian Denhardt ;;; Copyright © 2016 Mathieu Lirzin ;;; Copyright © 2015 David Thompson -;;; Copyright © 2017 Efraim Flashner ;;; Copyright © 2017 Mathieu Othacehe ;;; Copyright © 2018 Marius Bakke ;;; @@ -176,7 +175,7 @@ a symbol such as 'xz." (match compression ((or #f 'none) (values input '())) ('bzip2 (filtered-port `(,%bzip2 "-dc") input)) - ('xz (filtered-port `(,%xz "-dc" "-T0") input)) + ('xz (filtered-port `(,%xz "-dc") input)) ('gzip (filtered-port `(,%gzip "-dc") input)) (else (error "unsupported compression scheme" compression)))) @@ -186,7 +185,7 @@ a symbol such as 'xz." (match compression ((or #f 'none) (values input '())) ('bzip2 (filtered-port `(,%bzip2 "-c") input)) - ('xz (filtered-port `(,%xz "-c" "-T0") input)) + ('xz (filtered-port `(,%xz "-c") input)) ('gzip (filtered-port `(,%gzip "-c") input)) (else (error "unsupported compression scheme" compression)))) @@ -243,7 +242,7 @@ program--e.g., '(\"--fast\")." (match compression ((or #f 'none) (values output '())) ('bzip2 (filtered-output-port `(,%bzip2 "-c" ,@options) output)) - ('xz (filtered-output-port `(,%xz "-c" "-T0" ,@options) output)) + ('xz (filtered-output-port `(,%xz "-c" ,@options) output)) ('gzip (filtered-output-port `(,%gzip "-c" ,@options) output)) (else (error "unsupported compression scheme" compression)))) -- cgit v1.2.3 From 2a3b1b3235f3e082d309b411465b67983bc8cf71 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Wed, 18 Jul 2018 15:38:51 +0200 Subject: build-system: Add 'guile-build-system'. * guix/build-system/guile.scm, guix/build/guile-build-system.scm: New files. * Makefile.am (MODULES): Add them. * doc/guix.texi (Build Systems): Document 'guile-build-system'. --- Makefile.am | 2 + doc/guix.texi | 15 +++ guix/build-system/guile.scm | 202 ++++++++++++++++++++++++++++++++++++++ guix/build/guile-build-system.scm | 153 +++++++++++++++++++++++++++++ 4 files changed, 372 insertions(+) create mode 100644 guix/build-system/guile.scm create mode 100644 guix/build/guile-build-system.scm (limited to 'guix') diff --git a/Makefile.am b/Makefile.am index 6733f4f894..b4cd07ed22 100644 --- a/Makefile.am +++ b/Makefile.am @@ -111,6 +111,7 @@ MODULES = \ guix/build-system/asdf.scm \ guix/build-system/glib-or-gtk.scm \ guix/build-system/gnu.scm \ + guix/build-system/guile.scm \ guix/build-system/haskell.scm \ guix/build-system/perl.scm \ guix/build-system/python.scm \ @@ -149,6 +150,7 @@ MODULES = \ guix/build/glib-or-gtk-build-system.scm \ guix/build/gnu-build-system.scm \ guix/build/gnu-dist.scm \ + guix/build/guile-build-system.scm \ guix/build/perl-build-system.scm \ guix/build/python-build-system.scm \ guix/build/ocaml-build-system.scm \ diff --git a/doc/guix.texi b/doc/guix.texi index 84347d156b..f9b3ef0e55 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -4045,6 +4045,21 @@ specified with the @code{#:glib} parameter. Both phases are executed after the @code{install} phase. @end defvr +@defvr {Scheme Variable} guile-build-system +This build system is for Guile packages that consist exclusively of Scheme +code and that are so lean that they don't even have a makefile, let alone a +@file{configure} script. It compiles Scheme code using @command{guild +compile} (@pxref{Compilation,,, guile, GNU Guile Reference Manual}) and +installs the @file{.scm} and @file{.go} files in the right place. It also +installs documentation. + +This build system supports cross-compilation by using the @code{--target} +option of @command{guild compile}. + +Packages built with @code{guile-build-system} must provide a Guile package in +their @code{native-inputs} field. +@end defvr + @defvr {Scheme Variable} minify-build-system This variable is exported by @code{(guix build-system minify)}. It implements a minification procedure for simple JavaScript packages. diff --git a/guix/build-system/guile.scm b/guix/build-system/guile.scm new file mode 100644 index 0000000000..77a5f00b01 --- /dev/null +++ b/guix/build-system/guile.scm @@ -0,0 +1,202 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2018 Ludovic Courtès +;;; +;;; 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 . + +(define-module (guix build-system guile) + #:use-module (guix store) + #:use-module (guix utils) + #:use-module (guix packages) + #:use-module (guix derivations) + #:use-module (guix search-paths) + #:use-module (guix build-system) + #:use-module (guix build-system gnu) + #:use-module (ice-9 match) + #:use-module (srfi srfi-26) + #:export (%guile-build-system-modules + guile-build-system)) + +(define %guile-build-system-modules + ;; Build-side modules imported by default. + `((guix build guile-build-system) + ,@%gnu-build-system-modules)) + +(define* (lower name + #:key source inputs native-inputs outputs system target + #:allow-other-keys + #:rest arguments) + "Return a bag for NAME." + + ;; Note: There's no #:guile argument (unlike, for instance, + ;; 'ocaml-build-system' which has #:ocaml.) This is so we can keep + ;; procedures like 'package-for-guile-2.0' unchanged and simple. + + (define private-keywords + '(#:target #:inputs #:native-inputs)) + + (bag + (name name) + (system system) (target target) + (host-inputs `( + ,@inputs)) + (build-inputs `(,@(if source + `(("source" ,source)) + '()) + ,@native-inputs + ,@(map (cute assoc <> (standard-packages)) + '("tar" "gzip" "bzip2" "xz" "locales")))) + (outputs outputs) + (build (if target guile-cross-build guile-build)) + (arguments (strip-keyword-arguments private-keywords arguments)))) + +(define %compile-flags + ;; Flags passed to 'guild compile' by default. We choose a common + ;; denominator between Guile 2.0 and 2.2. + ''("-Wunbound-variable" "-Warity-mismatch" "-Wformat")) + +(define* (guile-build store name inputs + #:key source + (guile #f) + (phases '%standard-phases) + (outputs '("out")) + (search-paths '()) + (system (%current-system)) + (source-directory ".") + (compile-flags %compile-flags) + (imported-modules %guile-build-system-modules) + (modules '((guix build guile-build-system) + (guix build utils)))) + "Build SOURCE using Guile taken from the native inputs, and with INPUTS." + (define builder + `(begin + (use-modules ,@modules) + (guile-build #:name ,name + #:source ,(match (assoc-ref inputs "source") + (((? derivation? source)) + (derivation->output-path source)) + ((source) + source) + (source + source)) + #:source-directory ,source-directory + #:compile-flags ,compile-flags + #:phases ,phases + #:system ,system + #:outputs %outputs + #:search-paths ',(map search-path-specification->sexp + search-paths) + #:inputs %build-inputs))) + + (define guile-for-build + (match guile + ((? package?) + (package-derivation store guile system #:graft? #f)) + (#f ; the default + (let* ((distro (resolve-interface '(gnu packages commencement))) + (guile (module-ref distro 'guile-final))) + (package-derivation store guile system #:graft? #f))))) + + (build-expression->derivation store name builder + #:inputs inputs + #:system system + #:modules imported-modules + #:outputs outputs + #:guile-for-build guile-for-build)) + +(define* (guile-cross-build store name + #:key + (system (%current-system)) target + native-drvs target-drvs + (guile #f) + source + (outputs '("out")) + (search-paths '()) + (native-search-paths '()) + + (phases '%standard-phases) + (source-directory ".") + (compile-flags %compile-flags) + (imported-modules %guile-build-system-modules) + (modules '((guix build guile-build-system) + (guix build utils)))) + (define builder + `(begin + (use-modules ,@modules) + + (let () + (define %build-host-inputs + ',(map (match-lambda + ((name (? derivation? drv) sub ...) + `(,name . ,(apply derivation->output-path drv sub))) + ((name path) + `(,name . ,path))) + native-drvs)) + + (define %build-target-inputs + ',(map (match-lambda + ((name (? derivation? drv) sub ...) + `(,name . ,(apply derivation->output-path drv sub))) + ((name (? package? pkg) sub ...) + (let ((drv (package-cross-derivation store pkg + target system))) + `(,name . ,(apply derivation->output-path drv sub)))) + ((name path) + `(,name . ,path))) + target-drvs)) + + (guile-build #:source ,(match (assoc-ref native-drvs "source") + (((? derivation? source)) + (derivation->output-path source)) + ((source) + source) + (source + source)) + #:system ,system + #:target ,target + #:outputs %outputs + #:source-directory ,source-directory + #:compile-flags ,compile-flags + #:inputs %build-target-inputs + #:native-inputs %build-host-inputs + #:search-paths ',(map search-path-specification->sexp + search-paths) + #:native-search-paths ',(map + search-path-specification->sexp + native-search-paths) + #:phases ,phases)))) + + (define guile-for-build + (match guile + ((? package?) + (package-derivation store guile system #:graft? #f)) + (#f ; the default + (let* ((distro (resolve-interface '(gnu packages commencement))) + (guile (module-ref distro 'guile-final))) + (package-derivation store guile system #:graft? #f))))) + + (build-expression->derivation store name builder + #:system system + #:inputs (append native-drvs target-drvs) + #:outputs outputs + #:modules imported-modules + #:substitutable? substitutable? + #:guile-for-build guile-for-build)) + +(define guile-build-system + (build-system + (name 'guile) + (description "The build system for simple Guile packages") + (lower lower))) diff --git a/guix/build/guile-build-system.scm b/guix/build/guile-build-system.scm new file mode 100644 index 0000000000..0bed049436 --- /dev/null +++ b/guix/build/guile-build-system.scm @@ -0,0 +1,153 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2018 Ludovic Courtès +;;; +;;; 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 . + +(define-module (guix build guile-build-system) + #:use-module ((guix build gnu-build-system) #:prefix gnu:) + #:use-module (guix build utils) + #:use-module (srfi srfi-26) + #:use-module (ice-9 match) + #:use-module (ice-9 popen) + #:use-module (ice-9 rdelim) + #:use-module (guix build utils) + #:export (target-guile-effective-version + %standard-phases + guile-build)) + +(define* (target-guile-effective-version #:optional guile) + "Return the effective version of GUILE or whichever 'guile' is in $PATH. +Return #false if it cannot be determined." + (let* ((pipe (open-pipe* OPEN_READ + (if guile + (string-append guile "/bin/guile") + "guile") + "-c" "(display (effective-version))")) + (line (read-line pipe))) + (and (zero? (close-pipe pipe)) + (string? line) + line))) + +(define (file-sans-extension file) ;TODO: factorize + "Return the substring of FILE without its extension, if any." + (let ((dot (string-rindex file #\.))) + (if dot + (substring file 0 dot) + file))) + +(define %scheme-file-regexp + ;; Regexp to match Scheme files. + "\\.(scm|sls)$") + +(define %documentation-file-regexp + ;; Regexp to match README files and the likes. + "^(README.*|.*\\.html|.*\\.org|.*\\.md)$") + +(define* (set-locale-path #:key inputs native-inputs + #:allow-other-keys) + "Set 'GUIX_LOCPATH'." + (match (assoc-ref (or native-inputs inputs) "locales") + (#f #t) + (locales + (setenv "GUIX_LOCPATH" (string-append locales "/lib/locale")) + #t))) + +(define* (build #:key outputs inputs native-inputs + (source-directory ".") + (compile-flags '()) + (scheme-file-regexp %scheme-file-regexp) + target + #:allow-other-keys) + "Build files in SOURCE-DIRECTORY that match SCHEME-FILE-REGEXP." + (let* ((out (assoc-ref outputs "out")) + (guile (assoc-ref (or native-inputs inputs) "guile")) + (effective (target-guile-effective-version guile)) + (module-dir (string-append out "/share/guile/site/" + effective)) + (go-dir (string-append out "/lib/guile/" + effective "/site-ccache/")) + (guild (string-append guile "/bin/guild")) + (flags (if target + (cons (string-append "--target=" target) + compile-flags) + compile-flags))) + (if target + (format #t "Cross-compiling for '~a' with Guile ~a...~%" + target effective) + (format #t "Compiling with Guile ~a...~%" effective)) + (format #t "compile flags: ~s~%" flags) + + ;; Make installation directories. + (mkdir-p module-dir) + (mkdir-p go-dir) + + ;; Compile .scm files and install. + (setenv "GUILE_AUTO_COMPILE" "0") + (setenv "GUILE_LOAD_COMPILED_PATH" + (string-append go-dir + (match (getenv "GUILE_LOAD_COMPILED_PATH") + (#f "") + (path (string-append ":" path))))) + (for-each (lambda (file) + (let* ((go (string-append go-dir + (file-sans-extension file) + ".go"))) + ;; Install source module. + (install-file (string-append source-directory "/" file) + (string-append module-dir + "/" (dirname file))) + + ;; Install and compile module. + (apply invoke guild "compile" "-L" source-directory + "-o" go + (string-append source-directory "/" file) + flags))) + + ;; Arrange to strip SOURCE-DIRECTORY from file names. + (with-directory-excursion source-directory + (find-files "." scheme-file-regexp))) + #t)) + +(define* (install-documentation #:key outputs + (documentation-file-regexp + %documentation-file-regexp) + #:allow-other-keys) + "Install files that mactch DOCUMENTATION-FILE-REGEXP." + (let* ((out (assoc-ref outputs "out")) + (doc (string-append out "/share/doc/" + (strip-store-file-name out)))) + (for-each (cut install-file <> doc) + (find-files "." documentation-file-regexp)) + #t)) + +(define %standard-phases + (modify-phases gnu:%standard-phases + (delete 'bootstrap) + (delete 'configure) + (add-before 'install-locale 'set-locale-path + set-locale-path) + (replace 'build build) + (add-after 'build 'install-documentation + install-documentation) + (delete 'check) + (delete 'strip) + (delete 'validate-runpath) + (delete 'install))) + +(define* (guile-build #:key (phases %standard-phases) + #:allow-other-keys #:rest args) + "Build the given Guile package, applying all of PHASES in order." + (apply gnu:gnu-build #:phases phases args)) -- cgit v1.2.3 From 8440db459a10daa24282038f35bc0b6771bd51ab Mon Sep 17 00:00:00 2001 From: Marius Bakke Date: Mon, 23 Jul 2018 00:25:34 +0200 Subject: import: PyPI: Update redirected URL. * guix/import/pypi.scm (guix-package->pypi-name, pypi->guix-package): Update docstrings. (pypi-package?): Test for pypi.org, too. (pypi-fetch): s/pypi.python.org/pypi.org/ * tests/pypi.scm ("guix-package->pypi-name, new URL style", "pypi->guix-package", "pypi->guix-package, wheels"): Likewise. --- guix/import/pypi.scm | 10 +++++----- tests/pypi.scm | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'guix') diff --git a/guix/import/pypi.scm b/guix/import/pypi.scm index 6beab6b010..25560bac46 100644 --- a/guix/import/pypi.scm +++ b/guix/import/pypi.scm @@ -51,8 +51,7 @@ (define (pypi-fetch name) "Return an alist representation of the PyPI metadata for the package NAME, or #f on failure." - (json-fetch-alist (string-append "https://pypi.python.org/pypi/" - name "/json"))) + (json-fetch-alist (string-append "https://pypi.org/pypi/" name "/json"))) ;; For packages found on PyPI that lack a source distribution. (define-condition-type &missing-source-error &error @@ -87,7 +86,7 @@ package." (string-append "python-" (snake-case name)))) (define (guix-package->pypi-name package) - "Given a Python PACKAGE built from pypi.python.org, return the name of the + "Given a Python PACKAGE built from pypi.org, return the name of the package on PyPI." (define (url->pypi-name url) (hyphen-package-name->name+version @@ -269,7 +268,7 @@ VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE." (license ,(license->symbol license))))))) (define (pypi->guix-package package-name) - "Fetch the metadata for PACKAGE-NAME from pypi.python.org, and return the + "Fetch the metadata for PACKAGE-NAME from pypi.org, and return the `package' s-expression corresponding to that package, or #f on failure." (let ((package (pypi-fetch package-name))) (and package @@ -304,7 +303,8 @@ VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE." "Return true if PACKAGE is a Python package from PyPI." (define (pypi-url? url) - (or (string-prefix? "https://pypi.python.org/" url) + (or (string-prefix? "https://pypi.org/" url) + (string-prefix? "https://pypi.python.org/" url) (string-prefix? "https://pypi.io/packages" url))) (let ((source-url (and=> (package-source package) origin-uri)) diff --git a/tests/pypi.scm b/tests/pypi.scm index 74f13e9662..310c6c8f29 100644 --- a/tests/pypi.scm +++ b/tests/pypi.scm @@ -89,7 +89,7 @@ baz > 13.37") (dummy-package "foo" (source (dummy-origin (uri - "https://pypi.python.org/packages/a2/3b/4756e6a0ceb14e084042a2a65c615d68d25621c6fd446d0fc10d14c4ce7d/certbot-0.8.1.tar.gz")))))) + "https://pypi.org/packages/a2/3b/4756e6a0ceb14e084042a2a65c615d68d25621c6fd446d0fc10d14c4ce7d/certbot-0.8.1.tar.gz")))))) (test-equal "guix-package->pypi-name, several URLs" "cram" @@ -120,7 +120,7 @@ baz > 13.37") (mock ((guix http-client) http-fetch (lambda (url . rest) (match url - ("https://pypi.python.org/pypi/foo/json" + ("https://pypi.org/pypi/foo/json" (values (open-input-string test-json) (string-length test-json))) ("https://example.com/foo-1.0.0-py2.py3-none-any.whl" #f) @@ -182,7 +182,7 @@ baz > 13.37") (mock ((guix http-client) http-fetch (lambda (url . rest) (match url - ("https://pypi.python.org/pypi/foo/json" + ("https://pypi.org/pypi/foo/json" (values (open-input-string test-json) (string-length test-json))) ("https://example.com/foo-1.0.0-py2.py3-none-any.whl" #f) -- cgit v1.2.3