1

I'm currently using org-mode to organize my init files — specifically, working off a fork of emacs24-starter-kit. Recently, I had come across the idea of using org-tables to organize some of my things — I've had great success in configuring package-archive, package-pinned-packages and even pretty-symbols-alist for elisp-mode and lisp-interaction-mode.

I've hit a snag, though, in trying to create a list of packages that must be installed on every instance of emacs I use, on all machines I have emacs installed. The code looks like this on org-mode:

#+NAME:package-settings
| name               | repository   |
|--------------------+--------------|
| dired+             | MELPA        |
| form-feed          | MELPA-stable |
| org-bullets        | MELPA-stable |
| org-plus-contrib   | org          |
| powerline          | MELPA-stable |
| rainbow-delimiters | MELPA-stable |
| yasnippet          | MELPA-stable |
| color-theme        | MELPA        |

#+begin_src emacs-lisp :var name=package-settings[,0] repository=package-settings[,1]
  (when (require 'package nil 'noerror)
    (progn
      (require 'cl)
      (setq package-pinned-packages (pairlis name repository))
      (setq *pkg-to-install
            (let (result)
              (dolist (entry name result)
                (setq result (append result (list (make-symbol entry)))))))
      (dolist (pkg *pkg-to-install)
        (when (not (package-installed-p pkg))
          (package-install pkg)))
      (package-initialize))) ; and reinitialize again
#+end_src

However, when I do this, I get the following error message:

package-compute-transaction: Package `dired+-' is unavailable

Pressing C-x C-e on the affected sexp (i.e. (dolist pkg...) gets me this:

Debugger entered--Lisp error: (error "Package `dired+-' is unavailable")
  signal(error ("Package `dired+-' is unavailable"))
  error("Package `%s-%s' is unavailable" dired+ "")
  package-compute-transaction(nil ((dired+)))
  package-install(dired+)
  (progn (package-install pkg))
  (if (not (package-installed-p pkg)) (progn (package-install pkg)))
  (while --dolist-tail-- (setq pkg (car --dolist-tail--)) (if (not  (package-installed-p pkg)) (progn (package-install pkg))) (setq --dolist-tail-- (cdr --dolist-tail--)))
  (let ((--dolist-tail-- *pkg-to-install) pkg) (while --dolist-tail-- (setq pkg (car --dolist-tail--)) (if (not (package-installed-p pkg)) (progn (package-install pkg))) (setq --dolist-tail-- (cdr --dolist-tail--))))
  eval((let ((--dolist-tail-- *pkg-to-install) pkg) (while --dolist-tail-- (setq pkg (car --dolist-tail--)) (if (not (package-installed-p pkg)) (progn (package-install pkg))) (setq --dolist-tail-- (cdr --dolist-tail--)))) nil)
  eval-last-sexp-1(nil)
  eval-last-sexp(nil)
  call-interactively(eval-last-sexp nil nil)
  command-execute(eval-last-sexp)

I honestly don't know what could be wrong here. I managed to finangle the fact that org-babel exports the vars as (let ((name (quote ("dired+" "form-feed" ...)))...)...) by using make-symbol, but I've hit the limit in terms of my (admittedly still rather sketchy at places) understanding of elisp.

1
  • That error-message means "package-install doesn't know where to find dired+" (ignore the suffix "-"), you can solve this with (package-refresh-contents).
    – xuchunyang
    Sep 30, 2015 at 6:15

1 Answer 1

2
#+begin_src emacs-lisp :var name=package-settings[,0] repository=package-settings[,1]
  (require 'package)
  (require 'cl-lib)

  (setq package-pinned-packages (cl-pairlis name repository))

  (let ((pkgs (mapcar #'intern name)))
    (mapc (lambda (pkg)
            (unless (package-installed-p pkg)
              (unless (assoc pkg package-archive-contents)
                (package-refresh-contents))
              (package-install pkg)))
          pkgs))

  (package-initialize)
#+end_src
4
  • Okay, so that does work, which is great. Thank you! Ohhh, so that's what I was doing wrong, I was using make-symbol instead of intern (replacing make-symbol in my old code causes everything to fall into place). And rather than making a temporary symbol to hold on to the list of package symbols, you've used let and mapcar to transform name from a list of strings to a list of symbols, and then, since all we need are the side-effects, just used mapc to run through the whole “check if package-installed-p, and then… wait, assoc is used for what, again? Sep 30, 2015 at 7:10
  • The (unless (assoc pkg... test just runs once, and if it fails it doesn't try to run package-refresh-contents again, doesn't it? So if I have gibberish or misspell a package name in the table, it'll just refresh the package list once every time, right? Sep 30, 2015 at 7:13
  • You know what, I think the basic structure works out pretty well, and your use of intern basically solves my problem. Thank you very much! I think I'll just mark this as the correct answer. Sep 30, 2015 at 7:24
  • That tests if package.el knows pkg, if doesn't, call (package-refresh-contents) to fetch all packages's descriptions, if does, do nothing. So if you misspell a package name, (package-refresh-contents) will be called once for it, and then package-install will interrupt, further package will not be installed. mapc and mapcar are sequential, not parallel.
    – xuchunyang
    Sep 30, 2015 at 7:30

Your Answer

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

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