0

I have used some packages in init.el, after setup a new environment and copy init.el to .emacs/init.el, then start emacs will report packages missing.

I can install it one by one. but I would like to find a way to install it with command. I want to add such install in init.el but do not wish it impact on emacs startup time.

How can I do it? say I need install "js2-mode,skewer-mode".

1
  • Write a function that takes a list of packages as argument and for each one, it checks whether it is installed - if not, it installs it. Then add the definition and a call to the function to your init file. It will take a while the first time you start up emacs to install all the packages, but very little time on subsequent invocations, since everything will be installed. And you can comment out the call afterwards, so it wont' even do the checking.
    – NickD
    Sep 2, 2022 at 14:24

4 Answers 4

1

If you are using a recent enough Emacs, the Early Init File can help you. Namely, you can specify which packages you would want to have installed in the Early Init file:

(setq
 ;; archives to install packages from
 package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
                    ("melpa" . "https://melpa.org/packages/"))
 ;; packages to have installed
 package-selected-packages '(helm
                             magit))

Then, in your regular Init File, you can ensure that the packages are installed:

(unless package-archive-contents
  (package-refresh-contents))
(package-install-selected-packages 'noconfirm)

The biggest caveat is that you now have to manage package-selected-packages yourself.

4
  • Thanks, but package-refresh-contents will cost very long time when start emacs.
    – lucky1928
    Sep 2, 2022 at 15:14
  • That’s why it’s only run unless package-archive-contents. If you are sure that your archive contents are non-nil, you can remove that piece of code altogether.
    – d125q
    Sep 2, 2022 at 15:15
  • Thanks, I checked the package-archive-contents is nil, but it still run into the unless logic. which will cost few secs.
    – lucky1928
    Sep 2, 2022 at 15:22
  • In that case simply remove that code, but you’ll have to make sure the archive contents are non-nil by yourself. (That’s what I also do.)
    – d125q
    Sep 2, 2022 at 15:24
1

All you need is to manage your packages with use-package. With the following config, your packages will be automatically installed (when not installed) and updated (when new versions are available):

* General behaviour
** Package Management
*** Emacs Package Repositories
#+begin_src emacs-lisp 
  (require 'package)
  (setq package-archives
     '(("melpa" . "https://melpa.org/packages/")
       ("elp" . "https://elpa.gnu.org/packages/")
       ("gnu-devel" . "https://elpa.gnu.org/devel/")
       ("nongnu" . "https://elpa.nongnu.org/nongnu/")
       ))
#+end_src
*** Package config tool (=use-package=)
**** Package installation
- Auto install all packages called by =use-package=
#+begin_src emacs-lisp 
(require 'use-package-ensure)
(setq use-package-always-ensure t)
#+end_src
**** Package update
- Keep packages called by =use-package= automatically updated
#+begin_src emacs-lisp 
(use-package auto-package-update
  :config
  (setq auto-package-update-delete-old-versions t)
  (setq auto-package-update-hide-results t)
  (auto-package-update-maybe))
#+end_src

Each of your packages then have to be managed through use package. E.g. :

* Looks
** Themes
*** Exotica by default
    #+BEGIN_SRC emacs-lisp
      (use-package exotica-theme
    :config (load-theme 'exotica t))
    #+END_SRC```
3
  • Thanks, got a error: File is missing: Cannot open load file, No such file or directory, use-package-ensure
    – lucky1928
    Sep 2, 2022 at 20:15
  • Did you install use-package?
    – crocefisso
    Sep 2, 2022 at 23:37
  • use-package will natively be part of Emacs 29.1.
    – crocefisso
    Dec 30, 2022 at 22:04
1

Create a temp file to indicate if initialized or not, if not, then install packages and create the temp file. otherwise do nothing.

(defun install-pkgs-if-needed()
    (setq flag-file "~/.emacs.d/initial.txt")
    (if (not (file-exists-p flag-file))
        (progn      
            (setq package-selected-packages
                        '(
                            js2-mode
                            js2-refactor
                            skewer-mode
                            ))
            (unless package-archive-contents
                (package-refresh-contents))
  
            (package-install-selected-packages 'noconfirm)
            (with-temp-buffer (write-file flag-file))
            )
        (print "initial.txt file exist")
        )
)

(install-pkgs-if-needed)
0

I have a list of packages that I need to install in a custom variable (in the early-init.el) like so.

(defcustom timu-package-list
  '(0x0
    ...
    yasnippet
    ytel)
  "List of packages to be installed for the Emacs config to work as configured.
The packages will be installed with `timu-func-install-packages'."
  :type '(repeat symbol)
  :group 'timu)

The following function checks if a package is installed.

(defun timu-func-packages-installed-p ()
  "Check if all packages in `timu-package-list' are installed."
  (cl-every #'package-installed-p timu-package-list))

This functions installs a package if it is not installed.

(defun timu-func-require-package (package)
  "Install PACKAGE unless already installed."
  (unless (memq package timu-package-list)
    (add-to-list 'timu-package-list package))
  (unless (package-installed-p package)
    (package-install package)))

Install ALL the packages in case they are not installes

(defun timu-func-require-packages (packages)
  "Ensure PACKAGES are installed.
Missing packages are installed automatically."
  (mapc #'timu-func-require-package packages))

This is the command I the use in my init.el file to install the packages on demand. This would be the "one command". Note that this only installs missing packages. The above functions are helper functions.

(defun timu-func-install-packages ()
  "Install all packages listed in `timu-package-list' unless already installed."
  (interactive)
  (unless (timu-func-packages-installed-p)
    ;; check for new packages (package versions)
    (message "%s" "Reloading packages DB...")
    (package-refresh-contents)
    (message "%s" " done.")
    ;; install the missing packages
    (timu-func-require-packages timu-package-list)))

I got most of the code from this repo and adjusted it for case: https://github.com/bbatsov/prelude

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.