summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorAlan Pearce2014-07-19 13:23:56 +0100
committerAlan Pearce2014-07-19 13:24:29 +0100
commit641f304fb878ecfb0a1afe2d6e62281d0e3e94ab (patch)
tree9ebc0654172c4350e05af6ef11ed378c5eac3674 /content
parentdf381720a8be75415b163fc8ecbd9a237ecdc4cc (diff)
downloadwebsite-641f304fb878ecfb0a1afe2d6e62281d0e3e94ab.tar.xz
website-641f304fb878ecfb0a1afe2d6e62281d0e3e94ab.zip
Write post about Emacs package archive statistics
Diffstat (limited to 'content')
-rw-r--r--content/post/emacs-package-archive-statistics.md168
1 files changed, 168 insertions, 0 deletions
diff --git a/content/post/emacs-package-archive-statistics.md b/content/post/emacs-package-archive-statistics.md
new file mode 100644
index 0000000..b610011
--- /dev/null
+++ b/content/post/emacs-package-archive-statistics.md
@@ -0,0 +1,168 @@
1+++
2Categories = ["Emacs"]
3Description = "Working out which package archives I'm using"
4Tags = ["Emacs"]
5title = "Emacs Package Archive Statistics"
6date = 2014-07-19T13:19:54Z
7+++
8
9I use [cask][] for managing the dependencies of my Emacs
10configuration. Whenever I opened my `Cask` file, I wondered if I
11really was using all the sources I had defined:
12
13{{% highlight cl %}}
14(source gnu)
15(source marmalade)
16(source melpa)
17(source melpa-stable)
18(source org)
19{{% /highlight %}}
20
21It seemed quite strange that we have so many package repositories in
22the Emacs world and I'm not even using all of them. I find this state
23less than ideal, much as
24[Jorgen Schäfer details][state of emacs package archives]. My ideal
25package repository would be once that works with VCS releases, mostly
26because it's a much simpler process to work with than having to sign
27up to yet another website just to upload a package, then ensure it's
28kept up-to-date on every release.
29
30As such, I prefer the concepts behing [MELPA][] and [MELPA Stable][] to
31those of [Marmalade][]. [GNU ELPA][] doesn't appear to allow any
32submissions and [org][org archive] is specific to [org-mode]. I've
33also noticed that many packages I find and use are on github and so
34work with the [MELPA][] system. However, I don't like [MELPA's][MELPA]
35versioning: it just gets the latest code and puts the build date in
36the version, meaning that packages could break at any time.
37
38So, ideally I would use [MELPA Stable][] as much as possible and reduce my
39usage of [Marmalade][] and [MELPA][]. [GNU ELPA][] doesn't appear to have
40many packages, but I wasn't sure if I was using any.
41I couldn't see the information listed in the `*Packages*` buffer, so I
42decided to try to figure out how to generate some usage statistics.
43
44I found [how to get a list of installed packages][], but that just gives
45a list:
46
47{{% highlight cl %}}
48(ace-jump-mode ag auto-compile auto-indent-mode autopair ...)
49{{% /highlight %}}
50
51I needed to get more information about those packages. I looked at
52where `list-packages` gets that information from. It seems that
53`package-archive-contents` is a list of cons cells:
54
55{{% highlight cl %}}
56(org-plus-contrib .
57 [(20140714)
58 nil "Outline-based notes management and organizer" tar "org"])
59{{% /highlight %}}
60
61Then created a function to loop over the contents of
62`package-activated-list`, retrieving the corresponding contents of
63`package-archive-contents`:
64
65{{% highlight cl %}}
66(defun package-list-installed ()
67 (loop for pkg in package-activated-list
68 collect (assq pkg package-archive-contents)))
69{{% /highlight %}}
70
71This generates a list of arrays from `package-archive-contents`.
72There are some helper functions in package.el such as
73`package-desc-kind`. `package-desc-archive` was exactly what I
74needed. I happened to be using a pretest version of Emacs at the time
75and didn't know that it's not in 24.3, so I just made sure it was defined:
76
77{{% highlight cl %}}
78(if (not (fboundp #'package-desc-archive))
79 (defsubst package-desc-archive (desc)
80 (aref desc (1- (length desc)))))
81{{% /highlight %}}
82
83Weirdly, some of the arrays (seemingly the ones from the
84[org archive][]) had a different length, but the repository/archive was
85always the last element, which is why I used `(1- (length ))` and not
86a constant, like the other `package-desc-*` functions.
87
88To generate a list of statistics, I just needed to loop over the
89installed packages from `package-list-installed` and update a count
90for each archive:
91
92{{% highlight cl %}}
93(defun package-archive-stats ()
94 (let ((archives (makehash))
95 (assoc '()))
96 (dolist (arc package-archives)
97 (puthash (car arc) 0 archives))
98 (maphash (lambda (k v)
99 (setq assoc (cons (cons k v) assoc)))
100 (dolist (pkg (-filter #'identity (package-list-installed)) archives)
101 (let ((pkg-arc (package-desc-archive (cdr pkg))))
102 (incf (gethash pkg-arc archives)))))
103 assoc))
104{{% /highlight %}}
105
106Running this gives a list of cons cells:
107
108{{% highlight cl %}}
109(("gnu" . 0)
110 ("org" . 1)
111 ("melpa-stable" . 2)
112 ("melpa" . 106)
113 ("marmalade" . 1))
114{{% /highlight %}}
115
116I wrapped it in an interactive function so that I could check the
117numbers quickly:
118
119{{% highlight cl %}}
120(defun package-show-archive-stats ()
121 (interactive)
122 (message "%s" (package-archive-stats)))
123{{% /highlight %}}
124
125With that, I removed `(source gnu)` from my `Cask` file. Now I had
126another question. What package was installed from [marmalade][]? In
127the lisp fashion, I created yet another function:
128
129{{% highlight cl %}}
130(defun package-show-installed-from-archive (archive)
131 (interactive (list (helm-comp-read "Archive: " (mapcar #'car package-archives)
132 :must-match t)))
133 (let ((from-arc (mapcar #'car
134 (--filter (equalp (package-desc-archive (cdr it)) archive)
135 (package-list-installed)))))
136 (if (called-interactively-p)
137 (message "%s" from-arc)
138 from-arc)))
139{{% /highlight %}}
140(Non-helm users can replace `helm-comp-read` with
141`ido-completing-read` or similar)
142
143Running this with the argument `"marmalade"` gives:
144
145{{% highlight cl %}}
146(php-extras)
147{{% /highlight %}}
148
149I checked on [MELPA Stable][] and [MELPA][], but it's not available
150there. Given that I use [php-extras][] quite a bit at work, I can't remove
151[marmalade][] just yet. However, as it's a git repository, it should be
152easy for me to create a recipe for MELPA. Then I can remove marmalade
153from my [cask][] configuration. Hooray for simplification!
154
155Hopefully, packaging in Emacs will become simpler in the future.
156There are some interesting things in 24.4 like pinning packages to a
157repository, which would allow [MELPA Stable][] to be used even when
158[MELPA][] defines the same package with a higher "version".
159
160[cask]: https://github.com/cask/cask/
161[state of emacs package archives]: http://blog.jorgenschaefer.de/2014/06/the-sorry-state-of-emacs-lisp-package.html
162[marmalade]: http://marmalade-repo.org/
163[GNU ELPA]: http://elpa.gnu.org/packages/
164[MELPA]: http://hiddencameras.milkbox.net/
165[MELPA Stable]: http://melpa-stable.milkbox.net/
166[org archive]: http://orgmode.org/elpa.html
167[how to get a list of installed packages]: http://stackoverflow.com/questions/13866848/how-to-save-a-list-of-all-the-installed-packages-in-emacs-24
168[php-extras]: https://github.com/arnested/php-extras