Carlos ELPA

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:

Each package page shows its recipe as well.