elpaca
elpaca copied to clipboard
[Bug/Support]: How to install packages using emacs --batch?
Confirmation
- [x] I have checked the documentation (README, Wiki, docstrings, etc)
- [ ] I am checking these without reading them.
- [x] I have searched previous issues to see if my question is a duplicate.
Elpaca Version
commit 10e6544
Operating System
NixOS
Description
I'm writing a starter kit using leaf.el and elpaca as package manager. I want to implement a command that executes Emacs in batch mode and makes elpaca pull all packages enabled by the user, however this has proven unsuccessful as it only downloads recipes of Melpa and exists:
.emacs.d on version-1 (a9aea78) [!?⇡] via ❄ impure (devenv-shell-env)
➜ emacs --batch --load early-init.el --load init.el --eval "(elpaca-wait)"
INFO Scraping 15 files for loaddefs...
INFO Scraping 15 files for loaddefs...done
GEN ../elpaca-autoloads.el
Loading ./elpaca-autoloads (source)...
Loading /home/jorge/.backpack.d/init.el (source)...
Loading /home/jorge/.emacs.d/gears/ui/theme.el (source)...
Downloading MELPA recipes...
Downloading MELPA recipes...100%
.emacs.d on version-1 (a9aea78) [!?⇡] via ❄ impure (devenv-shell-env) took 8s
➜
I have found success by forgoing the usage of batch mode and instead using --kill -nw:
$ emacs --kill -nw --eval "(elpaca-wait)"
# Emacs open, shows a panel of elpaca narrating what's happening and then exits
I modified the installer to install another package of mine like so:
;; Elpaca Installer -*- lexical-binding: t; -*-
;; Copy below this line into your init.el
(defvar elpaca-installer-version 0.11)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
:ref nil :depth 1 :inherit ignore
:files (:defaults "elpaca-test.el" (:exclude "extensions"))
:build (:not elpaca--activate-package)))
(let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory))
(build (expand-file-name "elpaca/" elpaca-builds-directory))
(order (cdr elpaca-order))
(default-directory repo))
(add-to-list 'load-path (if (file-exists-p build) build repo))
(unless (file-exists-p repo)
(make-directory repo t)
(when (<= emacs-major-version 28) (require 'subr-x))
(condition-case-unless-debug err
(if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
((zerop (apply #'call-process `("git" nil ,buffer t "clone"
,@(when-let* ((depth (plist-get order :depth)))
(list (format "--depth=%d" depth) "--no-single-branch"))
,(plist-get order :repo) ,repo))))
((zerop (call-process "git" nil buffer t "checkout"
(or (plist-get order :ref) "--"))))
(emacs (concat invocation-directory invocation-name))
((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
"--eval" "(byte-recompile-directory \".\" 0 'force)")))
((require 'elpaca))
((elpaca-generate-autoloads "elpaca" repo)))
(progn (message "%s" (buffer-string)) (kill-buffer buffer))
(error "%s" (with-current-buffer buffer (buffer-string))))
((error) (warn "%s" err) (delete-directory repo 'recursive))))
(unless (require 'elpaca-autoloads nil t)
(require 'elpaca)
(elpaca-generate-autoloads "elpaca" repo)
(let ((load-source-file-function nil)) (load "./elpaca-autoloads"))))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))
(elpaca doct)
I saved it to /tmp/testing/.
From that directory I ran the following shell command:
$ emacs --script installer.el --eval '(elpaca-wait)'
Which seemed to exit immediately and did not result in a proper build.
However, adding --init-directory=. did the trick:
$ emacs --init-directory=. --script installer.el --eval '(elpaca-wait)'
This is because the installer expands file names against user-emacs-directory.
Does that help?
Hi, Progfolio
I'll need to test on my end.
On mié, oct 15 2025, Nicholas Vollmer wrote:
progfolio left a comment (progfolio/elpaca#486)
I modified the installer to install another package of mine like so:
;; Elpaca Installer -- lexical-binding: t; -- ;; Copy below this line into your init.el (defvar elpaca-installer-version 0.11) (defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) (defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) (defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" :ref nil :depth 1 :inherit ignore :files (:defaults "elpaca-test.el" (:exclude "extensions")) :build (:not elpaca--activate-package))) (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) (build (expand-file-name "elpaca/" elpaca-builds-directory)) (order (cdr elpaca-order)) (default-directory repo)) (add-to-list 'load-path (if (file-exists-p build) build repo)) (unless (file-exists-p repo) (make-directory repo t) (when (<= emacs-major-version 28) (require 'subr-x)) (condition-case-unless-debug err (if-let* ((buffer (pop-to-buffer-same-window "elpaca-bootstrap")) ((zerop (apply #'call-process `("git" nil ,buffer t "clone" ,@(when-let* ((depth (plist-get order :depth))) (list (format "--depth=%d" depth) "--no-single-branch")) ,(plist-get order :repo) ,repo)))) ((zerop (call-process "git" nil buffer t "checkout" (or (plist-get order :ref) "--")))) (emacs (concat invocation-directory invocation-name)) ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" "--eval" "(byte-recompile-directory "." 0 'force)"))) ((require 'elpaca)) ((elpaca-generate-autoloads "elpaca" repo))) (progn (message "%s" (buffer-string)) (kill-buffer buffer)) (error "%s" (with-current-buffer buffer (buffer-string)))) ((error) (warn "%s" err) (delete-directory repo 'recursive)))) (unless (require 'elpaca-autoloads nil t) (require 'elpaca) (elpaca-generate-autoloads "elpaca" repo) (let ((load-source-file-function nil)) (load "./elpaca-autoloads")))) (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca @.***)) (elpaca doct)
I saved it to /tmp/testing/.
$ emacs --script installer.el --eval '(elpaca-wait)'
Seemed to exit immediately and did not result in a proper build. However, adding --init-directory=. did the trick:
$ emacs --init-directory=. --script installer.el --eval '(elpaca-wait)'
This is because the installer expands file names against user-emacs-directory. Does that help?
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.
-- Jorge Araya
Contacto: Telegram: t.me/shackra · Signal: Shackra.28
Okay, I gave it a try and... I saw Emacs exit immediately, just like before.
This is the shell script I use to run the "ensuring" part:
8<---------------cut here---------------start------------->8--- #!/usr/bin/env sh
set -eu
ACTION="${1:-}"
if [ -z "$ACTION" ]; then
echo "❌ Error: missing argument" >&2
echo "Usage: $0
Buscar directorio de configuración
if [ -d "$HOME/.emacs.d" ]; then INIT_DIR="$HOME/.emacs.d" elif [ -d "$XDG_CONFIG_HOME/emacs" ]; then INIT_DIR="$XDG_CONFIG_HOME/emacs" else echo "❌ Error: Emacs configuration directory not found ($HOME/.emacs.d or $XDG_CONFIG_HOME/emacs)" >&2 exit 1 fi
if [ "$ACTION" = "ensure" ]; then echo "✅ Running Emacs in batch mode..." emacs --init-directory="$INIT_DIR" --script "$INIT_DIR"/ensure.el exit $? else echo "❌ Error: unknown action '$ACTION'" >&2 echo "available actions: ensure" >&2 exit 1 fi 8<---------------cut here---------------end--------------->8---
This is the Emacs Lisp code referenced above with adjustments:
8<---------------cut here---------------start------------->8--- (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" :ref nil :depth 1 :inherit ignore :files (:defaults "elpaca-test.el" (:exclude "extensions")) :build (:not elpaca--activate-package)))
(load-file (expand-file-name "early-init.el" user-emacs-directory)) ;; needed because of --script
(progn (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) (build (expand-file-name "elpaca/" elpaca-builds-directory)) (order (cdr elpaca-order)) (default-directory repo)) (unless (file-exists-p repo) (make-directory repo t) (condition-case-unless-debug err (if-let* ((buffer (pop-to-buffer-same-window "elpaca-bootstrap")) ((zerop (apply #'call-process `("git" nil ,buffer t "clone" ,@(when-let* ((depth (plist-get order :depth))) (list (format "--depth=%d" depth) "--no-single-branch")) ,(plist-get order :repo) ,repo)))) ((zerop (call-process "git" nil buffer t "checkout" (or (plist-get order :ref) "--")))) (emacs (concat invocation-directory invocation-name)) ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" "--eval" "(byte-recompile-directory "." 0 'force)"))) ((require 'elpaca)) ((elpaca-generate-autoloads "elpaca" repo))) (progn (message "%s" (buffer-string)) (kill-buffer buffer)) (error "%s" (with-current-buffer buffer (buffer-string)))) ((error) (warn "%s" err) (delete-directory repo 'recursive)))) (unless (require 'elpaca-autoloads nil t) (require 'elpaca) (elpaca-generate-autoloads "elpaca" repo) (let ((load-source-file-function nil)) (load "./elpaca-autoloads"))))
(elpaca @.***))
(add-hook 'elpaca-post-queue-hook (lambda () ;; (save-default-bg-fg-colors) (unless (gearp! :ui -treesit) (when (fboundp 'treesit-auto-install-all) (message "compiling tree-sitter grammars") (let ((treesit-auto-install t)) (treesit-auto-install-all)))) (kill-emacs 0)))
(backpack-load-gear-files) (elpaca-wait)) 8<---------------cut here---------------end--------------->8---
On mié, oct 15 2025, Nicholas Vollmer wrote:
progfolio left a comment (progfolio/elpaca#486)
I modified the installer to install another package of mine like so:
;; Elpaca Installer -- lexical-binding: t; -- ;; Copy below this line into your init.el (defvar elpaca-installer-version 0.11) (defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) (defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) (defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" :ref nil :depth 1 :inherit ignore :files (:defaults "elpaca-test.el" (:exclude "extensions")) :build (:not elpaca--activate-package))) (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) (build (expand-file-name "elpaca/" elpaca-builds-directory)) (order (cdr elpaca-order)) (default-directory repo)) (add-to-list 'load-path (if (file-exists-p build) build repo)) (unless (file-exists-p repo) (make-directory repo t) (when (<= emacs-major-version 28) (require 'subr-x)) (condition-case-unless-debug err (if-let* ((buffer (pop-to-buffer-same-window "elpaca-bootstrap")) ((zerop (apply #'call-process `("git" nil ,buffer t "clone" ,@(when-let* ((depth (plist-get order :depth))) (list (format "--depth=%d" depth) "--no-single-branch")) ,(plist-get order :repo) ,repo)))) ((zerop (call-process "git" nil buffer t "checkout" (or (plist-get order :ref) "--")))) (emacs (concat invocation-directory invocation-name)) ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" "--eval" "(byte-recompile-directory "." 0 'force)"))) ((require 'elpaca)) ((elpaca-generate-autoloads "elpaca" repo))) (progn (message "%s" (buffer-string)) (kill-buffer buffer)) (error "%s" (with-current-buffer buffer (buffer-string)))) ((error) (warn "%s" err) (delete-directory repo 'recursive)))) (unless (require 'elpaca-autoloads nil t) (require 'elpaca) (elpaca-generate-autoloads "elpaca" repo) (let ((load-source-file-function nil)) (load "./elpaca-autoloads")))) (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca @.***)) (elpaca doct)
I saved it to /tmp/testing/.
$ emacs --script installer.el --eval '(elpaca-wait)'
Seemed to exit immediately and did not result in a proper build. However, adding --init-directory=. did the trick:
$ emacs --init-directory=. --script installer.el --eval '(elpaca-wait)'
This is because the installer expands file names against user-emacs-directory. Does that help?
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.
-- Jorge Araya
Contacto: Telegram: t.me/shackra · Signal: Shackra.28
Okay, I gave it a try and... I saw Emacs exit immediately, just like before.
Are you trying the script I posted, or the one you posted in your most recent comment?
mine with attention to place anything missing from yours in mine
On vie, oct 17 2025, Nicholas Vollmer wrote:
progfolio left a comment (progfolio/elpaca#486)
Okay, I gave it a try and... I saw Emacs exit immediately, just like before.
Are you trying the script I posted, or the one you posted in your most recent comment?
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.
-- Jorge Araya
Contacto: Telegram: t.me/shackra · Signal: Shackra.28
Please try the steps I posted unaltered. It will help us to start from confirming whether or not the simple case works on your end.
alright, alright. I'll give it a try and report back soon.
On sáb, oct 18 2025, Nicholas Vollmer wrote:
progfolio left a comment (progfolio/elpaca#486)
Please try the steps I posted unaltered. It will help us to start from confirming whether or not the simple case works on your end.
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.
-- Jorge Araya
Contacto: Telegram: t.me/shackra · Signal: Shackra.28
I'll consider this closed for now. If you are able to demonstrate that the simple case is failing, feel free to leave a comment and we can investigate further. Thank you!