diff --git a/tribes/packages/mix.scm b/tribes/packages/mix.scm index 9b06821..f8720aa 100644 --- a/tribes/packages/mix.scm +++ b/tribes/packages/mix.scm @@ -1,7 +1,9 @@ (define-module (tribes packages mix) #:use-module (guix base32) + #:use-module (guix build-system trivial) #:use-module (guix gexp) #:use-module (guix packages) + #:use-module (guix utils) #:use-module (gnu packages admin) #:use-module (gnu packages bash) #:use-module (gnu packages base) @@ -9,7 +11,8 @@ #:use-module (gnu packages nss) #:use-module (gnu packages version-control) #:use-module (tribes packages otp) - #:export (fetch-mix-deps)) + #:export (fetch-mix-deps + mix-release-package)) (define* (fetch-mix-deps source #:key @@ -103,3 +106,174 @@ SOURCE according to mix.lock." #:recursive? #t #:leaked-env-vars ("http_proxy" "https_proxy" "LC_ALL" "LC_MESSAGES" "LANG" "COLUMNS")))) + +(define* (mix-release-package source + #:key + mix-fod-deps + name + version + home-page + synopsis + description + license + (native-inputs '()) + (inputs '()) + (path-inputs '()) + (aclocal-inputs '()) + (mix-env "prod") + (mix-target "host") + (compile-flags '()) + (mix-release-name "") + (remove-cookie? #t) + (setup-gexp #~(begin)) + (configure-gexp #f) + (build-gexp #f) + (install-gexp #f)) + "Return a package that builds SOURCE as an offline Mix release using +MIX-FOD-DEPS as a pre-fetched dependency tree." + (let* ((extra-path-dirs (map (lambda (input) + (file-append input "/bin")) + path-inputs)) + (aclocal-dirs (map (lambda (input) + (file-append input "/share/aclocal")) + aclocal-inputs)) + (default-configure-gexp + #~(invoke "mix" "deps.compile" "--no-deps-check" + "--skip-umbrella-children")) + (default-build-gexp + #~(invoke "mix" "compile" "--no-deps-check" #$@compile-flags)) + (default-install-gexp + (if (string=? mix-release-name "") + #~(invoke "mix" "release" "--no-deps-check" "--path" out) + #~(invoke "mix" "release" #$mix-release-name + "--no-deps-check" "--path" out))) + (configure-gexp (or configure-gexp default-configure-gexp)) + (build-gexp (or build-gexp default-build-gexp)) + (install-gexp (or install-gexp default-install-gexp)) + (builder-gexp + #~(begin + (use-modules (guix build utils)) + + (define out #$output) + (define work (string-append (getcwd) "/build")) + (define app-dir (string-append work "/app")) + (define deps-dir (string-append app-dir "/deps")) + (define certs-dir + #$(file-append nss-certs "/etc/ssl/certs")) + (define cert-file + (string-append work "/ca-certificates.crt")) + (define hex-lib-dir + #$(file-append elixir-hex-otp28 + "/lib/elixir/" + (version-major+minor + (package-version elixir-otp28)))) + (define aclocal-path + (string-join (list #$@aclocal-dirs) ":")) + (define path + (string-join + (list #$(file-append elixir-otp28 "/bin") + #$(file-append elixir-hex-otp28 "/bin") + #$(file-append rebar3 "/bin") + #$(file-append bash-minimal "/bin") + #$(file-append coreutils "/bin") + #$(file-append findutils "/bin") + #$(file-append git-minimal "/bin") + #$@extra-path-dirs + (or (getenv "PATH") "")) + ":")) + + (mkdir-p work) + (copy-recursively #+source app-dir #:follow-symlinks? #t) + (invoke #$(file-append coreutils "/bin/chmod") "-R" "u+w" app-dir) + #$@(if mix-fod-deps + (list + #~(begin + (copy-recursively #+mix-fod-deps deps-dir + #:follow-symlinks? #t) + (invoke #$(file-append coreutils "/bin/chmod") + "-R" "u+w" deps-dir))) + '()) + (invoke #$(file-append bash-minimal "/bin/sh") + "-c" + (string-append + #$(file-append coreutils "/bin/cat") + " " + certs-dir + "/*.pem > " + cert-file)) + + (setenv "PATH" path) + (setenv "HOME" (string-append app-dir "/.home")) + (setenv "MIX_HOME" (string-append app-dir "/.mix-home")) + (setenv "HEX_HOME" (string-append app-dir "/.hex")) + (setenv "XDG_CACHE_HOME" (string-append app-dir "/.cache")) + (setenv "MIX_ENV" #$mix-env) + (setenv "MIX_TARGET" #$mix-target) + (setenv "MIX_OS_CONCURRENCY_LOCK" "0") + (setenv "HEX_OFFLINE" "1") + (setenv "MIX_REBAR" #$(file-append rebar3 "/bin/rebar3")) + (setenv "MIX_REBAR3" #$(file-append rebar3 "/bin/rebar3")) + (setenv "REBAR_GLOBAL_CONFIG_DIR" (string-append work "/rebar3")) + (setenv "REBAR_CACHE_DIR" (string-append work "/rebar3.cache")) + (setenv "SHELL" #$(file-append bash-minimal "/bin/sh")) + (setenv "CONFIG_SHELL" #$(file-append bash-minimal "/bin/sh")) + (setenv "SSL_CERT_DIR" certs-dir) + (setenv "SSL_CERT_FILE" cert-file) + (setenv "HEX_CACERTS_PATH" cert-file) + (setenv "HEX_HTTP_CONCURRENCY" "1") + (setenv "HEX_HTTP_TIMEOUT" "120") + (setenv "LANG" "C.UTF-8") + (setenv "LC_CTYPE" "C.UTF-8") + (setenv "ELIXIR_ERL_OPTIONS" "+fnu") + (when (positive? (string-length aclocal-path)) + (setenv "ACLOCAL_PATH" aclocal-path)) + (let ((existing-elixir-libs (getenv "GUIX_ELIXIR_LIBS"))) + (setenv "GUIX_ELIXIR_LIBS" + (if existing-elixir-libs + (string-append hex-lib-dir ":" existing-elixir-libs) + hex-lib-dir))) + #$@(if mix-fod-deps + (list #~(setenv "MIX_DEPS_PATH" deps-dir)) + '()) + (mkdir-p (getenv "HOME")) + (mkdir-p (getenv "MIX_HOME")) + (mkdir-p (getenv "HEX_HOME")) + (mkdir-p (getenv "XDG_CACHE_HOME")) + + #$setup-gexp + + (with-directory-excursion app-dir + #$configure-gexp + #$build-gexp + #$install-gexp) + + (let ((cookie (string-append out "/releases/COOKIE"))) + (when (and #$remove-cookie? + (file-exists? cookie)) + (delete-file cookie))))) + (package-arguments + (list + #:modules '((guix build utils)) + #:builder builder-gexp))) + (package + (name name) + (version version) + (source source) + (build-system trivial-build-system) + (native-inputs + (append + (list bash-minimal + coreutils + findutils + git-minimal + nss-certs + rebar3 + elixir-otp28 + elixir-hex-otp28) + native-inputs)) + (inputs inputs) + (arguments package-arguments) + (home-page home-page) + (synopsis synopsis) + (description description) + (license license)))) diff --git a/tribes/packages/source.scm b/tribes/packages/source.scm index d86dfc6..dfd60e5 100644 --- a/tribes/packages/source.scm +++ b/tribes/packages/source.scm @@ -1,26 +1,19 @@ (define-module (tribes packages source) #:use-module ((guix licenses) #:prefix license:) - #:use-module (guix build-system trivial) #:use-module (guix download) #:use-module (guix git-download) #:use-module (guix gexp) #:use-module (guix packages) #:use-module (guix utils) - #:use-module (gnu packages admin) #:use-module (gnu packages autotools) - #:use-module (gnu packages bash) #:use-module (gnu packages base) #:use-module (gnu packages commencement) - #:use-module (gnu packages erlang) #:use-module (gnu packages gawk) #:use-module (gnu packages linux) #:use-module (gnu packages m4) - #:use-module (gnu packages nss) #:use-module (gnu packages perl) #:use-module (gnu packages pkg-config) - #:use-module (gnu packages version-control) #:use-module ((tribes packages mix) #:prefix mix:) - #:use-module (tribes packages otp) #:use-module (srfi srfi-1) #:use-module (srfi srfi-13) #:export (fetch-mix-deps @@ -186,169 +179,79 @@ using MIX-DEPS as the pre-fetched Mix dependency tree resolved from mix.lock." #:name (string-append name "-mix-deps") #:version version #:sha256 mix-deps-sha256)))) - (package - (name name) - (version version) - (source source) - (build-system trivial-build-system) - (native-inputs - (list autoconf - autoconf-wrapper - automake - bash-minimal - coreutils - elixir-otp28 - elixir-hex-otp28 - findutils - gcc-toolchain - gawk - git-minimal - grep - gnu-make - libtool - linux-libre-headers - m4 - nss-certs - perl - pkg-config - sed - rebar3)) - (arguments - (list - #:modules '((guix build utils)) - #:builder - #~(begin - (use-modules (guix build utils)) - - (define out #$output) - (define work (string-append (getcwd) "/build")) - (define app-dir (string-append work "/tribes")) - (define deps-dir (string-append app-dir "/deps")) - (define certs-dir - #$(file-append nss-certs "/etc/ssl/certs")) - (define cert-file - (string-append work "/ca-certificates.crt")) - (define hex-lib-dir - #$(file-append elixir-hex-otp28 - "/lib/elixir/" - (version-major+minor - (package-version elixir-otp28)))) - (define aclocal-path - (string-join - (list #$(file-append automake "/share/aclocal") - #$(file-append libtool "/share/aclocal")) - ":")) - (define kernel-headers-dir - #$(file-append linux-libre-headers "/include")) - (define path - (string-join - (list #$(file-append elixir-otp28 "/bin") - #$(file-append elixir-hex-otp28 "/bin") - #$(file-append rebar3 "/bin") - #$(file-append gcc-toolchain "/bin") - #$(file-append gnu-make "/bin") - #$(file-append autoconf-wrapper "/bin") - #$(file-append autoconf "/bin") - #$(file-append automake "/bin") - #$(file-append bash-minimal "/bin") - #$(file-append coreutils "/bin") - #$(file-append findutils "/bin") - #$(file-append libtool "/bin") - #$(file-append gawk "/bin") - #$(file-append grep "/bin") - #$(file-append m4 "/bin") - #$(file-append perl "/bin") - #$(file-append pkg-config "/bin") - #$(file-append sed "/bin") - #$(file-append git-minimal "/bin") - (or (getenv "PATH") "")) - ":")) - - (mkdir-p work) - (copy-recursively #+source app-dir #:follow-symlinks? #t) - (copy-recursively #+mix-deps-source deps-dir #:follow-symlinks? #t) - (invoke #$(file-append bash-minimal "/bin/sh") - "-c" - (string-append - #$(file-append coreutils "/bin/cat") - " " - certs-dir - "/*.pem > " - cert-file)) - (invoke #$(file-append coreutils "/bin/chmod") - "-R" "u+w" - app-dir - deps-dir) - - (setenv "PATH" path) - (setenv "HOME" (string-append app-dir "/.home")) - (setenv "MIX_HOME" (string-append app-dir "/.mix-home")) - (setenv "HEX_HOME" (string-append app-dir "/.hex")) - (setenv "XDG_CACHE_HOME" (string-append app-dir "/.cache")) - (setenv "MIX_DEPS_PATH" deps-dir) - (setenv "MIX_TARGET" "host") - (setenv "MIX_OS_CONCURRENCY_LOCK" "0") - (let ((existing-elixir-libs (getenv "GUIX_ELIXIR_LIBS"))) - (setenv "GUIX_ELIXIR_LIBS" - (if existing-elixir-libs - (string-append hex-lib-dir ":" existing-elixir-libs) - hex-lib-dir))) - (setenv "MIX_ENV" "prod") - (setenv "HEX_OFFLINE" "1") - (setenv "MIX_REBAR3" #$(file-append rebar3 "/bin/rebar3")) - (setenv "REBAR_GLOBAL_CONFIG_DIR" - (string-append work "/rebar3")) - (setenv "REBAR_CACHE_DIR" - (string-append work "/rebar3.cache")) - (setenv "ACLOCAL_PATH" aclocal-path) - (setenv "SHELL" #$(file-append bash-minimal "/bin/sh")) - (setenv "CONFIG_SHELL" #$(file-append bash-minimal "/bin/sh")) - (setenv "SSL_CERT_DIR" certs-dir) - (setenv "LANG" "C.UTF-8") - (setenv "LC_CTYPE" "C.UTF-8") - (setenv "ELIXIR_ERL_OPTIONS" "+fnu") - (setenv "SSL_CERT_FILE" cert-file) - (setenv "HEX_CACERTS_PATH" cert-file) - (let ((existing-cpath (getenv "CPATH"))) - (setenv "CPATH" - (if existing-cpath - (string-append kernel-headers-dir ":" existing-cpath) - kernel-headers-dir))) - (let ((existing-c-include-path (getenv "C_INCLUDE_PATH"))) - (setenv "C_INCLUDE_PATH" - (if existing-c-include-path - (string-append kernel-headers-dir ":" existing-c-include-path) - kernel-headers-dir))) - (setenv "CC" #$(file-append gcc-toolchain "/bin/gcc")) - (setenv "CXX" #$(file-append gcc-toolchain "/bin/g++")) - (setenv "CPP" - (string-append #$(file-append gcc-toolchain "/bin/gcc") - " -E")) - (mkdir-p (getenv "HOME")) - (mkdir-p (getenv "MIX_HOME")) - (mkdir-p (getenv "HEX_HOME")) - (mkdir-p (getenv "XDG_CACHE_HOME")) - - (with-directory-excursion app-dir - ;; Absinthe has been the last fragile dependency in Guix builds so - ;; far. Compile its immediate deps first, then compile Absinthe in - ;; its own pass before compiling the remaining dependency graph. - (invoke "mix" "deps.compile" "nimble_parsec" "telemetry" "decimal") - (let ((existing-erl-flags (getenv "ERL_FLAGS"))) - ;; Keep the scheduler count pinned while compiling Absinthe so - ;; toolchain-sensitive ordering issues stay deterministic. - (setenv "ERL_FLAGS" - (if existing-erl-flags - (string-append existing-erl-flags " +S 1:1") - "+S 1:1")) - (invoke "mix" "deps.compile" "absinthe" "--force") - (if existing-erl-flags - (setenv "ERL_FLAGS" existing-erl-flags) - (unsetenv "ERL_FLAGS"))) - (invoke "mix" "deps.compile") - (invoke "mix" "compile" "--no-deps-check") - (invoke "mix" "release" "--no-deps-check" "--path" out))))) - (home-page home-page) - (synopsis synopsis) - (description description) - (license license:asl2.0)))) + (mix:mix-release-package + source + #:mix-fod-deps mix-deps-source + #:name name + #:version version + #:home-page home-page + #:synopsis synopsis + #:description description + #:license license:asl2.0 + #:native-inputs + (list autoconf + autoconf-wrapper + automake + gcc-toolchain + gawk + grep + gnu-make + libtool + linux-libre-headers + m4 + perl + pkg-config + sed) + #:path-inputs + (list autoconf + autoconf-wrapper + automake + gcc-toolchain + gawk + grep + gnu-make + libtool + m4 + perl + pkg-config + sed) + #:aclocal-inputs + (list automake libtool) + #:setup-gexp + #~(begin + (define kernel-headers-dir + #$(file-append linux-libre-headers "/include")) + (let ((existing-cpath (getenv "CPATH"))) + (setenv "CPATH" + (if existing-cpath + (string-append kernel-headers-dir ":" existing-cpath) + kernel-headers-dir))) + (let ((existing-c-include-path (getenv "C_INCLUDE_PATH"))) + (setenv "C_INCLUDE_PATH" + (if existing-c-include-path + (string-append kernel-headers-dir ":" + existing-c-include-path) + kernel-headers-dir))) + (setenv "CC" #$(file-append gcc-toolchain "/bin/gcc")) + (setenv "CXX" #$(file-append gcc-toolchain "/bin/g++")) + (setenv "CPP" + (string-append #$(file-append gcc-toolchain "/bin/gcc") + " -E"))) + #:configure-gexp + #~(begin + ;; Absinthe has been the last fragile dependency in Guix builds so far. + ;; Compile its immediate deps first, then compile Absinthe in its own + ;; pass before compiling the remaining dependency graph. + (invoke "mix" "deps.compile" "nimble_parsec" "telemetry" "decimal") + (let ((existing-erl-flags (getenv "ERL_FLAGS"))) + ;; Keep the scheduler count pinned while compiling Absinthe so + ;; toolchain-sensitive ordering issues stay deterministic. + (setenv "ERL_FLAGS" + (if existing-erl-flags + (string-append existing-erl-flags " +S 1:1") + "+S 1:1")) + (invoke "mix" "deps.compile" "absinthe" "--force") + (if existing-erl-flags + (setenv "ERL_FLAGS" existing-erl-flags) + (unsetenv "ERL_FLAGS"))) + (invoke "mix" "deps.compile")))))