From 715f21baf9f598e6a8ab633d419961fada44816a Mon Sep 17 00:00:00 2001 From: Jonas Bernoulli Date: Sat, 16 Apr 2016 04:16:00 +0200 Subject: [PATCH] reincarnation commit --- Makefile | 39 ++ README.md | 9 + emir-report.el | 348 ++++++++++++++++++ emir.el | 938 +++++++++++++++++++++++++++++++++++++++++++++++++ emir.org | 927 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 2261 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 emir-report.el create mode 100644 emir.el create mode 100644 emir.org diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0cd516e --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +ELS = emir.el +ELS += emir-report.el + +DEPS = ape +DEPS += dash +DEPS += elx +DEPS += epkg +DEPS += emacsql +DEPS += finalize +DEPS += ghub +DEPS += magit +DEPS += melpa-db +DEPS += packed +DEPS += request +DEPS += with-editor + +ELCS = $(ELS:.el=.elc) +DFLAGS = $(addprefix -L ../,$(DEPS)) -L ../epkg/lisp -L ../magit/lisp +EFLAGS ?= $(DFLAGS) +EMACS ?= emacs +BATCH = $(EMACS) -batch -Q -L . $(EFLAGS) + +.PHONY: help clean + +help: + $(info make lisp - create *.elc) + $(info make clean - remove *.elc) + @printf "\n" + +all: lisp + +lisp: $(ELCS) +%.elc: %.el + @printf "Compiling %s\n" $< + @$(BATCH) -f batch-byte-compile $< + +clean: + @printf "Cleaning...\n" + @rm -f $(ELCS) diff --git a/README.md b/README.md new file mode 100644 index 0000000..6aaba2f --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +Maintain the Emacsmirror +======================== + +This is the package I use to maintain the [Emacsmirror]. It isn't +very useful for anybody else. [Epkg] is the user client which you +should be using instead. + +[emacsmirror]: https://github.com/emacsmirror +[epkg]: https://gitlab.com/tarsius/epkg diff --git a/emir-report.el b/emir-report.el new file mode 100644 index 0000000..c51f10c --- /dev/null +++ b/emir-report.el @@ -0,0 +1,348 @@ +;;; emir-report.el --- update Emacsmirror reports -*- lexical-binding: t -*- + +;; Copyright (C) 2016 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://gitlab.com/tarsius/emir +;; Keywords: local + +;; This file is not part of GNU Emacs. + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3 of the License, +;; or (at your option) any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt. + +;;; Commentary: + +;; The functions defined here are used to generate the statistics +;; that are published to https://emacsmirror.net/stats and tracked +;; at https://gitlab.com/tarsius/emacsmirror.net/tree/master/stats. + +;;; Code: + +(require 'dash) +(require 'emir) +(require 'org) + +;;; Variables + +(defvar emir-report-src "~/Repos/pages/emacsmirror.net/stats/") +(defvar emir-report-dst "~/Repos/pages/emacsmirror.net/_site/stats/") + +;;; Commands + +(defun emir-generate-reports () + (interactive) + (let ((org-confirm-babel-evaluate nil)) + (org-publish + `("emir" + :base-extension "org" + :base-directory ,emir-report-src + :publishing-directory ,emir-report-dst + :publishing-function org-html-publish-to-html) + t))) + +;;; Utilities + +(defun emir-melpa-packages () + (mapcar #'car (epkg-sql [:select name :from melpa-recipes]))) + +(defun emir-melpa-get (name select) + (let ((val (car (epkg-sql [:select $i1 :from melpa-recipes + :where (= name $s2)] + select name)))) + (if (vectorp select) val (car val)))) + +(defun emir-org-melpa-fetcher (name) + (or (emir-melpa-get name 'fetcher) "")) + +(cl-defmethod emir-org-link ((pkg epkg-package)) + (if (oref pkg repopage-format) + (format "[[%s][%s/%s]]" + (oref pkg repopage) + (oref pkg upstream-user) + (oref pkg upstream-name)) + (--if-let (or (oref pkg repopage) + (oref pkg homepage)) + (format "[[%s]]" it) + ""))) + +(cl-defmethod emir-org-link ((name string)) + (-let [(fetcher repo repopage url) + (car (epkg-sql [:select [fetcher repo repopage url] + :from melpa-recipes + :where (= name $s1)] + name))] + (if (memq fetcher '(github gitlab bitbucket)) + (format "[[%s][%s]]" repopage repo) + (--if-let (or repopage + (and url + (string-match-p "\\`https?://" url) + (replace-regexp-in-string "\\.git\\'" "" url))) + (format "[[%s]]" it) + "")))) + +(defmacro emir-with-org-header (header &rest body) + (declare (indent defun)) + `(append '((,@header) hline) ,@body)) + +;;; Compare +;;;; Summary + +(defun emir-archives-summary () + (require 'finder-inf) + (let ((ret `((builtin 0 0 + ,(length package--builtins) + ,(length (epkg-sql [:select * :from gelpa-packages + :where (= type ':core)])) + 0) + (elpa 0 0 0 + ,(length (epkg-sql [:select * :from gelpa-packages + :where type :in $v1 + :and (isnull unreleased)] + [:dir :subtree])) + 0) + (elpa-branch 0 0 0 + ,(length (epkg-sql [:select * :from gelpa-packages + :where (= type ':external)])) + 0) + (shelved 0 + ,(length (epkgs 'class 'epkg-shelved-package-p)) + 0 0 0)))) + (dolist (class (epkgs 'class 'epkg-mirrored-package--eieio-childp)) + (--if-let (assq class ret) + (cl-incf (nth 1 it)) + (push (list class 1 0 0 0 0) ret))) + (dolist (fetcher (epkg-sql [:select fetcher :from melpa-recipes])) + (setq fetcher (car fetcher)) + (--if-let (assq fetcher ret) + (cl-incf (nth 5 it)) + (push (list fetcher 0 0 0 0 1) ret))) + (emir-with-org-header ("Type" "Mirror" "Attic" "Emacs" "Gelpa" "Melpa") + (append (cl-sort (copy-sequence ret) #'> :key #'cadr) + (list 'hline + (append (--reduce (list 'total + (+ (nth 1 acc) (nth 1 it)) + (+ (nth 2 acc) (nth 2 it)) + (+ (nth 3 acc) (nth 3 it)) + (+ (nth 4 acc) (nth 4 it)) + (+ (nth 5 acc) (nth 5 it))) + ret))))))) + +(defun emir-archives-compare (symbol type nocache get-diff get-type) + (declare (indent 3)) + (cond ((not type) + (or (and (not nocache) + (symbol-value symbol)) + (set symbol + (let (alist) + (dolist (package (funcall get-diff)) + (-when-let (type (funcall get-type package)) + (-if-let (elt (assq type alist)) + (push package (cdr elt)) + (push (list type package) alist)))) + (cl-sort (mapcar (-lambda ((type . packages)) + (list type + (length packages) + (sort packages #'string<))) + alist) + #'> :key #'cadr))))) + ((eq type 'summary) + (emir-with-org-header ("Reason" "N") + (--map (butlast it) (funcall symbol nil nocache)))) + (t + (car (cddr (assq type (funcall symbol nil nocache))))))) + +;;;; Emacsmirror vs. Gelpa + +(defun emir-gelpa-shadowed () + (emir-with-org-header ("Package" "Type" "Gelpa" "Reason" "Link") + (let ((branches (emir--list-packages 'epkg-elpa-branch-package))) + (mapcar (lambda (name) + (-let* ((pkg (epkg name)) + ((source reason) + (or (cdr (assoc name emir-preferred-upstreams)) + '("" "")))) + (list name + source + (if (member name branches) "branch" "subtree") + reason + (emir-org-link pkg)))) + (emir-gelpa-only 'upstream))))) + +(defvar emir-gelpa-only nil) +(defun emir-gelpa-only (&optional type nocache) + (emir-archives-compare 'emir-gelpa-only type nocache + (lambda () + (nconc (emir--list-packages 'epkg-elpa-package) + (emir--list-packages 'epkg-elpa-branch-package))) + (lambda (package) + (let ((pkg (epkg package))) + (cond ((string-match "theme" package) 'theme) + ((epkg-builtin-package-p pkg) 'builtin) + ((assoc package emir-pending-packages) 'pending) + ((assoc package emir-ignored-packages) 'ignored) + ((not pkg) 'new) + ((not (memq (epkg-type pkg) '(elpa elpa-branch))) 'upstream)))))) + +;;;; Emacsmirror vs. Melpa + +(defvar emir-melpa-only nil) +(defun emir-melpa-only (&optional type nocache) + (let ((urls (epkgs 'url))) + (emir-archives-compare 'emir-melpa-only type nocache + (lambda () + (cl-set-difference (emir-melpa-packages) + (epkgs 'name) + :test #'equal)) + (lambda (package) + (-let [(fetcher url) + (car (epkg-sql [:select [fetcher url] + :from melpa-recipes + :where (= name $s1)] + package))] + (cond ((assoc package emir-pending-packages) 'pending) + ((assoc package emir-ignored-packages) 'ignored) + ((string-match-p "theme" package) 'theme) + ((eq fetcher 'wiki) 'wiki) + ((memq fetcher '(bzr cvs darcs fossil svn)) 'old-vc) + ((assoc package emir-minority-packages) 'minority) + ((member url urls) 'partial) + (t 'new))))))) + +(defvar emir-melpa-missing nil) +(defun emir-melpa-missing (&optional type nocache) + (emir-archives-compare 'emir-melpa-missing type nocache + (lambda () + (cl-set-difference (epkgs 'name) + (emir-melpa-packages) + :test #'equal)) + (lambda (package) + (epkg-type (epkg package))))) + +;;; Issues + +(defun emir-feature-conflicts () + (emir-with-org-header ("Feature" "Package") + (let (alist) + (dolist (name (epkgs 'name '(epkg-mirrored-package--eieio-childp + epkg-builtin-package-p))) + (dolist (feature (epkg-sql [:select feature :from provided + :where (and (= package $s1) + (isnull drop))] + name)) + (setq feature (car feature)) + (-if-let (elt (assq feature alist)) + (push name (cdr elt)) + (cl-pushnew (list feature name) alist)))) + (-mapcat (-lambda ((feature . providers)) + (and (> (length providers) 1) + (list (list feature providers)) + (--map (list feature it) + (sort providers #'string<)))) + (cl-sort alist #'string< :key #'car))))) + +(defun emir-unsatisfied-hard-dependencies () + (emir-with-org-header ("Package" "Type" "Melpa" "Feature") + (-mapcat (-lambda ((name class)) + (let (unsatisfied) + (-each (epkg-sql [:select feature :from required + :where (and (= package $s1) + (= hard 't) + (isnull drop)) + :order-by [(asc feature)]] + name) + (-lambda ((feature)) + (unless (epkg--required name feature) + (push feature unsatisfied)))) + (when unsatisfied + (let ((fetcher (emir-org-melpa-fetcher name))) + (--map (list name class fetcher it) + (sort unsatisfied #'string<)))))) + (epkgs [name class] 'epkg-mirrored-package--eieio-childp)))) + +(defun emir-unsatisfied-soft-dependencies () + (emir-with-org-header ("Package" "Type" "Melpa" "Feature") + (-mapcat (-lambda ((name class)) + (let (unsatisfied) + (-each (epkg-sql [:select feature :from required + :where (and (= package $s1) + (isnull hard) + (isnull drop)) + :order-by [(asc feature)]] + name) + (-lambda ((feature)) + (unless (epkg--required name feature) + (push feature unsatisfied)))) + (when unsatisfied + (let ((fetcher (emir-org-melpa-fetcher name))) + (--map (list name class fetcher it) + (sort unsatisfied #'string<)))))) + (epkgs [name class] 'epkg-mirrored-package--eieio-childp)))) + +(defun emir-hard-required-shelved () + (emir-with-org-header ("Package" "Type" "Melpa" "Feature") + (-mapcat (-lambda ((name class)) + (let (sight) + (-each (epkg-sql [:select feature :from required + :where (and (= package $s1) + (= hard 't) + (isnull drop)) + :order-by [(asc feature)]] + name) + (-lambda ((feature)) + (--when-let (epkg--required name feature) + (and (epkg-shelved-package-p (epkg it)) + (push feature sight))))) + (when sight + (let ((fetcher (emir-org-melpa-fetcher name))) + (--map (list name class fetcher it) + (sort sight #'string<)))))) + (epkgs [name class] 'epkg-mirrored-package--eieio-childp)))) + +(defun emir-soft-required-shelved () + (emir-with-org-header ("Package" "Type" "Melpa" "Feature") + (-mapcat (-lambda ((name class)) + (let (sight) + (-each (epkg-sql [:select feature :from required + :where (and (= package $s1) + (isnull hard) + (isnull drop)) + :order-by [(asc feature)]] + name) + (-lambda ((feature)) + (--when-let (epkg--required name feature) + (and (epkg-shelved-package-p (epkg it)) + (push feature sight))))) + (when sight + (let ((fetcher (emir-org-melpa-fetcher name))) + (--map (list name class fetcher it) + (sort sight #'string<)))))) + (epkgs [name class] 'epkg-mirrored-package--eieio-childp)))) + +(defun emir-orphans () + (emir-with-org-header ("Package" "Type" "Melpa") + (--map (list it + (epkg-type (epkg it)) + (if (string-prefix-p "emacsorphanage/" + (emir-melpa-get it 'repo)) + "(orphaned)" + (emir-org-melpa-fetcher it))) + (sort (--map (cdr (assq 'name it)) + (ghub-get "/orgs/emacsorphanage/repos")) + #'string<)))) + +;;; emir-report.el ends soon +(provide 'emir-report) +;; Local Variables: +;; indent-tabs-mode: nil +;; End: +;;; emir-report.el ends here diff --git a/emir.el b/emir.el new file mode 100644 index 0000000..0183b37 --- /dev/null +++ b/emir.el @@ -0,0 +1,938 @@ +;;; emir.el --- maintain the Emacsmirror -*- lexical-binding: t -*- + +;; Copyright (C) 2016 Jonas Bernoulli + +;; Author: Jonas Bernoulli +;; Homepage: https://gitlab.com/tarsius/emir +;; Keywords: local + +;; This file is not part of GNU Emacs. + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3 of the License, +;; or (at your option) any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt. + +;;; Commentary: + +;; This is the package I use to maintain the Emacsmirror. It isn't +;; very useful for anybody else. Epkg is the user client which you +;; should be using instead. + +;;; Code: + +(require 'borg) +(require 'closql) +(require 'dash) +(require 'dash-functional) +(require 'eieio) +(require 'elx) +(require 'emacsql-sqlite) +(require 'epkg) +(require 'ghub) +(require 'magit) +(require 'org) +(require 'packed) + +(defvar finder-no-scan-regexp) +(defvar finder--builtins-alist) + +;;; Options + +(defgroup emir nil + "Maintain the Emacsmirror." + :group 'local) + +(defcustom emir-emacs-repository "~/Repos/emacs/25.0.92/" + "The Emacs repository used to extract builtin packages." + :group 'emir + :type 'directory) + +(defcustom emir-ignored-dependencies nil + "List of dependencies that are ignored in all packages." + :group 'emir + :type '(repeat (list (string :tag "Name") + (string :tag "Reason")))) + +(defcustom emir-ignored-packages nil + "List of packages that should not be imported. +These packages should not be imported for a variety of reasons. " + :group 'emir + :type '(repeat (list (string :tag "Name") + (string :tag "Type") + (string :tag "Reason")))) + +(defcustom emir-minority-packages nil + "List of packages that should not be imported. +These packages should not be imported because their libraries are +part of repositories that contain much more than just Emacs lisp." + :group 'emir + :type '(repeat (list (string :tag "Name") + (string :tag "Type") + (string :tag "Reason")))) + +(defcustom emir-pending-packages nil + "List of packages that might eventually be imported. +These package only will be imported if and when upstream +has fixed known outstanding issues." + :group 'emir + :type '(repeat (list (string :tag "Name") + (string :tag "Type") + (string :tag "Reason")))) + +(defcustom emir-suspended-packages nil + "List of packages which are temporarily not being updated." + :group 'emir + :type '(repeat (list (string :tag "Name") + (string :tag "Type") + (string :tag "Reason")))) + +(defcustom emir-preferred-upstreams nil + "List of packages with multiple potential upstreams." + :group 'emir + :type '(repeat (list (string :tag "Name") + (string :tag "Type") + (string :tag "Reason")))) + +;;; Repository + +(defmacro with-epkg-repository (arg &rest body) + (declare (indent defun)) + `(let ((default-directory + ,(if (eq arg t) + 'epkg-repository + `(or (epkg-repository ,arg) + (error "Need package or string"))))) + ,@body)) + +(cl-defmethod epkg-repository ((pkg epkg-mirrored-package)) + (expand-file-name (format "mirror/%s/" (oref pkg name)) epkg-repository)) + +(cl-defmethod epkg-repository ((pkg epkg-shelved-package)) + (expand-file-name (format "attic/%s/" (oref pkg name)) epkg-repository)) + +(cl-defmethod epkg-repository ((_pkg epkg-builtin-package)) + emir-emacs-repository) + +(cl-defmethod epkg-repository ((_class (subclass epkg-elpa-package))) + (expand-file-name "import/gelpa/" epkg-repository)) + +(cl-defmethod epkg-repository ((_class (subclass epkg-elpa-branch-package))) + (expand-file-name "import/gelpa/" epkg-repository)) + +(cl-defmethod epkg-repository ((_class (subclass epkg-wiki-package))) + (expand-file-name "import/wiki/" epkg-repository)) + +;;; Add +;;;; Add Package + +;;;###autoload +(defun emir-add-package (name url class &rest plist) + (interactive + (let* ((url (emir-read-url "Add package from url")) + (type (epkg-read-type "Package type: " + (--when-let (emir--url-to-class url) + (substring (symbol-name it) 5 -8)))) + (name (magit-read-string + "Package name" + (->> (or (emir--url-get url 'upstream-name) "") + (replace-regexp-in-string "\\`emacs-" "") + (replace-regexp-in-string "\\`elisp-" "") + (replace-regexp-in-string "[.-]el\\'" ""))))) + (list name url (intern (format "epkg-%s-package" type))))) + (let ((pkg (apply class :name name :url url plist))) + (unless (epkg-wiki-package-p pkg) + (emir--assert-unknown name url)) + (with-epkg-repository t (emir-add pkg)) + (with-epkg-repository t (magit-call-git "add" "epkg.sqlite"))) + (emir--sort-submodule-sections)) + +(cl-defmethod emir-add ((pkg epkg-mirrored-package)) + (emir-init pkg) + (emir-gh-init pkg) + (emir-clone pkg) + (emir-push pkg) + (emir-update pkg) + (emir-gh-update pkg) + (emir--stage pkg)) + +(cl-defmethod emir-add :after ((pkg epkg-github-package)) + (emir-gh-prune pkg)) + +(cl-defmethod emir-add ((pkg epkg-subset-package)) + (emir-init pkg) + (emir-gh-init pkg) + (emir-import pkg) + (emir-push pkg) + (emir-clone pkg) + (emir-update pkg) + (emir-gh-update pkg)) + +(cl-defmethod emir-add ((pkg epkg-subtree-package)) + (emir-init pkg) + (emir-gh-init pkg) + (emir-clone pkg) + (emir-pull pkg) + (emir-push pkg) + (emir-update pkg) + (emir-gh-update pkg)) + +(cl-defmethod emir-add ((pkg epkg-builtin-package) &optional recreate) + (unless recreate + (closql-insert (epkg-db) pkg)) + (emir-update pkg)) + +(cl-defmethod emir-init ((pkg epkg-package) &optional recreate) + (unless recreate + (closql-insert (epkg-db) pkg)) + (with-slots (url mirror-url upstream-name mirror-name name mirrorpage) pkg + (when url + (emir--set-url pkg url)) + (unless url + (setf url (emir--format-url pkg 'url-format))) + (when (or (not mirror-name) (string-match-p "\\+" mirror-name)) + (setf mirror-name (replace-regexp-in-string "\\+" "-plus" name))) + (unless mirror-url + (setf mirror-url (emir--format-url pkg 'mirror-url-format))) + (unless upstream-name + (setf upstream-name name)) + (setf mirrorpage (format "https://github.com/%s/%s" + (if (epkg-shelved-package-p pkg) + "emacsattic" + "emacsmirror") + mirror-name)))) + +(defun emir--set-url (pkg url) + (oset pkg url + (if (oref pkg url-format) + (let ((i 0)) + (dolist (slot (emir--match-url (oref pkg url-format) url)) + (setf (slot-value pkg slot) + (match-string (cl-incf i) url))) + (emir--format-url pkg 'url-format)) + url))) + +(defun emir--format-url (pkg slot) + (--when-let (eieio-oref-default pkg slot) + (format-spec it `((?p . ,(oref pkg name)) + (?m . ,(oref pkg mirror-name)) + (?n . ,(oref pkg upstream-name)) + (?u . ,(oref pkg upstream-user)))))) + +(defun emir--match-url (format url &optional lax) + (with-temp-buffer + (insert (regexp-quote format)) + (goto-char (point-min)) + (let (slots) + (while (re-search-forward "%\\(.\\)" nil t) + (push (cdr (assq (string-to-char (match-string 1)) + '((?N . mirror-name) + (?n . upstream-name) + (?u . upstream-user)))) + slots) + (replace-match "\\([^/]+\\)" t t)) + (when (string-match (concat "^" (buffer-string) (unless lax "$")) url) + (nreverse slots))))) + +(defun emir--url-to-class (url) + (--first (ignore-errors (emir--match-url (oref-default it url-format) url)) + (closql--list-subclasses 'epkg-package))) + +(defun emir--url-get (url slot) + (-when-let* ((class (emir--url-to-class url)) + (slots (emir--match-url (oref-default class url-format) url)) + (value (cl-position slot slots))) + (match-string (1+ value) url))) + +(defun emir--assert-unknown (name url) + (--if-let (epkg name) + (cl-typecase it + (epkg-builtin-package (user-error "Package %s is already built-in" name)) + (epkg-shelved-package (user-error "Package %s is already shelved" name)) + (t (user-error "Package %s is already mirrored" name))) + (cond ((assoc name emir-minority-packages) + (user-error "Package %s is a minority" name)) + ((assoc name emir-pending-packages) + (user-error "Package %s is pending" name)) + ((assoc name emir-ignored-packages) + (user-error "Package %s is a ignored" name)))) + (--when-let (and url (cadr (assoc url (epkgs [url name])))) + (user-error "Another package, %s, is already mirrored from %s" it url)) + (let ((repo (expand-file-name (concat ".git/modules/" name) epkg-repository))) + (when (file-exists-p repo) + (user-error "Package %s used to be mirrored. Remove %s first" + name repo)))) + +;;;; Add Packages + +(defun emir-add-elpa-packages (&optional dry-run) + (interactive "P") + (emir-pull 'epkg-elpa-package) + (dolist (name (emir--list-packages 'epkg-elpa-package)) + (unless (epkg name) + (--if-let (or (assoc name emir-pending-packages) + (assoc name emir-ignored-packages) + (and (string-match "theme" name) (list nil "theme"))) + (message "Skipping %s (%s)...done" name (cadr it)) + (message "Adding %s..." name) + (emir--assert-unknown name nil) + (unless dry-run + (emir-add (epkg-elpa-package :name name))) + (message "Adding %s...done" name)))) + (unless dry-run + (emir--commit "add %n elpa %p"))) + +(defun emir-add-elpa-branch-packages (&optional dry-run) + (interactive "P") + (emir-pull 'epkg-elpa-package) + (dolist (name (emir--list-packages 'epkg-elpa-branch-package)) + (unless (epkg name) + (--if-let (assoc name emir-ignored-packages) + (message "Skipping %s (%s)...done" name (cadr it)) + (message "Adding %s..." name) + (emir--assert-unknown name nil) + (unless dry-run + (emir-add (epkg-elpa-branch-package :name name))) + (message "Adding %s...done" name)))) + (unless dry-run + (emir--commit "add %n elpa-branch %p"))) + +(defun emir-add-builtin-packages (&optional dry-run) + (interactive "P") + (dolist (name (epkg-sql [:select :distinct name :from builtin-packages + :order-by (asc name)])) + (setq name (car name)) + (unless (epkg name) + (--if-let (assoc name emir-ignored-packages) + (message "Skipping %s (%s)...done" name (cadr it)) + (message "Adding %s..." name) + (unless dry-run + (emir-add (epkg-builtin-package :name name :mirror-name name)) + (emir--commit "add %n builtin %p")) + (message "Adding %s...done" name))))) + +(defun emir-add-melpa-packages (&optional dry-run) + (interactive "P") + (let ((mirrored (epkgs 'url))) + (pcase-dolist (`(,name ,fetcher ,url ,branch) + (epkg-sql [:select [name fetcher url branch] + :from melpa-recipes])) + (unless (or (epkg name) + ;; (not url) + (memq fetcher '(bzr cvs darcs fossil svn)) + (member url mirrored) + (assoc name emir-minority-packages) + (assoc name emir-pending-packages) + (assoc name emir-ignored-packages) + (string-match "themes?" name)) + (if branch ; Probably okay, but needs special attention. + (user-error "Melpa imports %s from branch %s" name branch) + (message "Adding %s..." name) + (unless dry-run + (emir-add-package name url + (intern (format "epkg-%s-package" fetcher)))) + (message "Adding %s...done" name)))) + (emir--commit "add %n %p"))) + +;;; Update +;;;; Update Package + +(defvar emir-failed-updates nil) + +(defun emir-update-package (package &optional force) + (interactive (list (epkg-read-package "Update package: ") + current-prefix-arg)) + (let* ((pkg (epkg package)) + (tip (oref pkg hash))) + (condition-case err + (with-epkg-repository pkg + (when (cl-typep pkg 'epkg-mirrored-package) + (emir-pull pkg)) + (emir-update pkg) + (emir--stage pkg) + (when (or force (not (equal (oref pkg hash) tip))) + (emir-gh-update pkg) + (emir-push pkg))) + (magit-git-error + (push (oref pkg name) emir-failed-updates) + (message "%s" (error-message-string err))) + (epg-error + (push (oref pkg name) emir-failed-updates) + (signal (car err) (cdr err))) + (error + (push (oref pkg name) emir-failed-updates) + (message "%s" (error-message-string err)))))) + +(cl-defmethod emir-update ((pkg epkg-package)) + (with-epkg-repository pkg + (with-slots (name hash libraries library) pkg + (setf hash (magit-rev-parse "HEAD")) + (when (epkg-builtin-package-p pkg) + (setf libraries + (mapcar #'car (epkg-sql [:select library :from builtin-packages + :where (= name $s1)] + name))) + (setf library + (pcase name + ("emacs" nil) + ("nxml" "lisp/nxml/nxml-mode.el") + (_ (let ((main (concat "/" name ".el"))) + (--first (string-suffix-p main it) libraries)))))) + (--if-let (or library + (ignore-errors + (packed-main-library default-directory name nil t))) + (with-temp-buffer + (insert-file-contents it) + (oset pkg summary (elx-summary nil t)) + (oset pkg keywords (elx-keywords-list nil t t)) + (oset pkg license (elx-license)) + (oset pkg created (elx-created)) + (oset pkg updated (emir--updated pkg)) + (oset pkg authors (--map (list (car it) (cdr it)) (elx-authors))) + (oset pkg maintainers (--map (list (car it) (cdr it)) (elx-maintainers))) + (oset pkg commentary (elx-commentary nil t)) + (oset pkg repopage (emir--repopage pkg)) + (oset pkg homepage (emir--homepage pkg)) + (oset pkg wikipage (emir--wikipage pkg))) + (unless (or (epkg-shelved-package-p pkg) + (equal name "emacs")) + (error "Cannot determine main library"))))) + (emir--set-features pkg)) + +(define-error 'epg-error "GPG error") + +;;;; Update Packages + +(defun emir-update-packages (&optional predicate from message) + (interactive (list nil (car (emir-update-read-args)) "update %n %p")) + (dolist (pkg (epkgs nil (or predicate 'epkg-mirrored-package))) + (with-slots (name) pkg + (when (or (not from) (string< from name)) + (if (member name emir-suspended-packages) + (message "Skipping suspended %s" name) + (condition-case err + (progn (message "Updating %s..." name) + (emir-update-package name) + (when message + (emir--commit message)) + (message "Updating %s...done" name)) + (error (message "Updating %s...failed %s" name + (error-message-string err))))))))) + +;;;###autoload +(defun emir-update-git-packages (&optional from) + (interactive (emir-update-read-args)) + (emir-update-packages 'epkg-git-package--eieio-childp from) + (emir--commit "update %n git %p")) + +(defun emir-update-hg-packages (&optional from) + (interactive (emir-update-read-args)) + (emir-update-packages 'epkg-hg-package--eieio-childp from) + (emir--commit "update %n hg %p")) + +(defun emir-update-file-packages (&optional from) + (interactive (emir-update-read-args)) + (emir-update-packages 'epkg-file-package from) + (emir--commit "update %n file %p")) + +(defun emir-update-wiki-packages (&optional from) + (interactive (emir-update-read-args)) + (if (y-or-n-p "Did you run `emir-import-wiki-packages' before this? ") + (progn (emir-update-packages 'epkg-wiki-package from) + (emir--commit "update %n wiki %p")) + (user-error "Well, then do that now"))) + +(defun emir-update-elpa-packages (&optional from) + (interactive (emir-update-read-args)) + (emir-pull 'epkg-elpa-package) + (emir-import 'epkg-elpa-package) + (emir-update-packages 'epkg-elpa-package from) + (emir--commit "update %n elpa %p")) + +(defun emir-update-elpa-branch-packages (&optional from) + (interactive (emir-update-read-args)) + (emir-pull 'epkg-elpa-package) + (emir-update-packages 'epkg-elpa-package from) + (emir--commit "update %n elpa-branch %p")) + +(defun emir-update-read-args () + (when current-prefix-arg + (list (epkg-read-package "Limit to packages after: ")))) + +;;; Recreate + +(defun emir-recreate-package (package) + (interactive (list (epkg-read-package "Recreate package: "))) + (let ((pkg (epkg package))) + (emacsql-with-transaction (epkg-db) + (when (cl-typep pkg 'epkg-mirrored-package) + (emir-init pkg t)) + (emir-update pkg)))) + +(defun emir-recreate-packages (&optional filter from) + (interactive (cons nil (emir-update-read-args))) + (dolist (pkg (epkgs nil filter)) + (with-slots (name) pkg + (when (or (not from) (string< from name)) + (message "Recreating package %s..." name) + (emir-recreate-package name) + (message "Recreating package %s...done" name))))) + +(defun emir-recalculate-features (&optional filter) + (interactive) + (let ((pkgs (epkgs nil filter))) + (dolist (pkg pkgs) + (with-slots (name) pkg + (message "Recalculating features for %s..." name) + (emir--set-features pkg) + (message "Recalculating features for %s...done" name))))) + +(defun emir-recalculate-builtin-features () + (interactive) + (emir-recalculate-features 'epkg-builtin-package)) + +;;; Remove + +(defun emir-remove-package (name) + (interactive (list (epkg-read-package "Remove package: " t))) + (let ((pkg (epkg name))) + (unless (epkg-builtin-package-p pkg) + (with-epkg-repository t + (magit-git "add" ".gitmodules") + (let ((module-dir (epkg-repository pkg))) + (when (file-exists-p module-dir) + (magit-git "rm" "-f" module-dir)))) + (with-demoted-errors "Error: %S" + (ghub-delete (format "/repos/%s/%s" + (if (epkg-shelved-package-p pkg) + "emacsattic" + "emacsmirror") + (oref pkg mirror-name))))) + (closql-delete (epkg-db) pkg) + (with-epkg-repository t + (magit-call-git "add" "epkg.sqlite")) + (when (epkg-wiki-package-p pkg) + (with-epkg-repository 'epkg-wiki-package + (magit-call-git "branch" "-D" name))) + (with-demoted-errors "Error: %S" + (delete-directory + (expand-file-name (concat ".git/modules/" name) epkg-repository) t)))) + +;;; Shelve + +(defun emir-shelve-package (name) + (interactive (list (epkg-read-package "Shelve package: " t))) + (let ((pkg (epkg name))) + (ghub-delete (format "/repos/emacsmirror/%s" (oref pkg mirror-name))) + (with-epkg-repository t + (magit-git "mv" + (concat "mirror/" name) + (concat "attic/" name))) + (emir-init (setq pkg (epkg-shelved-package :name name)) t) + (with-slots (mirror-url) pkg + (with-epkg-repository t + (magit-git "config" "-f" ".gitmodules" + (concat "submodule." name ".url") mirror-url) + (magit-git "add" ".gitmodules" "epkg.sqlite")) + (with-epkg-repository pkg + (magit-git "remote" "rm" "mirror") + (magit-git "remote" "add" "attic" mirror-url))) + (emir-update pkg) + (emir-gh-init pkg) + (emir-push pkg))) + +;;; Migrate + +(defun emir-migrate-github-package (name url) + (interactive (list (epkg-read-package "Migrate: ") + (emir-read-url "Url"))) + (let ((pkg (epkg name))) + (oset pkg url url) + (emir-init pkg t) + (emir-update pkg) + (emir-gh-update pkg))) + +;;; Clone + +(cl-defmethod emir-clone ((pkg epkg-mirrored-package)) + (with-slots (name url upstream-branch mirror-url) pkg + (with-epkg-repository t + (magit-git "submodule" "add" "--name" name + "-b" (or upstream-branch "master") + url (concat "mirror/" name)) + (magit-git "config" "-f" ".gitmodules" + (concat "submodule." name ".url") mirror-url)) + (with-epkg-repository pkg + (when upstream-branch + (magit-git "branch" "-M" upstream-branch "master")) + (magit-git "remote" "add" "mirror" mirror-url) + (magit-call-git "fetch" "mirror")))) + +(cl-defmethod emir-clone :before ((pkg epkg-hg-package)) + ;; `git submodule' doesn't want to use `git remote-hg' + (with-slots (name url upstream-branch mirror-url) pkg + (with-epkg-repository t + (magit-git "clone" "-b" (or upstream-branch "master") + url (concat "mirror/" name))))) + +(cl-defmethod emir-clone ((pkg epkg-file-package)) + (with-slots (name mirror-url) pkg + (with-epkg-repository t + (magit-git "init" (concat "mirror/" name))) + (emir-pull pkg t) + (with-epkg-repository t + (magit-git "submodule" "add" "--name" name "-b" "master" + mirror-url (concat "mirror/" name))) + (with-epkg-repository pkg + (magit-git "remote" "add" "mirror" mirror-url) + (magit-git "config" "branch.master.remote" "mirror") + (magit-git "config" "branch.master.merge" "refs/heads/master")))) + +(cl-defmethod emir-clone :after ((pkg epkg-subtree-package)) + (with-epkg-repository pkg + (magit-git "checkout" "--detach" "HEAD") + (magit-git "branch" "-D" "master"))) + +(cl-defmethod emir-clone ((pkg epkg-subset-package)) + (with-slots (name mirror-url) pkg + (with-epkg-repository t + (magit-git "submodule" "add" "--name" name "-b" "master" + mirror-url (concat "mirror/" name))) + (with-epkg-repository pkg + (magit-git "remote" "rename" "origin" "mirror") + (magit-git "remote" "add" "import" + (concat "../../import/" + (if (epkg-wiki-package-p pkg) "wiki" "elpa"))) + (magit-git "config" "remote.import.fetch" + (format "refs/heads/%s%s:refs/remotes/import/master" + (pcase (eieio-object-class pkg) + ('epkg-wiki-package "") + ('epkg-elpa-package "directory/") + ('epkg-elpa-branch-package "externals/")) + name)) + (magit-git "fetch" "import") + (magit-git "config" "--remove-section" "branch.master") + (magit-git "branch" "--set-upstream-to=import/master")))) + +(cl-defmethod emir-clone ((pkg epkg-file-package)) (emir--clone-mirror pkg)) +(cl-defmethod emir-clone ((pkg epkg-mocking-package)) (emir--clone-mirror pkg)) +(defun emir--clone-mirror (pkg) + (with-slots (name mirror-url) pkg + (let ((archive (if (epkg-shelved-package-p pkg) "attic" "mirror"))) + (with-epkg-repository t + (magit-git "submodule" "add" "--name" name "-b" "master" + mirror-url (concat archive "/" name))) + (with-epkg-repository pkg + (magit-git "remote" "rename" "origin" archive))))) + +;;; Pull + +(cl-defmethod emir-pull ((pkg epkg-mirrored-package)) + (with-epkg-repository pkg + (magit-git "pull" "--ff-only" "origin"))) + +(cl-defmethod emir-pull ((pkg epkg-file-package) &optional force) + (with-epkg-repository pkg + (let ((magit-process-raise-error t)) + (magit-call-process "curl" "-O" (oref pkg url))) + (when (or (magit-anything-unstaged-p) force) + (magit-git "add" ".") + (let ((process-environment process-environment) + (mainlib (or (oref pkg library) + (ignore-errors + (packed-main-library default-directory + (oref pkg name) t t))))) + (when mainlib + (with-temp-buffer + (insert-file-contents mainlib) + (let ((maintainer (car (elx-maintainers)))) + (setenv "GIT_AUTHOR_NAME" (or (car maintainer) "unknown")) + (setenv "GIT_AUTHOR_EMAIL" (or (cdr maintainer) "unknown")))) + (setenv "GIT_COMMITTER_NAME" "Emacsmirror") + (setenv "GIT_COMMITTER_EMAIL" "import@emacsmirror.org") + (magit-git "commit" "-m" "updates")))))) + +(cl-defmethod emir-pull ((pkg epkg-subtree-package)) + (with-epkg-repository pkg + (magit-git "fetch" "origin") + (magit-git "checkout" "origin/master") + (magit-git "subtree" "-P" (oref pkg upstream-tree) "push" "." "master") + (magit-git "checkout" "master"))) + +(cl-defmethod emir-pull ((pkg epkg-subset-package)) + (with-epkg-repository pkg + (magit-git "pull" "--ff-only" "import"))) + +(cl-defmethod emir-pull ((class (subclass epkg-subset-package))) + (with-epkg-repository class + (magit-git "checkout" "master") + (magit-git "pull" "--ff-only" "origin"))) + +;;; Push + +(cl-defmethod emir-push ((pkg epkg-mirrored-package)) + (with-epkg-repository pkg + (magit-git "push" "mirror"))) + +(cl-defmethod emir-push ((pkg epkg-subset-package)) + (with-slots (name mirror-name mirror-url) pkg + (ghub-post (format "/orgs/emacsmirror/%s" mirror-name)) + (let ((class (eieio-object-class pkg))) + (with-epkg-repository class + (magit-git "push" mirror-url + (format (pcase class + ('epkg-wiki-package "%s:master") + ('epkg-elpa-package "directory/%s:master") + ('epkg-elpa-branch-package "externals/%s:master")) + name)))))) + +(cl-defmethod emir-push ((pkg epkg-shelved-package)) + (with-epkg-repository pkg + (magit-git "push" "attic"))) + +;;; Extract + +(cl-defmethod emir--updated ((_pkg epkg-mirrored-package)) + (replace-regexp-in-string + "-" "" (substring (magit-rev-format "%ci" "HEAD") 0 10))) + +(cl-defmethod emir--updated ((_pkg epkg-file-package)) + (or (elx-updated) + (cl-call-next-method))) + +(cl-defmethod emir--updated ((_pkg epkg-mocking-package))) + +(cl-defmethod emir--repopage ((pkg epkg-package)) + (emir--format-url pkg 'repopage-format)) + +(cl-defmethod emir--homepage ((pkg epkg-package)) + (or (caar (epkg-sql [:select [page] :from pkg-homepages + :where [(= package $s1)]] + (oref pkg name))) + (--when-let (lm-homepage) + (if (string-match-p "/$" it) + (substring it 0 -1) + it)) + (emir--format-url pkg 'homepage-format))) + +(cl-defmethod emir--wikipage ((pkg epkg-package)) + (--when-let (or (and (epkg-wiki-package-p pkg) (elx-wikipage)) + (caar (epkg-sql [:select [page] :from pkg-wikipages + :where [(= package $s1)]] + (oref pkg name))) + (let ((name (emir--normalize-wikipage (oref pkg name)))) + (or (caar (epkg-sql [:select [page] :from raw-wikipages + :where (= normalized $s1)] name)) + (caar (epkg-sql [:select [page] :from raw-wikipages + :where (= normalized $s1)] + (if (string-match "mode$" name) + (substring name 0 -4) + (concat name "mode"))))))) + (concat "http://emacswiki.org/" it))) + +;;; Features + +(cl-defmethod emir--set-features ((pkg epkg-package)) + (with-epkg-repository pkg + (let ((enable-local-variables nil) + (name (oref pkg name)) + provided hard soft) + (dolist (lib (if (epkg-builtin-package-p pkg) + (oref pkg libraries) + (packed-libraries default-directory name))) + (with-temp-buffer + (insert-file-contents lib) + (setq buffer-file-name lib) + (set-buffer-modified-p nil) + (with-syntax-table emacs-lisp-mode-syntax-table + (-let [(h s) (packed-required)] + (--each h (cl-pushnew it hard)) + (--each s (cl-pushnew it soft)) + (--each (packed-provided) + (cl-pushnew it provided)))))) + (emacsql-with-transaction (epkg-db) + (let ((drop (emir--lookup-feature 'provided 'drop t name)) + (join (emir--lookup-feature 'provided 'join t name))) + (epkg-sql [:delete-from provided :where (= package $s1)] name) + (dolist (feature provided) + (epkg-sql [:insert-into provided [package feature drop join] + :values $v1] + (vector name feature (and (memq feature drop) t) nil))) + (dolist (feature (-difference join provided)) + (push feature provided) + (epkg-sql [:insert-into provided [package feature drop join] + :values $v1] + (vector name feature nil t)))) + (let ((drop (emir--lookup-feature 'required 'drop t name)) + (ease (emir--lookup-feature 'required 'ease t name))) + (setq hard (-difference hard provided)) + (setq soft (-difference soft provided)) + (setq soft (-difference soft hard)) + (setq ease (-intersection ease hard)) + (setq soft (-union soft ease)) + (setq hard (-difference hard ease)) + (epkg-sql [:delete-from required :where (= package $s1)] name) + (dolist (feature hard) + (epkg-sql [:insert-into required [package feature hard ease drop] + :values $v1] + (vector name feature t nil + (or (and (assq feature emir-ignored-dependencies) 'global) + (and (memq feature drop) t))))) + (dolist (feature soft) + (epkg-sql [:insert-into required [package feature hard ease drop] + :values $v1] + (vector name feature nil + (and (memq feature ease) t) + (or (and (assq feature emir-ignored-dependencies) 'global) + (and (memq feature drop) t)))))))))) + +(defun emir--lookup-feature (table column value name) + (sort (mapcar #'car (epkg-sql [:select [feature] :from $i1 + :where (and (= $i2 $s3) + (= package $s4))] + table column value name)) + #'string<)) + +;;; Github + +(cl-defmethod emir-gh-init ((pkg epkg-package)) + (let ((org (if (epkg-shelved-package-p pkg) "emacsattic" "emacsmirror")) + (name (oref pkg mirror-name))) + (ghub-post (format "/orgs/%s/repos" org) nil `((name . ,name))) + (ghub-wait (format "/repos/%s/%s" org name)))) + +(cl-defmethod emir-gh-init ((pkg epkg-github-package)) + (with-slots (mirror-name upstream-user upstream-name) pkg + (ghub-post (format "/repos/%s/%s/forks" upstream-user upstream-name) + nil '((organization . "emacsmirror"))) + (ghub-wait (format "/repos/emacsmirror/%s" upstream-name)) + (unless (equal mirror-name upstream-name) + (ghub-patch (format "/repos/emacsmirror/%s" upstream-name) + nil `((name . ,mirror-name)))))) + +(cl-defmethod emir-gh-unsubscribe :after ((pkg epkg-package)) + (let ((org (if (epkg-shelved-package-p pkg) "emacsattic" "emacsmirror")) + (name (oref pkg name))) + (with-demoted-errors + (format "Failed to unsubscribe from %s/%s: %%S" org name) + (ghub-delete (format "/repos/%s/%s/subscription" org name))))) + +(cl-defmethod emir-gh-update ((pkg epkg-package)) + (with-demoted-errors + (format "Failed to update metadata for %s/%s: %%S" + (if (epkg-shelved-package-p pkg) "emacsattic" "emacsmirror") + (oref pkg mirror-name)) + (ghub-patch (format "/repos/emacsmirror/%s" (oref pkg mirror-name)) + nil `((name . ,(oref pkg mirror-name)) + (description . ,(oref pkg summary)) + (homepage . ,(oref pkg homepage)) + (has_issues . nil) + (has_wiki . nil) + (has_downloads . nil) + (default_branch . "master"))))) + +(cl-defmethod emir-gh-prune ((pkg epkg-github-package)) + (with-epkg-repository pkg + (--when-let (delete "master" (magit-list-remote-branches "mirror")) + (magit-git "push" "mirror" (--map (concat ":" it) it))))) + +;;; Import + +(defun emir-import-wiki-packages () + (interactive) + (emir-pull 'epkg-wiki-package) + (emir-import 'epkg-wiki-package)) + +(cl-defmethod emir-import ((class (subclass epkg-wiki-package))) + (message "Importing wiki packages...") + (with-epkg-repository class + (magit-process-buffer) + (magit-run-git-async "filter-emacswiki" "--tag" "--notes")) + (message "Importing wiki packages...done")) + +(cl-defmethod emir-import ((pkg epkg-wiki-package)) + (with-epkg-repository 'epkg-wiki-package + (with-slots (name) pkg + (magit-git "filter-emacswiki" "--tag" "--notes" name)))) + +(cl-defmethod emir-import ((class (subclass epkg-elpa-package))) + (--each (emir--list-packages class) + (message "Importing %s..." it) + (emir-import (epkg-elpa-package :name it)) + (message "Importing %s...done" it))) + +(cl-defmethod emir-import ((pkg epkg-elpa-package)) + (with-epkg-repository 'epkg-elpa-package + (with-slots (name) pkg + (magit-git "branch" "-f" (concat "directory/" name) "master") + (magit-git "filter-elpa" name)))) + +(cl-defmethod emir-import ((_pkg epkg-elpa-branch-package))) ; noop + +(cl-defmethod emir--list-packages ((class (subclass epkg-wiki-package))) + (with-epkg-repository class + (delete "master" (magit-list-local-branch-names)))) + +(cl-defmethod emir--list-packages ((class (subclass epkg-elpa-package))) + (-mapcat (lambda (line) + (setq line (cdr (split-string line))) + (and (equal (nth 0 line) "tree") + (list (nth 2 line)))) + (with-epkg-repository class + (magit-git-lines "ls-tree" "master:packages")))) + +(cl-defmethod emir--list-packages ((class (subclass epkg-elpa-branch-package))) + (--map (substring it 10) + (with-epkg-repository class + (magit-list-refnames "refs/heads/externals")))) + +;;; Utilities + +(defvar emir-url-history nil) + +(defun emir-read-url (prompt) + (magit-read-string prompt nil 'emir-url-history nil nil t)) + +(defun emir--stage (pkg) + (unless (epkg-builtin-package-p pkg) + (with-epkg-repository t + (magit-call-git "add" (epkg-repository pkg))))) + +(defun emir--commit (message &rest include) + (with-epkg-repository t + (let ((count (length (magit-staged-files nil "mirror")))) + (when (> count 0) + (emir--sort-submodule-sections) + (magit-git "commit" + "-m" (format-spec + message + `((?n . ,(number-to-string count)) + (?p . ,(if (> count 1) "packages" "package")))) + "-i" ".gitmodules" "epkg.sqlite" include))))) + +(defun emir--sort-submodule-sections () + (with-epkg-repository t + (borg--sort-submodule-sections ".git/config") + (borg--sort-submodule-sections ".gitmodules") + (magit-call-git "add" ".gitmodules"))) + +(defun emir--normalize-wikipage (string) + (->> string + (replace-regexp-in-string "\\+" "plus") + (replace-regexp-in-string "-" "") + downcase)) + +;;; emir.el ends soon +(provide 'emir) +(require 'emir-report) +;; Local Variables: +;; indent-tabs-mode: nil +;; End: +;;; emir.el ends here diff --git a/emir.org b/emir.org new file mode 100644 index 0000000..93fa798 --- /dev/null +++ b/emir.org @@ -0,0 +1,927 @@ +* _ + +#+STARTUP: overview +#+STARTUP: hideblocks +#+STARTUP: noindent +#+PROPERTY: header-args :results value table :noweb yes + +* list tables +#+BEGIN_SRC emacs-lisp + (epkg-sql [:select name :from sqlite_master :where (= type table)]) +#+END_SRC +#+RESULTS: +| packages | +| libraries | +| provided | +| required | +| keywords | +| authors | +| maintainers | +| pkg_homepages | +| pkg_wikipages | +| raw_wikipages | +| gelpa_packages | +| builtin_packages | +| melpa_recipes | + +* recreate ~packages~ table et al. +#+BEGIN_SRC emacs-lisp :results silent + (let (old new) + (closql-db 'epkg-database 'old (expand-file-name "old.sqlite" epkg-repository)) + (closql-db 'epkg-database 'new (expand-file-name "new.sqlite" epkg-repository)) + (emacsql-with-transaction new + (dolist (obj (closql-entries old)) + (message "%s..." (oref obj name)) + (closql--resolve-slots obj) + (pcase-let ((`(,class ,_db . ,rest) + (cl-coerce obj 'list))) + (setq obj (vconcat (list class nil) rest))) + (closql-insert new obj))) + ;; (setq epkg-db-version 1) + (emacsql new (format "PRAGMA user_version = %s" epkg-db-version))) +#+END_SRC +* recreate ~pkg-homepages~ table +#+BEGIN_SRC emacs-lisp :results silent :var rows=table--pkg-homepages + (defconst emir--db-schema-pkg-homepages + '([(package :not-null :primary-key) + (page :not-null)])) + (emacsql-with-transaction (epkg-db) + (epkg-sql [:drop-table-if-exists pkg-homepages]) + (epkg-sql [:create-table pkg-homepages $S1] emir--db-schema-pkg-homepages) + (pcase-dolist (`(,package ,page) rows) + (epkg-sql [:insert-into pkg-homepages :values [$s1 $s2]] package page))) +#+END_SRC +#+NAME: table--pkg-homepages +| active-menu | http://www.skamphausen.de/cgi-bin/ska/Software | +| adv-random-sig | http://www.zonix.de/projects/emacs/lisp | +| agchat | http://www.splode.com/~friedman/software/emacs-lisp | +| archie | http://quimby.gnus.org/elisp | +| auto-show-doc | http://www.cb1.com/~john/computing/emacs/lisp/elisp-dev-tools | +| autocap | http://www.loveshack.ukfsn.org/emacs | +| banner | http://www.cb1.com/~john/computing/emacs/lisp/misc | +| bar-cursor | http://www.northbound-train.com | +| bash-org | http://edward.oconnor.cx/elisp | +| bbdb | http://bbdb.sourceforge.net | +| bbdb-pilot-jwz | http://www.splode.com/~friedman/software/emacs-lisp | +| binclock | http://www.davep.org/emacs | +| blackbook | http://fly.srk.fer.hr/~hniksic | +| breadcrumb | http://breadcrumbemacs.sourceforge.net | +| breathe | http://www.cb1.com/~john/computing/emacs/lisp/well-being | +| brief | http://www.emacs.mirkolinkonline.de/spiele.html | +| buffer-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| bytecomp-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| c-comment-edit | http://www.wonderworks.com | +| cc-tempo-electric-support | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| cif | http://www.loveshack.ukfsn.org/emacs | +| cldoc | http://homepage1.nifty.com/bmonkey/emacs/index-en.html | +| cmucl-wire | http://emarsden.chez.com/downloads | +| cocol | http://lgarc.narod.ru/xemacs | +| coffee | http://emarsden.chez.com/downloads | +| comint-popup | http://www.splode.com/~friedman/software/emacs-lisp | +| completing-help | http://homepage1.nifty.com/bmonkey/emacs/index-en.html | +| constants | http://staff.science.uva.nl/~dominik/Tools/constants | +| constellations | http://www.davep.org/emacs | +| copy-directory | http://www.cb1.com/~john/computing/emacs/lisp/file-handling | +| couchdb | http://edward.oconnor.cx/elisp | +| csv | http://ulf.epplejasper.de/EmacsGeneralPurpose.html | +| csv-vocab-mode | http://www.cb1.com/~john/computing/emacs/lisp/natural-language | +| csv-writer | http://www.cb1.com/~john/computing/emacs/lisp/data-structures | +| cua-lite | http://www.northbound-train.com | +| cua-lite-bootstrap | http://www.northbound-train.com | +| cvs-scramble | http://www.splode.com/~friedman/software/emacs-lisp | +| cygwin-link | http://edward.oconnor.cx/elisp | +| czscm | http://www.splode.com/~friedman/software/emacs-lisp | +| dar | http://www.xsteve.at/prg/emacs/dar | +| dbfrobs | http://www.splode.com/~friedman/software/emacs-lisp | +| deep-copy | http://www.splode.com/~friedman/software/emacs-lisp | +| delatex | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| diacriticalize | http://www.splode.com/~friedman/software/emacs-lisp | +| diary-outlook | http://www.loveshack.ukfsn.org/emacs | +| dict-web | http://emarsden.chez.com/downloads | +| dictem | http://sourceforge.net/projects/dictem | +| dictionary | http://www.myrkr.in-berlin.de/dictionary/index.html | +| dir-shell | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| disptime | http://www.splode.com/~friedman/software/emacs-lisp | +| dms-sig | http://thesassers.com/dewey/DmsSig.html | +| doh | http://www.splode.com/~friedman/software/emacs-lisp | +| dvi-view | http://www.cb1.com/~john/computing/emacs/lisp/graphics | +| dwim-find | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| ediprolog | http://www.logic.at/prolog/ediprolog/ediprolog.html | +| edit-tree | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| em-joc | http://www.northbound-train.com | +| emacs-name | http://www.splode.com/~friedman/software/emacs-lisp | +| emacs-variants | http://www.splode.com/~friedman/software/emacs-lisp | +| emacs-wiki-boxes | http://sugarshark.com/ProjectPage.html | +| emms | http://www.gnu.org/software/emms | +| erc-track-score | https://julien.danjou.info/projects/emacs-packages#erc-track-score | +| escreen | http://www.splode.com/~friedman/software/emacs-lisp | +| ess | http://ess.r-project.org | +| etest | http://www.shellarchive.co.uk/content/etest.html | +| eval-expr | http://www.splode.com/~friedman/software/emacs-lisp | +| face-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| ff-paths | http://people.debian.org/~psg/elisp | +| fff | http://www.splode.com/~friedman/software/emacs-lisp | +| fff-elisp | http://www.splode.com/~friedman/software/emacs-lisp | +| fff-rfc | http://www.splode.com/~friedman/software/emacs-lisp | +| file-confirm | http://www.iki.fi/pema/emacs | +| file-ext | http://www.emacs.mirkolinkonline.de/extras.html | +| file-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| filename-cases | http://www.cb1.com/~john/computing/emacs/lisp/file-handling | +| filenames-in-env | http://www.cb1.com/~john/computing/emacs/lisp/file-handling | +| find-commands | http://www.cb1.com/~john/computing/emacs/lisp/elisp-dev-tools | +| find-empty-el-files | http://www.cb1.com/~john/computing/emacs/lisp/elisp-dev-tools | +| find-file-suggest | http://code.google.com/p/find-file-suggest | +| flame | http://www.splode.com/~friedman/software/emacs-lisp | +| flash-paren | http://www.splode.com/~friedman/software/emacs-lisp | +| flatten-saved-pages | http://www.cb1.com/~john/computing/emacs/lisp/webstuff | +| flyspell-textcat | http://os.inf.tu-dresden.de/~mp26/emacs.shtml | +| flyspell-timer | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| fm | http://www.anc.ed.ac.uk/~stephen/emacs | +| fmailutils | http://www.splode.com/~friedman/software/emacs-lisp | +| fscroll | http://www.davep.org/emacs | +| fshell | http://www.splode.com/~friedman/software/emacs-lisp | +| ftcp | http://www.splode.com/~friedman/software/emacs-lisp | +| ftelnet | http://www.splode.com/~friedman/software/emacs-lisp | +| garble | http://www.davep.org/emacs | +| gedcom | http://www.rempe-online.de/genealogie/lines | +| geek | http://www.splode.com/~friedman/software/emacs-lisp | +| geiser | http://www.nongnu.org/geiser | +| gentext-bindings | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| gentext-models | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| gnus-checker | http://www.shellarchive.co.uk/content/emacs.html | +| gnus-highlight | http://www.hardakers.net/elisp | +| google | http://edward.oconnor.cx/elisp | +| google-contacts | https://julien.danjou.info/projects/emacs-packages#google-contacts | +| google-maps | https://julien.danjou.info/projects/emacs-packages#google-maps | +| goto-char-other-window | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| grabbox | http://www.xsteve.at/prg/emacs | +| gresreg | http://www.bookshelf.jp | +| growl | http://edward.oconnor.cx/elisp | +| highlight-context-line | http://www.skamphausen.de/cgi-bin/ska/highlight-context-line | +| himarks-mode | http://lgarc.narod.ru/xemacs | +| hl-sexp | http://edward.oconnor.cx/elisp | +| hobo | http://www.northbound-train.com | +| horoscope | http://www.splode.com/~friedman/software/emacs-lisp | +| host-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| html-chooser-mode | http://www.dur.ac.uk/p.j.heslin/Software/Emacs | +| html-phrase-list | http://www.cb1.com/~john/computing/emacs/lisp/natural-language | +| html-toc | http://www.pvv.org/~rolfn | +| html5 | http://edward.oconnor.cx/elisp | +| hyde | http://nibrahim.net.in/2010/11/11/hyde_:_an_emacs_mode_for_jekyll_blogs.html | +| hyphenate | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| ibs | http://www.geekware.de/software/emacs | +| icmp-info | http://www.davep.org/emacs | +| iman | http://homepage1.nifty.com/bmonkey/emacs | +| indent-tabs-maybe | http://www.loveshack.ukfsn.org/emacs | +| info-apropos | http://www.phys.au.dk/~harder | +| infobook | http://www.splode.com/~friedman/software/emacs-lisp | +| inktc | http://www.splode.com/~friedman/software/emacs-lisp | +| insert-construct | http://www.cb1.com/~john/computing/emacs/lisp/handsfree | +| insertions | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| install | http://www.iro.umontreal.ca/~monnier/elisp | +| invoice | http://www.splode.com/~friedman/software/emacs-lisp | +| ion3 | http://www.xsteve.at/prg/emacs | +| ipp | http://emarsden.chez.com/downloads | +| iuscheme | http://www.cs.indiana.edu/chezscheme/emacs | +| java-find | http://www.northbound-train.com | +| jfolding | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| journal-search | http://www.cb1.com/~john/computing/emacs/lisp/webstuff | +| joystick | http://www.cb1.com/~john/computing/emacs/lisp/hardware | +| jpeg-mode | http://www.cb1.com/~john/computing/emacs/lisp/graphics | +| js-doctor | http://www.cb1.com/~john/computing/emacs/lisp/email | +| kbd-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| keymap-hacks | http://www.cb1.com/~john/computing/emacs/lisp/misc | +| keywiz | http://www.phys.au.dk/~harder | +| kibologize | http://www.splode.com/~friedman/software/emacs-lisp | +| kill-a-lawyer | http://www.splode.com/~friedman/software/emacs-lisp | +| labbook | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| lat1conv | http://www.splode.com/~friedman/software/emacs-lisp | +| lazy-desktop | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| lbdb | http://www.davep.org/emacs | +| ldif-ns | http://www.loveshack.ukfsn.org/emacs | +| lessage | http://www.cb1.com/~john/computing/emacs/lisp/misc | +| linuxproc | http://www.splode.com/~friedman/software/emacs-lisp | +| list-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| list-register | http://www.bookshelf.jp | +| listbuf | http://www.splode.com/~friedman/software/emacs-lisp | +| lmselect | http://edward.oconnor.cx/elisp | +| load-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| localized-source | http://www.cb1.com/~john/computing/emacs/lisp/natural-language | +| lookout | http://ulf.epplejasper.de/EmacsCalendarAndDiary.html | +| loop-constructs | http://gmarceau.qc.ca | +| lude | http://www.splode.com/~friedman/software/emacs-lisp | +| mail-directory | http://www.cb1.com/~john/computing/emacs/lisp/email | +| mailrc-mode | http://www.cb1.com/~john/computing/emacs/lisp/email | +| mallow | http://edward.oconnor.cx/elisp | +| malyon | http://www.ifarchive.org | +| manued | http://www.mpi-inf.mpg.de/~hitoshi/otherprojects/manued/index.shtml | +| map-win | http://www.splode.com/~friedman/software/emacs-lisp | +| mcomplete | http://homepage1.nifty.com/bmonkey/emacs/index-en.html | +| meditate | http://www.splode.com/~friedman/software/emacs-lisp | +| mew | http://www.mew.org | +| mhc | http://www.quickhack.net/mhc | +| mic-paren | http://www.gnuvola.org/software/j/mic-paren | +| misc-elisp-tools | http://www.cb1.com/~john/computing/emacs/lisp/elisp-dev-tools | +| mk-project | http://www.littleredbat.net/mk/code/mk-project.html | +| moccur-edit | http://www.bookshelf.jp | +| moo | http://www.splode.com/~friedman/software/emacs-lisp | +| motion-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| mouse-embrace | http://www.xsteve.at/prg/emacs | +| mouse-focus | http://www.skamphausen.de/cgi-bin/ska/mouse-focus | +| mpg123 | http://www.gentei.org/~yuuji/software/mpg123el | +| multi-find-file | http://www.cb1.com/~john/computing/emacs/lisp/file-handling | +| multiselect | http://www.skamphausen.de/cgi-bin/ska/multiselect | +| multr | http://lgarc.narod.ru/xemacs | +| muse-blog | https://julien.danjou.info/projects/emacs-packages#muse-blog | +| muse-definition | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| muse-settings | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| muse-trail | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| mutt-alias | http://www.davep.org/emacs | +| mwe-cambridge-permute | http://www.foldr.org/~michaelw/emacs | +| mwe-color-box | http://www.foldr.org/~michaelw/emacs | +| mwe-log-commands | http://www.foldr.org/~michaelw/emacs | +| netrexx-mode | http://zaaf.nl/emacs/emacs.html | +| nf-procmail-mode | http://www.splode.com/~friedman/software/emacs-lisp | +| ngn | http://www.davep.org/emacs | +| notes-mode | http://www.isi.edu/~johnh/SOFTWARE/NOTES_MODE/index.html | +| ns-browse | http://www.splode.com/~friedman/software/emacs-lisp | +| nukneval | http://www.davep.org/emacs | +| obarray-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| obfusurl | http://www.davep.org/emacs | +| objc-c-mode | http://www.foldr.org/~michaelw/objective-c/index.html#objc-mode | +| octal-chars | http://www.cb1.com/~john/computing/emacs/lisp/natural-language | +| odf-mode | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| offlineimap | https://julien.danjou.info/projects/emacs-packages#offlineimap | +| order-head | http://www.splode.com/~friedman/software/emacs-lisp | +| org-daypage | http://almostobsolete.net/daypage.html | +| osx-plist | http://edward.oconnor.cx/elisp | +| pack-windows | http://lampwww.epfl.ch/~schinz/elisp | +| pb-popup | http://www.splode.com/~friedman/software/emacs-lisp | +| pdb | http://www.loveshack.ukfsn.org/emacs | +| pgg-crypt | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| phrase | http://www.loveshack.ukfsn.org/emacs | +| pick-backup | http://nschum.de/src/emacs/pick-backup | +| plugin | http://gmarceau.qc.ca | +| pom | http://sugarshark.com/ProjectPage.html | +| prefixkey | http://lgarc.narod.ru/xemacs | +| proc-filters | http://www.splode.com/~friedman/software/emacs-lisp | +| progr-align | http://www.xsteve.at/prg/emacs | +| project-buffer-mode | http://repo.or.cz/w/project-buffer-mode.git | +| protbuf | http://www.splode.com/~friedman/software/emacs-lisp | +| protocols | http://www.davep.org/emacs | +| prove | http://www.shellarchive.co.uk/content/emacs.html | +| ps-stack-comments | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| pseudo-grep | http://www.cb1.com/~john/computing/emacs/lisp/file-handling | +| psvn | http://www.xsteve.at/prg/vc_svn | +| pwsafe | http://www.xsteve.at/prg/emacs | +| pylookup | http://taesoo.org/Opensource/Pylookup | +| qemu | http://racin.free.fr | +| qpdecode | http://www.splode.com/~friedman/software/emacs-lisp | +| quack | http://www.neilvandyke.org/quack | +| quick-task | http://www.xsteve.at/prg/emacs | +| randomsig | http://www.backmes.de/scripts+programs.html | +| rdict | http://lgarc.narod.ru/xemacs | +| read-all-emacs-help | http://www.cb1.com/~john/computing/emacs/lisp/elisp-dev-tools | +| recent | http://levana.de/emacs | +| record | http://gmarceau.qc.ca | +| redo | http://www.wonderworks.com | +| redshank | http://www.foldr.org/~michaelw/emacs/redshank | +| regression | http://www.cb1.com/~john/computing/emacs/lisp/misc | +| removable-media | http://www.cb1.com/~john/computing/emacs/lisp/file-handling | +| revive | http://www.gentei.org/~yuuji/software | +| riece | http://www.nongnu.org/riece | +| rijndael | http://josefsson.org/aes | +| rmail-frobs | http://www.splode.com/~friedman/software/emacs-lisp | +| rpn-edit | http://www.cb1.com/~john/computing/emacs/lisp/handsfree | +| save-undo | http://www.splode.com/~friedman/software/emacs-lisp | +| saveframes | http://www.iki.fi/pema/emacs | +| scrape | http://edward.oconnor.cx/elisp | +| screen-lines | http://homepage1.nifty.com/bmonkey/emacs/index-en.html | +| sendmail-alias | http://www.splode.com/~friedman/software/emacs-lisp | +| services | http://www.davep.org/emacs | +| setq-trap | http://www.splode.com/~friedman/software/emacs-lisp | +| shop | http://www.splode.com/~friedman/software/emacs-lisp | +| show-functions | http://aurelien.tisne.free.fr/emacs-pages/emacs.html | +| silly-mail | http://www.splode.com/~friedman/software/emacs-lisp | +| skip-initial-comments | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| slashdot | http://www.davep.org/emacs | +| smallurl | http://www.shellarchive.co.uk/content/emacs.html | +| smartsig | http://www.davep.org/emacs | +| soap | http://edward.oconnor.cx/elisp | +| spamprobe | http://www.davep.org/emacs | +| speechd | http://www.freebsoft.org/speechd-el | +| split-root | http://nschum.de/src/emacs/split-root | +| split-window-multi | http://www.cb1.com/~john/computing/emacs/lisp/appearance | +| spookmime | http://www.splode.com/~friedman/software/emacs-lisp | +| sqlplus-html | http://fly.srk.fer.hr/~hniksic | +| strfile | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| string-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| suggbind | http://www.splode.com/~friedman/software/emacs-lisp | +| swadesh-numbers | http://www.cb1.com/~john/computing/emacs/lisp/natural-language | +| swbuff-advice | http://www.northbound-train.com | +| swimmers | http://www.cb1.com/~john/computing/emacs/lisp/games | +| swiss-move | http://www.skamphausen.de/cgi-bin/ska/swiss-move | +| sww | http://www.xsteve.at/prg/emacs | +| sysadmin | http://www.cb1.com/~john/computing/emacs/lisp/sysadmin | +| task-mode | http://racin.free.fr/old/projects.html#task-mode | +| taskjuggler-mode | http://www.skamphausen.de/cgi-bin/ska/taskjuggler-mode | +| technorati | http://edward.oconnor.cx/elisp | +| tee | http://levana.de/emacs | +| texletter | http://www.skamphausen.de/cgi-bin/ska/Software | +| tiger | http://edward.oconnor.cx/elisp | +| timestamp | http://www.splode.com/~friedman/software/emacs-lisp | +| tld | http://www.davep.org/emacs | +| tmenu | http://homepage1.nifty.com/bmonkey/emacs/index-en.html | +| tmmofl-x | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| todoo | http://www.mulix.org/code.html | +| toggle-buffer | http://www.northbound-train.com | +| toggle-case | http://www.northbound-train.com | +| tokipona | http://edward.oconnor.cx/elisp | +| total-numbers | http://www.cb1.com/~john/computing/emacs/lisp/misc | +| tpum | http://lgarc.narod.ru/xemacs | +| track-scroll | http://www.skamphausen.de/cgi-bin/ska/track-scroll | +| twiddle | http://www.splode.com/~friedman/software/emacs-lisp | +| twiki-outline | http://www.splode.com/~friedman/software/emacs-lisp | +| u-appt | http://ulf.epplejasper.de/EmacsCalendarAndDiary.html | +| u-color-cycle | http://ulf.epplejasper.de/EmacsFunStuff.html | +| u-mandelbrot | http://ulf.epplejasper.de/EmacsFunStuff.html | +| uboat | http://www.splode.com/~friedman/software/emacs-lisp | +| unbind | http://www.davep.org/emacs | +| uniesc | http://www.loveshack.ukfsn.org/emacs | +| unique | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| update-autoloads | http://www.cb1.com/~john/computing/emacs/lisp/elisp-dev-tools | +| update-dns | http://www.splode.com/~friedman/software/emacs-lisp | +| upside-down | http://www.splode.com/~friedman/software/emacs-lisp | +| variant | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| variant-abbc | http://homepages.cs.ncl.ac.uk/phillip.lord/emacs.html | +| viewtex | http://www.splode.com/~friedman/software/emacs-lisp | +| vkill | http://www.splode.com/~friedman/software/emacs-lisp | +| vorbiscomment | http://www.phys.au.dk/~harder | +| warlord | http://www.splode.com/~friedman/software/emacs-lisp | +| watch-sexp | http://www.skamphausen.de/cgi-bin/ska/Software | +| watson | http://emarsden.chez.com/downloads | +| wb-line-number | http://homepage1.nifty.com/blankspace/emacs/elisp.html | +| webinfo | http://www.davep.org/emacs | +| what-domain | http://www.splode.com/~friedman/software/emacs-lisp | +| who-calls | http://www.phys.au.dk/~harder | +| win-disp-util | http://www.splode.com/~friedman/software/emacs-lisp | +| windows | http://www.gentei.org/~yuuji/software | +| with-file | http://www.cb1.com/~john/computing/emacs/lisp/file-handling | +| with-saved-messages | http://www.cb1.com/~john/computing/emacs/lisp/elisp-dev-tools | +| woof | http://www.xsteve.at/prg/emacs | +| wordnik | http://edward.oconnor.cx/elisp | +| words-in-elisp-symbols | http://www.cb1.com/~john/computing/emacs/lisp/natural-language | +| x-dict | http://www.xsteve.at/prg/emacs | +| xml-event | http://edward.oconnor.cx/elisp | +| xml-stream | http://edward.oconnor.cx/elisp | +| xrdb-mode | http://www.python.org/emacs | +| xterm-frobs | http://www.splode.com/~friedman/software/emacs-lisp | +| xterm-title | http://www.splode.com/~friedman/software/emacs-lisp | +| xwindow-ring | http://www.xsteve.at/prg/emacs | +| yank-whitespace | http://www.cb1.com/~john/computing/emacs/lisp/editing | +| yatex | http://www.yatex.org | +| youwill | http://www.splode.com/~friedman/software/emacs-lisp | +| yow-fns | http://www.splode.com/~friedman/software/emacs-lisp | +| ysq | http://www.splode.com/~friedman/software/emacs-lisp | +| ysq-modeline | http://www.splode.com/~friedman/software/emacs-lisp | + +* recreate ~pkg-wikipages~ table +#+BEGIN_SRC emacs-lisp :results silent :var rows=table--pkg-wikipages + (defconst emir--db-schema-pkg-wikipages + '([(package :not-null :primary-key) + (page :not-null)])) + (emacsql-with-transaction (epkg-db) + (epkg-sql [:drop-table-if-exists pkg-wikipages]) + (epkg-sql [:create-table pkg-wikipages $S1] emir--db-schema-pkg-wikipages) + (pcase-dolist (`(,package ,page) rows) + (epkg-sql [:insert-into pkg-wikipages :values [$s1 $s2]] package page))) +#+END_SRC +#+NAME: table--pkg-wikipages +| ajc-java-complete | AutoJavaComplete | +| arrange-buffers | rcircDisplayChannels | +| autolisp | AutoLispMode | +| bm | VisibleBookmarks | +| breadcrumb | BreadcrumbForEmacs | +| buqis | BufferQuickSwitcher | +| ca2 | CaMode | +| columnize | ColumnizeWords | +| corba | CorbaImplementation | +| coroutine | CoRoutines | +| cssh | ClusterSSH | +| cua-lite | CuaLightMode | +| cucumber-i18n | CucumberI18nEl | +| cursor-chg | ChangingCursorDynamically | +| deferred | DeferredTask | +| dired-filetype-face | DiredFileTypeFaces | +| ebs | EasyBufferSwitch | +| eform | ElectricFormMode | +| el-expectations | EmacsLispExpectations | +| eoops | EmacsObjectOrientedProgrammingSystem | +| erobot | EmacsRobots | +| escreen | EmacsScreen | +| ethan-wspace | EthanWhitespace | +| etom | EmacsToMaya | +| ewb | EmacsWebBrowser | +| fdlcap | RotateWordCapitalization | +| flymake-for-csharp | FlymakeCsharp | +| gobject-class | GObjectClassHelpers | +| google | GoogleInterface | +| inertial-scroll | InertialScrolling | +| ipa | InPlaceAnnotations | +| java-complete | JavaCompletion | +| jcl-command-subset | CommandSubset | +| kdic | KanjiDictionary | +| loops | LoopFindPackage | +| magpie | MagpieExpansion | +| markerpen | MarkerPens | +| mc | MidnightCommanderMode | +| member-functions | ExpandMemberFunctions | +| mhc | MessageHarmonizedCalendaring | +| modeline-posn | ModeLinePosition | +| move-and | DeleteKillAndCopy | +| mss | MakeSmartShortcuts | +| mu | MushMode | +| muse | EmacsMuse | +| mutt-alias | MuttAliases | +| mwe-log-commands | CommandLogMode | +| nc | NortonCommanderMode | +| nntodo | TodoGnus | +| oauth | OAuthLibrary | +| osx-plist | MacOSXPlist | +| pcmpl-ssh | PcompleteSSH | +| ps2pdf | PostScriptToPDF | +| psvn | SvnStatusMode | +| pushy | PushyCompletion | +| rational | RationalNumber | +| rcirc-groups | rcircGroupMode | +| repdet | RepetitionDetectionPackage | +| rfc | rfc-el | +| ri | RiEl | +| riece | RieceIrcClient | +| rvm | RvmEl | +| scrl-margs | ScrollMargs | +| summarye | SummaryEditMode | +| sys | SysPackage | +| tag | FileTagUpdate | +| technorati | TechnoratiClient | +| teco | TecoInterpreterInElisp | +| thing-opt | ThingAtPointOptional | +| tiling | QuickTiling | +| typing | TypingOfEmacs | +| vbnet-mode | VbDotNetMode | +| versions | VersionsPackage | +| window-number | NumberedWindows | +| workgroups | WorkgroupsForWindows | +| xray | XrayPackage | + +* recreate ~raw-wikipages~ table +#+BEGIN_SRC emacs-lisp :results silent + (defconst emir--db-schema-raw-wikipages + '([(page :not-null :primary-key) + (normalized :not-null)])) + (emacsql-with-transaction (epkg-db) + (epkg-sql [:drop-table-if-exists raw-wikipages]) + (epkg-sql [:create-table raw-wikipages $S1] emir--db-schema-raw-wikipages) + (with-epkg-repository 'epkg-wiki-package + (dolist (page (magit-list-files)) + (unless (string-match-p "\\." page) + (epkg-sql [:insert-into raw-wikipages :values $v1] + (vector page (emir--normalize-wikipage page))))))) +#+END_SRC +* recreate ~builtin-packages~ table +#+BEGIN_SRC emacs-lisp :results silent + (require 'finder) + (let ((default-directory emir-emacs-repository)) + (emacsql-with-transaction (epkg-db) + (epkg-sql [:drop-table-if-exists builtin-packages]) + (epkg-sql [:create-table builtin-packages $S1] + '([name library feature])) + (dolist (file (magit-git-items "ls-tree" "-z" "-r" "--name-only" + "HEAD" "lisp/")) + (when (and (string-match-p "\\.el$" file) + (not (string-equal file "lisp/gnus/.dir-locals.el")) + (not (string-match-p finder-no-scan-regexp file)) + (not (member file + '(;; Old versions: + "lisp/obsolete/old-emacs-lock.el" + "lisp/obsolete/old-whitespace.el" + "lisp/obsolete/otodo-mode.el" + ;; Moved to GNU Elpa: + "lisp/obsolete/crisp.el" + "lisp/obsolete/landmark.el")))) + (magit-with-blob "HEAD" file + (with-syntax-table emacs-lisp-mode-syntax-table + (let ((features (packed-provided))) + (epkg-sql + [:insert-into builtin-packages :values $v1] + (vector (cond ((not features) "emacs") + ((string-prefix-p "lisp/term/" file) "emacs") + ((string-prefix-p "lisp/leim/" file) "emacs") + ((string-prefix-p "lisp/obsolete/" file) "emacs") + ((lm-header "Package")) + ((--when-let (assoc (-> file + file-name-directory + directory-file-name + file-name-nondirectory) + finder--builtins-alist) + (symbol-name (cdr it)))) + ((-> file + file-name-nondirectory + file-name-sans-extension))) + file + (if (> (length features) 1) + features + (car features))))))))))) + ;; (nconc + ;; (list (list "Name" "Library" "Feature(s)") 'hline) + ;; (-map (-lambda ((name library feature)) + ;; (list name library (or feature ""))) + ;; (epkg-sql [:select * :from builtin-packages + ;; :order-by [(asc name) (asc library)]]))) +#+END_SRC + +* recreate ~gelpa-packages~ table +#+BEGIN_SRC emacs-lisp :results silent + (with-epkg-repository 'epkg-elpa-package + (emacsql-with-transaction (epkg-db) + (epkg-sql [:drop-table-if-exists gelpa-packages]) + (epkg-sql [:create-table gelpa-packages $S1] + '([name type unreleased url])) + (epkg-sql [:insert-into gelpa-packages + :values ["org" :core nil nil]]) + (with-temp-buffer + (insert-file-contents + (expand-file-name "externals-list" + (epkg-repository 'epkg-elpa-package))) + (pcase-dolist (`(,name ,type ,url) (read (current-buffer))) + (epkg-sql [:insert-into gelpa-packages :values $v1] + (vector name type nil url)))) + (dolist (dir (directory-files "packages/" t "^[^.]")) + (when (file-directory-p dir) + (let ((name (file-name-nondirectory dir))) + (unless (epkg-sql [:select * :from gelpa-packages :where (= name $s1)] + name) + (epkg-sql + [:insert-into gelpa-packages :values $v1] + (vector name :dir + (equal (with-temp-buffer + (insert-file-contents + (expand-file-name (concat name ".el") dir)) + (goto-char (point-min)) + (or (lm-header "package-version") + (lm-header "version"))) + "0") + nil)))))))) + ;; (nconc + ;; (list (list "Name" "Mirror" "Gelpa" "U" "Url") 'hline) + ;; (-map (-lambda ((name type unreleased url)) + ;; (list name + ;; (--when-let (epkg name) (epkg-type it)) + ;; type + ;; (or unreleased "") + ;; (or url ""))) + ;; (epkg-sql [:select * :from gelpa-packages :order-by (asc name)]))) +#+END_SRC + +* recreate ~melpa-recipes~ table +#+BEGIN_SRC emacs-lisp :results silent + (let ((default-directory (expand-file-name "import/melpa/" epkg-repository))) + (magit-git "checkout" "master") + (magit-git "clean" "-fdx" "recipes") + (magit-git "pull" "--ff-only" "origin") + (emacsql-with-transaction (epkg-db) + (epkg-sql [:drop-table-if-exists melpa-recipes]) + (epkg-sql [:create-table melpa-recipes $S1] + '([(fetcher :not-null) + (name :not-null) + (url :not-null) + repo + repopage + files + branch + commit + module + old-names + version-regexp] + (:primary-key [name url]))) + (dolist (file (directory-files + (expand-file-name "recipes/" default-directory) + t "^[^.]")) + (when (file-regular-p file) + (-let* (((name . plist) + (with-temp-buffer + (insert-file-contents file) + (read (current-buffer)))) + (fetcher (plist-get plist :fetcher)) + (repo (plist-get plist :repo))) + (message "Importing melpa recipe %s..." name) + (epkg-sql + [:insert-into melpa-recipes :values $v1] + (vector fetcher (symbol-name name) + (or (plist-get plist :url) + (pcase fetcher + ('github (format "git@github.com:%s.git" repo)) + ('gitlab (format "git@gitlab.com:%s.git" repo)) + ('bitbucket + (format "hg::ssh://hg@bitbucket.org/%s" repo)) + ('wiki + (format "https://www.emacswiki.org/emacs/download/%s.el" + name)))) + repo + (or (plist-get plist :repopage) + (pcase fetcher + ('github (format "https://github.com/%s" repo)) + ('gitlab (format "https://gitlab.com/%s" repo)) + ('bitbucket (format "https://bitbucket.org/%s" repo)))) + (plist-get plist :files) + (plist-get plist :branch) + (plist-get plist :commit) + (plist-get plist :module) + (plist-get plist :old-names) + (plist-get plist :version-regexp))) + (message "Importing melpa recipe %s...done" name)))))) + ;; (nconc + ;; (list (list "Name" "Mirror" "Melpa") 'hline) + ;; (-map (-lambda ((name type)) + ;; (list name + ;; (--when-let (epkg name) (epkg-type it)) + ;; type)) + ;; (epkg-sql [:select [name fetcher] :from melpa-recipes :order-by (asc name)]))) +#+END_SRC + +* set variable ~epkg-db-version~ +#+BEGIN_SRC emacs-lisp :results silent + (setq epkg-db-version 1) + (epkg-sql "PRAGMA user_version = %s" epkg-db-version) +#+END_SRC + +* set variable ~emir-old-attic-reasons~ +#+BEGIN_SRC emacs-lisp :results silent :var value=emir-old-attic-reasons + (setq emir-old-attic-reasons value) nil +#+END_SRC +#+NAME: emir-old-attic-reasons +| Name | Reason | +|----------------------------------+--------------------------------------------------------------------------------------------------| +| altmap | upstream: abandoned | +| ani-fcsh | not kosher | +| arrange | Rearrange and filter lists | +| arxiv-reader | wrong feature, unbalanced | +| asm86-mode | issues and upstream does not reply | +| aspectj | unmaintained | +| auto-arg-mode | no feature | +| auto-complete-acr | bundles *many* libraries, upstream doesn't reply | +| auto-recomp | the problem is more complex than this implementation beliefs; use auto-compile instead | +| aux-renum | no feature | +| balance | no feature | +| bang | upstream: obsolete | +| bavard | upstream repository removed after only 1 commit | +| bbdb-gnokii | upstream: unmaintained; see http://martin.meltin.net/hacks/emacs | +| beatnik | provides wrong feature, no response from upstream | +| blogger | no feature | +| buffer-charset | no feature | +| c-boxes | no feature | +| caselet | Cond/case statements with bindings before tests | +| ccm | mirror: unmaintained | +| cdb-gud | not kosher | +| cdt | not kosher | +| centering | unmaintained and broken | +| cfs | mirror: unmaintained | +| changelog-url | not kosher (no feature, should be a mode) | +| cib | no feature | +| closure | use built-in support in emacs-24 see | +| collab | not kosher | +| color-mode | not kosher | +| colour-schemes | not kosher | +| comint-scroll-to-bottom | uses a built-in function in a manner explicitly recommended against, author works on a successor | +| commented-info | no feature | +| common-directory | personal snippet | +| convert-email | snippet | +| copyedit | upstream: obsolete | +| cpad | I and/or the maintainer don't care enough to fix problems | +| csde | mirror: obsolete use csharp-mode | +| csense | upstream: abandoned before finished | +| cups | no feature | +| cus-directory | upstream: abandoned | +| cus-keymap | upstream: abandoned | +| cust-stub | obsolete; everyone has custom now | +| dconv | upstream: obsolete; use function parse-time-string instead | +| deldo | not kosher | +| desire | upstream: unmaintained; see http://martin.meltin.net/hacks/emacs | +| df | issues and upstream does not reply | +| diary-pilot | mirror: obsolete | +| diary-todo | upstream: unmaintained; see http://martin.meltin.net/hacks/emacs | +| dir-locals | use built-in support see | +| dired-isearch | upstream: deprecated | +| dirvars | use built-in support see | +| dotassoc | upstream: replaced by kv | +| doxymacs | import problems | +| duplicate-line | not kosher | +| dupwords | unmaintained and by now broken | +| e-blog | upstream: abandoned | +| eicq | only compatible with XEmacs | +| eiffel | upstream: unmaintained; see http://martin.meltin.net/hacks/emacs | +| ejab | mirror: obsolete use jabber | +| ejacs | upstream: unmaintained proof of concept | +| el-tools | renamed to erefactor | +| elite | unavailable and not kosher | +| elmake | upstream: abandoned | +| elpoint | mirror: unmaintained | +| elserv | mirror: obsolete use elnode | +| elunit | mirror: obsolete use ert | +| emacs-ringing | mirror: unmaintained | +| emeteo | old and maintainer does not respond | +| emhacks | unmaintained and no reply | +| emoji | upstream didn't respond to trivial pull request in 7 months despite several reminders | +| encap | Code to convert sexps to independent functions etc | +| ephotodb | mirror: unmaintained | +| equinox | snippet | +| erp | upstream: never worked; see https://github.com/tj64/erp-mode/pull/1 | +| espresso | upstream: superseded by js | +| etexshow | upstream: abandoned and likely does not work anymore | +| etrack | I want to track just the elisp but can't because it is inside a tarball | +| face-list | no feature | +| file-history | bundles unrelated libraries | +| fill-column-rule | renamed to fill-column-indicator | +| find-lib | use built-in support | +| find-library | use built-in support | +| fink | upstream: obsolete | +| folio | unmaintained | +| frb | interface to discontinued service | +| free-tagging | not kosher | +| ftnchek | wrong feature provided, also not kosher in parts | +| fx-misc | personal snippets | +| gb4e | no feature | +| gds | Google Desktop has been discontinued | +| generic-text | Generic things that get passed to TeX, LaTeX, html, troff, texinfo etc | +| geos-vote | no feature | +| gimp-shell | provides wrong feature and very old | +| gneve | not kosher | +| gnus-agent-toggle-thread | snippet | +| gnuserv | mirror: obsolete use emacsclient | +| goofey | issues and upstream does not reply | +| google-define-redux-supplemental | not kosher, unbalanced | +| gse-number-rect | Inserts incremental numbers in a rectangle | +| haddoc | upstream: abandoned | +| handhold | GUI for constructing tests | +| haskell | obsolete use haskell-mode | +| hatena-tools | upstream didn't respond to trivial pull request in 7 months despite several reminders | +| hbmk | Manage bookmarks in HTML | +| hebeng | not kosher ... oh wait :) | +| hs | integrated into haskell-mode | +| html-from-latex | Assistance for creating HTML from LaTeX documents | +| html-helper-imenu | I and/or the maintainer don't care enough to fix problems | +| ifind-mode | not kosher: use helm instead | +| immigrant | Delicatessen from other lisps | +| inferior-apl | not kosher | +| integrate | no feature | +| iread | upstream: obsolete | +| iresize | not kosher | +| ishl | obsolete; functionality part of isearch | +| iso-html | not kosher | +| javascript | obsolete (see http://emacswiki.org/emacs/JavaScriptMode) | +| javascript-mode | obsolete (see http://emacswiki.org/emacs/JavaScriptMode) | +| javatools | not kosher | +| jde-refactor | upstream: abandoned | +| jem-pkg | import problems | +| jess-mode | mirror: unmaintained | +| journal | Stuff for keeping a diary | +| kag-mode | import problems | +| keyring | upstream: unmaintained there are better options | +| killbuf | mirror: obsolete (for emacs18) | +| later-do | part of emms | +| ldots | no feature | +| lgit | upstream: deprecated use magit | +| light | part of ultratex | +| light-symbol | no feature | +| linmag-mode | not kosher (e.g. not balanced) | +| lisp-re | obsolete: use builtin rx | +| lisp-skels | no feature | +| listing | upstream: deprecated use tabulated-list | +| litprog | not ready yet https://github.com/vitoshka/litprog/issues/2#issuecomment-12756557 | +| local-vars | not kosher | +| locales | renamed to frame-bufs | +| locdict | no feature and likely obsolete | +| lsl-mode | upstream didn't respond to trivial pull request in 7 months despite several reminders | +| lui | part of circe, stand-alone is outdated | +| mail-reorder-headers | renamed to order-head | +| make-hex | no feature | +| mongolian | no feature | +| mupacs | mirror: unmaintained | +| nero | upstream: obsolete | +| nesc | wrong feature provided and trivial | +| nethack | mirror: unmaintained | +| new-subdirs-el | no feature | +| normalize-page | Rebuild a page usinga given template | +| noticeify | issues and upstream does not reply | +| nterm | upstream: abandoned | +| nunmove | not kosher | +| o-journal | shortlived fork | +| oacs | upstream: abandoned | +| oddx | upstream: abandoned | +| oprofile-mode | not kosher (lot's of undefined symbols) | +| org-camp | short-lived | +| org-ghi | obsolete; use org-sync | +| p4pymarshal | not kosher | +| paredit-viper-compat | mirror: obsolete | +| pases | not kosher | +| pde | contains some original code but is mostly just a collection of other packages | +| peepopen | hidden behind paywall or requires registration | +| perl-myvar | I and/or the maintainer don't care enough to fix problems | +| pigletfill | snippet | +| pilot-doc | mirror: obsolete | +| pilot-memo | mirror: obsolete | +| pinpoint-mode | abandoned draft | +| poor-mans-bidi | obsolete use builtin support | +| prosper | no feature | +| protocolarium | potentially useful no doubt, but also just experiments and unmaintained | +| qmake | not kosher | +| qs | not kosher | +| qsas | merged into fuzzy | +| rambledocs | Code to assist on-the-fly documentation | +| realplay | upstream: abandoned likely doesn't work anymore | +| recent-changes | Handling updating of pages in web trees | +| redspace | wrong feature, unbalanced | +| refactor | renamed to erefactor | +| relocate-page | Move a page, adjusting (local) URLs in it | +| rfc-util | unavailable and not kosher | +| rheeet-mail | provides wrong feature | +| rlpic | no feature | +| rmail-mime | mirror: obsolete | +| rss-helper | unmaintained and not feature provided | +| rtf | see README and age | +| safe-equal | Test even circular objects for equality | +| sandbox | no feature | +| save-local-vars | upstream: this never worked | +| screenplay | mirror: unmaintained | +| scrmable | I and/or the maintainer don't care enough to fix problems | +| search-engines | snippet | +| sgml-id | not kosher | +| shbuf | unmaintained and bundles external libraries | +| shell-plus | snippet | +| shime | upstream: deprecated use haskell | +| show-wspace | upstream: obsolete; use highlight-chars | +| siamese | never finished | +| simple-server | upstream: unmaintained ("inactive") | +| simplegeo | issues and upstream does not reply | +| smart-snippet | upstream: superseded by yasnippet | +| sorter | unmaintained, disfunctional and bad name | +| sourcepair | not kosher and unmaintained: use built-in ff-find-other-file function | +| spamtrap | no feature | +| spoiler-space | snippet | +| sql-complete | not kosher | +| sqlplus-mode | upstream: unmaintained; see http://martin.meltin.net/hacks/emacs | +| starteam | interface to obsolete service starbase.com | +| sublime | upstream: unmaintained | +| subtitles | no feature | +| symfony | has issues and upstream does not respond | +| tab-in-tabular | not kosher (author thinks not providing a feature is a good idea) | +| tagging | renamed to free-tagging | +| tehom-1 | Emacs lisp extensions for gnus' eforms | +| tehom-2 | Emacs lisp extensions for history lists | +| tehom-3 | Routines to save & restore complex elisp objects | +| tehom-4 | A variant completing-read that returns value | +| tehom-cl | Extra support for the cl package structures | +| tehom-font-lock | A little help for writing fontlock support | +| tehom-func-args | Expand almost any known elisp function to a template | +| tehom-inflisp | Additions to comint to support rtest | +| tehom-psgml | Psgml extensions | +| tehom-psgml-arrange | Rearrange XML/SGML easily | +| tehom-psgml-fold-by-key | Fold/unfold XML according to keywords | +| tehom-psgml-index | Create table-of-contents for html pages | +| tehom-psgml-link | Bare-bones hyperlinks in psgml | +| tehom-search | unfinished | +| tellicopy | not kosher | +| test | upstream: obsolete | +| test-unit | see README | +| tla-mode | unmaintained and unlikely this still works | +| traverselisp | upstream: obsolete | +| u8tex | Quail package to input in | +| undo-browse | broken; use undo-tree | +| unibasic | wrong feature provided and likely not used by anyone | +| unicode-helper | upstream: obsolete, use built-in support | +| vh-scroll | issues and upstream does not reply | +| vlog-mode | upstream: obsolete | +| vtags | provides wrong feature | +| wajig | upstream: obsolete | +| wave-client | upstream: deprecated | +| wclock | use built-in function display-time-world | +| wdoc-mode | I and/or the maintainer don't care enough to fix problems | +| wid-keymap | upstream: abandoned | +| wid-table | upstream: abandoned | +| wiki-dot | no feature | +| window-grid | part of chumpy-windows (possibily under a different name) | +| write-subdirs-el | no feature | +| x-face | obsolete | +| xbase | mirror: unmaintained; also no feature provided | +| xbbcode-mode | hidden behind paywall or requires registration | +| xiomacs | mirror: obsolete | +| xlsl-mode | hidden behind paywall or requires registration | +| xml-lite | probably obsolete | +| xml-weather | use of api costs money | +| xmlchars | no feature | +| xmonad | upstream: abandoned | +| xpkg | upstream: abandoned | +| xslide | mirror: unmaintained | +| xslt-process | mirror: unmaintained | +| yodel | no feature | +