Setup instructions
package.el
Add the archive to package-archives:
(require 'package)
(add-to-list 'package-archives
'("cpradog" . "https://elpa.cpradog.com/")
t)
Import the archive key. This is a one-time step:
(package-import-keyring
(url-file-local-copy "https://elpa.cpradog.com/archive-key.asc"))
Download the package list:
M-x package-refresh-contents
Require a valid signature
By default package.el installs a package whether or not it is signed. To refuse any package that does not carry a verified signature:
(setq package-check-signature t)
This applies to every entry in package-archives. If you also use an archive
that publishes no signatures, add its URL to package-unsigned-archives to
exempt it.
Archive key
The key is served from the same host as the packages. Check it against the fingerprint below before trusting the archive:
uid Carlos Prado Garcia <carlos.prado@cpradog.com>
fingerprint 37BC 545D 584E 7C89 3835 21CE 53F8 2593 B0F6 8B93
signing key A890CDA549A21E7B
Print the fingerprints of what you imported with:
(let ((ctx (epg-make-context 'OpenPGP)))
(setf (epg-context-home-directory ctx) package-gnupghome-dir)
(dolist (key (epg-list-keys ctx))
(dolist (sub-key (epg-key-sub-key-list key))
(message "%s %s"
(epg-sub-key-capability sub-key)
(epg-sub-key-fingerprint sub-key)))))
Elpaca
Add the archive’s menu to elpaca-menu-functions, after the Elpaca installer:
(defvar elpaca-menu-cpradog--index nil)
(defun elpaca-menu-cpradog (request &optional item)
"Answer elpaca's menu REQUEST for ITEM with the recipes of the cpradog archive."
(when (or (eq request 'update) (null elpaca-menu-cpradog--index))
(setq elpaca-menu-cpradog--index
(with-current-buffer
(url-retrieve-synchronously "https://elpa.cpradog.com/recipes.json" t)
(goto-char url-http-end-of-headers)
(mapcar (pcase-lambda (`(,name . ,properties))
(list name
:source "cpradog"
:recipe
(cons :package
(cons (symbol-name name)
(mapcan (pcase-lambda (`(,property . ,value))
(list (intern (format ":%s" property))
(pcase property
('fetcher (intern value))
('files (read value))
('old-names (mapcar #'intern value))
(_ value))))
properties)))))
(json-parse-buffer :object-type 'alist :array-type 'list)))))
(if item
(alist-get item elpaca-menu-cpradog--index)
elpaca-menu-cpradog--index))
(add-to-list 'elpaca-menu-functions #'elpaca-menu-cpradog)
M-x elpaca-update-menus picks up packages published after the menu was first read.
straight.el
Register the archive as a recipe repository, after the straight.el bootstrap:
(defun straight-recipes-cpradog-retrieve (package)
"Return the recipe the cpradog archive serves for PACKAGE, or nil."
(let ((default-directory (make-temp-file "straight-recipes-cpradog" t)))
(unwind-protect
(with-current-buffer
(url-retrieve-synchronously
(format "https://elpa.cpradog.com/recipes/%s" package) t)
(when (equal url-http-response-status 200)
(make-directory "recipes")
(write-region url-http-end-of-headers (point-max)
(expand-file-name (symbol-name package) "recipes/"))
(straight-recipes-melpa-retrieve package)))
(delete-directory default-directory t))))
(defun straight-recipes-cpradog-list ()
"Return the names of the packages the cpradog archive serves recipes for."
(with-current-buffer
(url-retrieve-synchronously "https://elpa.cpradog.com/recipes.json" t)
(goto-char url-http-end-of-headers)
(mapcar (lambda (entry) (symbol-name (car entry)))
(json-parse-buffer :object-type 'alist))))
(straight-use-recipes '(cpradog :local-repo nil))
Quelpa
Add the archive’s recipes to quelpa-melpa-recipe-stores, after loading Quelpa:
(with-current-buffer
(url-retrieve-synchronously "https://elpa.cpradog.com/recipes.json" t)
(goto-char url-http-end-of-headers)
(add-to-list 'quelpa-melpa-recipe-stores
(mapcar (pcase-lambda (`(,name . ,properties))
(cons name
(mapcan (pcase-lambda (`(,property . ,value))
(list (intern (format ":%s" property))
(pcase property
('fetcher (intern value))
('files (read value))
('old-names (mapcar #'intern value))
(_ value))))
properties)))
(json-parse-buffer :object-type 'alist :array-type 'list))))
Other package managers
The archive serves the recipe of every package in the MELPA format:
https://elpa.cpradog.com/recipes/NAMEholds the recipe of one package.https://elpa.cpradog.com/recipes.jsonlists every recipe, in the formhttps://melpa.org/recipes.jsontakes.
Each package page shows its recipe as well.