]> infiniteadaptability.org Git - channel/commitdiff
packages: add elixir
authoralex <[email protected]>
Mon, 1 Dec 2025 16:21:38 +0000 (08:21 -0800)
committeralex <[email protected]>
Mon, 1 Dec 2025 16:21:38 +0000 (08:21 -0800)
infiniteadaptability/packages/elixir.scm [new file with mode: 0644]

diff --git a/infiniteadaptability/packages/elixir.scm b/infiniteadaptability/packages/elixir.scm
new file mode 100644 (file)
index 0000000..5dd0639
--- /dev/null
@@ -0,0 +1,137 @@
+(define-module (infiniteadaptability packages elixir)
+  #:use-module (guix gexp)
+  #:use-module (guix git-download)
+  #:use-module (guix packages)
+  #:use-module (gnu packages)
+  #:use-module (gnu packages elixir)
+  #:use-module (infiniteadaptability packages erlang))
+
+(define-public elixir-1.19.2
+  (package
+    (inherit elixir)
+    (name "elixir")
+    (version "1.19.2")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/elixir-lang/elixir")
+             (commit (string-append "v" version))))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "0556xjkh5229afl22av2g8gkq5ak0gfipm90ybgnq2d2brd714xh"))))
+        (arguments
+     (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
+      #~(let* ((compiler-path "lib/elixir/src/elixir_erl_compiler.erl")
+               (compiler-path-orig (string-append compiler-path ".orig")))
+          (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")))
+                ;; We should not brake the formatting, so we need patch the
+                ;; following more accurately.
+                (substitute* "lib/mix/test/mix/tasks/cmd_test.exs"
+                 (("File\\.mkdir_p!\\(\"priv\"\\)" all)
+                   (string-append all "\n      sh = \""
+                                  (search-input-file inputs "/bin/sh") "\""))
+                 (("#!/bin/sh") "#!#{sh}"))))
+            (add-after 'replace-paths 'pre-install-source
+              (lambda* (#:key outputs #:allow-other-keys)
+                (copy-recursively
+                 "lib"
+                 (string-append (assoc-ref outputs "src") "/source/lib"))))
+            (add-after 'pre-install-source 'patch-elixir-compiler
+              ;; Temporarily patch the compiler to place correct source
+              ;; locations into module info instead of build directory.
+              (lambda* (#:key outputs #:allow-other-keys)
+                (copy-recursively compiler-path compiler-path-orig)
+                (let ((source (string-append "/tmp/guix-build-" #$name "-"
+                                             #$version ".drv-0"))
+                      (destination (assoc-ref outputs "src")))
+                  (substitute* compiler-path
+                    (("source, Source")
+                     (string-append "source, string:replace(Source, \""
+                                    source "\", \"" destination "\")"))))))
+            (add-before 'build 'set-deterministic
+              (lambda _
+                ;; Set deterministic compiler option.
+                (setenv "ERL_COMPILER_OPTIONS" "deterministic")))
+            (add-after 'build 'restore-and-recompile
+              ;; Unpatch the compiler and recompile it.
+              (lambda _
+                (copy-recursively compiler-path-orig compiler-path)
+                (delete-file compiler-path-orig)
+                (invoke "erlc" "-I" "lib/elixir/include"
+                        "-o" "lib/elixir/ebin" compiler-path)))
+            (add-after 'restore-and-recompile '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 _
+                ;; 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 can be sourced as an elixir script by other elixir
+                  ;; program, for example `iex -S mix`, so we should not wrap
+                  ;; mix into shell script.
+                  (substitute* (string-append out "/bin/mix")
+                    (("Mix.CLI.main\\(\\)")
+                     (format #f "\
+~~w[GUIX_ELIXIR_LIBS ERL_LIBS]
+|> Enum.map(&System.get_env/1)
+|> Enum.reject(&is_nil/1)
+|> Enum.join(\":\")
+|> case do \"\" -> :ok; erl_libs -> System.put_env(\"ERL_LIBS\", erl_libs) end
+System.put_env(\"MIX_REBAR3\", System.get_env(\"MIX_REBAR3\", \"~a\"))
+Mix.CLI.main()"
+                             (search-input-file inputs "/bin/rebar3"))))
+                  (for-each
+                   (lambda (program)
+                     (wrap-program (string-append out "/bin/" program)
+                       '("ERL_LIBS" prefix ("${GUIX_ELIXIR_LIBS}"))))
+                   programs))))))))
+    (inputs (modify-inputs (package-inputs elixir)
+              (replace "erlang" erlang-28.1.1)
+              (replace "rebar3" rebar)))))
+
+elixir-1.19.2