Emacs Package Archive Statistics
      I use
      cask
      for managing the dependencies of my Emacs
configuration.  Whenever I opened my
      Cask
      file, I wondered if I
really was using all the sources I had defined:
     
      (source gnu)
(source marmalade)
(source melpa)
(source melpa-stable)
(source org)
     
     It seemed quite strange that we have so many package repositories in the Emacs world and I’m not even using all of them. I find this state less than ideal, much as Jorgen Schäfer details. My ideal package repository would be once that works with VCS releases, mostly because it’s a much simpler process to work with than having to sign up to yet another website just to upload a package, then ensure it’s kept up-to-date on every release.
As such, I prefer the concepts behing MELPA and MELPA Stable to those of Marmalade. GNU ELPA doesn’t appear to allow any submissions and org is specific to org-mode. I’ve also noticed that many packages I find and use are on github and so work with the MELPA system. However, I don’t like MELPA’s versioning: it just gets the latest code and puts the build date in the version, meaning that packages could break at any time.
      So, ideally I would use
      MELPA Stable
      as much as possible and reduce my
usage of
      Marmalade
      and
      MELPA.
      GNU ELPA
      doesn’t appear to have
many packages, but I wasn’t sure if I was using any.
I couldn’t see the information listed in the
      *Packages*
      buffer, so I
decided to try to figure out how to generate some usage statistics.
     
I found how to get a list of installed packages, but that just gives a list:
      (ace-jump-mode ag auto-compile auto-indent-mode autopair ...)
     
     
      I needed to get more information about those packages.  I looked at
where
      list-packages
      gets that information from.  It seems that
      package-archive-contents
      is a list of cons cells:
     
      (org-plus-contrib .
				  [(20140714)
				  nil "Outline-based notes management and organizer" tar "org"])
     
     
      Then created a function to loop over the contents of
      package-activated-list, retrieving the corresponding contents of
      package-archive-contents:
     
      (defun package-list-installed ()
  (loop for pkg in package-activated-list
        collect (assq pkg package-archive-contents)))
     
     
      This generates a list of arrays from
      package-archive-contents.
There are some helper functions in package.el such as
      package-desc-kind.
      package-desc-archive
      was exactly what I
needed.  I happened to be using a pretest version of Emacs at the time
and didn’t know that it’s not in 24.3, so I just made sure it was defined:
     
      (if (not (fboundp #'package-desc-archive))
    (defsubst package-desc-archive (desc)
      (aref desc (1- (length desc)))))
     
     
      Weirdly, some of the arrays (seemingly the ones from the
      org archive) had a different length, but the repository/archive was
always the last element, which is why I used
      (1- (length ))
      and not
a constant, like the other
      package-desc-*
      functions.
     
      To generate a list of statistics, I just needed to loop over the
installed packages from
      package-list-installed
      and update a count
for each archive:
     
      (defun package-archive-stats ()
  (let ((archives (makehash))
        (assoc '()))
    (dolist (arc package-archives)
      (puthash (car arc) 0 archives))
    (maphash (lambda (k v)
               (setq assoc (cons (cons k v) assoc)))
             (dolist (pkg (-filter #'identity (package-list-installed)) archives)
               (let ((pkg-arc (package-desc-archive (cdr pkg))))
                 (incf (gethash pkg-arc archives)))))
    assoc))
     
     Running this gives a list of cons cells:
      (("gnu" . 0)
 ("org" . 1)
 ("melpa-stable" . 2)
 ("melpa" . 106)
 ("marmalade" . 1))
     
     I wrapped it in an interactive function so that I could check the numbers quickly:
      (defun package-show-archive-stats ()
  (interactive)
  (message "%s" (package-archive-stats)))
     
     
      With that, I removed
      (source gnu)
      from my
      Cask
      file.  Now I had
another question.  What package was installed from
      marmalade?  In
the lisp fashion, I created yet another function:
     
      (defun package-show-installed-from-archive (archive)
  (interactive (list (helm-comp-read "Archive: " (mapcar #'car package-archives)
                                      :must-match t)))
  (let ((from-arc (mapcar #'car
                          (--filter (equalp (package-desc-archive (cdr it)) archive)
                                    (package-list-installed)))))
    (if (called-interactively-p)
        (message "%s" from-arc)
      from-arc)))
     
     
      (Non-helm users can replace
      helm-comp-read
      with
      ido-completing-read
      or similar)
     
      Running this with the argument
      "marmalade"
      gives:
     
      (php-extras)
     
     I checked on MELPA Stable and MELPA, but it’s not available there. Given that I use php-extras quite a bit at work, I can’t remove marmalade just yet. However, as it’s a git repository, it should be easy for me to create a recipe for MELPA. Then I can remove marmalade from my cask configuration. Hooray for simplification!
Hopefully, packaging in Emacs will become simpler in the future. There are some interesting things in 24.4 like pinning packages to a repository, which would allow MELPA Stable to be used even when MELPA defines the same package with a higher “version”.