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.

  • 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 '15 at 6:15
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
  • 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? – Tariq Kamal Sep 30 '15 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? – Tariq Kamal Sep 30 '15 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. – Tariq Kamal Sep 30 '15 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 '15 at 7:30

This site is temporarily in read only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .