diff --git a/CODEOWNERS b/CODEOWNERS index 2daec3630cc..719f871e8ce 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -13,6 +13,7 @@ gnu/packages/fluidplug\.scm @guix/audio gnu/packages/music\.scm @guix/audio gnu/packages/xiph\.scm @guix/audio +gnu/packages/beam-.+\.scm$ @guix/beam gnu/packages/elixir(-.+|)\.scm$ @guix/beam guix/build/mix-build-system\.scm @guix/beam guix/build-system/mix\.scm @guix/beam @@ -20,7 +21,12 @@ gnu/packages/erlang(-.+|)\.scm$ @guix/beam guix/build/rebar-build-system\.scm @guix/beam guix/build-system/rebar\.scm @guix/beam guix/import/hexpm\.scm @guix/beam +guix/import/mix\.scm @guix/beam +guix/import/mix/mix-lock\.scm @guix/beam guix/scripts/import/hexpm\.scm @guix/beam +guix/scripts/import/mix\.scm @guix/beam +tests/import/hexpm\.scm @guix/beam +tests/import/mix\.scm @guix/beam gnu/packages/bioinformatics\.scm @guix/bioinformatics diff --git a/Makefile.am b/Makefile.am index 976c5cad742..0a9ec3113bc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,6 +22,7 @@ # Copyright © 2024 gemmaro # Copyright © 2025 Brice Waegeneire # Copyright © 2025 Florian Pelz +# Copyright © 2025 Igorj Gorjaĉev # # This file is part of GNU Guix. # @@ -320,6 +321,8 @@ MODULES = \ guix/import/launchpad.scm \ guix/import/luanti.scm \ guix/import/minetest.scm \ + guix/import/mix.scm \ + guix/import/mix/mix-lock.scm \ guix/import/nuget.scm \ guix/import/npm-binary.scm \ guix/import/opam.scm \ @@ -377,6 +380,7 @@ MODULES = \ guix/scripts/import/json.scm \ guix/scripts/import/luanti.scm \ guix/scripts/import/minetest.scm \ + guix/scripts/import/mix.scm \ guix/scripts/import/npm-binary.scm \ guix/scripts/import/nuget.scm \ guix/scripts/import/opam.scm \ @@ -577,6 +581,7 @@ SCM_TESTS = \ tests/import/hackage.scm \ tests/import/hexpm.scm \ tests/import/luanti.scm \ + tests/import/mix.scm \ tests/import/npm-binary.scm \ tests/import/nuget.scm \ tests/import/opam.scm \ diff --git a/doc/guix-cookbook.texi b/doc/guix-cookbook.texi index 83bce66c175..8d5c7187fee 100644 --- a/doc/guix-cookbook.texi +++ b/doc/guix-cookbook.texi @@ -29,6 +29,7 @@ Copyright @copyright{} 2025 45mg@* Copyright @copyright{} 2023 Marek Felšöci@* Copyright @copyright{} 2023 Konrad Hinsen@* Copyright @copyright{} 2023 Philippe Swartvagher@* +Copyright @copyright{} 2026 Igorj Gorjaĉev@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -140,6 +141,7 @@ Programmable and automated package definition Packaging Workflows * Packaging Rust Crates:: +* Packaging Elixir Applications:: Packaging Rust Crates @@ -1632,6 +1634,7 @@ systems, serving as extensions to the concise packaging guidelines @menu * Packaging Rust Crates:: +* Packaging Elixir Applications:: @end menu @node Packaging Rust Crates @@ -1987,6 +1990,108 @@ method, one of the most popular choices for Traditional Chinese users.") (license license:lgpl2.1+))) @end lisp +@node Packaging Elixir Applications +@subsection Packaging Elixir Applications + +In preparation, add the following packages to your environment: + +@example +$ guix shell elixir elixir-depscheck elixir-mix-audit +@end example + +In this example, we package @uref{https://livebook.dev, livebook}, +which is an interactive, web-based notebook environment for writing, +running, and sharing Elixir code with rich documentation and +visualizations. + +@enumerate +@item +We retrieve the @code{livebook} source code with the latest version +from the corresponding @code{git} repository: + +@example +$ git clone --branch v0.18.2 --depth 1 \ + https://github.com/livebook-dev/livebook +@end example + +We should prepare the following definiton for this package (the suggested +location for this definition should be @code{gnu/packages/beam-packages.scm} +or up to your mind): + +@lisp +(define-public livebook + (package + (name "livebook") + (version "0.18.2") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/livebook-dev/livebook") + (commit (string-append "v" version)))) + (file-name (git-file-name name version)) + (sha256 + (base32 + "1pq227nabslr7gh4qvg24wj4320djc0vrh6x6l23g3468x6znxjm")))) + (build-system mix-build-system) + (arguments + (list + #:tests? #f ; TODO: make them work a little bit later + #:vendorize? #t + #:phases + #~(modify-phases %standard-phases + (replace 'install + (lambda* (#:key outputs #:allow-other-keys) + (let ((out (assoc-ref outputs "out"))) + (copy-recursively "_build/prod/rel/livebook/" + out))))))) + (inputs (mix-inputs 'livebook)) + (synopsis "Web application for writing code notebooks") + (description "This package provides @code{Livebook}, a web application +for writing interactive and collaborative code notebooks.") + (home-page "https://livebook.dev/") + (license license:asl2.0))) +@end lisp + +The identifier used to invoke @code{mix-inputs}, in this case the scheme +symbol @code{'livebook}, must be unique, usually matching the variable name +of the package. + +@item +Navigate to the unpacked directory, then run the following commands: + +@example +$ mix deps.get +$ mix deps.audit +$ mix depscheck --verbose +@end example + +@command{mix deps.audit} checks known vulnerabilities and @command{mix +depscheck --verbose} checks licenses, for all the dependencies. We must +have an acceptable output (i.e. message ``No vulnerabilities found.'') of +@command{mix deps.audit} and ensure all dependencies are licensed with our +supported licenses (@pxref{Defining Packages,,, guix, GNU Guix Reference Manual}). + +@item +Import dependencies from the lockfile: + +@example +$ guix import --insert=gnu/packages/beam-packages.scm \ + mix --lockfile=/path/to/mix.lock livebook + +# or: +$ guix import -i gnu/packages/beam-packages.scm \ + mix -f /path/to/mix.lock livebook +@end example + +After that the package could be build by using the following command: + +@example +$ guix build livebook +@end example + +@end enumerate + @c ********************************************************************* @node System Configuration diff --git a/doc/guix.texi b/doc/guix.texi index 733c86afac1..7d5f7009054 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -151,6 +151,7 @@ Copyright @copyright{} 2025 Noé Lopez@* Copyright @copyright{} 2026 David Elsing@* Copyright @copyright{} 2026 Nguyễn Gia Phong@* Copyright @copyright{} 2026 Yarl Baudig@* +Copyright @copyright{} 2026 Igorj Gorjaĉev@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -15388,6 +15389,31 @@ Additional options include: Traverse the dependency graph of the given upstream package recursively and generate package expressions for all those packages that are not yet in Guix. +@item --mix-inputs +@itemx -m +Use vendored @code{mix-inputs} for @code{input} field instead of common +dependencies. +@end table + +@item mix +@cindex mix +Import metadata from the @file{mix.lock}, Elixir's +@uref{https://hexdocs.pm/elixir/introduction-to-mix.html, mix} lock file, +as in this example: + +@example +guix import mix -f mix.lock yourapp +@end example + +Mandatory options are: + +@table @code +@item --lockfile=@var{file} +@itemx -f @var{file} +@option{--lockfile} must be a @file{mix.lock} file. + +@xref{Packaging Elixir Applications,,, guix-cookbook, GNU Guix Cookbook}, for +packaging workflow utilizing it. @end table @end table diff --git a/etc/teams.scm b/etc/teams.scm index c26a0c11f83..49029ed2feb 100755 --- a/etc/teams.scm +++ b/etc/teams.scm @@ -482,15 +482,21 @@ already exists. Lookup team IDs among CURRENT-TEAMS." #:name "Erlang/Elixir/BEAM team" #:description "The virtual machine at the core of the Erlang Open Telecom Platform (OTP), Erlang and Elxir languages and packages, development -of Rebar and Mix build systems and Hex.pm importer." - #:scope (list (make-regexp* "^gnu/packages/elixir(-.+|)\\.scm$") +of Rebar and Mix build systems, Hex.pm and Mix importers." + #:scope (list (make-regexp* "^gnu/packages/beam-.+\\.scm$") + (make-regexp* "^gnu/packages/elixir(-.+|)\\.scm$") "guix/build/mix-build-system.scm" "guix/build-system/mix.scm" (make-regexp* "^gnu/packages/erlang(-.+|)\\.scm$") "guix/build/rebar-build-system.scm" "guix/build-system/rebar.scm" "guix/import/hexpm.scm" - "guix/scripts/import/hexpm.scm"))) + "guix/import/mix.scm" + "guix/import/mix/mix-lock.scm" + "guix/scripts/import/hexpm.scm" + "guix/scripts/import/mix.scm" + "tests/import/hexpm.scm" + "tests/import/mix.scm"))) (define-team bioinformatics (team 'bioinformatics diff --git a/gnu/local.mk b/gnu/local.mk index bec862195cc..1663548db7b 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -75,6 +75,7 @@ # Copyright © 2025 Nigko Yerden # Copyright © 2025 Cayetano Santos # Copyright © 2025 bdunahu +# Copyright © 2025 Igorj Gorjaĉev # # This file is part of GNU Guix. # @@ -175,6 +176,9 @@ GNU_SYSTEM_MODULES = \ %D%/packages/bash.scm \ %D%/packages/batik.scm \ %D%/packages/bdw-gc.scm \ + %D%/packages/beam-apps.scm \ + %D%/packages/beam-packages.scm \ + %D%/packages/beam-sources.scm \ %D%/packages/benchmark.scm \ %D%/packages/bioconductor.scm \ %D%/packages/bioinformatics.scm \ diff --git a/gnu/packages/beam-apps.scm b/gnu/packages/beam-apps.scm new file mode 100644 index 00000000000..0fa7b96307f --- /dev/null +++ b/gnu/packages/beam-apps.scm @@ -0,0 +1,25 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2025 Igorj Gorjaĉev +;;; +;;; 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 (gnu packages beam-apps) + #:use-module ((guix licenses) #:prefix license:) + #:use-module (guix gexp) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix git-download) + #:use-module (guix build-system mix)) diff --git a/gnu/packages/beam-packages.scm b/gnu/packages/beam-packages.scm new file mode 100644 index 00000000000..3144afb1486 --- /dev/null +++ b/gnu/packages/beam-packages.scm @@ -0,0 +1,43 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2025 Igorj Gorjaĉev +;;; +;;; 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 (gnu packages beam-packages) + #:use-module (guix gexp) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix git-download) + #:use-module (guix build-system mix) + #:use-module (gnu packages beam-sources) + #:export (lookup-mix-inputs)) + +;;; +;;; This file is managed by ‘guix import’. Do NOT add definitions manually. +;;; +;;; BEAM libraries fetched from hex.pm. +;;; + +(define aaaa-separator 'begin-of-beam-packages) + +(define cccc-separator 'end-of-beam-packages) + + +;;; +;;; Mix inputs. +;;; + +(define-mix-inputs lookup-mix-inputs) diff --git a/gnu/packages/beam-sources.scm b/gnu/packages/beam-sources.scm new file mode 100644 index 00000000000..efc2db9606e --- /dev/null +++ b/gnu/packages/beam-sources.scm @@ -0,0 +1,29 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2025 Igorj Gorjaĉev +;;; +;;; 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 (gnu packages beam-sources) + #:use-module (guix gexp) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix git-download) + #:use-module (guix build-system mix)) + +;;; +;;; BEAM libraries requiring modification. +;;; These packages are hidden, as they are not interesting to users. +;;; diff --git a/guix/build-system/mix.scm b/guix/build-system/mix.scm index 224f4ff94ca..709fed017f7 100644 --- a/guix/build-system/mix.scm +++ b/guix/build-system/mix.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2023 Pierre-Henry Fröhring ;;; Copyright © 2025 Giacomo Leidi +;;; Copyright © 2025 Igorj Gorjaĉev ;;; ;;; This file is part of GNU Guix. ;;; @@ -28,7 +29,10 @@ #:use-module (guix build mix-build-system) #:use-module (guix build-system gnu) #:use-module (guix build-system) + #:use-module (guix diagnostics) + #:use-module (guix download) #:use-module (guix gexp) + #:use-module (guix i18n) #:use-module (guix monads) #:use-module (guix packages) #:use-module (guix search-paths) @@ -37,7 +41,12 @@ #:use-module (ice-9 match) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) - #:export (mix-build-system hexpm-uri)) + #:export (mix-build-system + hexpm-uri + beam-name->package-name + hexpm-source + define-mix-inputs + mix-inputs)) (define (default-elixir-hex) (@* (gnu packages elixir) elixir-hex)) @@ -64,6 +73,48 @@ See: https://github.com/hexpm/specifications/blob/main/endpoints.md" strip-prefix) name)) +(define (beam-name->package-name name) + (downstream-package-name "beam-" name)) + +;; NOTE: Only use this procedure in (gnu packages beam-packages). +(define* (hexpm-source package-name hexpm-name hexpm-version hexpm-hash + #:key (patches '()) (snippet #f)) + (origin + (method url-fetch) + (uri (hexpm-uri hexpm-name hexpm-version)) + (file-name + (string-append "beam-" package-name "-" hexpm-version ".tar")) + (sha256 (base32 hexpm-hash)) + (modules '((guix build utils))) + (patches patches) + (snippet snippet))) + +(define-syntax define-mix-inputs + (syntax-rules (=>) + ((_ lookup inputs ...) + (define lookup + (let ((table (make-hash-table))) + (letrec-syntax ((record + (syntax-rules (=>) + ((_) #t) + ((_ (name => lst) rest (... ...)) + (begin + (hashq-set! table 'name (filter identity lst)) + (record rest (... ...))))))) + (record inputs ...) + (lambda (name) + "Return the inputs for NAME." + (hashq-ref table name)))))))) + +(define* (mix-inputs name #:key (module '(gnu packages beam-packages))) + "Lookup Mix inputs for NAME defined in MODULE, return an empty list if +unavailable." + (let ((lookup (module-ref (resolve-interface module) 'lookup-mix-inputs))) + (or (lookup name) + (begin + (warning (G_ "no Mix inputs available for '~a'~%") name) + '())))) + ;; A number of environment variables specific to the Mix build system are ;; reflected here. They are documented at ;; https://hexdocs.pm/mix/Mix.html#module-environment-variables. Other @@ -75,6 +126,9 @@ See: https://github.com/hexpm/specifications/blob/main/endpoints.md" source (tests? #t) (test-flags ''()) + (vendorize? #f) + (vendor-symlinks? #t) + (vendor-dir "guix-vendor") (mix-path #f) ;See MIX_PATH. (mix-exs "mix.exs") ;See MIX_EXS. (build-per-environment #t) ;See :build_per_environment. @@ -110,6 +164,9 @@ See: https://github.com/hexpm/specifications/blob/main/endpoints.md" #:system #$system #:tests? #$tests? #:test-flags #$test-flags + #:vendorize? #$vendorize? + #:vendor-symlinks? #$vendor-symlinks? + #:vendor-dir #$vendor-dir #:mix-path #$mix-path #:mix-exs #$mix-exs #:mix-environments '#$mix-environments diff --git a/guix/build/mix-build-system.scm b/guix/build/mix-build-system.scm index f16fb1eaae9..7a68b28559e 100644 --- a/guix/build/mix-build-system.scm +++ b/guix/build/mix-build-system.scm @@ -1,6 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2023 Pierre-Henry Fröhring -;;; Copyright © 2024, 2026 Igorj Gorjaĉev +;;; Copyright © 2024-2026 Igorj Gorjaĉev ;;; Copyright © 2024, 2025 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. @@ -48,7 +48,13 @@ VERSION are installed." (string-append path "/lib/elixir/" version)) -(define* (strip-prefix name #:optional (prefix "elixir-")) +(define %elixir-prefix "elixir-") + +(define %beam-prefix "beam-") + +(define %vendorize-env-var "GUIX_MIX_VENDOR_DIR") + +(define* (strip-prefix name #:optional (prefix %elixir-prefix)) "Return NAME without the prefix PREFIX." (if (string-prefix? prefix name) (string-drop name (string-length prefix)) @@ -83,9 +89,73 @@ working directory." (define (list-directories dir) "List absolute paths of directories directly under the directory DIR." (map (cute string-append dir "/" <>) - (scandir dir (lambda (filename) - (and (not (member filename '("." ".."))) - (directory-exists? (string-append dir "/" filename))))))) + (scandir + dir (lambda (filename) + (and (not (member filename '("." ".."))) + (directory-exists? (string-append dir "/" filename))))))) + +(define* (unpack-vendorize #:key vendorize? vendor-dir inputs + #:allow-other-keys) + "Unpack vendored packages." + (define (inputs->beam-inputs inputs) + "Filter using the label part from INPUTS." + (filter-map (lambda (input) + (match input + ((name . file) + (and (beam-package? name) file)))) + inputs)) + (define (beam-input->upstream-name beam-input) + "Convert BEAM-INPUT into upstream package name." + ((compose + (cute package-name->elixir-name <> %beam-prefix) + (cute substring <> 33) + basename) + beam-input)) + (define (copy-or-unpack-beam-package beam-input dep-dir) + "Copy contents, if BEAM-INPUT is a checkout package, otherwise unpack it." + (or (directory-exists? dep-dir) + (if (file-is-directory? beam-input) + (copy-recursively beam-input dep-dir) + (begin + (mkdir-p dep-dir) + (invoke "sh" "-c" + (string-append "tar -xOf " beam-input + " contents.tar.gz" + " | tar -xz -C " dep-dir)))))) + (and + vendorize? + (begin + (mkdir-p vendor-dir) + (setenv %vendorize-env-var (canonicalize-path vendor-dir)) + (let ((beam-inputs (delete-duplicates (inputs->beam-inputs inputs)))) + (unless (null? beam-inputs) + (for-each + (lambda (beam-input) + (let* ((upstream-name (beam-input->upstream-name beam-input)) + (dep-dir (string-append vendor-dir "/" upstream-name))) + (copy-or-unpack-beam-package beam-input dep-dir))) + beam-inputs)))))) + +(define* (symlink-vendorize #:key vendorize? vendor-symlinks? + #:allow-other-keys) + (and + vendorize? + vendor-symlinks? + (let* ((vendor-dir (getenv %vendorize-env-var)) + (deps-dir (list-directories vendor-dir))) + (for-each + (lambda (dep-dir) + (let ((snapshot (string-contains dep-dir "_snapshot"))) + (and + snapshot + (let ((canonical + (string-drop-right + dep-dir (- (string-length dep-dir) snapshot)))) + (symlink dep-dir canonical))))) + deps-dir)))) + +(define (beam-package? name) + (string-prefix? %beam-prefix name)) (define* (set-mix-env #:key inputs mix-path mix-exs #:allow-other-keys) "Set environment variables. @@ -113,22 +183,32 @@ See: https://hexdocs.pm/mix/1.15.7/Mix.html#module-environment-variables" (%elixir-version (elixir-version inputs)) (format #t "Elixir version: ~a~%" (%elixir-version))) -(define* (build #:key mix-environments #:allow-other-keys) + +(define* (build #:key mix-environments vendorize? + #:allow-other-keys) "Builds the Mix project." (for-each (lambda (mix-env) (setenv "MIX_ENV" mix-env) - (invoke "mix" "compile" "--no-deps-check" - "--no-prune-code-paths")) + (if vendorize? + (invoke "mix" "release") + (invoke "mix" "compile" "--no-prune-code-paths" + "--no-deps-check"))) mix-environments)) -(define* (check #:key (tests? #t) (test-flags '()) #:allow-other-keys) +(define* (check #:key (tests? #t) (test-flags '()) + vendorize? + #:allow-other-keys) "Test the Mix project." (if tests? - (begin + (let ((maybe-no-deps-check-flag + (if vendorize? '() '("--no-deps-check")))) (setenv "MIX_ENV" "test") - (apply invoke "mix" "do" "compile" "--no-deps-check" - "--no-prune-code-paths" "+" "test" - "--no-deps-check" test-flags)) + (apply invoke + (append '("mix" "do" "compile") + maybe-no-deps-check-flag + '("--no-prune-code-paths" "+" "test") + maybe-no-deps-check-flag + test-flags))) (format #t "tests? = ~a~%" tests?))) (define* (remove-mix-dirs . _) @@ -137,7 +217,7 @@ We do not want to copy them to the installation directory." (for-each delete-file-recursively (find-files "." (file-name-predicate "\\.mix$") #:directories? #t))) -(define (package-name->elixir-name name+ver) +(define* (package-name->elixir-name name+ver #:optional (prefix %elixir-prefix)) "Convert the Guix package NAME-VER to the corresponding Elixir name-version format. Example: elixir-a-pkg-1.2.3 -> a_pkg or elixir-a-pkg-0.0.0-0.e51e36e -> a_pkg" @@ -146,7 +226,7 @@ format. Example: elixir-a-pkg-1.2.3 -> a_pkg or elixir-a-pkg-0.0.0-0.e51e36e (cute string-join <> "_") (cute drop-right <> (if git-version? 2 1)) (cute string-split <> #\-)) - (strip-prefix name+ver))) + (strip-prefix name+ver prefix))) (define* (install #:key inputs @@ -155,13 +235,24 @@ format. Example: elixir-a-pkg-1.2.3 -> a_pkg or elixir-a-pkg-0.0.0-0.e51e36e build-per-environment #:allow-other-keys) "Install build artifacts in the store." - (let* ((lib-name (package-name->elixir-name name)) - (lib-dir (string-append (elixir-libdir (assoc-ref outputs "out")) "/" lib-name)) - (root (getenv "MIX_BUILD_ROOT")) - (env (if build-per-environment "prod" "shared"))) - (mkdir-p lib-dir) - (copy-recursively (string-append (mix-build-dir root env) "/" lib-name) lib-dir - #:follow-symlinks? #t))) + (if (beam-package? name) + (let* ((out (assoc-ref outputs "out")) + (excluded '("CHECKSUM" "contents.tar.gz" "environment-variables" + "metadata.config" "VERSION")) + (files + (filter + (lambda (f) + (not (member f (cons* "." ".." excluded)))) + (scandir ".")))) + (mkdir-p out) + (apply invoke "cp" "-r" (append files (list out)))) + (let* ((lib-name (package-name->elixir-name name)) + (lib-dir (string-append (elixir-libdir (assoc-ref outputs "out")) "/" lib-name)) + (root (getenv "MIX_BUILD_ROOT")) + (env (if build-per-environment "prod" "shared"))) + (mkdir-p lib-dir) + (copy-recursively (string-append (mix-build-dir root env) "/" lib-name) lib-dir + #:follow-symlinks? #t)))) (define %standard-phases (modify-phases gnu:%standard-phases @@ -170,6 +261,8 @@ format. Example: elixir-a-pkg-1.2.3 -> a_pkg or elixir-a-pkg-0.0.0-0.e51e36e (add-after 'install-locale 'set-mix-env set-mix-env) (add-after 'set-mix-env 'set-elixir-version set-elixir-version) (replace 'unpack unpack) + (add-after 'unpack 'unpack-vendorize unpack-vendorize) + (add-after 'unpack-vendorize 'symlink-vendorize symlink-vendorize) (replace 'build build) (replace 'check check) (add-before 'install 'remove-mix-dirs remove-mix-dirs) diff --git a/guix/import/hexpm.scm b/guix/import/hexpm.scm index 885e416fea6..e0b2ac8de1d 100644 --- a/guix/import/hexpm.scm +++ b/guix/import/hexpm.scm @@ -177,33 +177,37 @@ as symbols." (define* (make-hexpm-sexp #:key name version tarball-url home-page synopsis description license language build-system dependencies + mix-inputs? #:allow-other-keys) "Return the `package' s-expression for a hexpm package with the given NAME, VERSION, TARBALL-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE. The created package's name will stem from LANGUAGE. BUILD-SYSTEM defined the -build-system, and DEPENDENCIES the inputs for the package." - (call-with-temporary-output-file - (lambda (temp port) - (and (url-fetch tarball-url temp) - (values - `(package - (name ,(hexpm-name->package-name name language)) - (version ,version) - (source (origin - (method url-fetch) - (uri (hexpm-uri ,name version)) - (sha256 (base32 ,(guix-hash-url temp))))) - (build-system ,build-system) - ,@(maybe-inputs (dependencies->package-names dependencies) 'inputs) - (synopsis ,synopsis) - (description ,(beautify-description description)) - (home-page ,(match home-page - (() "") - (_ home-page))) - (license ,(match license - (() #f) - ((license) license) - (_ `(list ,@license)))))))))) +build-system, and DEPENDENCIES or MIX-INPUTS? the inputs for the package." + (let ((package-name (hexpm-name->package-name name language))) + (call-with-temporary-output-file + (lambda (temp port) + (and (url-fetch tarball-url temp) + (values + `(package + (name ,package-name) + (version ,version) + (source (origin + (method url-fetch) + (uri (hexpm-uri ,name version)) + (sha256 (base32 ,(guix-hash-url temp))))) + (build-system ,build-system) + ,@(if mix-inputs? + `((inputs (mix-inputs ',(string->symbol package-name)))) + (maybe-inputs (dependencies->package-names dependencies) 'inputs)) + (synopsis ,synopsis) + (description ,(beautify-description description)) + (home-page ,(match home-page + (() "") + (_ home-page))) + (license ,(match license + (() #f) + ((license) license) + (_ `(list ,@license))))))))))) (define (strings->licenses strings) "Convert the list of STRINGS into a list of license objects." @@ -221,11 +225,13 @@ object, ordered from newest to oldest." (sort (map hexpm-version-number (hexpm-versions package)) version>?)) -(define* (hexpm->guix-package package-name #:key version #:allow-other-keys) - "Fetch the metadata for PACKAGE-NAME from hexpms.io, and return the +(define* (hexpm->guix-package package-name #:key version + mix-inputs? #:allow-other-keys) + "Fetch the metadata for PACKAGE-NAME from hex.pm, and return the `package' s-expression corresponding to that package, or #f on failure. When VERSION is specified, attempt to fetch that version; otherwise fetch the -latest version of PACKAGE-NAME." +latest version of PACKAGE-NAME. It can use `inputs` with `mix-inputs` when +MIX-INPUTS? is specified." (define package (lookup-hexpm package-name)) @@ -277,6 +283,7 @@ latest version of PACKAGE-NAME." #:name package-name #:version version-number #:dependencies dependencies + #:mix-inputs? mix-inputs? #:home-page (or (and (not (eq? docs-html-url 'null)) docs-html-url) ;; TODO: Homepage? diff --git a/guix/import/mix.scm b/guix/import/mix.scm new file mode 100644 index 00000000000..89a6e6fa4e9 --- /dev/null +++ b/guix/import/mix.scm @@ -0,0 +1,143 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2025 Igorj Gorjaĉev +;;; +;;; 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 mix) + #:use-module (guix import mix mix-lock) + #:use-module (guix base16) + #:use-module (guix base32) + #:use-module (guix read-print) + #:use-module (guix scripts download) + #:autoload (guix utils) (find-definition-location) + #:use-module (ice-9 match) + #:use-module (ice-9 textual-ports) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (srfi srfi-71) + #:use-module (guix build-system mix) + #:export (mix-lock->expressions + mix-inputs-from-lockfile + find-mix-inputs-location + extract-mix-inputs)) + + +;;; +;;; Convert ‘mix.lock’ to Guix sources. +;;; + +(define (mix-lock->expressions lockfile package-name) + "Given LOCKFILE, a 'mix.lock' file, import its content as source +expressions. Return a source list and a mix inputs entry for PACKAGE-NAME +referencing all imported sources." + (define (mix-lock-entry->guix-source mix-lock-entry) + (match mix-lock-entry + (('mix-lock-entry + ('entry-name entry-name) + ('entry-hexpm + ('hexpm-name hexpm-name) + ('hexpm-version hexpm-version) + _ + ('hexpm-checksum hexpm-checksum))) + `(define + ,(string->symbol + (string-append + (beam-name->package-name entry-name) "-" hexpm-version)) + (hexpm-source ,entry-name ,hexpm-name ,hexpm-version + ,(bytevector->nix-base32-string + (base16-string->bytevector hexpm-checksum))))) + ;; Git snapshot. + (('mix-lock-entry + ('entry-name entry-name) + ('entry-git + ('git-url git-url) + ('git-commit git-commit))) + (begin + (let* ((version (string-append "snapshot." (string-take git-commit 7))) + (checksum + (second + (string-split + (with-output-to-string + (lambda _ + (guix-download "-g" git-url + (string-append "--commit=" git-commit)))) + #\newline)))) + `(define + ,(string->symbol + (string-append + (beam-name->package-name entry-name) "-" version)) + (origin + (method git-fetch) + (uri (git-reference + (url ,git-url) + (commit ,git-commit))) + (file-name + (git-file-name + ,(beam-name->package-name entry-name) ,version)) + (sha256 (base32 ,checksum))))))) + (else #f))) + + (let* ((source-expressions + (filter-map mix-lock-entry->guix-source + (mix-lock-string->scm + (call-with-input-file lockfile get-string-all)))) + (beam-inputs-entry + `(,(string->symbol package-name) => + (list ,@(map second source-expressions))))) + (values source-expressions beam-inputs-entry))) + +(define* (mix-inputs-from-lockfile #:optional (lockfile "mix.lock")) + "Given LOCKFILE (default to \"mix.lock\" in current directory), return a +source list imported from it, to be used as package inputs. This procedure +can be used for adding a manifest file within the source tree of a BEAM +application." + (let ((source-expressions + mix-inputs-entry + (mix-lock->expressions lockfile "mix-inputs-temporary"))) + (eval-string + (call-with-output-string + (lambda (port) + (for-each + (cut pretty-print-with-comments port <>) + `((use-modules (guix build-system mix)) + ,@source-expressions + (define-mix-inputs lookup-mix-inputs ,mix-inputs-entry) + (lookup-mix-inputs 'mix-inputs-temporary)))))))) + +(define (find-mix-inputs-location file) + "Search in FILE for a top-level definition of mix inputs. Return the +location if found, or #f otherwise." + (find-definition-location file 'lookup-mix-inputs + #:define-prefix 'define-mix-inputs)) + +(define* (extract-mix-inputs file #:key exclude) + "Search in FILE for a top-level definition of mix inputs. If found, +return its entries excluding EXCLUDE, or an empty list otherwise." + (call-with-input-file file + (lambda (port) + (do ((syntax (read-syntax port) + (read-syntax port))) + ((match (syntax->datum syntax) + (('define-mix-inputs 'lookup-mix-inputs _ ...) #t) + ((? eof-object?) #t) + (_ #f)) + (or (and (not (eof-object? syntax)) + (match (syntax->datum syntax) + (('define-mix-inputs 'lookup-mix-inputs inputs ...) + (remove (lambda (mix-input-entry) + (eq? exclude (first mix-input-entry))) + inputs)))) + '())))))) diff --git a/guix/import/mix/mix-lock.scm b/guix/import/mix/mix-lock.scm new file mode 100644 index 00000000000..4d2c9ecec50 --- /dev/null +++ b/guix/import/mix/mix-lock.scm @@ -0,0 +1,201 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2025 Igorj Gorjaĉev +;;; +;;; 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 mix mix-lock) + #:use-module (ice-9 peg) + #:export (mix-lock-string->scm + + entry-git + entry-hexpm + entry-name + git-commit + git-url + hexpm-build-system + hexpm-build-systems + hexpm-name + hexpm-version + mix-lock + mix-lock-entry)) + +;;; +;;; PEG parser for ‘mix.lock’. +;;; + +(define (mix-lock-string->scm str) + (peg:tree (search-for-pattern mix-lock str))) + +;; Auxiliar peg patterns +(define-peg-pattern numeric-char body + (range #\0 #\9)) + +(define-peg-pattern lowercase-char body + (range #\a #\z)) + +(define-peg-pattern uppercase-char body + (range #\A #\Z)) + +(define-peg-pattern alphabetic-char body + (or lowercase-char uppercase-char)) + +(define-peg-pattern alphanumeric-char body + (or alphabetic-char numeric-char)) + +(define-peg-pattern space-char body + (+ (or " " "\t" "\n" "\r"))) + +(define-peg-pattern opt-space-char body + (* space-char)) + +;; string: "string" +(define-peg-pattern string-char body + (or alphanumeric-char + space-char + "_" "." "~" "=" "<" ">" "/" ":" "-")) + +(define-peg-pattern string body + (and (ignore "\"") + (* string-char) + (ignore "\""))) + +;; atom: :hex or true | false | nil +(define-peg-pattern atom-char body + (or alphanumeric-char "_" "@" "?" "!")) + +(define-peg-pattern atom body + (or + (and (ignore ":") + (+ atom-char)) + "true" "false" "nil")) + +;; list: [ ... ] +(define-peg-pattern list body + (and (ignore "[") + (* (and + (ignore (? ", ")) + (or value key-value))) + (ignore "]"))) + +;; tuple: { ... } +(define-peg-pattern tuple body + (and (ignore "{") + (* (and + (ignore (? ", ")) + value)) + (ignore "}") + (ignore (? "\n")))) + +;; syntactic sugar for [{key, value} ...] +(define-peg-pattern key-value body + (ignore + (and (+ atom-char) ": " value))) + +;; value may be string, atom, tuple, list +(define-peg-pattern value body + (and (ignore opt-space-char) + (or string atom tuple list) + (ignore opt-space-char))) + +;; ignore several constructions +(define-peg-pattern ignore-string body + (ignore + (and "\"" + (* (or string-char + space-char)) + "\""))) + +(define-peg-pattern ignore-comma-space body + (ignore ", ")) + +(define-peg-pattern ignore-list body + (ignore (and "[" + (* (and + (? ", ") + (or value key-value))) + "]"))) + +;; exported symbols +(define-peg-pattern entry-name all + string) + +(define-peg-pattern hexpm-name all + atom) + +(define-peg-pattern hexpm-version all + string) + +(define-peg-pattern hexpm-checksum all + string) + +(define-peg-pattern hexpm-build-system all + (capture (+ (or alphanumeric-char "_" "-")))) + +(define-peg-pattern hexpm-build-systems all + (and (ignore "[") + (capture + (* (and (ignore ":") + (capture hexpm-build-system) + (ignore (? ", "))))) + (ignore "]"))) + +(define-peg-pattern git-url all + string) + +(define-peg-pattern git-commit all + string) + +(define-peg-pattern entry-hexpm all + (and + (ignore ": {:hex, ") + hexpm-name + ignore-comma-space + (capture hexpm-version) + ignore-comma-space + ignore-string + ignore-comma-space + (capture hexpm-build-systems) + ignore-comma-space + ignore-list + ignore-comma-space + ignore-string + ignore-comma-space + (capture hexpm-checksum) + (ignore "}"))) + +(define-peg-pattern entry-git all + (and + (ignore ": {:git, ") + git-url + ignore-comma-space + git-commit + ignore-comma-space + ignore-list + (ignore "}"))) + +(define-peg-pattern mix-lock-entry all + (and (ignore (? " ")) + (capture entry-name) + (or + entry-hexpm + entry-git) + (ignore (? ",\n")))) + +;; mix.lock +(define-peg-pattern mix-lock all + (and (ignore "%{\n") + (* mix-lock-entry) + (ignore "}"))) diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm index 464fa372cd9..ef33ef5f408 100644 --- a/guix/scripts/import.scm +++ b/guix/scripts/import.scm @@ -7,6 +7,7 @@ ;;; Copyright © 2021 Xinglu Chen ;;; Copyright © 2022 Philip McGrath ;;; Copyright © 2024 Herman Rimm +;;; Copyright © 2025 Igorj Gorjaĉev ;;; ;;; This file is part of GNU Guix. ;;; @@ -63,6 +64,7 @@ (define importers '("composer" "cpan" "cran" "crate" "egg" "elm" "elpa" "gem" "gnu" "go" "hackage" "hexpm" "json" "luanti" "minetest" ; deprecated + "mix" "npm-binary" "nuget" "opam" "pypi" "stackage" "texlive")) (define (resolve-importer name) @@ -143,10 +145,10 @@ PROC callback." ((or ("-i" file importer args ...) ("--insert" file importer args ...)) (let* ((define-prefixes - `(,@(if (member importer '("crate")) - '(define) - '()) - define-public)) + `(,@(if (member importer '("crate" "mix")) + '(define) + '()) + define-public)) (define-prefix? (cut member <> define-prefixes)) (find-and-insert (lambda (expr) @@ -172,9 +174,9 @@ PROC callback." ((importer args ...) (let ((print (lambda (expr) (leave-on-EPIPE - (pretty-print-with-comments - (current-output-port) expr) - ;; Two newlines: one after the closing paren, and - ;; one to leave a blank line. - (newline) (newline))))) + (pretty-print-with-comments + (current-output-port) expr) + ;; Two newlines: one after the closing paren, and + ;; one to leave a blank line. + (newline) (newline))))) (import-as-definitions importer args print))))) diff --git a/guix/scripts/import/hexpm.scm b/guix/scripts/import/hexpm.scm index eb9a1b0af58..c6452731299 100644 --- a/guix/scripts/import/hexpm.scm +++ b/guix/scripts/import/hexpm.scm @@ -47,6 +47,8 @@ Import and convert the hex.pm package for PACKAGE-NAME.\n")) (newline) (display (G_ " -r, --recursive import packages recursively")) + (display (G_ " + -m, --mix-inputs use mix-inputs for input field")) (newline) (show-bug-report-information)) @@ -62,6 +64,9 @@ Import and convert the hex.pm package for PACKAGE-NAME.\n")) (option '(#\r "recursive") #f #f (lambda (opt name arg result) (alist-cons 'recursive #t result))) + (option '("mix-inputs") #f #f + (lambda (opt name arg result) + (alist-cons 'mix-inputs #t result))) %standard-import-options)) @@ -94,7 +99,9 @@ Import and convert the hex.pm package for PACKAGE-NAME.\n")) (_ #f)) (hexpm-recursive-import name version)) ;; Single import - (let ((sexp (hexpm->guix-package name #:version version))) + (let* ((mix-inputs (assoc-ref opts 'mix-inputs)) + (sexp (hexpm->guix-package name #:version version + #:mix-inputs? mix-inputs))) (unless sexp (leave (G_ "failed to download meta-data for package '~a'~%") spec)) diff --git a/guix/scripts/import/mix.scm b/guix/scripts/import/mix.scm new file mode 100644 index 00000000000..476ff9de484 --- /dev/null +++ b/guix/scripts/import/mix.scm @@ -0,0 +1,122 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2025 Igorj Gorjaĉev +;;; +;;; 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 mix) + #:use-module (guix ui) + #:use-module (guix utils) + #:use-module (guix read-print) + #:use-module (guix scripts) + #:use-module (guix import mix) + #:use-module (guix scripts import) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-37) + #:use-module (srfi srfi-71) + #:use-module (ice-9 match) + #:export (guix-import-mix)) + + +;;; +;;; Command-line options. +;;; + +(define %default-options + '()) + +(define (show-help) + (display (G_ "Usage: guix import mix PACKAGE-NAME +Import package dependencies from its 'mix.lock'.\n")) + (display (G_ " + -h, --help display this help and exit")) + (display (G_ " + -V, --version display version information and exit")) + (newline) + (display (G_ " + -f, --lockfile=FILE import dependencies from FILE, a 'mix.lock' file")) + (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 mix"))) + (option '(#\f "lockfile") #f #t + (lambda (opt name arg result) + (if (file-exists? arg) + (alist-cons 'lockfile arg result) + (leave (G_ "file '~a' does not exist~%") arg)))) + %standard-import-options)) + + +;;; +;;; Entry point. +;;; + +(define (guix-import-mix . args) + (define (parse-options) + ;; Return the alist of option values. + (parse-command-line args %options (list %default-options) + #:build-options? #f)) + + (let* ((opts (parse-options)) + (lockfile (assoc-ref opts 'lockfile)) + (file-to-insert (assoc-ref opts 'file-to-insert)) + (args (filter-map (match-lambda + (('argument . value) + value) + (_ #f)) + (reverse opts)))) + (match args + ((spec) + (define-values (name version) + (package-name->name+version spec)) + + (if lockfile + (let ((source-expressions + _ + (mix-lock->expressions lockfile name))) + (when file-to-insert + (let* ((source-expressions + mix-inputs-entry + (mix-lock->expressions lockfile name)) + (term (first mix-inputs-entry)) + (mix-inputs + `(define-mix-inputs lookup-mix-inputs + ,@(sort + (cons mix-inputs-entry + (extract-mix-inputs + file-to-insert #:exclude term)) + (lambda (a b) + (string< (symbol->string (first a)) + (symbol->string (first b))))))) + (_ + (and=> (find-mix-inputs-location file-to-insert) + delete-expression)) + (port (open-file file-to-insert "a"))) + (pretty-print-with-comments port mix-inputs) + (newline port) + (close-port port))) + source-expressions))) + (() + (leave (G_ "too few arguments~%"))) + ((many ...) + (leave (G_ "too many arguments~%")))))) diff --git a/tests/import/hexpm.scm b/tests/import/hexpm.scm index 1e746f9b344..e99eb0e3944 100644 --- a/tests/import/hexpm.scm +++ b/tests/import/hexpm.scm @@ -250,4 +250,48 @@ (x (pk 'fail x #f)))))) +(test-assert "hexpm-with-mix-inputs" + ;; Replace network resources with sample data. + (mock ((guix http-client) http-fetch + (lambda (url . rest) + (match url + ("https://hex.pm/api/packages/bla" + (values (open-input-string test-bla-package) + (string-length test-bla-package))) + ("https://hex.pm/api/packages/bla/releases/1.5.0" + (values (open-input-string test-bla-release) + (string-length test-bla-release))) + (_ (error "http-fetch got unexpected URL: " url))))) + (mock ((guix build download) url-fetch + (lambda* (url file-name + #:key + (mirrors '()) verify-certificate?) + (with-output-to-file file-name + (lambda () + (display + (match url + ("https://repo.hex.pm/tarballs/bla-1.5.0.tar" + "source") + (_ (error "url-fetch got unexpected URL: " url)))))))) + (match (hexpm->guix-package "bla" #:mix-inputs? #t) + (`(package + (name "erlang-bla") + (version "1.5.0") + (source + (origin + (method url-fetch) + (uri (hexpm-uri "bla" version)) + (sha256 + (base32 + "0zcl4dgcmqwl1g5xb901pd6dz61r1xgmac9mqlwvh022paa6gks1")))) + (build-system rebar-build-system) + (inputs (mix-inputs 'erlang-bla)) + (synopsis "A cool package") + (description "This package provides a cool package.") + (home-page "https://hex.pm/packages/bla") + (license (list license:expat license:asl2.0))) + #t) + (x + (pk 'fail x #f)))))) + (test-end "hexpm") diff --git a/tests/import/mix.scm b/tests/import/mix.scm new file mode 100644 index 00000000000..46d33165a35 --- /dev/null +++ b/tests/import/mix.scm @@ -0,0 +1,97 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2025 Igorj Gorjaĉev +;;; +;;; 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-mix) + #:use-module (guix import mix) + #:use-module (guix base32) + #:use-module (guix build-system mix) + #:use-module (gcrypt hash) + #:use-module (guix tests) + #:use-module (srfi srfi-11) + #:use-module (srfi srfi-64) + #:use-module (ice-9 binary-ports) + #:use-module (ice-9 match)) + +(define test-mix-lock-file + "\ +%{ + \"gen_stage\": {:hex, :gen_stage, \"1.3.2\", \ +\"7c77e5d1e97de2c6c2f78f306f463bca64bf2f4c3cdd606affc0100b89743b7b\", \ +[:mix], [], \"hexpm\", \ +\"0ffae547fa777b3ed889a6b9e1e64566217413d018cabd825f786e843ffe63e7\"}, + \"eini\": {:hex, :eini_beam, \"2.2.4\", \ +\"02143b1dce4dda4243248e7d9b3d8274b8d9f5a666445e3d868e2cce79e4ff22\", \ +[:rebar3], [], \"hexpm\", \ +\"12de479d144b19e09bb92ba202a7ea716739929afdf9dff01ad802e2b1508471\"}, + \"erlydtl\": {:git, \"https://github.com/manuel-rubio/erlydtl.git\", \ +\"dffa1a73ee2bfba14195b8b3964c39f007ff1284\", []}, +}") + +(define temp-file + (string-append "t-mix-" (number->string (getpid)))) + +(test-begin "mix") + +(test-assert "mix-lock-file-import" + (begin + (call-with-output-file temp-file + (lambda (port) + (display test-mix-lock-file port))) + (mock + ((guix scripts download) guix-download + (lambda _ + (format #t "~a~%~a~%" + "/gnu/store/m43vixiijc26ni5p9zvbvjrs311h4fsm-erlydtl-dffa1a7" + "1jhcfh0idadlh9999kjzx1riqjw0k05wm6ii08xkjvirhjg0vawh"))) + (let-values + (((source-expressions beam-inputs-entry) + (mix-lock->expressions temp-file "test"))) + (and + (match source-expressions + ('((define beam-gen-stage-1.3.2 + (hexpm-source + "gen_stage" "gen_stage" "1.3.2" + "1rv3zqzq8vkqby1bvjhqs09p88b68pkf3fd6i7c3wyvpz93ybyhg")) + (define beam-eini-2.2.4 + (hexpm-source + "eini" "eini_beam" "2.2.4" + "0wc4a2qy40nq3bqdzygxka93jrvixakh58ibp6dy06ab2jflgphj")) + (define beam-erlydtl-snapshot.dffa1a7 + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/manuel-rubio/erlydtl.git") + (commit "dffa1a73ee2bfba14195b8b3964c39f007ff1284"))) + (file-name (git-file-name "beam-erlydtl" "snapshot.dffa1a7")) + (sha256 + (base32 + "1jhcfh0idadlh9999kjzx1riqjw0k05wm6ii08xkjvirhjg0vawh"))))) + #t) + (x + (pk 'fail (pretty-print-with-comments (current-output-port) x) #f))) + (match beam-inputs-entry + (`(test => (list beam-gen-stage-1.3.2 + beam-eini-2.2.4 + beam-erlydtl-snapshot.dffa1a7)) + #t) + (x + (pk 'fail x #f)))))))) + +(test-end "mix") + +(false-if-exception (delete-file temp-file))