4

Based on this reply, my code has the following function that installs its dependencies:

(defun literef-install-packages()
  "Install any missing packages. The code is taken from
`https://stackoverflow.com/a/10093312/2725810'."

  (setq package-list '(org org-ref pdf-tools smooth-scrolling company))

                    ; list the repositories containing them
  (setq package-archives '(("elpa" . "http://tromey.com/elpa/")
               ("gnu" . "http://elpa.gnu.org/packages/")
               ("marmalade" . "http://marmalade-repo.org/packages/")
               ("melpa" . "http://melpa.milkbox.net/packages/")))
  (package-initialize)
  (unless package-archive-contents
    (package-refresh-contents))

  (dolist (package package-list)
    (unless (package-installed-p package)
      (when 
        (yes-or-no-p (concat
            "The package " (symbol-name package)
            " is not installed. Install it? "))
        (package-install package)
        (when (eq package 'pdf-tools) (pdf-tools-install))))))

The problems is that Emacs comes with built-in org, which makes it impossible to install the version from MELPA by using (package-install 'org), since the package is "already installed". How do I fix my code to work for org as well as it works for the other packages?

I looked through package.el to find a way to get to the list of available packages. The closest I found was the variable package-alist. However, it only contains 20 entries, so it is not what I am looking for.

In addition, I do not know how to technically install a package with a specified version. Namely (package-install 'org) says that the package is already installed, but (package-install 'org-9.1.14) says that such a package is not available, although I do see org version 9.1.14 in the package manager and am able to install it from there.

The other idea is to uninstall the built-in org first so as to be able to use (package-install 'org) to install the latest version. However, I do not know what to supply as an argument to (package-delete).

UPDATE: I have posted my solution here.

3 Answers 3

1

Package management in emacs has many options. package.el has been part of emacs distribution since version 24, but it not the last word on it.

The default package.el knows about package repositories using variable package-archives. It should include at least MELPA.

Its user interface is dired-like that needs you to call up the dynamically created list of packages with list-packages. You can then mark and install packages as well as delete them. It also automatically detects upgrades to already installed packages and prompts you upgade them with U.

An enhancement to this is paradox that among other things adds a global command that can be configured to upgrade packages asynchronously: paradox-upgrade-packages.

use-package helps you to organize package configurion in your init file better then using default commands and is highly recommended.

Package managers usually focus on installing the latest version of packages. If you want to define exact versions for development and reproducibility, you should use cask.

There are more package managers that give you finer control. For example, look into straight.el that allows you to maintain and use local copies of package git repositories.

Finally, you should not try to delete built-in packages but override them with newer versions.

7
  • Thank you for this informative reply. My code uses features that appeared first in version 9 of org, so it needs version 9 or later of org to work. The built-in version that comes with Emacs 25 installed by default on Ubuntu 18.04 is earlier. So, all I want to do in my code is somehow install whichever version of org is currently available in MELPA. Can I do this with the functions of package.el or should I rather prefer paradox or something else? Nov 12, 2018 at 9:17
  • You can do it with package.el. Get started with it and learn more when you have time and a specific need.
    – Heikki
    Nov 12, 2018 at 9:19
  • Could you please hint at which functions and variables of package.el do I need to look at for this specific need of installing org from MELPA in your reply? Some lines of code would be very much appreciated. Nov 12, 2018 at 9:22
  • I though I already did :) . The simplest way, assuming you have MELPA included, is to go to the package list, search a line with first field 'org', press enter and click the install button on the new buffer. Check the version of org and it if it still shows the old one, run org-reload.
    – Heikki
    Nov 12, 2018 at 9:31
  • May be I did not emphasize this enough. I need to perform the installation by using the API, without using the user interface. My code installs all its dependencies automatically. The only package that gives me problems is org, since it is built-in. Nov 12, 2018 at 9:31
0

The code says

  (unless (package-installed-p package)

So it will always skip upgrading org because it is already installed. A simple solution is to add (package-install "org") outside the dolist loop.

4
  • I tried (unless (eq (package-installed-p package) t). It still does not work, because `(package-install 'org) does not do anything... When I evaluate it separately it says "package already installed". Nov 12, 2018 at 9:52
  • Try (package-reinstall "org")
    – Heikki
    Nov 12, 2018 at 9:53
  • It gives an error Debugger entered--Lisp error: (wrong-type-argument arrayp nil). It looks like it tries to call (package-delete) and fails... Nov 12, 2018 at 9:56
  • I am stumped. Hopefully someone else can help.
    – Heikki
    Nov 12, 2018 at 10:00
0

I have a project whose documentation is built using Org-mode, and unfortunately some of our continuous-integration platform have versions of Org that are too old. What I ended up doing it forcefully update Org whenever the build detects a version that is too old. The tricky part was to somehow unload the old version before compiling the new one, otherwise the byte-compilation would get confused in some scenarios.

Here is the relevant part of that code:

(package-initialize)
(require 'cl)
(setq features-before features)
(require 'org-version)

; The Org version that ships with emacs is usually too old.
(when (version< org-version "9.1")
  (warn "Org-mode is too old; attempting to download a more recent version")
  ;; we need to unload any bits of org that were loaded before calling
  ;; install package, otherwise the byte code might mix the two versions.
  (dolist (feature (set-difference features features-before))
    (when (and (featurep feature)
               (let ((feature-name (symbol-name feature)))
                 (or (string-prefix-p "org" feature-name)
                     (string-prefix-p "ob" feature-name))))
      (message "unloading feature %s" feature)
      (unload-feature feature t)))
  ;; install org-plus-contrib, not org, as the former includes htmlize
  (add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)
  (package-refresh-contents)
  (let ((org-p-c (cadr (assq 'org-plus-contrib package-archive-contents))))
    (package-install org-p-c)))

Note that all of this is run as a script in batch mode, so I know org isn't loaded until I check its version.

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.