Subject: [PATCH] mix-build-system: draft 1

From: Pierre-Henry Fröhring <[email-masked]>
Date: Sat, 28 Oct 2023 22:19:10 +0200

This commit introduces a mix-build-system. The provided code ensures that the
following code runs without errors:

./pre-inst-env guix build elixir-machete

A key challenge is the lack of bit reproducibility, in part due to rebar3's
lack of bit reproducibility. Future patches may address this, and I welcome
feedback.

Given the changes, splitting them into focused patches might be best. As a
first-time contributor, I seek advice on a suitable patch sequence.

I also request guidance from the Guix community for a seamless
integration. Please suggest next steps for the mix-build-system integration.

Thank you.
---
 gnu/packages/elixir-xyz.scm       | 327 ++++++++++
 gnu/packages/elixir.scm           | 164 +++--
 gnu/packages/emacs-xyz.scm        |  20 +
 gnu/packages/erlang-xyz.scm       | 650 +++++++++++++++++++
 gnu/packages/erlang.scm           | 996 +++++++++---------------------
 guix/build-system/mix.scm         | 185 ++++++
 guix/build-system/rebar.scm       | 320 +++++++---
 guix/build/mix-build-system.scm   | 373 +++++++++++
 guix/build/rebar-build-system.scm | 302 +++++----
 9 files changed, 2377 insertions(+), 960 deletions(-)
 create mode 100644 gnu/packages/elixir-xyz.scm
 create mode 100644 gnu/packages/erlang-xyz.scm
 create mode 100644 guix/build-system/mix.scm
 create mode 100644 guix/build/mix-build-system.scm

diff --git a/gnu/packages/elixir-xyz.scm b/gnu/packages/elixir-xyz.scm
new file mode 100644
index 00000000..767f9db7
--- /dev/null
+++ b/gnu/packages/elixir-xyz.scm
@@ -0,0 +1,327 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2023 Pierre-Henry Fröhring <[email-masked]>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu packages elixir-xyz)
+  #:use-module ((guix licenses)
+                #:prefix license:)
+  #:use-module (gnu packages)
+  #:use-module (gnu packages erlang-xyz)
+  #:use-module (gnu packages linux)
+  #:use-module (guix gexp)
+  #:use-module (guix packages)
+  #:use-module (guix build-system mix)
+  #:use-module (guix download))
+
+(define-public elixir-nimble-parsec
+  (package
+    (name "elixir-nimble-parsec")
+    (version "1.3.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "0rxiw6jzz77v0j460wmzcprhdgn71g1hrz3mcc6djn7bnb0f70i6"))))
+    (build-system mix-build-system)
+    (arguments
+     (list
+      #:tests? #f))
+    (synopsis "Text-based parser combinators")
+    (description
+     "This library provides primitives for efficient parser combinators, allowing
+for higher-level combinators through composition.")
+    (home-page "https://hexdocs.pm/nimble_parsec/")
+    (license license:asl2.0)))
+
+(define-public elixir-makeup
+  (package
+    (name "elixir-makeup")
+    (version "1.1.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "19jpprryixi452jwhws3bbks6ki3wni9kgzah3srg22a3x8fsi8a"))))
+    (build-system mix-build-system)
+    (propagated-inputs (list elixir-nimble-parsec))
+    (arguments
+     (list
+      #:tests? #f))
+    (synopsis "Syntax highlighter for source code")
+    (description
+     "Makeup is a generic syntax highlighter in the style of Pygments suitable for use in code hosting,
+forums, wikis or other applications that need to prettify source code.")
+    (home-page "https://hexdocs.pm/makeup/")
+    (license license:bsd-2)))
+
+(define-public elixir-telemetry-metrics
+  (package
+    (name "elixir-telemetry-metrics")
+    (version "0.6.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1iilk2n75kn9i95fdp8mpxvn3rcn3ghln7p77cijqws13j3y1sbv"))))
+    (build-system mix-build-system)
+    ;; There is no test/ in the source.
+    (arguments
+     (list
+      #:tests? #f))
+    (propagated-inputs (list erlang-telemetry))
+    (synopsis
+     "Provides a common interface for defining metrics based on Telemetry events")
+    (description
+     "Common interface for defining metrics based on :telemetry events. Metrics are
+aggregations of Telemetry events with specific name, providing a
+view of the system's behaviour over time.")
+    (home-page "https://hexdocs.pm/telemetry_metrics/")
+    (license license:asl2.0)))
+
+(define-public elixir-jason
+  (package
+    (name "elixir-jason")
+    (version "1.4.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "18d70i31bz11nr6vgsjn5prvhkvwqbyf3xq22ck5cnsnzp6ixc7v"))))
+    (build-system mix-build-system)
+    ;; There is no test/ in the source.
+    (arguments
+     (list
+      #:tests? #f))
+    (synopsis "JSON parser and generator")
+    (description
+     "Parser and generator are written in pure Elixir and optimized for speed. They
+are at least twice as fast as other Elixir/Erlang libraries (e.g.
+Poison). The performance is comparable to jiffy, which is implemented in C as
+a NIF.")
+    (home-page "https://hexdocs.pm/jason/")
+    (license license:asl2.0)))
+
+(define-public elixir-file-system
+  (package
+    (name "elixir-file-system")
+    (version "0.2.10")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1p0myxmnjjds8bbg69dd6fvhk8q3n7lb78zd4qvmjajnzgdmw6a1"))))
+    (build-system mix-build-system)
+    (inputs (list inotify-tools))
+    (arguments
+     (list
+      #:tests? #f ;There is no test/ in the source.
+      #:phases #~(modify-phases %standard-phases
+                   (add-after 'unpack 'rm-priv
+                     (lambda _
+                       ;; This directory represents source code not needed on UNIX systems.
+                       ;; Since we aim at UNIX systems, it is deleted.
+                       (delete-file-recursively "priv"))))))
+    (synopsis "File system change watcher")
+    (description "Provides a file system change watcher wrapper based on
+[fs](https://github.com/synrc/fs).")
+    (home-page "https://hexdocs.pm/file_system/")
+    (license license:wtfpl2)))
+
+(define-public elixir-bunt
+  (package
+    (name "elixir-bunt")
+    (version "0.2.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "19bp6xh052ql3ha0v3r8999cvja5d2p6cph02mxphfaj4jsbyc53"))))
+    (build-system mix-build-system)
+    (arguments
+     (list
+      #:tests? #f))
+    (synopsis "256 color ANSI coloring in the terminal")
+    (description "256 color ANSI coloring in the terminal.")
+    (home-page "https://hexdocs.pm/bunt/")
+    (license license:expat)))
+
+(define-public elixir-inch-ex
+  (package
+    (name "elixir-inch-ex")
+    (version "2.0.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1a4rjcy3hn5pc40si1d1y7qg0b0mnxx6pw825la67ky8r9gfrl4n"))))
+    (build-system mix-build-system)
+    (arguments
+     (list
+      #:tests? #f))
+    (propagated-inputs (list elixir-bunt elixir-jason))
+    (synopsis
+     "Offers a Mix task for suggestions on enhancing your inline documentation")
+    (description
+     "This package provides a Mix task that gives you hints where to improve your
+inline docs.")
+    (home-page "https://hex.pm/packages/inch_ex")
+    (license license:expat)))
+
+(define-public elixir-castore
+  (package
+    (name "elixir-castore")
+    (version "1.0.4")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1y44amb8falsmrfzpkmf7qp6215g9kdl76g91dpna4af2jwc264l"))))
+    (build-system mix-build-system)
+    ;; There is no test/ in the source.
+    (arguments
+     (list
+      #:tests? #f))
+    (synopsis "Up-to-date CA certificate store")
+    (description "Up-to-date CA certificate store.")
+    (home-page "https://hexdocs.pm/castore/")
+    (license license:asl2.0)))
+
+(define-public elixir-excoveralls
+  (package
+    (name "elixir-excoveralls")
+    (version "0.18.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "02x69ll5scvraky0k5gacvnnmldv5k04kgk02x087d9w3y8vn28i"))))
+    (build-system mix-build-system)
+    (propagated-inputs (list elixir-castore elixir-jason))
+    ;; No test/ folder.
+    (arguments
+     (list
+      #:tests? #f))
+    (synopsis "Coverage report tool with coveralls.io integration")
+    (description
+     "Library that reports test coverage statistics, with the option to
+post to coveralls.io service. It uses Erlang's cover to generate coverage
+information, and posts the test coverage results to coveralls.io through the
+JSON API.")
+    (home-page "https://hexdocs.pm/excoveralls/")
+    (license license:expat)))
+
+(define-public elixir-credo
+  (package
+    (name "elixir-credo")
+    (version "1.7.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "18jqi9s9r1587njzdxycvmmbma30cay9iamni4f3ih54jmh1r1z9"))))
+    (build-system mix-build-system)
+    (propagated-inputs (list elixir-bunt elixir-file-system elixir-jason))
+    (native-inputs (list elixir-excoveralls elixir-inch-ex))
+    (synopsis "Static code analysis tool")
+    (description
+     "Credo is a static code analysis tool for the Elixir language with a focus on
+teaching and code consistency. Credo can show you refactoring opportunities in
+your code, complex code fragments, warn you about common mistakes, show
+inconsistencies in your naming scheme and - if needed - help you enforce a
+desired coding style.")
+    (home-page "https://hexdocs.pm/credo/")
+    (license license:expat)))
+
+(define-public elixir-erlex
+  (package
+    (name "elixir-erlex")
+    (version "0.2.6")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "0x8c1j62y748ldvlh46sxzv5514rpzm809vxn594vd7y25by5lif"))))
+    (build-system mix-build-system)
+    (arguments
+     (list
+      #:tests? #f))
+    (synopsis
+     "Convert Erlang style structs and error messages to equivalent Elixir")
+    (description
+     "Converted structs and error messages are useful for pretty printing things
+like Dialyzer errors and Observer .state. NOTE: Because this code calls the
+Elixir formatter, it requires Elixir 1.6+.")
+    (home-page "https://hexdocs.pm/erlex/")
+    (license license:asl2.0)))
+
+(define-public elixir-dialyxir
+  (package
+    (name "elixir-dialyxir")
+    (version "1.4.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "00cqwhd1wabwds44jz94rvvr8z8cp12884d3lp69fqkrszb9bdw4"))))
+    (build-system mix-build-system)
+    (arguments
+     (list
+      #:tests? #f))
+    (propagated-inputs (list elixir-erlex))
+    (synopsis "Mix tasks to simplify use of Dialyzer")
+    (description
+     "Mix Tasks are usable from the directory of the mix project you want to analyze.")
+    (home-page "https://hexdocs.pm/dialyxir/")
+    (license license:asl2.0)))
+
+(define-public elixir-machete
+  (package
+    (name "elixir-machete")
+    (version "0.2.8")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "0952603bmqsf6v3ja99zpbnbx5d52i4xksjkfj3irl45ccq5pgq9"))))
+    (build-system mix-build-system)
+    (native-inputs (list elixir-credo elixir-dialyxir))
+    (synopsis "Literate test matchers for ExUnit")
+    (description
+     "Machete provides ergonomic match operators that act as building blocks to let
+you define test expectations that can match data against any combination of
+literals, variables, or parametrically defined matchers.")
+    (home-page "https://hexdocs.pm/machete/")
+    (license license:expat)))
+
+;;;
+;;; Avoid adding new packages to the end of this file. To reduce the chances
+;;; of a merge conflict, place them above by existing packages with similar
+;;; functionality or similar names.
+;;;
diff --git a/gnu/packages/elixir.scm b/gnu/packages/elixir.scm
index 724b4251..d1ac1d07 100644
--- a/gnu/packages/elixir.scm
+++ b/gnu/packages/elixir.scm
@@ -7,6 +7,7 @@
 ;;; Copyright © 2018 Nikita <[email-masked]>
 ;;; Copyright © 2021 Oskar Köök <[email-masked]>
 ;;; Copyright © 2021 Cees de Groot <[email-masked]>
+;;; Copyright © 2023 Pierre-Henry Fröhring <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -24,14 +25,21 @@
 ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
 
 (define-module (gnu packages elixir)
-  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module ((guix licenses)
+                #:prefix license:)
+  #:use-module (gnu packages compression)
+  #:use-module (gnu packages erlang)
+  #:use-module (gnu packages version-control)
+  #:use-module (gnu packages)
+  #:use-module (guix build utils)
+  #:use-module (guix build-system copy)
   #:use-module (guix build-system gnu)
+  #:use-module (guix download)
   #:use-module (guix gexp)
   #:use-module (guix git-download)
   #:use-module (guix packages)
-  #:use-module (gnu packages)
-  #:use-module (gnu packages erlang)
-  #:use-module (gnu packages version-control))
+  #:use-module (guix search-paths)
+  #:use-module (guix utils))
 
 (define-public elixir
   (package
@@ -52,57 +60,109 @@ (define-public elixir
      (list
       #:test-target "test"
       #:parallel-tests? #f ;see <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32171#23>
-      #:make-flags #~(list (string-append "PREFIX=" #$output))
-      #:phases
-      #~(modify-phases %standard-phases
-          (add-after 'unpack 'make-git-checkout-writable
-            (lambda _
-              (for-each make-file-writable (find-files "."))))
-          (add-after 'make-git-checkout-writable 'replace-paths
-            (lambda* (#:key inputs #:allow-other-keys)
-              ;; Note: references end up obfuscated in binary BEAM files where
-              ;; they may be invisible to the GC and graft code:
-              ;; <https://issues.guix.gnu.org/54304#11>.
-              (substitute* '("lib/mix/lib/mix/release.ex"
-                             "lib/mix/lib/mix/tasks/release.init.ex")
-                (("#!/bin/sh")
-                 (string-append "#!" (search-input-file inputs "/bin/sh"))))
-              (substitute* "bin/elixir"
-                (("ERTS_BIN=\n")
-                 (string-append
-                  "ERTS_BIN="
-                  ;; Elixir Releases will prepend to ERTS_BIN the path of
-                  ;; a copy of erl.  We detect if a release is being generated
-                  ;; by checking the initial ERTS_BIN value: if it's empty, we
-                  ;; are not in release mode and can point to the actual erl
-                  ;; binary in Guix store.
-                  "\nif [ -z \"$ERTS_BIN\" ]; then ERTS_BIN="
-                  (string-drop-right (search-input-file inputs "/bin/erl") 3)
-                  "; fi\n")))
-              (substitute* "bin/mix"
-                (("#!/usr/bin/env elixir")
-                 (string-append "#!" #$output "/bin/elixir")))))
-          (add-before 'build 'make-current
-            ;; The Elixir compiler checks whether or not to compile files by
-            ;; inspecting their timestamps.  When the timestamp is equal to the
-            ;; epoch no compilation will be performed.  Some tests fail when
-            ;; files are older than Jan 1, 2000.
-            (lambda _
-              (for-each (lambda (file)
-                          (let ((recent 1400000000))
-                            (utime file recent recent 0 0)))
-                        (find-files "." ".*"))))
-          (add-before 'check 'set-home
-            (lambda* (#:key inputs #:allow-other-keys)
-              ;; Some tests require access to a home directory.
-              (setenv "HOME" "/tmp")))
-          (delete 'configure))))
-    (inputs
-     (list erlang git))
+      #:make-flags #~(list (string-append "PREFIX="
+                                          #$output))
+      #:phases #~(modify-phases %standard-phases
+                   (add-after 'unpack 'make-git-checkout-writable
+                     (lambda _
+                       (for-each make-file-writable
+                                 (find-files "."))))
+                   (add-after 'make-git-checkout-writable 'replace-paths
+                     (lambda* (#:key inputs #:allow-other-keys)
+                       ;; Note: references end up obfuscated in binary BEAM files where
+                       ;; they may be invisible to the GC and graft code:
+                       ;; <https://issues.guix.gnu.org/54304#11>.
+                       (substitute* '("lib/mix/lib/mix/release.ex"
+                                      "lib/mix/lib/mix/tasks/release.init.ex")
+                         (("#!/bin/sh")
+                          (string-append "#!"
+                                         (search-input-file inputs "/bin/sh"))))
+                       (substitute* "bin/elixir"
+                         (("ERTS_BIN=\n")
+                          (string-append "ERTS_BIN="
+                                         ;; Elixir Releases will prepend to ERTS_BIN the path of
+                                         ;; a copy of erl.  We detect if a release is being generated
+                                         ;; by checking the initial ERTS_BIN value: if it's empty, we
+                                         ;; are not in release mode and can point to the actual erl
+                                         ;; binary in Guix store.
+                                         "\nif [ -z \"$ERTS_BIN\" ]; then ERTS_BIN="
+                                         (string-drop-right (search-input-file inputs
+                                                                               "/bin/erl") 3)
+                                         "; fi\n")))
+                       (substitute* "bin/mix"
+                         (("#!/usr/bin/env elixir")
+                          (string-append "#!"
+                                         #$output "/bin/elixir")))))
+                   (add-before 'build 'make-current
+                     ;; The Elixir compiler checks whether or not to compile files by
+                     ;; inspecting their timestamps.  When the timestamp is equal to the
+                     ;; epoch no compilation will be performed.  Some tests fail when
+                     ;; files are older than Jan 1, 2000.
+                     (lambda _
+                       (for-each (lambda (file)
+                                   (let ((recent 1400000000))
+                                     (utime file recent recent 0 0)))
+                                 (find-files "." ".*"))))
+                   (add-before 'check 'set-home
+                     (lambda* (#:key inputs #:allow-other-keys)
+                       ;; Some tests require access to a home directory.
+                       (setenv "HOME" "/tmp")))
+                   (delete 'configure)
+                   (add-after 'install 'wrap-programs
+                     (lambda* (#:key inputs outputs #:allow-other-keys)
+                       (let* ((out (assoc-ref outputs "out"))
+                              (programs '("elixir" "elixirc" "iex" "mix")))
+                         (for-each (lambda (program)
+                                     (wrap-program (string-append out "/bin/"
+                                                                  program)
+                                       '("ERL_LIBS" prefix
+                                         ("${GUIX_ERL_LIBS}")))) programs)))))))
+    (inputs (list erlang git))
+    (native-search-paths
+     (list (search-path-specification
+            (variable "GUIX_ERL_LIBS")
+            (files (list "lib/erlang/lib"
+                         (string-append "lib/elixir/"
+                                        (version-major+minor version)))))))
     (home-page "https://elixir-lang.org/")
     (synopsis "Elixir programming language")
-    (description "Elixir is a dynamic, functional language used to build
+    (description
+     "Elixir is a dynamic, functional language used to build
 scalable and maintainable applications.  Elixir leverages the Erlang VM, known
 for running low-latency, distributed and fault-tolerant systems, while also
 being successfully used in web development and the embedded software domain.")
     (license license:asl2.0)))
+
+(define-public mix-hex
+  (package
+    (name "mix-hex")
+    (version "2.0.5")
+    (source
+     (origin
+       (method url-fetch)
+       (uri "https://builds.hex.pm/installs/1.14.0/hex-2.0.5.ez")
+       (sha256
+        (base32 "0j4s17zsshq9hv3qxflcqrfwh4p27d2rv7xmgdmfdfxp086mfvry"))))
+    (build-system copy-build-system)
+    (native-inputs (list unzip))
+    (arguments
+     (list
+      #:phases #~(modify-phases %standard-phases
+                   (replace 'unpack
+                     (lambda* (#:key source #:allow-other-keys)
+                       ;; A *.ez file is a kind of *.zip file.
+                       ;; See: https://www.erlang.org/doc/man/code#loading-of-code-from-archive-files
+                       (invoke "unzip" source))))
+      #:install-plan #~'(("hex-2.0.5" "lib/"))))
+    (synopsis "Package manager for the Erlang VM")
+    (description
+     "This project currently provides tasks that integrate with Mix, Elixir's build
+tool.")
+    (home-page "https://hexdocs.pm/makeup_elixir/")
+    (license license:bsd-2)))
+
+;;;
+;;; Avoid adding new packages to the end of this file. To reduce the chances
+;;; of a merge conflict, place them above by existing packages with similar
+;;; functionality or similar names.
+;;;
diff --git a/gnu/packages/emacs-xyz.scm b/gnu/packages/emacs-xyz.scm
index 10c4b0a6..13f07f20 100644
--- a/gnu/packages/emacs-xyz.scm
+++ b/gnu/packages/emacs-xyz.scm
@@ -135,6 +135,7 @@
 ;;; Copyright © 2023 Sergiu Ivanov <[email-masked]>
 ;;; Copyright © 2023 Camilo Q.S. (Distopico) <[email-masked]>
 ;;; Copyright © 2023 Thanos Apollo <[email-masked]>
+;;; Copyright © 2023 Pierre-Henry Fröhring <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -7578,6 +7579,25 @@ (define-public emacs-org-fragtog
 your cursor steps onto them, and re-enabled when the cursor leaves.")
     (license license:gpl3+)))
 
+(define-public emacs-erlang
+  (package
+    (name "emacs-erlang")
+    (version (package-version erlang))
+    (source
+     (package-source erlang))
+    (build-system emacs-build-system)
+    (arguments
+     `(#:phases (modify-phases %standard-phases
+                  (add-before 'expand-load-path 'change-working-directory
+                    (lambda _
+                      (chdir "lib/tools/emacs") #t)))))
+    (home-page "https://www.erlang.org/")
+    (synopsis "Erlang major mode for Emacs")
+    (description
+     "This package provides an Emacs major mode for editing Erlang source
+files.")
+    (license license:asl2.0)))
+
 (define-public emacs-ob-erlang
   (let ((revision "1")
         (commit "a029c23902b4ad73b84f262a7fc5b98d87b63dfd"))
diff --git a/gnu/packages/erlang-xyz.scm b/gnu/packages/erlang-xyz.scm
new file mode 100644
index 00000000..e1f1a77e
--- /dev/null
+++ b/gnu/packages/erlang-xyz.scm
@@ -0,0 +1,650 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2023 Pierre-Henry Fröhring <[email-masked]>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu packages erlang-xyz)
+  #:use-module ((guix licenses)
+                #:prefix license:)
+  #:use-module (gnu packages base)
+  #:use-module (gnu packages)
+  #:use-module (guix build-system rebar)
+  #:use-module (guix download)
+  #:use-module (guix gexp)
+  #:use-module (guix git-download)
+  #:use-module (guix hg-download)
+  #:use-module (guix packages)
+  #:use-module (guix utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (guix git-download)
+  #:use-module (gnu packages version-control)
+  #:use-module (srfi srfi-26))
+
+(define-public erlang-unicode-util-compat
+  (package
+    (name "erlang-unicode-util-compat")
+    (version "0.7.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "08952lw8cjdw8w171lv8wqbrxc4rcmb3jhkrdb7n06gngpbfdvi5"))))
+    (build-system rebar-build-system)
+    (synopsis "Unicode compatibility library for Erlang < 20")
+    (description "Unicode compatibility library for Erlang < 20.")
+    (home-page "https://hex.pm/packages/unicode_util_compat")
+    (license license:asl2.0)))
+
+(define-public erlang-idna
+  (package
+    (name "erlang-idna")
+    (version "6.1.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1sjcjibl34sprpf1dgdmzfww24xlyy34lpj7mhcys4j4i6vnwdwj"))))
+    (build-system rebar-build-system)
+    (propagated-inputs (list erlang-unicode-util-compat))
+    (synopsis
+     "Erlang Internationalized Domain Names in Applications (IDNA) protocol")
+    (description
+     "Library to register and look up IDNs in a way
+   that does not require changes to the DNS itself.  IDNA is only meant for
+processing domain names, not free text. See: RFC 5891.")
+    (home-page "https://hexdocs.pm/idna/")
+    (license license:expat)))
+
+(define-public erlang-bear
+  (package
+    (name "erlang-bear")
+    (version "1.0.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1nsri73b50n5v1a8252mm8car84j2b53bq7alq6zz16z3a86fyqm"))))
+    (build-system rebar-build-system)
+    (synopsis "Statistics functions for Erlang")
+    (description
+     "This package provides a set of statistics functions for erlang.")
+    (home-page "https://hex.pm/packages/bear")
+    (license license:asl2.0)))
+
+(define-public erlang-erlang-color
+  (package
+    (name "erlang-erlang-color")
+    (version "1.0.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "0f707vxihn3f9m3zxal38ajcihnfcwms77jcax0gbzn8i7jya5vb"))))
+    (build-system rebar-build-system)
+    (synopsis "ANSI colors for your Erlang")
+    (description "ANSI colors for your Erlang.")
+    (home-page "https://hex.pm/packages/erlang_color")
+    (license license:expat)))
+
+(define-public erlang-tdiff
+  (package
+    (name "erlang-tdiff")
+    (version "0.1.2")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "0xbq7p9ii2kp49ms1kylj92ih2jiwvqwimb8jy4aalljz5lf3hp0"))))
+    (build-system rebar-build-system)
+    (synopsis "Library to compute the difference between two strings")
+    (description
+     "Erlang implementation of the O(ND) differnence algorithm by EUGENE W. MYERS.")
+    (home-page "https://hex.pm/packages/tdiff")
+    (license license:lgpl2.0)))
+
+(define-public erlang-rebar3-ex-doc
+  (package
+    (name "erlang-rebar3-ex-doc")
+    (version "0.2.21")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "0c720shjf03y4slj56q5nxgyhqif0926cs3pvl3zbv1i64qh8wdm"))))
+    (build-system rebar-build-system)
+    (synopsis "rebar3 plugin for generating docs with ex_doc")
+    (description
+     "rebar3_ex_doc is a rebar3 plugin for creating documentation with ex_doc. It
+includes ex_doc as an escript, eliminating the need for Elixir installation or
+compiling ex_doc dependencies.")
+    (home-page "https://hexdocs.pm/rebar3_ex_doc/")
+    (license license:asl2.0)))
+
+(define-public erlang-samovar
+  (package
+    (name "erlang-samovar")
+    (version "1.0.2")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1nfw5vbzcvqzpsahwxz7zjlshg31pa9f306g3hzm1kfx5rsyvry4"))))
+    (build-system rebar-build-system)
+    (synopsis "SEMVER library for Erlang")
+    (description "SEMVER library for Erlang")
+    (home-page "https://hexdocs.pm/samovar/")
+    (license license:isc)))
+
+(define-public erlang-geas
+  (package
+    (name "erlang-geas")
+    (version "2.7.14")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1maxv5zg2ckrikr8xpxgg9kpfaxvahqilbkl9dl9ibchlgrbj6i4"))))
+    (build-system rebar-build-system)
+    (propagated-inputs (list erlang-samovar))
+    (synopsis
+     "Tool to detect the runnable official Erlang release window for your project")
+    (description
+     "Geas will tell you also what are the offending functions in the beam/source
+files that reduce the available window, if some beam files are compiled native
+and the installed patches and recommend patches that should be installed
+depending your code.")
+    (home-page "https://hexdocs.pm/geas/")
+    (license license:isc)))
+
+(define-public erlang-covertool
+  (package
+    (name "erlang-covertool")
+    (version "2.0.4")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1p0c1n3nl4063xwi1sv176l1x68xqf07qwvj444a5z888fx6i5aw"))))
+    (build-system rebar-build-system)
+    (home-page "https://github.com/covertool/covertool")
+    (synopsis "Convert code-coverage data generated by @code{cover} into
+Cobertura XML reports")
+    (description
+     "This package provides a build tool and plugin to convert
+exported Erlang @code{cover} data sets into Cobertura XML reports, which can
+then be feed to the Jenkins Cobertura plug-in. On @emph{hex.pm}, this plugin
+was previously called @code{rebar_covertool}.")
+    (license license:bsd-2)))
+
+(define-public erlang-telemetry
+  (package
+    (name "erlang-telemetry")
+    (version "1.2.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1mgyx9zw92g6w8fp9pblm3b0bghwxwwcbslrixq23ipzisfwxnfs"))))
+    (build-system rebar-build-system)
+    (native-inputs (list erlang-covertool))
+    (synopsis "Dynamic dispatching library for metrics and instrumentations")
+    (description
+     "Telemetry is a lightweight library for dynamic dispatching of events, with a
+focus on metrics and instrumentation. Any Erlang or Elixir library can use
+telemetry to emit events. Application code and other libraries can then hook
+into those events and run custom handlers.")
+    (home-page "https://hexdocs.pm/telemetry/")
+    (license license:asl2.0)))
+
+(define-public erlang-rebar3-git-vsn
+  (package
+    (name "erlang-rebar3-git-vsn")
+    (version "1.1.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1dfz56034pa25axly9vqdzv3phkn8ll0qwrkws96pbgcprhky1hx"))))
+    (build-system rebar-build-system)
+    (inputs (list git-minimal/pinned))
+    (arguments
+     `(
+       ;; Running the tests require binary artifact (tar-file containing
+       ;; samples git repos)  TODO: remove these from the source
+       #:tests? #f
+                #:phases (modify-phases %standard-phases
+                           (add-after 'unpack 'patch-path
+                             (lambda* (#:key inputs #:allow-other-keys)
+                               (let ((git (assoc-ref inputs "git-minimal")))
+                                 (substitute* "src/rebar3_git_vsn.erl"
+                                   (("rebar_utils:sh\\(\"git " _)
+                                    (string-append "rebar_utils:sh(\"" git "/bin/git ")))))))))
+    (home-page "https://github.com/soranoba/rebar3_git_vsn")
+    (synopsis "Rebar3 plugin for generating the version from git")
+    (description "This plugin adds support for generating the version from
+a git checkout.")
+    (license license:expat)))
+
+(define-public erlang-getopt
+  (package
+    (name "erlang-getopt")
+    (version "1.0.2")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "09pasi7ki1rivw9sl7xndj5qgjbdqvcscxk83yk85yr28gm9l0m0"))))
+    (build-system rebar-build-system)
+    (home-page "https://github.com/jcomellas/getopt")
+    (synopsis "Command-line options parser for Erlang")
+    (description "This package provides an Erlang module to parse command line
+arguments using the GNU getopt syntax.")
+    (license license:bsd-3)))
+
+(define-public erlang-edown
+  (package
+    (name "erlang-edown")
+    (version "0.8.4")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "0ij47gvgs6yfqphj0f54qjzj18crj8y1dsjjlzpp3dp8pscqzbqw"))))
+    (build-system rebar-build-system)
+    (home-page "https://github.com/uwiger/edown")
+    (synopsis "Markdown extension for EDoc")
+    (description "This package provides an extension for EDoc for generating
+Markdown.")
+    (license license:asl2.0)))
+
+(define-public erlang-bbmustache
+  (package
+    (name "erlang-bbmustache")
+    (version "1.12.2")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "0fvvaxdpziygxl30j59g98qkh2n47xlb7w5dfpsm2bfcsnj372v8"))))
+    (build-system rebar-build-system)
+    (inputs (list erlang-getopt erlang-rebar3-git-vsn erlang-edown)) ;for building the docs
+    (arguments
+     `(#:tests? #f ;requires mustache specification file
+       #:phases (modify-phases %standard-phases
+                  (add-before 'build 'build-more
+                    (lambda _
+                      (invoke "rebar3" "as" "dev" "escriptize")))
+                  (add-after 'install 'install-escript
+                    (lambda* (#:key outputs #:allow-other-keys)
+                      (let* ((out (assoc-ref outputs "out")))
+                        (install-file "_build/dev/bin/bbmustache"
+                                      (string-append out "/bin"))))))))
+    (home-page "https://github.com/soranoba/bbmustache/")
+    (synopsis "Binary pattern match Based Mustache template engine for Erlang")
+    (description "This Erlang library provides a Binary pattern match Based
+Mustache template engine")
+    (license license:expat)))
+
+(define-public erlang-certifi
+  (package
+    (name "erlang-certifi")
+    (version "2.9.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "0ha6vmf5p3xlbf5w1msa89frhvfk535rnyfybz9wdmh6vdms8v96"))))
+    (build-system rebar-build-system)
+    (arguments
+     `(#:tests? #f)) ;have not been updated for latest cert bundle
+    (home-page "https://github.com/certifi/erlang-certifi/")
+    (synopsis "Erlang CA certificate bundle")
+    (description
+     "This Erlang library contains a CA bundle that you can
+reference in your Erlang application.  This is useful for systems that do not
+have CA bundles that Erlang can find itself, or where a uniform set of CAs is
+valuable.
+
+This an Erlang specific port of certifi.  The CA bundle is derived from
+Mozilla's canonical set.")
+    (license license:bsd-3)))
+
+(define-public erlang-cf
+  (package
+    (name "erlang-cf")
+    (version "0.3.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "0wknz4xkqkhgvlx4vx5619p8m65v7g87lfgsvfy04jrsgm28spii"))))
+    (build-system rebar-build-system)
+    (home-page "https://github.com/project-fifo/cf")
+    (synopsis "Terminal colour helper for Erlang io and io_lib")
+    (description "This package provides a helper library for termial colour
+printing extending the io:format syntax to add colours.")
+    (license license:expat)))
+
+(define-public erlang-yamerl
+  (package
+    (name "erlang-yamerl")
+    (version "0.10.0")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             ;; There are no tests included on Hex.
+             (url "https://github.com/yakaz/yamerl")
+             (commit (string-append "v" version))))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "0if8abgmispcfk7zhd0a5dndzwzbsmqrbyrm5shk375r2dbbwak6"))))
+    (build-system rebar-build-system)
+    (synopsis "YAML and JSON parser in pure Erlang")
+    (description
+     "Erlang application to parse YAML 1.1 and YAML 1.2 documents, as well as
+JSON documents.")
+    (home-page "https://hexdocs.pm/yamerl/")
+    (license license:bsd-2)))
+
+(define-public erlang-cth-readable
+  (package
+    (name "erlang-cth-readable")
+    (version "1.5.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "104xgybb6iciy6i28pyyrarqzliddi8kjyq43ajaav7y5si42rb8"))))
+    (build-system rebar-build-system)
+    (propagated-inputs (list erlang-cf))
+    (arguments
+     `(#:tests? #f)) ;no test-suite in hex-pm package
+    (home-page "https://github.com/ferd/cth_readable")
+    (synopsis "Common Test hooks for more readable logs for Erlang")
+    (description
+     "This package provides an OTP library to be used for CT log
+outputs you want to be readable around all that noise they contain.")
+    (license license:bsd-3)))
+
+(define-public erlang-erlware-commons
+  (package
+    (name "erlang-erlware-commons")
+    (version "1.6.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "18qam9xdzi74wppb0cj4zc8161i0i8djr79z8662m6d276f2jz5m"))))
+    (build-system rebar-build-system)
+    (propagated-inputs (list erlang-cf))
+    (native-inputs (list git-minimal/pinned)) ;Required for tests
+    (arguments
+     `(#:phases (modify-phases %standard-phases
+                  (add-before 'check 'check-setup
+                    (lambda _
+                      (setenv "TERM" "xterm")))))) ;enable color in logs
+    (home-page "https://erlware.github.io/erlware_commons/")
+    (synopsis "Additional standard library for Erlang")
+    (description "Erlware Commons is an Erlware project focused on all aspects
+of reusable Erlang components.")
+    (license license:expat)))
+
+(define-public erlang-eunit-formatters
+  (package
+    (name "erlang-eunit-formatters")
+    (version "0.5.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1jb3hzb216r29x2h4pcjwfmx1k81431rgh5v0mp4x5146hhvmj6n"))))
+    (build-system rebar-build-system)
+    (home-page "https://github.com/seancribbs/eunit_formatters")
+    (synopsis "Better output for eunit suites")
+    (description "This package provides a better output for Erlang eunits.")
+    (license license:asl2.0)))
+
+(define-public erlang-hex-core
+  (package
+    (name "erlang-hex-core")
+    (version "0.8.4")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "06p65hlm29ky03vs3fq3qz6px2ylwp8b0f2y75wdf5cm0kx2332b"))))
+    (build-system rebar-build-system)
+    (arguments
+     `(#:phases (modify-phases %standard-phases
+                  (replace 'check
+                    (lambda* (#:key tests? #:allow-other-keys)
+                      (when tests?
+                        (invoke "rebar3" "as" "test" "proper")))))))
+    (inputs (list erlang-proper erlang-rebar3-proper))
+    (home-page "https://github.com/hexpm/hex_core")
+    (synopsis "Reference implementation of Hex specifications")
+    (description "This package provides the reference implementation of Hex
+specifications.")
+    (license license:asl2.0)))
+
+(define-public erlang-jsone
+  (package
+    (name "erlang-jsone")
+    (version "1.7.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1gaxiw76syjp3s9rygskm32y9799b917q752rw8bxj3bxq93g8x3"))))
+    (build-system rebar-build-system)
+    (arguments
+     `(#:phases (modify-phases %standard-phases
+                  (add-after 'unpack 'disable-covertool
+                    ;; no need to generate a coverage report
+                    (lambda _
+                      (substitute* "rebar.config"
+                        (("\\{project_plugins, \\[covertool\\]\\}\\." _)
+                         "")))))))
+    (home-page "https://github.com/sile/jsone/")
+    (synopsis "Erlang JSON Library")
+    (description "An Erlang library for encoding and decoding JSON data.")
+    (license license:expat)))
+
+(define-public erlang-parse-trans
+  (package
+    (name "erlang-parse-trans")
+    (version "3.4.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "16p4c2xjrvz16kzpr9pmcvi6nxq6rwckqi9fp0ksibaxwxn402k2"))))
+    (build-system rebar-build-system)
+    (inputs (list erlang-getopt))
+    (home-page "https://github.com/uwiger/parse_trans")
+    (synopsis "Parse transform utilities for Erlang")
+    (description
+     "This package captures some useful patterns in parse
+transformation and code generation for Erlang.
+
+For example generating standardized accessor functions for records or
+evaluating an expression at compile-time and substitute the result as a
+compile-time constant.")
+    (license license:asl2.0)))
+
+(define-public erlang-proper
+  (package
+    (name "erlang-proper")
+    (version "1.4.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1fwcas4a9kz3w3z1jqdk9lw8822srfjk9lcpvbxkxlsv3115ha0q"))))
+    (build-system rebar-build-system)
+    (arguments
+     `(#:phases (modify-phases %standard-phases
+                  (add-after 'unpack 'disable-covertool
+                    ;; no need to generate a coverage report
+                    (lambda _
+                      (substitute* "rebar.config"
+                        (("\\{plugins, \\[covertool\\]\\}\\." _)
+                         "")))))))
+    (home-page "https://proper-testing.github.io/")
+    (synopsis "QuickCheck-inspired property-based testing tool for Erlang")
+    (description
+     "PropEr is a tool for the automated, semi-random,
+property-based testing of Erlang programs.  It is fully integrated with
+Erlang's type language, and can also be used for the model-based random
+testing of stateful systems.")
+    (license license:gpl3+)))
+
+(define-public erlang-jsx
+  (package
+    (name "erlang-jsx")
+    (version "3.1.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1wr7jkxm6nlgvd52xhniav64xr9rml2ngb35rwjwqlqvq7ywhp0c"))))
+    (build-system rebar-build-system)
+    (synopsis "Streaming, evented JSON parsing toolkit")
+    (description
+     "An Erlang application for consuming, producing and manipulating json.")
+    (home-page "https://github.com/talentdeficit/jsx")
+    (license license:expat)))
+
+(define-public erlang-providers
+  (package
+    (name "erlang-providers")
+    (version "1.9.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "05y0kz3xgx77hzn1l05byaisvmk8bgds7c22hrh0a5ba81sfi1yj"))))
+    (build-system rebar-build-system)
+    (propagated-inputs (list erlang-erlware-commons erlang-getopt))
+    (home-page "https://github.com/tsloughter/providers")
+    (synopsis "Erlang providers library")
+    (description "This package provides an Erlang providers library.")
+    (license license:asl2.0)))
+
+(define-public erlang-relx
+  (package
+    (name "erlang-relx")
+    (version "4.6.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "02gmfx1vxg9m3mq4njsqhs4972l4nb8m5p1pdcf64g09ccf17y1g"))))
+    (build-system rebar-build-system)
+    (propagated-inputs (list erlang-bbmustache))
+    (home-page "https://erlware.github.io/relx/")
+    (synopsis "Release assembler for Erlang/OTP Releases")
+    (description
+     "Relx assembles releases for an Erlang/OTP release.  Given a
+release specification and a list of directories in which to search for OTP
+applications it will generate a release output.  That output depends heavily on
+what plugins available and what options are defined, but usually it is simply
+a well configured release directory.")
+    (license license:asl2.0)))
+
+(define-public erlang-ssl-verify-fun
+  (package
+    (name "erlang-ssl-verify-fun")
+    (version "1.1.6")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1026l1z1jh25z8bfrhaw0ryk5gprhrpnirq877zqhg253x3x5c5x"))))
+    (build-system rebar-build-system)
+    (home-page "https://github.com/deadtrickster/ssl_verify_fun.erl")
+    (synopsis "SSL verification functions for Erlang")
+    (description "This package provides SSL verification functions for
+Erlang.")
+    (license license:expat)))
+
+(define-public erlang-rebar3-raw-deps
+  (package
+    (name "erlang-rebar3-raw-deps")
+    (version "2.0.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1pzmm3m8gb2s9jn8fp6shzgfmy4mvh2vdci0z6nsm74ma3ffh1i3"))))
+    (build-system rebar-build-system)
+    (home-page "https://github.com/soranoba/rebar3_raw_deps")
+    (synopsis "Rebar3 plugin for supporting \"raw\" dependencies")
+    (description "This plugin provides support for handling non-OTP
+applications as a dependent libraries.")
+    (license license:expat)))
+
+(define-public erlang-rebar3-proper
+  (package
+    (name "erlang-rebar3-proper")
+    (version "0.12.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (hexpm-uri name version))
+       (sha256
+        (base32 "1f174fb6h2071wr7qbw9aqqvnglzsjlylmyi8215fhrmi38w94b6"))))
+    (build-system rebar-build-system)
+    (home-page "https://github.com/ferd/rebar3_proper")
+    (synopsis "Rebar3 PropEr plugin")
+    (description "This plugin allows running PropEr test suites from within
+rebar3.")
+    (license license:bsd-3)))
+
+;;;
+;;; Avoid adding new packages to the end of this file. To reduce the chances
+;;; of a merge conflict, place them above by existing packages with similar
+;;; functionality or similar names.
+;;;
diff --git a/gnu/packages/erlang.scm b/gnu/packages/erlang.scm
index c53cb72c..df17558b 100644
--- a/gnu/packages/erlang.scm
+++ b/gnu/packages/erlang.scm
@@ -10,6 +10,7 @@
 ;;; Copyright © 2022 jgart <[email-masked]>
 ;;; Copyright © 2023 wrobell <[email-masked]>
 ;;; Copyright © 2023 Tim Johann <[email-masked]>
+;;; Copyright © 2023 Pierre-Henry Fröhring <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -27,160 +28,182 @@
 ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
 
 (define-module (gnu packages erlang)
-  #:use-module ((guix licenses) #:prefix license:)
-  #:use-module (guix gexp)
-  #:use-module (guix build-system gnu)
-  #:use-module (guix build-system emacs)
-  #:use-module (guix build-system rebar)
-  #:use-module (guix download)
-  #:use-module (guix git-download)
-  #:use-module (guix packages)
-  #:use-module (guix utils)
-  #:use-module (gnu packages)
+  #:use-module ((guix licenses)
+                #:prefix license:)
+  #:use-module (gnu packages elixir)
   #:use-module (gnu packages fontutils)
   #:use-module (gnu packages gl)
   #:use-module (gnu packages ncurses)
   #:use-module (gnu packages perl)
-  #:use-module (gnu packages version-control)
   #:use-module (gnu packages tls)
-  #:use-module (gnu packages wxwidgets))
+  #:use-module (gnu packages erlang-xyz)
+  #:use-module (gnu packages version-control)
+  #:use-module (gnu packages wxwidgets)
+  #:use-module (gnu packages)
+  #:use-module (guix build utils)
+  #:use-module (guix build-system emacs)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix build-system rebar)
+  #:use-module (guix download)
+  #:use-module (guix gexp)
+  #:use-module (guix git-download)
+  #:use-module (guix packages)
+  #:use-module (guix utils))
 
 (define-public erlang
   (package
     (name "erlang")
     (version "25.3.2")
-    (source (origin
-              (method git-fetch)
-              ;; The tarball from http://erlang.org/download contains many
-              ;; pre-compiled files, so we use this snapshot of the source
-              ;; repository.
-              (uri (git-reference
-                    (url "https://github.com/erlang/otp")
-                    (commit (string-append "OTP-" version))))
-              (file-name (git-file-name name version))
-              (sha256
-               (base32
-                "092lym5a181gz89nscw7kqhw1wa6qvgcpkj80q4i9p79mxmsr1nj"))
-              (patches (search-patches "erlang-man-path.patch"))))
+    (source
+     (origin
+       (method git-fetch)
+       ;; The tarball from http://erlang.org/download contains many
+       ;; pre-compiled files, so we use this snapshot of the source
+       ;; repository.
+       (uri (git-reference
+             (url "https://github.com/erlang/otp")
+             (commit (string-append "OTP-" version))))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "092lym5a181gz89nscw7kqhw1wa6qvgcpkj80q4i9p79mxmsr1nj"))
+       (patches (search-patches "erlang-man-path.patch"))))
     (build-system gnu-build-system)
-    (native-inputs
-     `(("perl" ,perl)
+    (native-inputs `(("perl" ,perl)
 
-       ;; Erlang's documentation is distributed in a separate tarball.
-       ("erlang-manpages"
-        ,(origin
-           (method url-fetch)
-           (uri (string-append "http://erlang.org/download/otp_doc_man_"
-                               (version-major+minor version) ".tar.gz"))
-           (sha256
-            (base32
-             "0vnpds5q17xc4jjj3sbsllpx68wyhgvx70714vkzyd68rbjmhmk7"))))))
-    (inputs
-     (list ncurses openssl wxwidgets))
-    (propagated-inputs
-     (list fontconfig glu mesa))
+                     ;; Erlang's documentation is distributed in a separate tarball.
+                     ("erlang-manpages" ,(origin
+                                           (method url-fetch)
+                                           (uri (string-append
+                                                 "http://erlang.org/download/otp_doc_man_"
+                                                 (version-major+minor version)
+                                                 ".tar.gz"))
+                                           (sha256 (base32
+                                                    "0vnpds5q17xc4jjj3sbsllpx68wyhgvx70714vkzyd68rbjmhmk7"))))))
+    (inputs (list ncurses openssl wxwidgets))
+    (propagated-inputs (list fontconfig glu mesa))
     (arguments
      `(#:test-target "release_tests"
-       #:configure-flags
-       (list "--disable-saved-compile-time"
-             "--enable-dynamic-ssl-lib"
-             "--enable-native-libs"
-             "--enable-shared-zlib"
-             "--enable-smp-support"
-             "--enable-threads"
-             "--enable-wx"
-             (string-append "--with-ssl=" (assoc-ref %build-inputs "openssl")))
-       #:modules ((srfi srfi-19)        ; make-time, et cetera.
+       #:configure-flags (list "--disable-saved-compile-time"
+                               "--enable-dynamic-ssl-lib"
+                               "--enable-native-libs"
+                               "--enable-shared-zlib"
+                               "--enable-smp-support"
+                               "--enable-threads"
+                               "--enable-wx"
+                               (string-append "--with-ssl="
+                                              (assoc-ref %build-inputs
+                                                         "openssl")))
+       #:modules ((srfi srfi-19)
+                                        ;make-time, et cetera.
                   (guix build utils)
                   (guix build gnu-build-system))
-       #:phases
-       (modify-phases %standard-phases
-         (delete 'bootstrap)
-         ;; The are several code fragments that embed timestamps into the
-         ;; output. Here, we alter those fragments to use the value of
-         ;; SOURCE_DATE_EPOCH instead.
-         (add-after 'unpack 'remove-timestamps
-           (lambda _
-             (let ((source-date-epoch
-                    (time-utc->date
-                     (make-time time-utc 0 (string->number
-                                            (getenv "SOURCE_DATE_EPOCH"))))))
-               (substitute* "lib/reltool/src/reltool_target.erl"
-                 (("Date = date\\(\\),")
-                  (string-append "Date = "
-                                 (date->string source-date-epoch
-                                               "'{~Y,~m,~d}',"))))
-               (substitute* "lib/reltool/src/reltool_target.erl"
-                 (("Time = time\\(\\),")
-                  (string-append "Time = "
-                                 (date->string source-date-epoch
-                                               "'{~H,~M,~S}',"))))
-               (substitute* '("lib/reltool/src/reltool_target.erl"
-                              "lib/sasl/src/systools_make.erl")
-                 (("date\\(\\), time\\(\\),")
-                  (date->string source-date-epoch
-                                "{~Y,~m,~d}, {~H,~M,~S},")))
-               (substitute* "lib/dialyzer/test/small_SUITE_data/src/gs_make.erl"
-                 (("tuple_to_list\\(date\\(\\)\\),tuple_to_list\\(time\\(\\)\\)")
-                  (date->string
-                   source-date-epoch
-                   "tuple_to_list({~Y,~m,~d}), tuple_to_list({~H,~M,~S})")))
-               (substitute* "lib/snmp/src/compile/snmpc_mib_to_hrl.erl"
-                 (("\\{Y,Mo,D\\} = date\\(\\),")
-                  (date->string source-date-epoch
-                                "{Y,Mo,D} = {~Y,~m,~d},")))
-               (substitute* "lib/snmp/src/compile/snmpc_mib_to_hrl.erl"
-                 (("\\{H,Mi,S\\} = time\\(\\),")
-                  (date->string source-date-epoch
-                                "{H,Mi,S} = {~H,~M,~S},"))))))
-         (add-after 'unpack 'patch-/bin/sh
-           (lambda* (#:key inputs #:allow-other-keys)
-             (let ((sh (search-input-file inputs "/bin/sh")))
-               (substitute* "erts/etc/unix/run_erl.c"
-                 (("sh = \"/bin/sh\";")
-                  (string-append "sh = \"" sh "\";")))
-               (substitute* "erts/emulator/sys/unix/sys_drivers.c"
-                 (("SHELL \"/bin/sh\"")
-                  (string-append "SHELL \"" sh "\"")))
-               (substitute* "erts/emulator/sys/unix/erl_child_setup.c"
-                 (("SHELL \"/bin/sh\"")
-                  (string-append "SHELL \"" sh "\"")))
-               (substitute* "lib/kernel/src/os.erl"
-                 (("/bin/sh") sh)))))
-         (add-after 'patch-source-shebangs 'patch-source-env
-           (lambda _
-             (let ((escripts
-                    (append
-                        (find-files "." "\\.escript")
-                        (find-files "lib/stdlib/test/escript_SUITE_data/")
-                      '("erts/lib_src/utils/make_atomics_api"
-                        "erts/preloaded/src/add_abstract_code"
-                        "lib/diameter/bin/diameterc"
-                        "lib/reltool/examples/display_args"
-                        "lib/reltool/examples/mnesia_core_dump_viewer"
-                        "lib/snmp/src/compile/snmpc.src"
-                        "make/verify_runtime_dependencies"
-                        "make/emd2exml.in"))))
-               (substitute* escripts
-                 (("/usr/bin/env") (which "env"))))))
-         (add-before 'configure 'set-erl-top
-           (lambda _
-             (setenv "ERL_TOP" (getcwd))))
-         (add-after 'install 'patch-erl
-           ;; This only works after install.
-           (lambda* (#:key outputs #:allow-other-keys)
-             (let ((out (assoc-ref outputs "out")))
-               (substitute* (string-append out "/bin/erl")
-                 (("basename") (which "basename"))
-                 (("dirname") (which "dirname"))))))
-         (add-after 'install 'install-doc
-           (lambda* (#:key inputs outputs #:allow-other-keys)
-             (let* ((out (assoc-ref outputs "out"))
-                    (manpages (assoc-ref inputs "erlang-manpages"))
-                    (share (string-append out "/share/")))
-               (mkdir-p share)
-               (with-directory-excursion share
-                 (invoke "tar" "xvf" manpages))))))))
+       #:phases (modify-phases %standard-phases
+                  (delete 'bootstrap)
+                  ;; The are several code fragments that embed timestamps into the
+                  ;; output. Here, we alter those fragments to use the value of
+                  ;; SOURCE_DATE_EPOCH instead.
+                  (add-after 'unpack 'remove-timestamps
+                    (lambda _
+                      (let ((source-date-epoch (time-utc->date (make-time
+                                                                time-utc 0
+                                                                (string->number
+                                                                 (getenv
+                                                                  "SOURCE_DATE_EPOCH"))))))
+                        (substitute* "lib/reltool/src/reltool_target.erl"
+                          (("Date = date\\(\\),")
+                           (string-append "Date = "
+                                          (date->string source-date-epoch
+                                                        "'{~Y,~m,~d}',"))))
+                        (substitute* "lib/reltool/src/reltool_target.erl"
+                          (("Time = time\\(\\),")
+                           (string-append "Time = "
+                                          (date->string source-date-epoch
+                                                        "'{~H,~M,~S}',"))))
+                        (substitute* '("lib/reltool/src/reltool_target.erl"
+                                       "lib/sasl/src/systools_make.erl")
+                          (("date\\(\\), time\\(\\),")
+                           (date->string source-date-epoch
+                                         "{~Y,~m,~d}, {~H,~M,~S},")))
+                        (substitute* "lib/dialyzer/test/small_SUITE_data/src/gs_make.erl"
+                          (("tuple_to_list\\(date\\(\\)\\),tuple_to_list\\(time\\(\\)\\)")
+                           (date->string source-date-epoch
+                                         "tuple_to_list({~Y,~m,~d}), tuple_to_list({~H,~M,~S})")))
+                        (substitute* "lib/snmp/src/compile/snmpc_mib_to_hrl.erl"
+                          (("\\{Y,Mo,D\\} = date\\(\\),")
+                           (date->string source-date-epoch
+                                         "{Y,Mo,D} = {~Y,~m,~d},")))
+                        (substitute* "lib/snmp/src/compile/snmpc_mib_to_hrl.erl"
+                          (("\\{H,Mi,S\\} = time\\(\\),")
+                           (date->string source-date-epoch
+                                         "{H,Mi,S} = {~H,~M,~S},"))))))
+                  (add-after 'unpack 'patch-/bin/sh
+                    (lambda* (#:key inputs #:allow-other-keys)
+                      (let ((sh (search-input-file inputs "/bin/sh")))
+                        (substitute* "erts/etc/unix/run_erl.c"
+                          (("sh = \"/bin/sh\";")
+                           (string-append "sh = \"" sh "\";")))
+                        (substitute* "erts/emulator/sys/unix/sys_drivers.c"
+                          (("SHELL \"/bin/sh\"")
+                           (string-append "SHELL \"" sh "\"")))
+                        (substitute* "erts/emulator/sys/unix/erl_child_setup.c"
+                          (("SHELL \"/bin/sh\"")
+                           (string-append "SHELL \"" sh "\"")))
+                        (substitute* "lib/kernel/src/os.erl"
+                          (("/bin/sh")
+                           sh)))))
+                  (add-after 'patch-source-shebangs 'patch-source-env
+                    (lambda _
+                      (let ((escripts (append (find-files "." "\\.escript")
+                                              (find-files
+                                               "lib/stdlib/test/escript_SUITE_data/")
+                                              '("erts/lib_src/utils/make_atomics_api"
+                                                "erts/preloaded/src/add_abstract_code"
+                                                "lib/diameter/bin/diameterc"
+                                                "lib/reltool/examples/display_args"
+                                                "lib/reltool/examples/mnesia_core_dump_viewer"
+                                                "lib/snmp/src/compile/snmpc.src"
+                                                "make/verify_runtime_dependencies"
+                                                "make/emd2exml.in"))))
+                        (substitute* escripts
+                          (("/usr/bin/env")
+                           (which "env"))))))
+                  (add-before 'configure 'set-erl-top
+                    (lambda _
+                      (setenv "ERL_TOP"
+                              (getcwd))))
+                  (add-after 'install 'patch-erl
+                    ;; This only works after install.
+                    (lambda* (#:key outputs #:allow-other-keys)
+                      (let ((out (assoc-ref outputs "out")))
+                        (substitute* (string-append out "/bin/erl")
+                          (("basename")
+                           (which "basename"))
+                          (("dirname")
+                           (which "dirname"))))))
+                  (add-after 'patch-erl 'wrap-programs
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (let* ((out (assoc-ref outputs "out"))
+                             (programs '("erl" "erlc" "escript")))
+                        (for-each (lambda (program)
+                                    (wrap-program (string-append out "/bin/"
+                                                                 program)
+                                      '("ERL_LIBS" ":" prefix
+                                        ("${GUIX_ERL_LIBS}")))) programs))))
+                  (add-after 'wrap-programs 'install-doc
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (let* ((out (assoc-ref outputs "out"))
+                             (manpages (assoc-ref inputs "erlang-manpages"))
+                             (share (string-append out "/share/")))
+                        (mkdir-p share)
+                        (with-directory-excursion share
+                          (invoke "tar" "xvf" manpages))))))))
+    (native-search-paths
+     (list (search-path-specification
+            (variable "GUIX_ERL_LIBS")
+            (files (list "lib/erlang/lib"
+                         (string-append "lib/elixir/"
+                                        (version-major+minor (package-version
+                                                              elixir))))))))
     (home-page "https://www.erlang.org/")
     (synopsis "The Erlang programming language")
     (description
@@ -191,414 +214,13 @@ (define-public erlang
 built-in support for concurrency, distribution and fault tolerance.")
     ;; Erlang is distributed under the Apache License 2.0, but some components
     ;; have other licenses. See 'system/COPYRIGHT' in the source distribution.
-    (license (list license:asl2.0 license:bsd-2 license:bsd-3 license:expat
-                   license:lgpl2.0+ license:tcl/tk license:zlib))))
-
-(define-public emacs-erlang
-  (package
-    (name "emacs-erlang")
-    (version (package-version erlang))
-    (source (package-source erlang))
-    (build-system emacs-build-system)
-    (arguments
-     `(#:phases
-       (modify-phases %standard-phases
-         (add-before 'expand-load-path 'change-working-directory
-           (lambda _ (chdir "lib/tools/emacs") #t)))))
-    (home-page "https://www.erlang.org/")
-    (synopsis "Erlang major mode for Emacs")
-    (description
-     "This package provides an Emacs major mode for editing Erlang source
-files.")
-    (license license:asl2.0)))
-
-(define-public erlang-bbmustache
-  (package
-    (name "erlang-bbmustache")
-    (version "1.12.2")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "bbmustache" version))
-       (sha256
-        (base32 "0fvvaxdpziygxl30j59g98qkh2n47xlb7w5dfpsm2bfcsnj372v8"))))
-    (build-system rebar-build-system)
-    (inputs
-     (list erlang-getopt rebar3-git-vsn
-           erlang-edown))  ; for building the docs
-    (arguments
-     `(#:tests? #f ;; requires mustache specification file
-       #:phases
-       (modify-phases %standard-phases
-         (add-before 'build 'build-more
-           (lambda _
-             (invoke "rebar3" "as" "dev" "escriptize")))
-         (add-after 'install 'install-escript
-           (lambda* (#:key outputs #:allow-other-keys)
-             (let* ((out (assoc-ref outputs "out")))
-               (install-file "_build/dev/bin/bbmustache"
-                             (string-append out "/bin"))))))))
-    (home-page "https://github.com/soranoba/bbmustache/")
-    (synopsis "Binary pattern match Based Mustache template engine for Erlang")
-    (description "This Erlang library provides a Binary pattern match Based
-Mustache template engine")
-    (license license:expat)))
-
-(define-public erlang-certifi
-  (package
-    (name "erlang-certifi")
-    (version "2.9.0")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "certifi" version))
-       (sha256
-        (base32 "0ha6vmf5p3xlbf5w1msa89frhvfk535rnyfybz9wdmh6vdms8v96"))))
-    (build-system rebar-build-system)
-    (arguments
-     `(#:tests? #f)) ;; have not been updated for latest cert bundle
-    (home-page "https://github.com/certifi/erlang-certifi/")
-    (synopsis "Erlang CA certificate bundle")
-    (description "This Erlang library contains a CA bundle that you can
-reference in your Erlang application.  This is useful for systems that do not
-have CA bundles that Erlang can find itself, or where a uniform set of CAs is
-valuable.
-
-This an Erlang specific port of certifi.  The CA bundle is derived from
-Mozilla's canonical set.")
-    (license license:bsd-3)))
-
-(define-public erlang-cf
-  (package
-    (name "erlang-cf")
-    (version "0.3.1")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "cf" version))
-       (sha256
-        (base32 "0wknz4xkqkhgvlx4vx5619p8m65v7g87lfgsvfy04jrsgm28spii"))))
-    (build-system rebar-build-system)
-    (home-page "https://github.com/project-fifo/cf")
-    (synopsis "Terminal colour helper for Erlang io and io_lib")
-    (description "This package provides a helper library for termial colour
-printing extending the io:format syntax to add colours.")
-    (license license:expat)))
-
-(define-public erlang-yamerl
-  (package
-    (name "erlang-yamerl")
-    (version "0.10.0")
-    (source
-     (origin
-       (method git-fetch)
-       (uri (git-reference
-             ;; There are no tests included on Hex.
-             (url "https://github.com/yakaz/yamerl")
-             (commit (string-append "v" version))))
-       (file-name (git-file-name name version))
-       (sha256
-        (base32 "0if8abgmispcfk7zhd0a5dndzwzbsmqrbyrm5shk375r2dbbwak6"))))
-    (build-system rebar-build-system)
-    (synopsis "YAML and JSON parser in pure Erlang")
-    (description
-     "Erlang application to parse YAML 1.1 and YAML 1.2 documents, as well as
-JSON documents.")
-    (home-page "https://hexdocs.pm/yamerl/")
-    (license license:bsd-2)))
-
-(define-public erlang-covertool
-  (package
-    (name "erlang-covertool")
-    (version "2.0.4")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "covertool" version))
-       (sha256
-        (base32 "1p0c1n3nl4063xwi1sv176l1x68xqf07qwvj444a5z888fx6i5aw"))))
-    (build-system rebar-build-system)
-    (home-page "https://github.com/covertool/covertool")
-    (synopsis "Convert code-coverage data generated by @code{cover} into
-Cobertura XML reports")
-    (description "This package provides a build tool and plugin to convert
-exported Erlang @code{cover} data sets into Cobertura XML reports, which can
-then be feed to the Jenkins Cobertura plug-in.
-
-On @emph{hex.pm}, this plugin was previously called @code{rebar_covertool}.")
-    (license license:bsd-2)))
-
-(define-public erlang-cth-readable
-  (package
-    (name "erlang-cth-readable")
-    (version "1.5.1")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "cth_readable" version))
-       (sha256
-        (base32 "104xgybb6iciy6i28pyyrarqzliddi8kjyq43ajaav7y5si42rb8"))))
-    (build-system rebar-build-system)
-    (propagated-inputs
-     (list erlang-cf))
-    (arguments
-     `(#:tests? #f)) ;; no test-suite in hex-pm package
-    (home-page "https://github.com/ferd/cth_readable")
-    (synopsis "Common Test hooks for more readable logs for Erlang")
-    (description "This package provides an OTP library to be used for CT log
-outputs you want to be readable around all that noise they contain.")
-    (license license:bsd-3)))
-
-(define-public erlang-edown
-  (package
-    (name "erlang-edown")
-    (version "0.8.4")
-    (source
-      (origin
-        (method url-fetch)
-        (uri (hexpm-uri "edown" version))
-        (sha256
-          (base32 "0ij47gvgs6yfqphj0f54qjzj18crj8y1dsjjlzpp3dp8pscqzbqw"))))
-    (build-system rebar-build-system)
-    (home-page "https://github.com/uwiger/edown")
-    (synopsis "Markdown extension for EDoc")
-    (description "This package provides an extension for EDoc for generating
-Markdown.")
-    (license license:asl2.0)))
-
-(define-public erlang-erlware-commons
-  (package
-    (name "erlang-erlware-commons")
-    (version "1.6.0")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "erlware_commons" version))
-       (sha256
-        (base32 "18qam9xdzi74wppb0cj4zc8161i0i8djr79z8662m6d276f2jz5m"))))
-    (build-system rebar-build-system)
-    (propagated-inputs
-     (list erlang-cf))
-    (native-inputs
-     (list git-minimal/pinned))  ;; Required for tests
-    (arguments
-     `(#:phases
-       (modify-phases %standard-phases
-         (add-before 'check 'check-setup
-           (lambda _
-             (setenv "TERM" "xterm")))))) ; enable color in logs
-    (home-page "https://erlware.github.io/erlware_commons/")
-    (synopsis "Additional standard library for Erlang")
-    (description "Erlware Commons is an Erlware project focused on all aspects
-of reusable Erlang components.")
-    (license license:expat)))
-
-(define-public erlang-eunit-formatters
-  (package
-    (name "erlang-eunit-formatters")
-    (version "0.5.0")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "eunit_formatters" version))
-       (sha256
-        (base32 "1jb3hzb216r29x2h4pcjwfmx1k81431rgh5v0mp4x5146hhvmj6n"))))
-    (build-system rebar-build-system)
-    (home-page "https://github.com/seancribbs/eunit_formatters")
-    (synopsis "Better output for eunit suites")
-    (description "This package provides a better output for Erlang eunits.")
-    (license license:asl2.0)))
-
-(define-public erlang-getopt
-  (package
-    (name "erlang-getopt")
-    (version "1.0.2")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "getopt" version))
-       (sha256
-        (base32 "09pasi7ki1rivw9sl7xndj5qgjbdqvcscxk83yk85yr28gm9l0m0"))))
-    (build-system rebar-build-system)
-    (home-page "https://github.com/jcomellas/getopt")
-    (synopsis "Command-line options parser for Erlang")
-    (description "This package provides an Erlang module to parse command line
-arguments using the GNU getopt syntax.")
-    (license license:bsd-3)))
-
-(define-public erlang-hex-core
-  (package
-    (name "erlang-hex-core")
-    (version "0.8.4")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "hex_core" version))
-       (sha256
-        (base32 "06p65hlm29ky03vs3fq3qz6px2ylwp8b0f2y75wdf5cm0kx2332b"))))
-    (build-system rebar-build-system)
-    (arguments
-     `(#:phases
-       (modify-phases %standard-phases
-         (replace 'check
-           (lambda* (#:key tests? #:allow-other-keys)
-             (when tests?
-               (invoke "rebar3" "as" "test" "proper")))))))
-    (inputs
-     (list erlang-proper rebar3-proper))
-    (home-page "https://github.com/hexpm/hex_core")
-    (synopsis "Reference implementation of Hex specifications")
-    (description "This package provides the reference implementation of Hex
-specifications.")
-    (license license:asl2.0)))
-
-(define-public erlang-jsone
-  (package
-    (name "erlang-jsone")
-    (version "1.7.0")
-    (source
-      (origin
-        (method url-fetch)
-        (uri (hexpm-uri "jsone" version))
-        (sha256
-          (base32 "1gaxiw76syjp3s9rygskm32y9799b917q752rw8bxj3bxq93g8x3"))))
-    (build-system rebar-build-system)
-    (arguments
-     `(#:phases
-       (modify-phases %standard-phases
-         (add-after 'unpack 'disable-covertool
-           ;; no need to generate a coverage report
-           (lambda _
-             (substitute* "rebar.config"
-               (("\\{project_plugins, \\[covertool\\]\\}\\." _) "")))))))
-    (home-page "https://github.com/sile/jsone/")
-    (synopsis "Erlang JSON Library")
-    (description "An Erlang library for encoding and decoding JSON data.")
-    (license license:expat)))
-
-(define-public erlang-parse-trans
-  (package
-    (name "erlang-parse-trans")
-    (version "3.4.1")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "parse_trans" version))
-       (sha256
-        (base32 "16p4c2xjrvz16kzpr9pmcvi6nxq6rwckqi9fp0ksibaxwxn402k2"))))
-    (build-system rebar-build-system)
-    (inputs
-     (list erlang-getopt))
-    (home-page "https://github.com/uwiger/parse_trans")
-    (synopsis "Parse transform utilities for Erlang")
-    (description "This package captures some useful patterns in parse
-transformation and code generation for Erlang.
-
-For example generating standardized accessor functions for records or
-evaluating an expression at compile-time and substitute the result as a
-compile-time constant.")
-    (license license:asl2.0)))
-
-(define-public erlang-proper
-  (package
-    (name "erlang-proper")
-    (version "1.4.0")
-    (source
-      (origin
-        (method url-fetch)
-        (uri (hexpm-uri "proper" version))
-        (sha256
-          (base32 "1fwcas4a9kz3w3z1jqdk9lw8822srfjk9lcpvbxkxlsv3115ha0q"))))
-    (build-system rebar-build-system)
-    (arguments
-     `(#:phases
-       (modify-phases %standard-phases
-         (add-after 'unpack 'disable-covertool
-           ;; no need to generate a coverage report
-           (lambda _
-             (substitute* "rebar.config"
-               (("\\{plugins, \\[covertool\\]\\}\\." _) "")))))))
-    (home-page "https://proper-testing.github.io/")
-    (synopsis "QuickCheck-inspired property-based testing tool for Erlang")
-    (description "PropEr is a tool for the automated, semi-random,
-property-based testing of Erlang programs.  It is fully integrated with
-Erlang's type language, and can also be used for the model-based random
-testing of stateful systems.")
-    (license license:gpl3+)))
-
-(define-public erlang-jsx
-  (package
-    (name "erlang-jsx")
-    (version "3.1.0")
-    (source (origin
-              (method url-fetch)
-              (uri (hexpm-uri "jsx" version))
-              (sha256
-               (base32
-                "1wr7jkxm6nlgvd52xhniav64xr9rml2ngb35rwjwqlqvq7ywhp0c"))))
-    (build-system rebar-build-system)
-    (synopsis "Streaming, evented JSON parsing toolkit")
-    (description
-     "An Erlang application for consuming, producing and manipulating json.")
-    (home-page "https://github.com/talentdeficit/jsx")
-    (license license:expat)))
-
-(define-public erlang-providers
-  (package
-    (name "erlang-providers")
-    (version "1.9.0")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "providers" version))
-       (sha256
-        (base32 "05y0kz3xgx77hzn1l05byaisvmk8bgds7c22hrh0a5ba81sfi1yj"))))
-    (build-system rebar-build-system)
-    (propagated-inputs
-     (list erlang-erlware-commons erlang-getopt))
-    (home-page "https://github.com/tsloughter/providers")
-    (synopsis "Erlang providers library")
-    (description "This package provides an Erlang providers library.")
-    (license license:asl2.0)))
-
-(define-public erlang-relx
-  (package
-    (name "erlang-relx")
-    (version "4.6.0")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "relx" version))
-       (sha256
-        (base32 "02gmfx1vxg9m3mq4njsqhs4972l4nb8m5p1pdcf64g09ccf17y1g"))))
-    (build-system rebar-build-system)
-    (propagated-inputs
-     (list erlang-bbmustache))
-    (home-page "https://erlware.github.io/relx/")
-    (synopsis "Release assembler for Erlang/OTP Releases")
-    (description "Relx assembles releases for an Erlang/OTP release.  Given a
-release specification and a list of directories in which to search for OTP
-applications it will generate a release output.  That output depends heavily on
-what plugins available and what options are defined, but usually it is simply
-a well configured release directory.")
-    (license license:asl2.0)))
-
-(define-public erlang-ssl-verify-fun
-  (package
-    (name "erlang-ssl-verify-fun")
-    (version "1.1.6")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "ssl_verify_fun" version))
-       (sha256
-        (base32 "1026l1z1jh25z8bfrhaw0ryk5gprhrpnirq877zqhg253x3x5c5x"))))
-    (build-system rebar-build-system)
-    (home-page "https://github.com/deadtrickster/ssl_verify_fun.erl")
-    (synopsis "SSL verification functions for Erlang")
-    (description "This package provides SSL verification functions for
-Erlang.")
-    (license license:expat)))
+    (license (list license:asl2.0
+                   license:bsd-2
+                   license:bsd-3
+                   license:expat
+                   license:lgpl2.0+
+                   license:tcl/tk
+                   license:zlib))))
 
 (define-public rebar3
   (package
@@ -616,56 +238,71 @@ (define-public rebar3
     (build-system gnu-build-system)
     ;; TODO: remove vendored modules, install man-page, install lib(?)
     (arguments
-     `(#:phases
-       (modify-phases %standard-phases
-         (delete 'bootstrap)
-         (add-after 'unpack 'unpack-dependency-sources
-           (lambda* (#:key inputs #:allow-other-keys)
-             (for-each
-              (lambda (pkgname)
-                (let* ((src (string-append pkgname "-source"))
-                       (input (assoc-ref inputs src))
-                       (checkouts-dir (string-append "_checkouts/" pkgname))
-                       (lib-dir (string-append "_build/default/lib/" pkgname)))
-                  (mkdir-p checkouts-dir)
-                  (invoke "tar" "-xf" input "-C" checkouts-dir)
-                  (invoke "tar" "-xzf"
-                          (pk (string-append checkouts-dir "/contents.tar.gz"))
-                          "-C" checkouts-dir)
-                  (mkdir-p lib-dir)
-                  (copy-recursively checkouts-dir lib-dir)))
-              (list "bbmustache" "certifi" "cf" "cth_readable"
-                    "eunit_formatters" "getopt" "hex_core" "erlware_commons"
-                    "parse_trans" "relx" "ssl_verify_fun" "providers"))))
-         (delete 'configure)
-         (replace 'build
-           (lambda _
-             (setenv "HOME" (getcwd))
-             (invoke "./bootstrap")))
-         (replace 'install
-           (lambda* (#:key outputs #:allow-other-keys)
-             (let* ((out (assoc-ref outputs "out")))
-               (install-file "rebar3" (string-append out "/bin")))))
-         (delete 'check))))
-    (native-inputs
-     (list erlang))
-    (inputs
-     `(("bbmustache-source" ,(package-source erlang-bbmustache))
-       ("certifi-source" ,(package-source erlang-certifi))
-       ("cf-source" ,(package-source erlang-cf))
-       ("cth_readable-source" ,(package-source erlang-cth-readable))
-       ("erlware_commons-source" ,(package-source erlang-erlware-commons))
-       ("eunit_formatters-source" ,(package-source erlang-eunit-formatters))
-       ("getopt-source" ,(package-source erlang-getopt))
-       ("hex_core-source" ,(package-source erlang-hex-core))
-       ("parse_trans-source" ,(package-source erlang-parse-trans))
-       ("relx-source" ,(package-source erlang-relx))
-       ("ssl_verify_fun-source" ,(package-source erlang-ssl-verify-fun))
-       ("providers-source" ,(package-source erlang-providers))))
+     `(#:phases (modify-phases %standard-phases
+                  (delete 'bootstrap)
+                  (add-after 'unpack 'unpack-dependency-sources
+                    (lambda* (#:key inputs #:allow-other-keys)
+                      (for-each (lambda (pkgname)
+                                  (let* ((src (string-append pkgname "-source"))
+                                         (input (assoc-ref inputs src))
+                                         (checkouts-dir (string-append
+                                                         "_checkouts/" pkgname))
+                                         (lib-dir (string-append
+                                                   "_build/default/lib/"
+                                                   pkgname)))
+                                    (mkdir-p checkouts-dir)
+                                    (invoke "tar" "-xf" input "-C"
+                                            checkouts-dir)
+                                    (invoke "tar" "-xzf"
+                                            (pk (string-append checkouts-dir
+                                                               "/contents.tar.gz")) "-C"
+                                                               checkouts-dir)
+                                    (mkdir-p lib-dir)
+                                    (copy-recursively checkouts-dir lib-dir)))
+                                (list "bbmustache"
+                                      "certifi"
+                                      "cf"
+                                      "cth_readable"
+                                      "eunit_formatters"
+                                      "getopt"
+                                      "hex_core"
+                                      "erlware_commons"
+                                      "parse_trans"
+                                      "relx"
+                                      "ssl_verify_fun"
+                                      "providers"))))
+                  (delete 'configure)
+                  (replace 'build
+                    (lambda _
+                      (setenv "HOME"
+                              (getcwd))
+                      (invoke "./bootstrap")))
+                  (replace 'install
+                    (lambda* (#:key outputs #:allow-other-keys)
+                      (let* ((out (assoc-ref outputs "out")))
+                        (install-file "rebar3"
+                                      (string-append out "/bin")))))
+                  (delete 'check))))
+    (native-inputs (list erlang))
+    (inputs `(("bbmustache-source" ,(package-source erlang-bbmustache))
+              ("certifi-source" ,(package-source erlang-certifi))
+              ("cf-source" ,(package-source erlang-cf))
+              ("cth_readable-source" ,(package-source erlang-cth-readable))
+              ("erlware_commons-source" ,(package-source
+                                          erlang-erlware-commons))
+              ("eunit_formatters-source" ,(package-source
+                                           erlang-eunit-formatters))
+              ("getopt-source" ,(package-source erlang-getopt))
+              ("hex_core-source" ,(package-source erlang-hex-core))
+              ("parse_trans-source" ,(package-source erlang-parse-trans))
+              ("relx-source" ,(package-source erlang-relx))
+              ("ssl_verify_fun-source" ,(package-source erlang-ssl-verify-fun))
+              ("providers-source" ,(package-source erlang-providers))))
     (home-page "https://rebar3.org/")
     (synopsis "Sophisticated build-tool for Erlang projects that follows OTP
 principles")
-    (description "@code{rebar3} is an Erlang build tool that makes it easy to
+    (description
+     "@code{rebar3} is an Erlang build tool that makes it easy to
 compile and test Erlang applications, port drivers and releases.
 
 @code{rebar3} is a self-contained Erlang script, so it's easy to distribute or
@@ -676,84 +313,19 @@ (define-public rebar3
 of locations (git, hg, etc).")
     (license license:asl2.0)))
 
-(define-public rebar3-raw-deps
-  (package
-    (name "rebar3-raw-deps")
-    (version "2.0.0")
-    (source
-     (origin
-       (method url-fetch)
-       (uri (hexpm-uri "rebar3_raw_deps" version))
-       (sha256
-        (base32 "1pzmm3m8gb2s9jn8fp6shzgfmy4mvh2vdci0z6nsm74ma3ffh1i3"))))
-    (build-system rebar-build-system)
-    (home-page "https://github.com/soranoba/rebar3_raw_deps")
-    (synopsis "Rebar3 plugin for supporting \"raw\" dependencies")
-    (description "This plugin provides support for handling non-OTP
-applications as a dependent libraries.")
-    (license license:expat)))
-
-(define-public rebar3-git-vsn
-  (package
-    (name "rebar3-git-vsn")
-    (version "1.1.1")
-    (source
-      (origin
-        (method url-fetch)
-        (uri (hexpm-uri "rebar3_git_vsn" version))
-        (sha256
-          (base32 "1dfz56034pa25axly9vqdzv3phkn8ll0qwrkws96pbgcprhky1hx"))))
-    (build-system rebar-build-system)
-    (inputs
-     (list git-minimal/pinned))
-    (arguments
-     `(;; Running the tests require binary artifact (tar-file containing
-       ;; samples git repos)  TODO: remove these from the source
-       #:tests? #f
-       #:phases
-       (modify-phases %standard-phases
-         (add-after 'unpack 'patch-path
-           (lambda* (#:key inputs #:allow-other-keys)
-             (let ((git (assoc-ref inputs "git-minimal")))
-               (substitute* "src/rebar3_git_vsn.erl"
-                 (("rebar_utils:sh\\(\"git " _)
-                  (string-append "rebar_utils:sh(\"" git "/bin/git ")))))))))
-    (home-page "https://github.com/soranoba/rebar3_git_vsn")
-    (synopsis "Rebar3 plugin for generating the version from git")
-    (description "This plugin adds support for generating the version from
-a git checkout.")
-    (license license:expat)))
-
-(define-public rebar3-proper
-  (package
-    (name "rebar3-proper")
-    (version "0.12.1")
-    (source
-      (origin
-        (method url-fetch)
-        (uri (hexpm-uri "rebar3_proper" version))
-        (sha256
-          (base32 "1f174fb6h2071wr7qbw9aqqvnglzsjlylmyi8215fhrmi38w94b6"))))
-    (build-system rebar-build-system)
-    (home-page "https://github.com/ferd/rebar3_proper")
-    (synopsis "Rebar3 PropEr plugin")
-    (description "This plugin allows running PropEr test suites from within
-rebar3.")
-    (license license:bsd-3)))
-
 (define-public erlang-lfe
   (package
     (name "erlang-lfe")
     (version "2.1.2")
-    (source (origin
-              (method git-fetch)
-              (uri (git-reference
-                    (url "https://github.com/lfe/lfe")
-                    (commit "v2.1.2")))
-              (file-name (git-file-name name version))
-              (sha256
-               (base32
-                "180hz1p2v3vb6yyzcfwircmljlnd86ln8z80lzy3mwlyrcxblvxy"))))
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/lfe/lfe")
+             (commit "v2.1.2")))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "180hz1p2v3vb6yyzcfwircmljlnd86ln8z80lzy3mwlyrcxblvxy"))))
     (build-system gnu-build-system)
     (arguments
      (list
@@ -761,49 +333,47 @@ (define-public erlang-lfe
                   (srfi srfi-26)
                   (guix build gnu-build-system)
                   (guix build utils))
-      #:make-flags #~(list (string-append "PREFIX=" #$output) "CC=gcc")
-      #:phases
-      #~(modify-phases %standard-phases
-          (delete 'configure)
-          ;; The following is inspired by rebar-build-system.scm
-          (add-before 'check 'erlang-depends
-            (lambda* (#:key inputs #:allow-other-keys)
-              (define input-directories
-                (list #$(this-package-native-input "rebar3-proper")
-                      #$(this-package-native-input "erlang-proper")))
-              (mkdir-p "_checkouts")
-              (for-each
-               (lambda (input-dir)
-                 (let ((elibdir (string-append input-dir "/lib/erlang/lib")))
-                   (when (directory-exists? elibdir)
-                     (for-each
-                      (lambda (dirname)
-                        (let ((src (string-append elibdir "/" dirname))
-                              (dest (string-append "_checkouts/" dirname)))
-                          (when (not (file-exists? dest))
-                            ;; Symlinking will not work, since rebar3 will try
-                            ;; to overwrite the _build directory several times
-                            ;; with the contents of _checkout, so we copy the
-                            ;; directory tree to _checkout and make it
-                            ;; writable.
-                            (copy-recursively src dest #:follow-symlinks? #t)
-                            (for-each (cut chmod <> #o777)
-                                      (find-files dest)))))
-                      (scandir elibdir (lambda (file)
-                                         (and (not (member file '("." "..")))
-                                              (file-is-directory?
-                                               (string-append elibdir
-                                                              "/"
-                                                              file)))))))))
-               input-directories)))
-          (replace 'check
-            (lambda* (#:key tests? #:allow-other-keys)
-              (when tests?
-                (begin
-                  (setenv "REBAR_CACHE_DIR" "/tmp")
-                  (invoke "make" "-j" (number->string (parallel-job-count))
-                          "tests"))))))))
-    (native-inputs (list rebar3 rebar3-proper erlang-proper))
+      #:make-flags #~(list (string-append "PREFIX="
+                                          #$output) "CC=gcc")
+      #:phases #~(modify-phases %standard-phases
+                   (delete 'configure)
+                   ;; The following is inspired by rebar-build-system.scm
+                   (add-before 'check 'erlang-depends
+                     (lambda* (#:key inputs #:allow-other-keys)
+                       (define input-directories
+                         (list #$(this-package-native-input "rebar3-proper")
+                               #$(this-package-native-input "erlang-proper")))
+                       (mkdir-p "_checkouts")
+                       (for-each
+                        (lambda (input-dir)
+                          (let ((elibdir (string-append input-dir "/lib/erlang/lib")))
+                            (when (directory-exists? elibdir)
+                              (for-each
+                               (lambda (dirname)
+                                 (let ((src (string-append elibdir "/" dirname))
+                                       (dest (string-append "_checkouts/" dirname)))
+                                   (when (not (file-exists? dest))
+                                     ;; Symlinking will not work, since rebar3 will try
+                                     ;; to overwrite the _build directory several times
+                                     ;; with the contents of _checkout, so we copy the
+                                     ;; directory tree to _checkout and make it
+                                     ;; writable.
+                                     (copy-recursively src dest #:follow-symlinks? #t)
+                                     (for-each (cut chmod <> 511) (find-files dest)))))
+                               (scandir elibdir
+                                        (lambda (file)
+                                          (and (not (member file '("." "..")))
+                                               (file-is-directory? (string-append elibdir "/" file)))))))))
+                        input-directories)))
+                   (replace 'check
+                     (lambda* (#:key tests? #:allow-other-keys)
+                       (when tests?
+                         (begin
+                           (setenv "REBAR_CACHE_DIR" "/tmp")
+                           (invoke "make" "-j"
+                                   (number->string (parallel-job-count))
+                                   "tests"))))))))
+    (native-inputs (list rebar3 erlang-rebar3-proper erlang-proper))
     (propagated-inputs (list erlang))
     (home-page "https://github.com/lfe/lfe")
     (synopsis "Lisp Flavoured Erlang")
@@ -812,3 +382,9 @@ (define-public erlang-lfe
 compiler.  Code produced with it is compatible with \"normal\" Erlang
  code.  An LFE evaluator and shell is also included.")
     (license license:asl2.0)))
+
+;;;
+;;; Avoid adding new packages to the end of this file. To reduce the chances
+;;; of a merge conflict, place them above by existing packages with similar
+;;; functionality or similar names.
+;;;
diff --git a/guix/build-system/mix.scm b/guix/build-system/mix.scm
new file mode 100644
index 00000000..8201b715
--- /dev/null
+++ b/guix/build-system/mix.scm
@@ -0,0 +1,185 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2023 Pierre-Henry Fröhring <[email-masked]>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+;; Commentary:
+;;
+;; Standard build procedure for Elixir packages using 'mix'.  This is
+;; implemented as an extension of 'gnu-build-system'.
+;;
+;; Code:
+
+(define-module (guix build-system mix)
+  #:use-module (gnu packages base)
+  #:use-module (gnu packages elixir)
+  #:use-module (guix build mix-build-system)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix build-system)
+  #:use-module (guix search-paths)
+  #:use-module (guix monads)
+  #:use-module (guix packages)
+  #:use-module (guix store)
+  #:use-module (guix gexp)
+  #:use-module (guix utils)
+  #:export (mix-build-system hexpm-uri))
+
+;;
+;; hexpm
+;;
+
+(define (hexpm-uri name version)
+  "Return the URI where to fetch the sources of a Hex package NAME at VERSION.
+
+See: https://github.com/hexpm/specifications/blob/main/endpoints.md"
+  (string-append "https://repo.hex.pm/tarballs/"
+                 (string-replace-substring (strip-elixir-prefix name) "-" "_")
+                 "-" version ".tar"))
+
+;;
+;; utils
+;;
+
+(define utils-locales
+  (make-glibc-utf8-locales glibc
+                           #:locales (list "en_US")
+                           #:name "glibc-utf8-locales"))
+
+(define (utils-elixir-default)
+  "Return the default Elixir package."
+  ;; Lazily resolve the binding to avoid a circular dependency.
+  (let ((elixir (resolve-interface '(gnu packages elixir))))
+    (module-ref elixir
+                'elixir)))
+
+(define utils-imported-modules
+  `((guix build mix-build-system)
+    ,@%gnu-build-system-modules))
+
+(define utils-modules
+  '((guix build mix-build-system)
+    (guix build utils)))
+
+;;
+;; mix
+;;
+
+(define* (mix-build name
+                    inputs
+                    #:key source
+                    (tests? #t)
+                    (phases '%standard-phases)
+                    (outputs '("out"))
+                    (search-paths '())
+                    (system (%current-system))
+                    (guile #f)
+                    (imported-modules utils-imported-modules)
+                    (modules utils-modules))
+  "Build SOURCE using Elixir, and with INPUTS."
+
+  (define builder
+    (with-imported-modules imported-modules
+      #~(begin
+
+          (use-modules #$@(sexp->gexp modules))
+
+          #$(with-build-variables inputs outputs
+              #~(mix-build #:name #$name
+                           #:source #+source
+                           #:system #$system
+                           #:tests? #$tests?
+                           #:phases #$(if (pair?
+                                           phases)
+                                          (sexp->gexp
+                                           phases)
+                                          phases)
+                           #:outputs %outputs
+                           #:search-paths '#$(sexp->gexp
+                                              (map
+                                               search-path-specification->sexp
+                                               search-paths))
+                           #:inputs
+                           %build-inputs)))))
+
+  (mlet %store-monad
+      ((guile (package->derivation (or guile
+                                       (default-guile)) system
+                                       #:graft? #f)))
+    (gexp->derivation name
+                      builder
+                      #:system system
+                      #:graft? #f ;consistent with 'gnu-build'
+                      #:target #f
+                      #:guile-for-build guile)))
+
+(define* (mix-lower name
+                    #:key source
+                    inputs
+                    native-inputs
+                    outputs
+                    system
+                    target
+                    (elixir (utils-elixir-default))
+                    #:allow-other-keys #:rest arguments)
+  "Return a bag for NAME."
+
+  ;; The value associated to these keywords are used in the bag below and are
+  ;; not to be used in the arguments.
+  (define private-keywords
+    '(#:inputs #:native-inputs #:outputs #:system #:target #:elixir))
+
+  ;; All that is necessary to complete the build.
+  (define build-inputs
+    ;; If these packages are not present, then Elixir emits these errors:
+    ;; dirname: command not found
+    ;; basename: command not found
+    `(,@(standard-packages)
+
+      ;; If no UTF-8 is present, then Elixir emits this warning:
+      ;;
+      ;; warning: the VM is running with native name encoding of latin1
+      ;; which may cause Elixir to malfunction as it expects utf8. Please
+      ;; ensure your locale is set to UTF-8 (which can be verified by
+      ;; running "locale" in your shell)
+      ("glibc-utf8-locales" ,utils-locales)
+
+      ("elixir" ,elixir)
+
+      ;; If Hex is not present, mix cannot build packages.
+      ("mix-hex" ,mix-hex)
+
+      ,@native-inputs
+
+      ,@inputs))
+
+  (define host-inputs
+    (if target inputs
+        '()))
+
+  (bag (name name)
+       (system system)
+       (build-inputs build-inputs)
+       (host-inputs host-inputs)
+       (outputs outputs)
+       (build mix-build)
+       (arguments (strip-keyword-arguments private-keywords arguments))))
+
+(define mix-build-system
+  (build-system (name 'mix)
+                (description "The standard Mix build system")
+                (lower mix-lower)))
+
+;;; mix.scm ends here
diff --git a/guix/build-system/rebar.scm b/guix/build-system/rebar.scm
index de1294ec..e1258a78 100644
--- a/guix/build-system/rebar.scm
+++ b/guix/build-system/rebar.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2016 Ricardo Wurmus <[email-masked]>
 ;;; Copyright © 2020 Hartmut Goebel <[email-masked]>
+;;; Copyright © 2023 Pierre-Henry Fröhring <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -21,99 +22,171 @@ (define-module (guix build-system rebar)
   #:use-module (guix store)
   #:use-module (guix utils)
   #:use-module (guix gexp)
+  #:use-module (ice-9 regex)
   #:use-module (guix packages)
   #:use-module (guix monads)
   #:use-module (guix search-paths)
+  #:use-module (ice-9 match)
   #:use-module (guix build-system)
   #:use-module (guix build-system gnu)
-  #:export (hexpm-uri
-            hexpm-package-url
-            %rebar-build-system-modules
-            rebar-build
-            rebar-build-system))
+  #:use-module (srfi srfi-1)
+  #:export (hexpm-uri hexpm-package-url %rebar-build-system-modules
+                      rebar-build rebar-build-system))
 
 ;;;
-;;; Definitions for the hex.pm repository,
+;;; pkg-name
 ;;;
 
-;; URL and paths from
-;; https://github.com/hexpm/specifications/blob/master/endpoints.md
-(define %hexpm-repo-url
+(define pkg-name-prefix
+  "erlang-")
+
+;; Pattern that an Erlang Guix package is expected to match.
+(define pkg-name-prefix-re
+  (format #f "^~a(.*)" pkg-name-prefix))
+
+(define (pkg-name->match name)
+  "Return the match object from NAME if NAME starts with pkg-name-prefix."
+  (string-match pkg-name-prefix-re name))
+
+(define (pkg-name? name)
+  "Test if NAME is the name of an Erlang Guix package.
+
+Example: erlang-ssl-verify-fun is the name of an Erlang Guix package."
+  (or (pkg-name->match name) #f))
+
+(define (pkg-name->suffix name)
+  "Return the suffix of the name of an Erlang Guix package."
+  (regexp-substitute #f
+                     (pkg-name->match name) 1))
+
+(define* (pkg-name->library-directory-name name
+                                           #:key (version ""))
+  "Return the name of the library directory associated to NAME.
+
+Example: if an Erlang Guix package name is \"erlang-ssl-verify-fun\" and its
+version is 1.2.3, then the associated library directory name is:
+\"ssl_verify_fun-1.2.3\".
+
+See:
+  - \"Library directory\" description: https://www.erlang.org/doc/man/code#code-path
+"
+  (string-append (string-replace-substring (pkg-name->suffix name) "-" "_")
+                 (if (string= version "") ""
+                     (string-append "-" version))))
+
+;;;
+;;; hexpm
+;;;
+
+;; See: https://github.com/hexpm/specifications/blob/master/endpoints.md
+(define hexpm
   (make-parameter "https://repo.hex.pm"))
 
-(define hexpm-package-url
-  (string-append (%hexpm-repo-url) "/tarballs/"))
+(define hexpm-tarballs
+  (string-append (hexpm) "/tarballs/"))
 
-(define (hexpm-uri name version)
+(define (hexpm->uri name version)
   "Return a URI string for the package hosted at hex.pm corresponding to NAME
-and VERSION."
-  (string-append hexpm-package-url name "-" version ".tar"))
+and VERSION.
+
+XXX: should a warning be emitted?
+If NAME is not an Erlang Guix package name, then emit a warning. The download
+will fail if it is not correct anyway."
+
+  (define (warn-about name)
+    (format #t "AssertionWarning 4dcbff27
+  Assertion: re matches name.
+    re = ~a
+    name = ~a
+" pkg-name-prefix-re name) name)
+
+  (define (name->archive-name name)
+    (if (pkg-name? name)
+        (string-append (pkg-name->library-directory-name name
+                                                         #:version version)
+                       ".tar")
+        (string-append (warn-about name) "-" version ".tar")))
+
+  (string-append hexpm-tarballs
+                 (name->archive-name name)))
 
 ;;
-;; Standard build procedure for Erlang packages using Rebar.
+;; utils
 ;;
 
-(define %rebar-build-system-modules
-  ;; Build-side modules imported by default.
-  `((guix build rebar-build-system)
-    ,@%gnu-build-system-modules))
-
-(define (default-rebar3)
-  "Return the default Rebar3 package."
+(define (utils-rebar-default)
   ;; Lazily resolve the binding to avoid a circular dependency.
   (let ((erlang-mod (resolve-interface '(gnu packages erlang))))
-    (module-ref erlang-mod 'rebar3)))
+    (module-ref erlang-mod
+                'rebar3)))
 
-(define (default-erlang)
-  "Return the default Erlang package."
+(define (utils-erlang-default)
   ;; Lazily resolve the binding to avoid a circular dependency.
   (let ((erlang-mod (resolve-interface '(gnu packages erlang))))
-    (module-ref erlang-mod 'erlang)))
-
-(define* (lower name
-                #:key source inputs native-inputs outputs system target
-                (rebar (default-rebar3))
-                (erlang (default-erlang))
-                #:allow-other-keys
-                #:rest arguments)
-  "Return a bag for NAME from the given arguments."
-  (define private-keywords
-    '(#:target #:rebar #:erlang #:inputs #:native-inputs))
-
-  (and (not target)                               ;XXX: no cross-compilation
-       (bag
-         (name name)
-         (system system)
-         (host-inputs `(,@(if source
-                              `(("source" ,source))
-                              '())
-                        ,@inputs))
-         (build-inputs `(("rebar" ,rebar)
-                         ("erlang" ,erlang) ;; for escriptize
-                         ,@native-inputs
-                         ;; Keep the standard inputs of 'gnu-build-system'.
-                         ,@(standard-packages)))
-         (outputs outputs)
-         (build rebar-build)
-         (arguments (strip-keyword-arguments private-keywords arguments)))))
-
-(define* (rebar-build name inputs
-                       #:key
-                       guile source
-                       (rebar-flags ''("skip_deps=true" "-vv"))
-                       (tests? #t)
-                       (test-target "eunit")
-                       ;; TODO: install-name  ; default: based on guix package name
-                       (install-profile "default")
-                       (phases '(@ (guix build rebar-build-system)
-                                   %standard-phases))
-                       (outputs '("out"))
-                       (search-paths '())
-                       (native-search-paths '())
-                       (system (%current-system))
-                       (imported-modules %rebar-build-system-modules)
-                       (modules '((guix build rebar-build-system)
-                                  (guix build utils))))
+    (module-ref erlang-mod
+                'erlang)))
+
+(define utils-imported-modules
+  `((guix build rebar-build-system)
+    ,@%gnu-build-system-modules))
+
+;;
+;; source
+;;
+;; If s is a Source, then s has the form (list <name> <source>) where:
+;;   <name> is a string representing the name of a library directory.
+;;   <origin> is an origin (see: guix/packages.scm) which represents the
+;;   source code associated to this library.
+;;
+
+(define source->name
+  car)
+(define source->origin
+  cadr)
+
+;;
+;; input
+;;
+;; If i is an Input, then i has the form (list <name> <package>) where:
+;;   <name> is a string representing the name of a package.
+;;   <package> is a package with the associated name.
+
+(define input->name
+  car)
+(define input->package
+  cadr)
+
+(define (input->source input)
+  "Return a Source associated to the Input INPUT."
+  (match input
+    ((name package)
+     (list (pkg-name->library-directory-name name)
+           (package-source package)))))
+
+;;
+;; rebar
+;;
+
+(define* (rebar-build name
+                      inputs
+                      #:key guile
+                      source
+                      ;; XXX: these are useless.
+                      (rebar-flags ''("skip_deps=true" "-vv"))
+                      (tests? #t)
+                      (test-target "eunit")
+                      ;; TODO: install-name  ; default: based on guix package name
+                      (install-profile "default")
+                      (phases '(@ (guix build rebar-build-system)
+                                  %standard-phases))
+                      (outputs '("out"))
+                      (search-paths '())
+                      (native-search-paths '())
+                      (system (%current-system))
+                      (imported-modules utils-imported-modules)
+                      (modules '((guix build rebar-build-system)
+                                 (guix build utils)))
+                      (sources-erlang '()))
   "Build SOURCE with INPUTS."
 
   (define builder
@@ -122,35 +195,94 @@ (define* (rebar-build name inputs
           (use-modules #$@(sexp->gexp modules))
 
           #$(with-build-variables inputs outputs
+
               #~(rebar-build #:source #+source
-                      #:system #$system
-                      #:name #$name
-                      #:rebar-flags #$rebar-flags
-                      #:tests? #$tests?
-                      #:test-target #$test-target
-                      ;; TODO: #:install-name #$install-name
-                      #:install-profile #$install-profile
-                      #:phases #$(if (pair? phases)
-                                     (sexp->gexp phases)
-                                     phases)
-                      #:outputs %outputs
-                      #:search-paths '#$(sexp->gexp
-                                         (map search-path-specification->sexp
-                                              search-paths))
-                      #:inputs %build-inputs)))))
-
-  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
-                                                  system #:graft? #f)))
+                             #:sources-erlang '#$sources-erlang
+                             #:system #$system
+                             #:name #$name
+                             #:rebar-flags #$rebar-flags
+                             #:tests? #$tests?
+                             #:test-target #$test-target
+                             ;; TODO: #:install-name #$install-name
+                             #:install-profile #$install-profile
+                             #:phases #$(if (pair?
+                                             phases)
+                                            (sexp->gexp
+                                             phases)
+                                            phases)
+                             #:outputs %outputs
+                             #:search-paths '#$(sexp->gexp
+                                                (map
+                                                 search-path-specification->sexp
+                                                 search-paths))
+                             #:inputs
+                             %build-inputs)))))
+
+  (mlet %store-monad
+      ((guile (package->derivation (or guile
+                                       (default-guile)) system
+                                       #:graft? #f)))
+
     ;; Note: Always pass #:graft? #f.  Without it, ALLOWED-REFERENCES &
     ;; co. would be interpreted as referring to grafted packages.
-    (gexp->derivation name builder
+    (gexp->derivation name
+                      builder
                       #:system system
                       #:target #f
                       #:graft? #f
                       #:guile-for-build guile)))
 
+(define* (rebar-lower name
+                      #:key (erlang (utils-erlang-default))
+                      inputs
+                      native-inputs
+                      outputs
+                      (rebar (utils-rebar-default))
+                      source
+                      system
+                      target
+                      #:allow-other-keys #:rest arguments)
+  "Return a bag for NAME from the given arguments."
+
+  (let* ((erlang-packages ;List of Erlang packages.
+          (filter (lambda (input)
+                    (pkg-name? (input->name input)))
+                  (append inputs native-inputs)))
+
+         (erlang-sources (map (lambda (input)
+                                (input->source input)) erlang-packages)))
+
+    (define private-keywords
+      '(#:target #:rebar #:erlang #:inputs #:native-inputs #:sources-erlang))
+
+    (and (not target) ;XXX: no cross-compilation
+         (bag (name name)
+              (system system)
+              (host-inputs inputs)
+              (build-inputs `(,@(standard-packages) ("erlang" ,erlang)
+                              ("rebar" ,rebar)
+                              ,@inputs
+                              ,@native-inputs))
+              (outputs outputs)
+              (build rebar-build)
+              (arguments (append (list #:sources-erlang erlang-sources)
+                                 (strip-keyword-arguments private-keywords
+                                                          arguments)))))))
+
 (define rebar-build-system
-  (build-system
-    (name 'rebar)
-    (description "The standard Rebar build system")
-    (lower lower)))
+  (build-system (name 'rebar)
+                (description "The standard Rebar build system")
+                (lower rebar-lower)))
+
+;;;
+;;; Exports
+;;;
+
+(define hexpm-uri
+  hexpm->uri)
+
+(define hexpm-package-url
+  hexpm-tarballs)
+
+(define %rebar-build-system-modules
+  utils-imported-modules)
diff --git a/guix/build/mix-build-system.scm b/guix/build/mix-build-system.scm
new file mode 100644
index 00000000..1d17ae49
--- /dev/null
+++ b/guix/build/mix-build-system.scm
@@ -0,0 +1,373 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2023 Pierre-Henry Fröhring <[email-masked]>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+;; Commentary:
+;;
+;; Builder-side code of the standard Mix package build procedure.
+;;
+;; The standard procedure is presented here:
+;;   https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html#project-compilation
+;;
+;; It boils down to:
+;;   1) MIX_ENV=prod mix compile
+;;   2) mix test
+;;
+;; Most of the code here comes from the necessity to convince mix to compile
+;; without accessing the network. Here is the procedure adapted for Guix:
+;;   if:
+;;     1) `<source>' is an archive of a package downloaded from hex.pm.
+;;           See: https://github.com/hexpm/specifications/blob/main/package_tarball.md
+;;     2) `<hex-lib>' is the name of the Hex library, e.g. hex-2.0.5.
+;;        `<hex-path>' is the path in the store of Hex.
+;;          See: `(gnu packages elixir)'
+;;
+;;   then the steps to build a package pkg are:
+;;     1)   tar <source>
+;;     2)   tar contents.tar.gz
+;;     3)   export MIX_ENV=prod
+;;     4)   export MIX_HOME=.mix
+;;     5)   export MIX_ARCHIVES="$(MIX_HOME)"/archives
+;;     6)   mkdir -p "$(MIX_ARCHIVES)"
+;;     7)   ln -snd <hex-path>/lib/<hex-lib> "$(MIX_ARCHIVES)"/<hex-lib>/<hex-lib>
+;;     8)   <profile> is either `prod' or `shared' depending on mix.exs
+;;            see: `build_per_environment' in mix documentation.
+;;     9)   For all Elixir or Erlang package p in inputs, we have <p-name> the name
+;;          of the associated library (e.g. hex-2.0.5). We must:
+;;            install p under _build/<profile>/lib/<p-name>
+;;            install p source _build/<profile>/lib/<p-name>
+;;     10)  mix compile --no-deps-check
+;;     11)  mix test --no-deps-check
+;;     12)  install build artifacts under #$out/lib/elixir/X.Y/
+;;            where X and Y are the major and minor version numbers of Elixir.
+;;
+;; Code:
+
+(define-module (guix build mix-build-system)
+  #:use-module (guix build utils)
+  #:use-module ((guix build gnu-build-system)
+                #:prefix gnu:)
+  #:use-module (ice-9 regex)
+  #:use-module (ice-9 ftw)
+  #:use-module (srfi srfi-1)
+  #:export (mix-build strip-elixir-prefix %standard-phases))
+
+;;
+;; version
+;;
+
+;; XXX: copied from (guix utils) since not available from the build side.
+;; XXX: There may be a way to avoid this duplicated code?
+(define (version-prefix version-string num-parts)
+  "Truncate version-string to the first num-parts components of the version.
+For example, (version-prefix \"2.1.47.4.23\" 3) returns \"2.1.47\""
+  (string-join (take (string-split version-string #\.) num-parts) "."))
+
+;; XXX: copied from (guix utils) since not available from the build side.
+;; XXX: There may be a way to avoid this duplicated code?
+(define (version-major+minor version-string)
+  "Return \"<major>.<minor>\", where major and minor are the major and
+minor version numbers from version-string."
+  (version-prefix version-string 2))
+
+;;
+;; pkg
+;;
+
+;; The prefix of Elixir packages as a regular expression.
+(define pkg-elixir-prefix
+  "^elixir-")
+
+;; The prefix of Erlang packages as a regular expression.
+(define pkg-erlang-prefix
+  "^erlang-")
+
+(define (pkg-name->library-name name)
+  "Return the name of the Mix project deduced from the name of the Guix package.
+
+For example: elixir-a-pkg-1.0.2 → a_pkg"
+
+  (let* ((re (format #f "~a(.*)" pkg-elixir-prefix))
+         (re-match (string-match re name))
+         (name-version (if re-match
+                           (regexp-substitute #f re-match 1)
+                           (error (format #f "AssertionError d722a480
+  Assertion: re matches name.
+    re = ~a
+    name = ~a" re
+    name)))))
+
+    ;; A snake_case name.
+    (string-join (drop-right (string-split name-version #\-) 1) "_")))
+
+(define (pkg->dir-install elixir-store pkg-store pkg-name)
+  "Return the path under the path PKG-STORE where to install the package named PKG-NAME given the path of the Elixir used to build ELIXIR-STORE.
+
+Example:
+  - if:
+    - elixir-store = /gnu/store/…elixir-1.14.0
+    - pkg-store = /gnu/store/…kv-1.0.0
+    - pkg-name = elixir-kv
+  - then:
+    - (pkg->dir-install elixir-store pkg-store pkg-name) = /gnu/store/…kv-1.0.0/lib/elixir/1.14/kv"
+  (let ((X.Y (path->elixir-X.Y elixir-store))
+        (lib-name (pkg-name->library-name pkg-name)))
+    (string-append (path->elixir-lib pkg-store X.Y) "/" lib-name)))
+
+;;
+;; mix
+;;
+
+;; See: https://hexdocs.pm/mix/1.15.7/Mix.html#module-environments
+(define mix-MIX_HOME
+  "MIX_HOME")
+(define mix-MIX_ENV
+  "MIX_ENV")
+(define mix-MIX_ENV-prod
+  "prod")
+
+(define (mix-target-dir)
+  "Return the directory where build artifacts are to be installed according to
+MIX_ENV in the current directory."
+
+  (format #f "_build/~a/lib"
+          (getenv mix-MIX_ENV)))
+
+;;
+;; path
+;;
+
+(define (path->elixir-lib path X.Y)
+  "Return the path of the directory where libraries of an Elixir package are installed in the store."
+  (string-append path "/lib/elixir/" X.Y))
+
+(define (path->erlang-lib path)
+  "Return the path of the directory where libraries of an Erlang package are installed in the store."
+  (string-append path "/lib/erlang/lib"))
+
+(define (path->elixir-X.Y elixir)
+  "Given a path in the store where elixir has been installed, return its
+version as X.Y where X and Y are its major and minor versions."
+  (let ((version (last (string-split elixir #\-))))
+    (version-major+minor version)))
+
+;;
+;; phase
+;;
+
+(define* (phase-unpack #:key source #:allow-other-keys)
+  "Unpack SOURCE."
+  (invoke "tar" "xvf" source)
+  (invoke "tar" "xvf" "contents.tar.gz"))
+
+(define* (phase-configure-mix-env #:key (mix-env mix-MIX_ENV-prod)
+                                  #:allow-other-keys)
+  "Set default MIX_ENV."
+
+  (let ((values (list mix-MIX_ENV-prod "shared")))
+    (when (not (member mix-env values string=?))
+      (error (format #f "AssertionError 45f9a67d
+  Assertion: mix-env is one of values.
+    values = ~a
+" values)))
+    (setenv mix-MIX_ENV mix-env)))
+
+(define* (phase-install-hex #:key inputs name #:allow-other-keys)
+  "Install Hex."
+
+  (let* ((hex-lib (string-append (assoc-ref inputs "mix-hex") "/lib"))
+         (hex-name (last (scandir hex-lib)))
+         (MIX_ARCHIVES "MIX_ARCHIVES")
+         (hex-archive-path ""))
+
+    (setenv mix-MIX_HOME ".mix")
+    (setenv MIX_ARCHIVES
+            (string-append (getenv mix-MIX_HOME) "/archives"))
+    (set! hex-archive-path
+          (string-append (getenv MIX_ARCHIVES) "/" hex-name))
+    (mkdir-p hex-archive-path)
+    (symlink (string-append hex-lib "/" hex-name)
+             (string-append hex-archive-path "/" hex-name))))
+
+;; Below are definitions useful to understand the following code.
+;;
+;; - « p : StorePath » means that « p is a String that represents a path of a
+;;   package in the store ».
+;;
+;; - « i : Input » means that i has the form (key . path) where key : String that
+;;   represent the name of a package and path : StorePath.
+;;
+;; - « al : AList » means that « al is an Association List ».
+;;
+;; - « al : AList Input » means that « al is an Association List of Input ».
+;;
+;; - « p : Pkg » means that p has the form (type . path) where type is either
+;;   'erlang or 'elixir and path : StorePath.
+;;
+;; - « l : Lib » means that p has the form (lib-name . lib-path) where
+;;   lib-name is the name of an Erlang or Elixir library and lib-path is its path.
+(define* (phase-install-dependencies #:key inputs #:allow-other-keys)
+  "Install dependencies."
+
+  (let ((target-dir (mix-target-dir))
+        (X.Y (path->elixir-X.Y (assoc-ref inputs "elixir"))))
+
+    ;; Where to install the dependencies.
+    (mkdir-p target-dir)
+
+    (define (install-lib lib)
+      "Install a Lib LIB under target-dir."
+      ;; XXX: use match
+      (let ((lib-name (car lib))
+            (lib-path (cdr lib)))
+        (let ((target (string-append target-dir "/" lib-name)))
+          (symlink lib-path target))))
+
+    (define (install-libs libraries)
+      "Install the set of the list of Lib LIBRARIES under target-dir."
+      (for-each (lambda (lib)
+                  (install-lib lib)) libraries))
+
+    (define (pkg->libraries pkg)
+      "Return the list of Lib libraries associated to a Pkg."
+      ;; XXX: use match
+      (let* ((pkg-type (car pkg))
+             (pkg-path (cdr pkg))
+             (lib-folder (cond
+                          ((eq? pkg-type
+                                'elixir)
+                           (path->elixir-lib pkg-path X.Y))
+                          ((eq? pkg-type
+                                'erlang)
+                           (path->erlang-lib pkg-path)))))
+        (map (lambda (lib-name)
+               (cons lib-name
+                     (string-append lib-folder "/" lib-name)))
+             (drop (scandir lib-folder) 2))))
+
+    (define (install-pkg-libraries pkg)
+      "Install all libraries of a given Pkg PKG under target-dir."
+      (install-libs (pkg->libraries pkg)))
+
+    (define (input->pkg input)
+      "Return a Pkg if Input INPUT is an Erlang or Elixir Input else #f."
+      (let ((type? (cond
+                    ((string-match pkg-erlang-prefix
+                                   (car input))
+                     'erlang)
+                    ((string-match pkg-elixir-prefix
+                                   (car input))
+                     'elixir)
+                    (#t #f))))
+        (if type?
+            (cons type?
+                  (cdr input)) #f)))
+
+    (define (inputs->pkgs inputs)
+      "Return the a list of Pkg, one for each Erlang or Elixir Input in INPUTS."
+      (filter pair?
+              (map input->pkg inputs)))
+
+    (for-each (lambda (pkg)
+                (install-pkg-libraries pkg))
+              (inputs->pkgs inputs))))
+
+(define* (phase-build . args_ignored)
+  "Builds the Mix project according to MIX_ENV."
+  (invoke "mix" "compile" "--no-deps-check"))
+
+(define* (phase-check #:key (tests? #t) name #:allow-other-keys)
+  "Test the Mix project."
+  (if tests?
+      (begin
+        (let ((mix-env (getenv mix-MIX_ENV)))
+          (setenv mix-MIX_ENV "test")
+          (invoke "mix" "test" "--no-deps-check")
+          (setenv mix-MIX_ENV mix-env)))
+      (format #t "Tests have been skipped since test? parameter value was: ~a.
+"
+              tests?)))
+
+(define* (phase-remove-mix-dirs . ignored_args)
+  "Remove all .mix/ directories."
+  (let ((mix-dirs (find-files "."
+                              (file-name-predicate (format #f "\\~a$"
+                                                           (getenv
+                                                            mix-MIX_HOME)))
+                              #:directories? #t)))
+    (for-each (lambda (mix-dir)
+                (delete-file-recursively mix-dir)) mix-dirs)))
+
+(define* (phase-install #:key inputs outputs name #:allow-other-keys)
+  "Install build artifacts in the store."
+  (let ((dir-build (string-append (mix-target-dir) "/"
+                                  (pkg-name->library-name name)))
+        (dir-install (pkg->dir-install (assoc-ref inputs "elixir")
+                                       (assoc-ref outputs "out") name)))
+    (mkdir-p dir-install)
+    (copy-recursively dir-build dir-install
+                      #:follow-symlinks? #t)))
+
+(define mix-%standard-phases
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (replace 'unpack
+      phase-unpack)
+    (add-after 'unpack 'condifure-mix-env
+      phase-configure-mix-env)
+    (add-after 'patch-generated-file-shebangs 'install-hex
+      phase-install-hex)
+    (add-after 'install-hex 'install-dependencies
+      phase-install-dependencies)
+    (replace 'build
+      phase-build)
+    (replace 'check
+      phase-check)
+    (add-before 'install 'remove-mix-dirs
+      phase-remove-mix-dirs)
+    (replace 'install
+      phase-install)))
+
+(define* (mix-build #:key inputs
+                    (phases mix-%standard-phases)
+                    #:allow-other-keys #:rest args)
+  "Build the given Mix package, applying all of PHASES in order."
+  (apply gnu:gnu-build
+         #:inputs inputs
+         #:phases phases
+         args))
+
+;;
+;; This section gather exports.
+;;
+
+(define (strip-elixir-prefix name)
+  (let* ((re (format #f "~a(.*)" pkg-elixir-prefix))
+         (re-match (string-match re name)))
+
+    (if re-match
+        (regexp-substitute #f re-match 1)
+        (error (format #f "AssertionError d722a480
+  Assertion: re matches name.
+    re = ~a
+    name = ~a" re name)))))
+
+(define %standard-phases
+  mix-%standard-phases)
+
+;;; mix-build-system.scm ends here
diff --git a/guix/build/rebar-build-system.scm b/guix/build/rebar-build-system.scm
index fb664228..80813225 100644
--- a/guix/build/rebar-build-system.scm
+++ b/guix/build/rebar-build-system.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2016, 2018 Ricardo Wurmus <[email-masked]>
 ;;; Copyright © 2019 Björn Höfling <[email-masked]>
 ;;; Copyright © 2020, 2022 Hartmut Goebel <[email-masked]>
+;;; Copyright © 2023 Pierre-Henry Fröhring <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -19,129 +20,222 @@
 ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
 
 (define-module (guix build rebar-build-system)
-  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
-  #:use-module ((guix build utils) #:hide (delete))
+  #:use-module ((guix build gnu-build-system)
+                #:prefix gnu:)
+  #:use-module ((guix build utils)
+                #:hide (delete))
   #:use-module (ice-9 match)
   #:use-module (ice-9 ftw)
+  #:use-module (ice-9 string-fun)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 regex)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-26)
-  #:export (rebar-build
-            %standard-phases))
+  #:export (rebar-build %standard-phases))
 
 ;;
 ;; Builder-side code of the standard build procedure for Erlang packages using
 ;; rebar3.
 ;;
-;; TODO: Think about whether bindir ("ebin"), libdir ("priv") and includedir
-;; "(include") need to be configurable
 
-(define %erlang-libdir "/lib/erlang/lib")
-
-(define* (erlang-depends #:key inputs #:allow-other-keys)
-  (define input-directories
-    (match inputs
-      (((_ . dir) ...)
-       dir)))
-  (mkdir-p "_checkouts")
-
-  (for-each
-   (lambda (input-dir)
-     (let ((elibdir (string-append input-dir %erlang-libdir)))
-       (when (directory-exists? elibdir)
-         (for-each
-          (lambda (dirname)
-            (let ((dest (string-append elibdir "/" dirname))
-                  (link (string-append "_checkouts/" dirname)))
-              (when (not (file-exists? link))
-                ;; RETHINK: Maybe better copy and make writable to avoid some
-                ;; error messages e.g. when using with rebar3-git-vsn.
-                (symlink dest link))))
-          (list-directories elibdir)))))
-   input-directories))
-
-(define* (unpack #:key source #:allow-other-keys)
-  "Unpack SOURCE in the working directory, and change directory within the
-source.  When SOURCE is a directory, copy it in a sub-directory of the current
-working directory."
-  (let ((gnu-unpack (assoc-ref gnu:%standard-phases 'unpack)))
-    (gnu-unpack #:source source)
-    ;; Packages from hex.pm typically have a contents.tar.gz containing the
-    ;; actual source. If this tar file exists, extract it.
-    (when (file-exists? "contents.tar.gz")
-      (invoke "tar" "xvf" "contents.tar.gz"))))
-
-(define* (build #:key (rebar-flags '()) #:allow-other-keys)
-  (apply invoke `("rebar3" "compile" ,@rebar-flags)))
-
-(define* (check #:key target (rebar-flags '()) (tests? (not target))
-                (test-target "eunit")
-                #:allow-other-keys)
-  (if tests?
-      (apply invoke `("rebar3" ,test-target ,@rebar-flags))
-      (format #t "test suite not run~%")))
+;;
+;; utils
+;;
 
-(define (erlang-package? name)
-  "Check if NAME correspond to the name of an Erlang package."
-  (string-prefix? "erlang-" name))
-
-(define (package-name-version->erlang-name name+ver)
-  "Convert the Guix package NAME-VER to the corresponding Erlang name-version
-format.  Essentially drop the prefix used in Guix and replace dashes by
-underscores."
-  (let* ((name- (package-name->name+version name+ver)))
-    (string-join
-     (string-split
-      (if (erlang-package? name-)  ; checks for "erlang-" prefix
-          (string-drop name- (string-length "erlang-"))
-          name-)
-      #\-)
-     "_")))
-
-(define (list-directories directory)
+(define (utils-list-directories directory)
   "Return file names of the sub-directory of DIRECTORY."
   (scandir directory
            (lambda (file)
-             (and (not (member file '("." "..")))
+             (and (not (member file
+                               '("." "..")))
                   (file-is-directory? (string-append directory "/" file))))))
 
-(define* (install #:key name outputs
-                  (install-name (package-name-version->erlang-name name))
-                  (install-profile "default") ; build profile outputs to install
-                  #:allow-other-keys)
-  (let* ((out (assoc-ref outputs "out"))
-         (pkg-dir (string-append out %erlang-libdir "/" install-name)))
-    (let ((bin-dir (string-append "_build/" install-profile "/bin"))
-          (lib-dir (string-append "_build/" install-profile "/lib")))
-      ;; install _build/PROFILE/bin
-      (when (file-exists? bin-dir)
-        (copy-recursively bin-dir out #:follow-symlinks? #t))
-      ;; install _build/PROFILE/lib/*/{ebin,include,priv}
-      (for-each
-       (lambda (*)
-         (for-each
-          (lambda (dirname)
-            (let ((src-dir (string-append lib-dir "/" * "/" dirname))
-                  (dst-dir (string-append pkg-dir "/" dirname)))
-              (when (file-exists? src-dir)
-                (copy-recursively src-dir dst-dir #:follow-symlinks? #t))
-              (false-if-exception
-               (delete-file (string-append dst-dir "/.gitignore")))))
-          '("ebin" "include" "priv")))
-       (list-directories lib-dir))
-      (false-if-exception
-       (delete-file (string-append pkg-dir "/priv/Run-eunit-loop.expect"))))))
-
-(define %standard-phases
+;;
+;; source
+;;
+
+(define source->name
+  car)
+(define source->tar
+  cadr)
+
+;;
+;; tar
+;;
+
+(define* (tar-unpack tar)
+  (invoke "tar" "xvf" tar)
+  (invoke "tar" "xvf" "contents.tar.gz")
+
+  ;; Prevent an error message at install phase.
+  ;; .
+  ;; rebar3 compile produces a symlinks like so in _build/:
+  ;; priv -> ../../../../priv
+  ;; priv -> ../../../../include
+  ;;
+  ;; The install phase copies whatever has been built to the output directory.
+  ;; If the priv/ directory is absent, then an error `i/o error:
+  ;; _build/…/priv: No such file or directory' occurs. So, we make sure that a
+  ;; directory exists.
+  (for-each (lambda (dir)
+              (mkdir-p dir))
+            (list "priv" "include")))
+
+;;;
+;;; pkg-name
+;;;
+
+(define pkg-name-prefix
+  "erlang-")
+
+(define pkg-name-prefix-re
+  (format #f "^~a(.*)" pkg-name-prefix))
+
+(define (pkg-name? name)
+  (string-match (format #f "^~a" pkg-name-prefix) name))
+
+(define (pkg-name->name name)
+  (regexp-substitute #f
+                     (string-match pkg-name-prefix-re name) 1))
+
+(define* (pkg-name->lib-name name)
+  "erlang-a-b-1.0.2 -> a_b-1.0.2"
+
+  (let ((elements (string-split (pkg-name->name name) #\-)))
+    (string-append (string-join (drop-right elements 1) "_") "-"
+                   (last elements))))
+
+(define* (pkg-name->build-dir name
+                              #:key (profile "default"))
+  (string-append (format #f "_build/~a/lib/" profile)
+                 (car (string-split (pkg-name->lib-name name) #\-))))
+
+(define (lib-name-no-version lib-name)
+  (car (string-split lib-name #\-)))
+
+;;
+;; phase
+;;
+
+(define* (phase-unpack #:key source #:allow-other-keys)
+  (tar-unpack source))
+
+(define (phase-configure-HOME . ignored_args)
+  "In some cases, it is needed for the environment variable HOME to be defined
+as a directory with write permission.
+
+Examples of errors:
+  - Could not write to \"/homeless-shelter/.cache/rebar3/hex\". Please ensure the path is writeable.
+"
+
+  (let ((HOME "HOME")
+        (tmp "/tmp"))
+    (setenv HOME tmp)
+    (format #t "~a=~a\n" HOME tmp)))
+
+(define* (phase-configure-dependencies #:key name
+                                       version
+                                       inputs
+                                       sources-erlang
+                                       (install-profile "default")
+                                       #:allow-other-keys)
+
+  ;; If source in sources-erlang, then install it under _checkouts/.
+  ;; see: https://rebar3.org/docs/configuration/dependencies/#checkout-dependencies
+  (let ((_checkouts "_checkouts"))
+    (mkdir-p _checkouts)
+    (for-each (lambda (source)
+                (match source
+                  ((name tar)
+                   (let ((src (string-append _checkouts "/" name)))
+                     (mkdir-p src)
+                     (with-directory-excursion src
+                       (tar-unpack tar))))
+                  (_ #f))) sources-erlang))
+
+  ;; If input in inputs is an Erlang package, then install it under _build/.
+  (let ((_build (format #f "_build/~a/checkouts" install-profile)))
+    (mkdir-p _build)
+    (match inputs
+      (((_ . dirs) ..1)
+       (for-each (lambda (dir)
+                   (let ((elib (string-append dir "/lib/erlang/lib")))
+                     (when (directory-exists? elib)
+                       (for-each (lambda (dirname)
+                                   (let ((src (string-append elib "/" dirname))
+                                         (dest (string-append _build "/"
+                                                              (lib-name-no-version
+                                                               dirname))))
+                                     (copy-recursively src dest
+                                                       #:log #f)
+                                     (mkdir-p (string-append dest "/priv"))))
+                                 (utils-list-directories elib))))) dirs))
+      (_ #f))))
+
+(define* (phase-build #:key name
+                      (rebar-flags '()) #:allow-other-keys)
+  (apply invoke
+         `("rebar3" "compile"
+           ,@rebar-flags)))
+
+(define* (phase-check #:key target
+                      (rebar-flags '())
+                      (tests? (not target))
+                      (test-target "eunit")
+                      #:allow-other-keys)
+  (if tests?
+      (apply invoke
+             `("rebar3" ,test-target
+               ,@rebar-flags))
+      (format #t "test suite not run~%")))
+
+(define* (phase-install #:key name outputs
+                        (install-profile "default") #:allow-other-keys)
+  (let* ((build-dir (pkg-name->build-dir name
+                                         #:profile install-profile))
+         (out-build-dir (string-append (assoc-ref outputs "out")
+                                       "/lib/erlang/lib/"
+                                       (pkg-name->lib-name name))))
+
+    (mkdir-p out-build-dir)
+    (copy-recursively build-dir out-build-dir
+                      #:follow-symlinks? #t)))
+
+;;
+;; rebar
+;;
+
+(define rebar-%standard-phases
   (modify-phases gnu:%standard-phases
-    (replace 'unpack unpack)
+    (replace 'unpack
+      phase-unpack)
+    (add-after 'unpack 'configure-HOME
+      phase-configure-HOME)
     (delete 'bootstrap)
     (delete 'configure)
-    (add-before 'build 'erlang-depends erlang-depends)
-    (replace 'build build)
-    (replace 'check check)
-    (replace 'install install)))
+    (add-before 'build 'configure-dependencies
+      phase-configure-dependencies)
+    (replace 'build
+      phase-build)
+    (replace 'check
+      phase-check)
+    (replace 'install
+      phase-install)))
 
-(define* (rebar-build #:key inputs (phases %standard-phases)
+(define* (rebar-build #:key inputs
+                      (phases rebar-%standard-phases)
                       #:allow-other-keys #:rest args)
   "Build the given Erlang package, applying all of PHASES in order."
-  (apply gnu:gnu-build #:inputs inputs #:phases phases args))
+  (apply gnu:gnu-build
+         #:inputs inputs
+         #:phases phases
+         args))
+
+;;
+;; Exported bindings.
+;;
+
+(define %standard-phases rebar-%standard-phases)
+
+
+;;; rebar-build-system.scm ends here

base-commit: 4dfbc536689b07e56aead3dd864b8af54613d091
-- 
2.41.0