[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] master 2f1f7bb 2/4: * GNUmakefile, admin: Move files to the `el
From: |
Stefan Monnier |
Subject: |
[nongnu] master 2f1f7bb 2/4: * GNUmakefile, admin: Move files to the `elpa-admin` branch |
Date: |
Thu, 10 Dec 2020 18:19:11 -0500 (EST) |
branch: master
commit 2f1f7bb69deb98d1bd5b55808342499cef0162e9
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>
* GNUmakefile, admin: Move files to the `elpa-admin` branch
---
GNUmakefile | 281 ----------
admin/archive-contents.el | 1364 ---------------------------------------------
admin/ert-support.el | 55 --
admin/forward-diffs.py | 438 ---------------
admin/hv.sh | 47 --
admin/update-archive.sh | 235 --------
6 files changed, 2420 deletions(-)
diff --git a/GNUmakefile b/GNUmakefile
deleted file mode 100644
index 1b53f4e..0000000
--- a/GNUmakefile
+++ /dev/null
@@ -1,281 +0,0 @@
-# Makefile for GNU Emacs Lisp Package Archive.
-#
-
-EMACS=emacs --batch
-
-ARCHIVE_TMP=archive-tmp
-
-.PHONY: archive-tmp changelogs process-archive archive-full org-fetch clean
all do-it
-
-all: all-in-place
-
-CR_EXCEPTIONS=copyright_exceptions
-.PHONY: check_copyrights
-check_copyrights:
- @echo "Compute exceptions >$(CR_EXCEPTIONS)~"
- @export LC_ALL=C; \
- (cd packages && \
- find . -name '.git' -prune -o \
- -name 'test' -prune -o \
- -name '*.el' -print0 | \
- xargs -0 grep -L 'Free Software Foundation, Inc' | \
- grep -v '\(\.dir-locals\|.-\(pkg\|autoloads\)\)\.el$$'; \
- find . -name '.git' -prune -o -name '*.el' -type f -print | \
- while read f; do \
- fquoted="$$(echo $$f|tr '|' '_')"; \
- sed -n -e '/[Cc]opyright.*, *[1-9][-0-9]*,\?$$/N' \
- -e '/Free Software Foundation/d' \
- -e "s|^\\(.*;.*[Cc]opyright\\)|$$fquoted:\\1|p" \
- "$$f"; \
- done) | sort >$(CR_EXCEPTIONS)~
- diff -u "$(CR_EXCEPTIONS)" "$(CR_EXCEPTIONS)~"
-
-build/%:
- $(EMACS) -l $(CURDIR)/admin/archive-contents.el \
- -f batch-make-one-package $*
-
-build-all:
- $(EMACS) -l $(CURDIR)/admin/archive-contents.el \
- -f batch-make-all-packages
-
-## Deploy the package archive to archive/, with packages in
-## archive/packages/:
-archive: archive-tmp
- $(MAKE) $(MFLAGS) process-archive
-
-archive-tmp: packages
- -rm -r $(ARCHIVE_TMP)
- mkdir -p $(ARCHIVE_TMP)
- cp -a packages/. $(ARCHIVE_TMP)/packages
-
-# Use && after the cd commands, not ;, to ensure the build fails
-# immediately if the directory $(ARCHIVE_TMP)/packages does not exist.
-# For process-archive this is crucial; otherwise batch-make-archive in
-# archive-contents.el will interpret directories in the current
-# directory as unreleased packages, and recursively delete them,
-# including .git. Prior to using &&, running "make process-archive"
-# could silently delete all local git history!
-process-archive:
- # FIXME, we could probably speed this up significantly with
- # rules like "%.tar: ../%/ChangeLog" so we only rebuild the packages
- # that have indeed changed.
- cd $(ARCHIVE_TMP)/packages && \
- $(EMACS) -l $(CURDIR)/admin/archive-contents.el \
- -f batch-make-archive
- @cd $(ARCHIVE_TMP)/packages && \
- for pt in *; do \
- if [ -f "$${pt}/.elpaignore" ]; then \
- ignore="$${pt}/.elpaignore"; \
- else \
- ignore="/dev/null"; \
- fi; \
- if [ -d $$pt ]; then \
- echo "Creating tarball $${pt}.tar" && \
- tar --exclude-vcs -X "$$ignore" -chf $${pt}.tar $$pt; \
- rm -rf $${pt}; \
- fi; \
- done
- mkdir -p archive/packages
- mv archive/packages archive/packages-old
- mv $(ARCHIVE_TMP)/packages archive/packages
- chmod -R a+rX archive/packages
- rm -rf archive/packages-old
- rm -rf $(ARCHIVE_TMP)
-
-## Deploy the package archive to archive/ including the Org daily:
-archive-full: archive-tmp org-fetch
- $(MAKE) $(MFLAGS) process-archive
- #mkdir -p archive/admin
- #cp admin/* archive/admin/
-
-# FIXME: Turn it into an `external', which will require adding the notion of
-# "snapshot" packages.
-org-fetch: archive-tmp
- -cd $(ARCHIVE_TMP)/packages &&
\
- pkgname=`wget -q -O- https://orgmode.org/elpa/|perl -ne 'push @f, $$1
if m/(org-\d{8})\.tar/; END { @f = sort @f; print "$$f[-1]\n"}'`; \
- wget -q https://orgmode.org/elpa/$${pkgname}.tar -O $${pkgname}.tar;
\
- if [ -f $${pkgname}.tar ]; then
\
- tar xf $${pkgname}.tar;
\
- rm -f $${pkgname}.tar;
\
- mv $${pkgname} org;
\
- fi
-
-clean:
-# rm -rf archive $(ARCHIVE_TMP)
- rm -f packages/*/*-autoloads.el
- find packages -name '*.elc' -print0 | xargs -0 rm -f
-
-########## Rules for in-place installation ####################################
-pkgs := $(foreach pkg, $(wildcard packages/*), \
- $(if $(shell [ -d "$(pkg)" ] && echo true), $(pkg)))
-
-define SET-diff
-$(shell $(file > .tmp.setdiff, $(1)) \
- $(file >> .tmp.setdiff, $(2)) \
- $(file >> .tmp.setdiff, $(2)) \
- tr ' ' '\n' < .tmp.setdiff | sort | uniq -u ; rm .tmp.setdiff)
-endef
-
-define FILTER-nonsrc
-$(filter-out %-autoloads.el %-pkg.el %/.dir-locals.el, $(1))
-endef
-
-define RULE-srcdeps
-$(1): $$(call FILTER-nonsrc, $$(wildcard $$(dir $(1))/*.el))
-endef
-
-# Compute the set of autolods files and their dependencies.
-autoloads := $(foreach pkg, $(pkgs), $(pkg)/$(notdir $(pkg))-autoloads.el)
-
-# FIXME: In 99% of the cases, autoloads can be generated in any order.
-# But the `names' package is an exception because it sets up an advice that
-# changes the way autload.el operates, and that advice is needed when creating
-# the autoloads file of packages that use `names'.
-# The right solution is to check the Package-Requires and create the autoloads
-# files in topological order, but for now we can just do it the ad-hoc way and
-# add hand-made dependencies between autoloads files, and explicitly
-# load the names-autoloads file when building autoloads files. An example entry
-# is commented below, this is what should be done if a package depends on
Names.
-
-# packages/aggressive-indent/aggressive-indent-autoloads.el: \
-# packages/names/names-autoloads.el
-
-$(foreach al, $(autoloads), $(eval $(call RULE-srcdeps, $(al))))
-%-autoloads.el:
- @#echo 'Generating autoloads for $@'
- @cd $(dir $@) && \
- $(EMACS) -l $(CURDIR)/admin/archive-contents.el \
- --eval "(require 'package)" \
- --eval "(load (expand-file-name \"../names/names-autoloads.el\")
t t)" \
- --eval "(package-generate-autoloads \"$$(basename $$(pwd))\" \
- \"$$(pwd)\")"
-
-# Put into elcs the set of elc files we need to keep up-to-date.
-# I.e. one for each .el file in each package root, except for the -pkg.el,
-# the -autoloads.el, the .el files that are marked "no-byte-compile", and
-# files matching patterns in packages' .elpaignore files.
-included_els := $(shell tar -cvhf /dev/null --exclude-ignore=.elpaignore \
- --exclude-vcs packages 2>&1 | grep '\.el$$')
-
-# included_els := $(wildcard packages/*/*.el)
-
-# els := $(call FILTER-nonsrc, $(wildcard packages/*/*.el \
-# packages/*/*/*.el \
-# packages/*/*/*/*.el \
-# packages/*/*/*/*/*.el))
-els := $(call FILTER-nonsrc, $(included_els))
-naive_elcs := $(patsubst %.el, %.elc, $(els))
-current_elcs := $(shell find packages -name '*.elc' -print)
-
-extra_els := $(call SET-diff, $(els), $(patsubst %.elc, %.el, $(current_elcs)))
-nbc_els := $(foreach el, $(extra_els), \
- $(if $(shell grep '^;.*no-byte-compile: *t' "$(el)"), $(el)))
-elcs := $(call SET-diff, $(naive_elcs), $(patsubst %.el, %.elc, $(nbc_els)))
-
-# '(dolist (al (quote ($(patsubst %, "%", $(autoloads))))) (load
(expand-file-name al) nil t))'
-%.elc: %.el
- @echo 'Byte compiling $<'
- @$(EMACS) \
- --eval "(setq package-directory-list nil \
- load-prefer-newer t \
- package-user-dir \"$(abspath packages)\")" \
- -f package-initialize \
- -L $(dir $@) -f batch-byte-compile $<
-
-.PHONY: elcs
-elcs: $(elcs)
-
-# Remove .elc files that don't have a corresponding .el file any more.
-extra_elcs := $(call SET-diff, $(current_elcs), $(naive_elcs))
-.PHONY: $(extra_elcs)
-$(extra_elcs):; rm $@
-
-# # Put into single_pkgs the set of -pkg.el files we need to keep up-to-date.
-# # I.e. all the -pkg.el files for the single-file packages.
-pkg_descs:=$(foreach pkg, $(pkgs), $(pkg)/$(notdir $(pkg))-pkg.el)
-#$(foreach al, $(single_pkgs), $(eval $(call RULE-srcdeps, $(al))))
-%-pkg.el: %.el
- @echo 'Generating description file $@'
- @$(EMACS) -l admin/archive-contents.el \
- -f batch-generate-description-file "$@"
-
-.PHONY: all-in-place
-# Use order-only prerequisites, so that autoloads are done first.
-all-in-place: | $(extra_elcs) $(autoloads) $(pkg_descs) elcs
-
-
-#### `make package/<pkgname>` to compile the files of a single package ####
-
-define RULE-singlepkg
-$(filter $(1)/%, $(elcs)): $1/$(notdir $(1))-pkg.el \
- $1/$(notdir $(1))-autoloads.el
-$(1): $(filter $(1)/%, $(elcs))
-endef
-$(foreach pkg, $(pkgs), $(eval $(call RULE-singlepkg, $(pkg))))
-
-
-#### `make package/<pkgname>` to populate one package's subdirectory ####
-
-MISSING_script := (sed -ne 's|^.("\([^"]*\)".*|packages/\1|p' externals-list; \
- ls -1d packages/*; ls -1d packages/*) \
- | sort | uniq -u
-MISSING_PKGS := $(shell $(MISSING_script))
-
-$(MISSING_PKGS):
- $(EMACS) -l admin/archive-contents.el \
- -f batch-archive-update-worktrees "$(@F)"
-
-
-#### Fetching updates from upstream ####
-
-.PHONY: fetch/%
-fetch/%:
- $(EMACS) -l admin/archive-contents.el -f batch-fetch-and-show "$*"
-
-.PHONY: fetch-all
-fetch-all:
- $(EMACS) -l admin/archive-contents.el -f batch-fetch-and-show "-"
-
-.PHONY: sync/%
-sync/%:
- $(EMACS) -l admin/archive-contents.el -f batch-fetch-and-push "$*"
-
-.PHONY: sync-all
-sync-all:
- $(EMACS) -l admin/archive-contents.el -f batch-fetch-and-push "-"
-
-
-############### Rules to prepare the externals ################################
-
-.PHONY:
-externals:
- $(EMACS) -l admin/archive-contents.el \
- -f archive-add/remove/update-externals
-
-
-
-
-################### Testing ###############
-
-PACKAGE_DIRS = $(shell find packages -maxdepth 1 -type d)
-PACKAGES=$(subst /,,$(subst packages,,$(PACKAGE_DIRS)))
-
-TOP =$(shell pwd)
-
-define test_template
-$(1)-test:
- cd packages/$(1);\
- $(EMACS) -l $(TOP)/admin/ert-support.el \
- --eval "(ert-support-test-package \"$(TOP)\" '$(1))" \
-
-$(1)-test-log:
- $(MAKE) $(1)-test > packages/$(1)/$(1).log 2>&1 || { stat=ERROR; }
-endef
-
-$(foreach package,$(PACKAGES),$(eval $(call test_template,$(package))))
-
-PACKAGES_TESTS=$(addsuffix -test-log,$(PACKAGES))
-PACKAGES_LOG=$(foreach package,$(PACKAGES),packages/$(package)/$(package).log)
-
-check: $(PACKAGES_TESTS)
- $(EMACS) -l ert -f ert-summarize-tests-batch-and-exit $(PACKAGES_LOG)
diff --git a/admin/archive-contents.el b/admin/archive-contents.el
deleted file mode 100644
index 2853a42..0000000
--- a/admin/archive-contents.el
+++ /dev/null
@@ -1,1364 +0,0 @@
-;;; archive-contents.el --- Auto-generate an Emacs Lisp package archive. -*-
lexical-binding:t -*-
-
-;; Copyright (C) 2011-2020 Free Software Foundation, Inc
-
-;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
-
-;; This program 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 program 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.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Missing from GNU ELPA script:
-;; - check_copyrights
-;; - Support for :core (seems to be partly working, actually, tho it likely
-;; doesn't select the right release revision).
-;; - Support for Org's package
-;; - Send email announcements
-;; - Fix archive name and URL
-
-;; TODO:
-;; - Eliminate hardcoded `build/packages' directory structure
-;; - support for rebuilding index.html, archive-contents, and <pkg>.html
-;; - support for building the Info files
-;; - support for README.md for some packages
-;; - support for Tramp as core
-
-;;; Code:
-
-(eval-when-compile (require 'cl-lib))
-(require 'lisp-mnt)
-(require 'package)
-(require 'pcase)
-
-
-(defconst archive--release-subdir "archive/"
- "Subdirectory where the ELPA release files (tarballs, ...) will be placed.")
-(defconst archive--devel-subdir "archive-devel/"
- "Subdirectory where the ELPA bleeding edge files (tarballs, ...) will be
placed.")
-(defconst archive--name "NonGNU")
-(defconst archive--gitrepo "emacs/nongnu.git")
-(defconst archive--url "http://elpa.gnu.org/nongnu/")
-
-
-
-(defvar archive--debug nil)
-(defun archive--message (&rest args)
- (when archive--debug (apply #'message args)))
-
-(defconst archive-re-no-dot "\\`\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"
- "Regular expression matching all files except \".\" and \"..\".")
-
-(defun archive--version-to-list (vers)
- (when vers
- (let ((l (version-to-list vers)))
- ;; Signal an error for things like "1.02" which is parsed as "1.2".
- (cl-assert (equal vers (package-version-join l)) nil
- "Unsupported version syntax %S" vers)
- l)))
-
-(defun archive--convert-require (elt)
- (let ((vers (archive--version-to-list (car (cdr elt)))))
- (if vers
- (list (car elt) vers)
- (list (car elt)))))
-
-(defun archive--dirname (dir &optional base)
- (file-name-as-directory (expand-file-name dir base)))
-
-(defun archive--delete-elc-files (dir &optional only-orphans)
- "Recursively delete all .elc files in DIR.
-Delete backup files also."
- (dolist (f (directory-files dir t archive-re-no-dot))
- (cond ((file-directory-p f)
- (archive--delete-elc-files f))
- ((or (and (string-match "\\.elc\\'" f)
- (not (and only-orphans
- (file-readable-p (replace-match ".el" t t f)))))
- (backup-file-name-p f))
- (delete-file f)))))
-
-(defun batch-make-archive ()
- "Process package content directories and generate the archive-contents file."
- (let ((packages '(1))) ; format-version.
- (dolist (dir (directory-files default-directory nil archive-re-no-dot))
- (condition-case v
- (if (not (file-directory-p dir))
- (message "Skipping non-package file %s" dir)
- (let* ((pkg (file-name-nondirectory dir))
- (pkg-spec (archive--get-package-spec pkg))
- (autoloads-file (expand-file-name (concat pkg
"-autoloads.el") dir)))
- ;; Omit autoloads and .elc files from the package.
- (when (file-exists-p autoloads-file)
- (delete-file autoloads-file))
- (archive--delete-elc-files dir)
- (let ((metadata (or (with-demoted-errors
- ;;(format "batch-make-archive %s: %%s" dir)
- (archive--metadata dir pkg-spec))
- '(nil "0"))))
- ;; (nth 1 metadata) is nil for "org" which is the only package
- ;; still using the "org-pkg.el file to specify the metadata.
- (if (and (nth 1 metadata)
- (or (equal (nth 1 metadata) "0")
- ;; Old deprecated convention.
- (< (string-to-number (nth 1 metadata)) 0)))
- (progn ;; Negative version: don't publish this package yet!
- (message "Package %s not released yet!" dir)
- (delete-directory dir 'recursive))
- (push (if (car metadata)
- (apply #'archive--process-simple-package
- dir pkg (cdr metadata))
- (when (nth 1 metadata)
- (archive--write-pkg-file dir pkg metadata))
- (archive--process-multi-file-package dir pkg))
- packages)))))
- ((debug error) (error "Error in %s: %S" dir v))))
- (with-temp-buffer
- (pp (nreverse packages) (current-buffer))
- (write-region nil nil "archive-contents"))))
-
-(defun archive--update-archive-contents (pkg-desc dir)
- "Update the `archive-contents' file in DIR with new package PKG-DESC."
- (let* ((filename (expand-file-name "archive-contents" dir))
- (ac (if (file-exists-p filename)
- (archive--form-from-file-contents filename)
- '(1))))
- (archive--message "current AC: %S" ac)
- (setf (alist-get (car pkg-desc) (cdr ac)) (cdr pkg-desc))
- (setf (cdr ac) (sort (cdr ac)
- (lambda (x y)
- (string-lessp (symbol-name (car x)) (symbol-name
(car y))))))
- (archive--message "new AC: %S" ac)
- (with-temp-buffer
- (pp ac (current-buffer))
- (write-region nil nil filename)
- (let ((default-directory (expand-file-name dir)))
- (archive--html-make-index (cdr ac))))))
-
-(defun archive--get-release-revision (dir pkgname &optional vers version-map)
- "Get the REVISION that corresponds to current release.
-This is either found from VERS in VERSION-MAP or by looking at the last
-commit which modified the \"Version:\" pseudo header."
- (while (and version-map
- (not (member vers (car version-map))))
- (pop version-map))
- (or (nth 2 (car version-map))
- (let* ((default-directory (archive--dirname dir))
- (release-rev
- (with-temp-buffer
- (if (equal 0 ;Don't signal an error if call errors out.
- (archive--call
- (current-buffer)
- "git" "log" "-n1" "--oneline" "--no-patch"
- "--pretty=format:%H"
- "-L" (concat "/^;;* *\\(Package-\\)\\?Version:/,+1:"
- pkgname ".el")))
- (buffer-string)
- (cons 'error (buffer-string))))))
- (if (stringp release-rev)
- (progn
- (archive--message "Found release rev: %S" release-rev)
- release-rev)
- (archive--message "Can't find release rev: %s" (cdr release-rev))
- nil))))
-
-(defun archive--get-last-release (pkg-spec)
- "Return (VERSION . REV) of the last release.
-Assumes that the current worktree holds a snapshot version."
- (with-temp-buffer
- (setq default-directory (archive--dirname (car pkg-spec) "packages"))
- (if (not (equal 0 ;Don't signal an error if call errors out.
- (archive--call
- (current-buffer)
- "git" "log" "-n1" "--oneline" "--no-patch"
- "--pretty=format:%H"
- "-L" (concat "/^;;* *\\(Package-\\)\\?Version:/,+1:"
- (car pkg-spec) ".el"))))
- (progn
- (archive--message "Error in git-log:\n" (buffer-string))
- nil)
- (goto-char (point-min))
- (let ((last-chg-rev (buffer-substring (point) (line-end-position))))
- (erase-buffer)
- (if (not (equal 0 ;Don't signal an error if call errors
out.
- (archive--call
- (current-buffer)
- "git" "log" "-n1" "--oneline"
- "--pretty=format:%H"
- "-L" (concat "/^;;* *\\(Package-\\)\\?Version:/,+1:"
- (car pkg-spec) ".el")
- (concat last-chg-rev "~1"))))
- (progn
- (archive--message "Error in git-log:\n" (buffer-string))
- nil)
- (goto-char (point-min))
- (let ((rev (buffer-substring (point) (line-end-position)))
- (case-fold-search t))
- (if (not (re-search-forward "^\\+.*Version:[ \t]*\\(.+?\\)[ \t]*$"
- nil t))
- (archive--message "No previous release version found")
- (let* ((vers (match-string 1))
- (vl (condition-case err (version-to-list vers)
- (error (archive--message "Error: %S" err) nil))))
- (cond
- ((null vl)
- (archive--message "Invalid previous release version"))
- ((member -4 vl)
- (archive--message "Previous version was also snapshot"))
- (t
- (cons (package-version-join vl) rev)))))))))))
-
-(defun archive--select-revision (dir pkgname rev)
- "Checkout revision REV in DIR of PKGNAME.
-Do it without leaving the current branch."
- (let ((cur-rev (vc-working-revision
- (expand-file-name (concat pkgname ".el") dir))))
- (if (equal rev cur-rev)
- (archive--message "Current revision is already desired revision!")
- (with-temp-buffer
- (let ((default-directory (archive--dirname dir)))
- (archive--call (current-buffer) "git" "status" "--porcelain")
- (if (not (zerop (buffer-size)))
- (error "git-status not clean:\n%s" (buffer-string))
- (archive--call (current-buffer) "git" "reset" "--merge" rev)
- (archive--message "Reverted to release revision %s\n%s"
- rev (buffer-string))))))))
-
-(defun archive--make-one-tarball (tarball dir pkg-spec metadata
- &optional revision-function)
- "Create file TARBALL for PKGNAME if not done yet.
-Return non-nil if a new tarball was created."
- (archive--message "Building tarball %s..." tarball)
- (if (or (file-readable-p tarball)
- (file-readable-p (replace-regexp-in-string
- "\\.tar\\'" ".el" tarball)))
- (progn
- (archive--message "Tarball %s already built!" tarball)
- nil)
- (let* ((destdir (file-name-directory tarball))
- (pkgname (car pkg-spec))
- (_ (unless (file-directory-p destdir) (make-directory destdir)))
- (vers (nth 1 metadata))
- (elpaignore (expand-file-name ".elpaignore" dir))
- (re (concat "\\`" (regexp-quote pkgname)
- "-\\([0-9].*\\)\\.\\(tar\\|el\\)\\(\\.[a-z]*z\\)?\\'"))
- (oldtarballs
- (mapcar
- (lambda (file)
- (string-match re file)
- (cons (match-string 1 file) file))
- (directory-files destdir nil re))))
- (delete-file (expand-file-name (format "%s-pkg.el" pkgname) dir))
- (when revision-function
- (archive--select-revision dir pkgname (funcall revision-function)))
- ;; FIXME: Build Info files and corresponding `dir' file.
- (archive--write-pkg-file dir pkgname metadata)
- ;; FIXME: Allow renaming files or selecting a subset of the files!
- (archive--call nil "tar"
- "--exclude-vcs"
- "-X" (if (file-readable-p elpaignore)
- elpaignore "/dev/null")
- "--transform"
- (format "s|^packages/%s|%s-%s|" pkgname pkgname vers)
- "-chf" tarball
- (concat "packages/" pkgname))
- (let* ((pkgdesc
- ;; FIXME: `archive--write-pkg-file' wrote the metadata to
- ;; <pkg>-pkg.el and then `archive--process-multi-file-package'
- ;; reads it back. We could/should skip the middle man.
- (archive--process-multi-file-package
- dir pkgname 'dont-rename)))
- (archive--message "%s: %S" pkgname pkgdesc)
- (archive--update-archive-contents pkgdesc destdir)
- (when (and nil revision-function) ;FIXME: Circumstantial evidence.
- ;; Various problems:
- ;; - If "make build/foo" is used by the developers in order to test
- ;; the build of their package, they'll end up with those spurious
- ;; tags which may end up spreading to unintended places.
- ;; - The tags created in elpa.gnu.org won't spread to nongnu.git
- ;; because that account can't push to git.sv.gnu.org anyway.
- (let ((default-directory (archive--dirname dir)))
- (archive--call nil "git" "tag" "-f"
- (format "%s-release/%s-%s"
- archive--name pkgname vers))))
- ;; FIXME: Send email announcement!
- (let ((link (expand-file-name (format "%s.tar" pkgname) destdir)))
- (when (file-exists-p link) (delete-file link))
- (make-symbolic-link (file-name-nondirectory tarball) link))
- (dolist (oldtarball oldtarballs)
- ;; lzip compress oldtarballs.
- (let ((file (cdr oldtarball)))
- (when (string-match "\\.\\(tar\\|el\\)\\'" file)
- ;; Don't compress the file we just created.
- (unless (equal file (file-name-nondirectory tarball))
- (archive--call nil "lzip" (expand-file-name file destdir))
- (setf (cdr oldtarball) (concat file ".lz"))))))
- (let* ((default-directory (expand-file-name destdir)))
- ;; Apparently this also creates the <pkg>-readme.txt file.
- (archive--html-make-pkg pkgdesc pkg-spec
- `((,vers . ,(file-name-nondirectory tarball))
- . ,oldtarballs)
- dir))
- (message "Built new package %s!" tarball)
- 'new))))
-
-(defun archive--get-devel-version (dir)
- "Compute the date-based pseudo-version used for devel builds."
- (let* ((default-directory (archive--dirname dir))
- (gitdate
- (with-temp-buffer
- (archive--call (current-buffer)
- "git" "show" "--pretty=format:%cI" "--no-patch")
- (buffer-string)))
- (verdate
- ;; Convert Git's date into something that looks like a version
number.
- ;; While we're at it, convert Git's date into its UTC equivalent,
- ;; to try and make sure time-versions are monotone.
- (let ((process-environment (cons "TZ=UTC" process-environment)))
- (with-temp-buffer
- (archive--call (current-buffer)
- "date" "-d" gitdate "+%Y%m%d.%H%M%S")
- (buffer-string)))))
- ;; Get rid of leading zeros since ELPA's version numbers don't allow them.
- (replace-regexp-in-string "\\(?:\\`\\|[^0-9]\\)0+" "\\1"
- ;; Remove trailing newline or anything untoward.
- (replace-regexp-in-string "[^.0-9]+" ""
- verdate))))
-
-(defun archive--get-package-spec (pkgname)
- "Retrieve the property list for PKGNAME from `externals-list'."
- (let* ((specs (archive--form-from-file-contents "externals-list"))
- (spec (assoc pkgname specs)))
- (if (null spec)
- (error "Unknown package `%S`" pkgname)
- spec)))
-
-(defun batch-make-all-packages (&rest _)
- "Check all the packages and build the relevant new tarballs."
- (let* ((specs (archive--form-from-file-contents "externals-list")))
- (dolist (spec specs)
- (with-demoted-errors "Build error: %S"
- (archive--make-one-package spec)))))
-
-(defun batch-make-one-package (&rest _)
- "Build the new tarballs (if needed) for one particular package."
- (while command-line-args-left
- (archive--make-one-package (archive--get-package-spec
- (pop command-line-args-left)))))
-
-(defun archive--make-one-package (pkg-spec)
- "Build the new tarballs (if needed) for PKG-SPEC."
- (archive--message "Checking package %s for updates..." (car pkg-spec))
- (let* ((pkgname (car pkg-spec))
- (dir (expand-file-name pkgname "packages"))
- (_ (if (eq (nth 1 pkg-spec) :core)
- (archive--core-package-sync pkg-spec)
- (archive--external-package-sync pkg-spec)))
- (_ (archive--message "pkg-spec for %s: %S" pkgname pkg-spec))
- (metadata (archive--metadata dir pkg-spec))
- (vers (nth 1 metadata)))
- (archive--message "metadata = %S" metadata)
- (if (null metadata)
- (error "No metadata found for package: %s" pkgname)
- ;; Disregard the simple/multi distinction. This might have been useful
- ;; in a distant past, but nowadays it's just unneeded extra complexity.
- (setf (car metadata) nil)
- ;; First, try and build the devel tarball
- ;; Do it before building the release tarball, because building
- ;; the release tarball may revert to some older commit.
- (let* ((date-version (archive--get-devel-version dir))
- ;; Add a ".0." so that when the version number goes from
- ;; NN.MM to NN.MM.1 we don't end up with the devel build
- ;; of NN.MM comparing as more recent than NN.MM.1.
- ;; But be careful to turn "2.3" into "2.3.0.DATE"
- ;; and "2.3b" into "2.3b0.DATE".
- (devel-vers
- (concat vers (if (string-match "[0-9]\\'" vers) ".")
- "0." date-version))
- (tarball (concat archive--devel-subdir
- (format "%s-%s.tar" pkgname devel-vers)))
- (new
- (let ((archive--name (concat archive--name "-devel")))
- ;; Build the archive-devel tarball.
- (archive--make-one-tarball tarball
- dir pkg-spec
- `(nil ,devel-vers
- . ,(nthcdr 2 metadata))))))
-
- ;; Try and build the latest release tarball.
- (cond
- ((or (equal vers "0")
- ;; -4 is used for "NN.MMsnapshot" and "NN.MM-git"
- (member '-4 (version-to-list vers)))
- (cond
- ((equal vers "0")
- (archive--message "Package %s not released yet!" pkgname))
- ((not new)
- (archive--message "Nothing new for package %s!" pkgname))
- (t
- ;; If this revision is a snapshot, check to see if there's
- ;; a previous non-snapshot revision and build it if needed.
- (let* ((last-rel (archive--get-last-release pkg-spec))
- (tarball (concat archive--release-subdir
- (format "%s-%s.tar"
- pkgname (car last-rel)))))
- (if (not last-rel)
- (archive--message "Package %s not released yet!" pkgname)
- (archive--make-one-tarball
- tarball dir pkg-spec
- `(nil ,(car last-rel) . ,(nthcdr 2 metadata))
- (lambda () (cdr last-rel))))))))
- (t
- (let ((tarball (concat archive--release-subdir
- (format "%s-%s.tar" pkgname vers))))
- (archive--make-one-tarball
- tarball dir pkg-spec metadata
- (lambda ()
- (archive--get-release-revision
- dir pkgname vers
- (plist-get (cdr pkg-spec) :version-map)))))))))))
-
-(defun archive--call (destination program &rest args)
- "Like ‘call-process’ for PROGRAM, DESTINATION, ARGS.
-The INFILE and DISPLAY arguments are fixed as nil."
- ;; (message "call-process %s %S" program args)
- (apply #'call-process program nil destination nil args))
-
-(defconst archive--revno-re "[0-9a-f]+")
-
-(defun archive-prepare-packages (srcdir)
- "Prepare the `packages' directory inside the Git checkout.
-Expects to be called from within the `packages' directory.
-\"Prepare\" here is for subsequent construction of the packages and archive,
-so it is meant to refresh any generated files we may need.
-Currently only refreshes the ChangeLog files."
- (setq srcdir (archive--dirname srcdir))
- (let* ((wit ".changelog-witness")
- (prevno (with-temp-buffer
- (insert-file-contents wit)
- (if (looking-at (concat archive--revno-re "$"))
- (match-string 0)
- (error "Can't find previous revision name"))))
- (new-revno
- (or (with-temp-buffer
- (let ((default-directory srcdir))
- (archive--call '(t) "git" "rev-parse" "HEAD")
- (goto-char (point-min))
- (when (looking-at (concat archive--revno-re "$"))
- (match-string 0))))
- (error "Couldn't find the current revision's name")))
- (pkgs '()))
- (unless (equal prevno new-revno)
- (with-temp-buffer
- (let ((default-directory srcdir))
- (unless (zerop (archive--call '(t) "git" "diff"
- "--dirstat=cumulative,0"
- prevno))
- (error "Error signaled by git diff --dirstat %d" prevno)))
- (goto-char (point-min))
- (while (re-search-forward "^[ \t.0-9%]* packages/\\([-[:alnum:]]+\\)/$"
- nil t)
- (push (match-string 1) pkgs))))
- (let ((default-directory (expand-file-name "packages/")))
- (dolist (pkg pkgs)
- (condition-case v
- (when (file-directory-p pkg)
- (archive--make-changelog pkg (expand-file-name "packages/"
- srcdir)))
- (error (message
- "Error in archive-prepare-packages for package %S:\n %S"
- pkg v)))))
- (write-region new-revno nil wit nil 'quiet)
- ;; Also update the ChangeLog of external packages.
- (let ((default-directory (expand-file-name "packages/")))
- (dolist (dir (directory-files "."))
- (and (not (member dir '("." "..")))
- (file-directory-p dir)
- (let* ((gitdir (expand-file-name
- (concat "packages/" dir "/.git")
- srcdir))
- (index (cond
- ((file-directory-p gitdir)
- (expand-file-name
- (concat "packages/" dir "/.git/index")
- srcdir))
- ((file-readable-p gitdir)
- (with-temp-buffer
- (insert-file-contents gitdir)
- (goto-char (point-min))
- (if (looking-at "gitdir:[ \t]*")
- (progn
- (delete-region (match-beginning 0)
- (match-end 0))
- (expand-file-name "index"
(buffer-string)))
- (message "Can't find gitdir in %S" gitdir)
- nil)))
- (t nil)))
- (cl (expand-file-name "ChangeLog" dir)))
- (and index
- (file-exists-p index)
- (or (not (file-exists-p cl))
- (file-newer-than-file-p index cl))))
- (archive--make-changelog
- dir (expand-file-name "packages/" srcdir)))))
- ))
-
-(defconst archive-default-url-format (concat archive--url "%s.html"))
-(defconst archive-default-url-re (format archive-default-url-format ".*"))
-
-
-(defun archive--override-version (pkg-spec orig-fun header)
- (let ((str (funcall orig-fun header)))
- (or (if (or (equal header "version")
- (and str (equal header "package-version")))
- (let ((version-map (plist-get (cdr pkg-spec) :version-map))
- (dont-release (plist-get (cdr pkg-spec) :dont-release)))
- (or (cadr (assoc str version-map))
- (and str dont-release
- (string-match dont-release str)
- (replace-match "snapshot" t t str)))))
- str)))
-
-;; Some packages use version numbers which `version-to-list' doesn't
-;; recognize out of the box. So here we help.
-
-(add-to-list 'version-regexp-alist '("^[-.+ ]*beta-?$" . -2)) ;"1.0.0-beta-3"
-(add-to-list 'version-regexp-alist '("^[-.+ ]*dev$" . -4)) ;2.5-dev
-
-(defun archive--metadata (dir pkg-spec)
- "Return a list (SIMPLE VERSION DESCRIPTION REQ EXTRAS),
-where SIMPLE is non-nil if the package is simple;
-VERSION is the version string of the simple package;
-DESCRIPTION is the brief description of the package;
-REQ is a list of requirements;
-EXTRAS is an alist with additional metadata.
-
-PKG is the name of the package and DIR is the directory where it is."
- (let* ((pkg (car pkg-spec))
- (mainfile (expand-file-name (concat pkg ".el") dir))
- (files (directory-files dir nil "\\`dir\\'\\|\\.el\\'")))
- (setq files (delete (concat pkg "-pkg.el") files))
- (setq files (delete (concat pkg "-autoloads.el") files))
- (cond
- ((file-exists-p mainfile)
- (with-temp-buffer
- (insert-file-contents mainfile)
- (goto-char (point-min))
- (let* ((pkg-desc
- (unwind-protect
- (progn
- (when (or (plist-get (cdr pkg-spec) :version-map)
- (plist-get (cdr pkg-spec) :dont-release))
- (advice-add 'lm-header :around
- (apply-partially
- #'archive--override-version
- pkg-spec)))
- (package-buffer-info))
- (advice-remove 'lm-header
- #'archive--override-version)))
- (extras (package-desc-extras pkg-desc))
- (version (package-desc-version pkg-desc))
- (keywords (lm-keywords-list))
- ;; (_ (archive--version-to-list version)) ; Sanity check!
- (pt (lm-header "package-type"))
- (simple (if pt (equal pt "simple") (= (length files) 1)))
- (found-url (alist-get :url extras))
- (found-keywords (alist-get :keywords extras)))
-
- (when (and keywords (not found-keywords))
- ;; Using an old package-buffer-info which doesn't include
- ;; keywords. Fix it by hand.
- (push (cons :keywords keywords) extras))
- (unless found-url
- ;; Provide a good default URL.
- (push (cons :url (format archive-default-url-format pkg)) extras))
- (list simple
- (package-version-join version)
- (package-desc-summary pkg-desc)
- (package-desc-reqs pkg-desc)
- extras))))
- (t
- (error "Can't find main file %s file in %s" mainfile dir)))))
-
-(defun archive--process-simple-package (dir pkg vers desc req extras)
- "Deploy the contents of DIR into the archive as a simple package.
-Rename DIR/PKG.el to PKG-VERS.el, delete DIR, and return the descriptor."
- ;; Write DIR/foo.el to foo-VERS.el and delete DIR
- (let ((src (expand-file-name (concat pkg ".el") dir)))
- (funcall (if (file-symlink-p src) #'copy-file #'rename-file)
- src (concat pkg "-" vers ".el")))
- ;; Add the content of the ChangeLog.
- (let ((cl (expand-file-name "ChangeLog" dir)))
- (with-current-buffer (find-file-noselect (concat pkg "-" vers ".el"))
- (goto-char (point-max))
- (re-search-backward "^;;;.*ends here")
- (re-search-backward "^(provide")
- (skip-chars-backward " \t\n")
- (insert "\n\n;;;; ChangeLog:\n\n")
- (let* ((start (point))
- (end (copy-marker start t)))
- (condition-case nil
- (insert-file-contents cl)
- (file-error (message "Can't find %S's ChangeLog file" pkg)))
- (goto-char end)
- (unless (bolp) (insert "\n"))
- (while (progn (forward-line -1) (>= (point) start))
- (insert ";; ")))
- (set (make-local-variable 'backup-inhibited) t)
- (basic-save-buffer) ;Less chatty than save-buffer.
- (kill-buffer)))
- (delete-directory dir t)
- (cons (intern pkg) (vector (archive--version-to-list vers)
- req desc 'single extras)))
-
-(defun archive--make-changelog (dir srcdir)
- "Export Git log info of DIR into a ChangeLog file."
- (message "Refreshing ChangeLog in %S" dir)
- (let ((default-directory (archive--dirname dir)))
- (with-temp-buffer
- (set-buffer-multibyte nil)
- (let ((coding-system-for-read 'binary)
- (coding-system-for-write 'binary))
- (when (file-readable-p "ChangeLog") (insert-file-contents "ChangeLog"))
- (let ((old-md5 (md5 (current-buffer))))
- (erase-buffer)
- (let ((default-directory (archive--dirname dir srcdir)))
- (archive--call (current-buffer) ; hmm, why not use ‘t’ here? --ttn
- "git" "log" "--date=short"
- "--format=%cd %aN <%ae>%n%n%w(80,8,8)%B%n"
- "."))
- (tabify (point-min) (point-max))
- (goto-char (point-min))
- (while (re-search-forward "\n\n\n+" nil t)
- (replace-match "\n\n"))
- (if (equal old-md5 (md5 (current-buffer)))
- (message "ChangeLog's md5 unchanged for %S" dir)
- (write-region (point-min) (point-max) "ChangeLog" nil 'quiet)))))))
-
-(defun archive--alist-to-plist-args (alist)
- (mapcar (lambda (x)
- (if (and (not (consp x))
- (or (keywordp x)
- (not (symbolp x))
- (memq x '(nil t))))
- x `',x))
- (apply #'nconc
- (mapcar (lambda (pair) (list (car pair) (cdr pair))) alist))))
-
-(defun archive--plist-args-to-alist (plist)
- (let (alist)
- (while plist
- (let ((value (cadr plist)))
- (when value
- (cl-assert (keywordp (car plist)))
- (push (cons (car plist)
- (if (eq 'quote (car-safe value)) (cadr value) value))
- alist)))
- (setq plist (cddr plist)))
- alist))
-
-(defun archive--process-multi-file-package (dir pkg &optional dont-rename)
- "Deploy the contents of DIR into the archive as a multi-file package.
-Rename DIR/ to PKG-VERS/, and return the descriptor."
- (let* ((exp (archive--multi-file-package-def dir pkg))
- (vers (nth 2 exp))
- (req-exp (nth 4 exp))
- (req (mapcar #'archive--convert-require
- (if (eq 'quote (car-safe req-exp)) (nth 1 req-exp)
- (when req-exp
- (error "REQ should be a quoted constant: %S"
- req-exp)))))
- (extras (archive--plist-args-to-alist (nthcdr 5 exp))))
- (unless (equal (nth 1 exp) pkg)
- (error (format "Package name %s doesn't match file name %s"
- (nth 1 exp) pkg)))
- (unless dont-rename (rename-file dir (concat pkg "-" vers)))
- (cons (intern pkg) (vector (archive--version-to-list vers)
- req (nth 3 exp) 'tar extras))))
-
-(defun archive--form-from-file-contents (filename)
- (with-temp-buffer
- (insert-file-contents filename)
- ;; This is unnecessary because ‘with-temp-buffer’ generates a new
- ;; (empty) buffer, and ‘insert-file-contents’ inserts after point.
- ;; In other words, point is alraedy at bob.
- ;;- (goto-char (point-min))
- (read (current-buffer))))
-
-(defun archive--multi-file-package-def (dir pkg)
- "Return the `define-package' form in the file DIR/PKG-pkg.el."
- (let ((pkg-file (expand-file-name (concat pkg "-pkg.el") dir)))
- (unless (file-exists-p pkg-file)
- (error "File not found: %s" pkg-file))
- (archive--form-from-file-contents pkg-file)))
-
-(defun archive-refresh-pkg-file ()
- ;; Note: Used via --batch by GNUmakefile rule.
- (let* ((dir (directory-file-name default-directory))
- (pkg (file-name-nondirectory dir))
- (pkg-spec (archive--get-package-spec pkg)))
- (archive--write-pkg-file dir pkg (archive--metadata dir pkg-spec))))
-
-(defun archive--write-pkg-file (pkg-dir name metadata)
- ;; FIXME: Use package-generate-description-file!
- (let ((pkg-file (expand-file-name (concat name "-pkg.el") pkg-dir))
- (print-level nil)
- (print-quoted t)
- (print-length nil))
- (write-region
- (concat (format ";; Generated package description from %s.el -*-
no-byte-compile: t -*-\n"
- name)
- (prin1-to-string
- (cl-destructuring-bind (version desc requires extras)
- (cdr metadata)
- (nconc
- (list 'define-package
- name
- version
- desc
- (list 'quote
- ;; Turn version lists into string form.
- (mapcar
- (lambda (elt)
- (list (car elt)
- (package-version-join (cadr elt))))
- requires)))
- (archive--alist-to-plist-args extras))))
- "\n")
- nil
- pkg-file)))
-
-(defun batch-generate-description-file (&rest _)
- "(Re)build the <PKG>-pkg.el file for particular packages."
- (while command-line-args-left
- (let* ((file (pop command-line-args-left))
- (dir (file-name-directory file))
- (pkg (file-name-nondirectory (directory-file-name dir)))
- (pkg-spec (archive--get-package-spec pkg)))
- (archive--write-pkg-file dir pkg
- (archive--metadata dir pkg-spec)))))
-
-;;; Make the HTML pages for online browsing.
-
-(defun archive--html-header (title &optional header)
- (format "<!DOCTYPE HTML PUBLIC>
-<html lang=\"en\" xml:lang=\"en\">
- <head>
- <title>%s</title>
- <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">
- <link rel=\"shortcut icon\" type=\"image/png\" href=\"../favicon.png\">
- <link rel=\"stylesheet\"
href=\"//code.cdn.mozilla.net/fonts/fira.css\">
- <link rel=\"stylesheet\" type=\"text/css\" href=\"../layout.css\">
- <script src=\"../javascript/jquery.min.js\"
type=\"text/javascript\"></script>
- <script src=\"../javascript/jquery.filtertable.min.js\"
type=\"text/javascript\"></script>
- <script src=\"../javascript/package-search.js\"
type=\"text/javascript\"></script>
- <meta name=\"viewport\"
content=\"initial-scale=1.0,maximum-scale=1.0,width=device-width\" />
- </head>
- <body>
-
- <div class=\"wrapper\">
-
- <div class=\"header small\">
- <div class=\"container\">
- <h1>%s</h1>
- </div>
- </div>
-
- <div class=\"container\">\n"
- title (or header title)))
-
-(defun archive--html-bytes-format (bytes) ;Aka memory-usage-format.
- (setq bytes (/ bytes 1024.0))
- (let ((units '("KiB" "MiB" "GiB" "TiB")))
- (while (>= bytes 1024)
- (setq bytes (/ bytes 1024.0))
- (setq units (cdr units)))
- (cond
- ((>= bytes 100) (format "%4.0f %s" bytes (car units)))
- ((>= bytes 10) (format "%4.1f %s" bytes (car units)))
- (t (format "%4.2f %s" bytes (car units))))))
-
-(defun archive--get-prop (prop name srcdir mainsrcfile)
- (let ((kprop (intern (format ":%s" (downcase prop)))))
- (or
- (let ((pkgdescfile (expand-file-name (format "%s-pkg.el" name)
- srcdir)))
- (when (file-readable-p pkgdescfile)
- (let* ((desc (archive--form-from-file-contents pkgdescfile))
- (val-exp (plist-get (cdr desc) kprop)))
- (if (eq 'quote (car-safe val-exp))
- (cadr val-exp)
- val-exp))))
- (when (file-readable-p mainsrcfile)
- (with-temp-buffer
- (insert-file-contents mainsrcfile)
- (lm-header prop))))))
-
-(defun archive--get-section (hsection fsection srcdir mainsrcfile)
- (when (consp fsection)
- (while (cdr-safe fsection)
- (setq fsection
- (if (file-readable-p (expand-file-name (car fsection) srcdir))
- (car fsection)
- (cdr fsection))))
- (when (consp fsection) (setq fsection (car fsection))))
- (cond
- ((file-readable-p (expand-file-name fsection srcdir))
- (with-temp-buffer
- (insert-file-contents (expand-file-name fsection srcdir))
- (buffer-string)))
- ((file-readable-p mainsrcfile)
- (with-temp-buffer
- (insert-file-contents mainsrcfile)
- (emacs-lisp-mode) ;lm-section-start needs the outline-mode setting.
- (let ((start (lm-section-start hsection)))
- (when start
- (insert
- (prog1
- (buffer-substring start (lm-section-end hsection))
- (erase-buffer)))
- (emacs-lisp-mode)
- (goto-char (point-min))
- (delete-region (point) (line-beginning-position 2))
- (uncomment-region (point-min) (point-max))
- (when (looking-at "^\\([ \t]*\n\\)+")
- (replace-match ""))
- (goto-char (point-max))
- (skip-chars-backward " \t\n")
- (delete-region (point) (point-max))
- (buffer-string)))))))
-
-(defun archive--quote (txt)
- (replace-regexp-in-string "<" "<"
- (replace-regexp-in-string "&" "&" txt)))
-
-(defun archive--insert-repolinks (pkg-spec url)
- (when url
- (insert (format "<dt>Home page</dt> <dd><a href=%S>%s</a></dd>\n"
- url (archive--quote url)))
- (when (string-match archive-default-url-re url)
- (setq url nil)))
- (let* ((git-sv "http://git.savannah.gnu.org/")
- (urls
- (if (eq (nth 1 pkg-spec) :core)
- (let* ((files (nth 2 pkg-spec))
- (file (if (listp files)
- (directory-file-name
- (file-name-directory
- (try-completion "" files)))
- files)))
- (mapcar (lambda (s) (concat s file))
- `("cgit/emacs.git/tree/"
- ,(if (listp files)
- "gitweb/?p=emacs.git;a=tree;f="
- "gitweb/?p=emacs.git;a=blob;f="))))
- (mapcar (lambda (s) (format s archive--gitrepo (car pkg-spec)))
- '("cgit/%s/?h=externals/%s"
- "gitweb/?p=%s;a=shortlog;h=refs/heads/externals/%s")))))
- (insert (format
- (concat (format "<dt>Browse %srepository</dt> <dd>" (if url
"ELPA's " ""))
- "<a href=%S>%s</a> or <a href=%S>%s</a></dd>\n")
- (concat git-sv (nth 0 urls))
- 'CGit
- (concat git-sv (nth 1 urls))
- 'Gitweb))))
-
-(defun archive--html-make-pkg (pkg pkg-spec files &optional srcdir)
- (let* ((name (symbol-name (car pkg)))
- (latest (package-version-join (aref (cdr pkg) 0)))
- (srcdir (or srcdir
- (expand-file-name name "../../build/packages")))
- (mainsrcfile (expand-file-name (format "%s.el" name) srcdir))
- (desc (aref (cdr pkg) 2)))
- (cl-assert (equal name (car pkg-spec)))
- (with-temp-buffer
- (insert (archive--html-header
- (format "%s ELPA - %s" archive--name name)
- (format "<a href=\"index.html\">%s ELPA</a> - %s"
- archive--name name)))
- (insert (format "<h2 class=\"package\">%s</h2>" name))
- (insert "<dl>")
- (insert (format "<dt>Description</dt><dd>%s</dd>\n" (archive--quote
desc)))
- (if (zerop (length latest))
- (insert "<dd>This package "
- (if files (concat "is not in " archive--name " ELPA any
more")
- "has not been released yet")
- ".</dd>\n")
- (let* ((file (cdr (assoc latest files)))
- (attrs (file-attributes file)))
- (insert (format "<dt>Latest</dt> <dd><a href=%S>%s</a>, %s,
%s</dd>\n"
- file (archive--quote file)
- (format-time-string "%Y-%b-%d" (nth 5 attrs))
- (archive--html-bytes-format (nth 7 attrs))))))
- (let ((maint (archive--get-prop "Maintainer" name srcdir mainsrcfile)))
- (when maint
- (when (consp maint)
- (archive--message "maint=%S" maint)
- (setq maint (concat (if (car maint) (concat (car maint) " "))
- "<" (cdr maint) ">")))
- (insert (format "<dt>Maintainer</dt> <dd>%s</dd>\n" (archive--quote
maint)))))
- (archive--insert-repolinks
- pkg-spec
- (or (cdr (assoc :url (aref (cdr pkg) 4)))
- (archive--get-prop "URL" name srcdir mainsrcfile)))
- (insert "</dl>")
- (insert (format "<p>To install this package, run in Emacs:</p>
- <pre>M-x <span class=\"kw\">package-install</span> RET
<span class=\"kw\">%s</span> RET</pre>"
- name))
- ;; FIXME: Use README.md for some packages (such as markdown-mode).
- (let ((rm (archive--get-section
- "Commentary" '("README" "README.rst"
- ;; Most README.md files seem to be currently
- ;; worse than the Commentary: section :-(
- ;; "README.md"
- "README.org")
- srcdir mainsrcfile)))
- (when rm
- (write-region rm nil (concat name "-readme.txt"))
- (insert "<h2>Full description</h2><pre>\n" (archive--quote rm)
- "\n</pre>\n")))
- ;; (message "latest=%S; files=%S" latest files)
- (unless (< (length files) (if (zerop (length latest)) 1 2))
- (insert (format "<h2>Old versions</h2><table>\n"))
- (dolist (file
- (sort files (lambda (f1 f2) (version< (car f2) (car f1)))))
- (unless (equal (pop file) latest)
- (let ((attrs (file-attributes file)))
- (insert (format "<tr><td><a
href=%S>%s</a></td><td>%s</td><td>%s</td>\n"
- file (archive--quote file)
- (format-time-string "%Y-%b-%d" (nth 5 attrs))
- (archive--html-bytes-format (nth 7 attrs)))))))
- (insert "</table>\n"))
- (let ((news (archive--get-section
- "News" '("NEWS" "NEWS.rst" "NEWS.md" "NEWS.org")
- srcdir mainsrcfile)))
- (when news
- (insert "<h2>News</h2><pre>\n" (archive--quote news) "\n</pre>\n")))
- (insert "</body>\n")
- (write-region (point-min) (point-max) (concat name ".html")))))
-
-(defun archive--html-make-index (pkgs)
- (with-temp-buffer
- (insert (archive--html-header (concat archive--name " ELPA Packages")))
- (insert "<table>\n")
- (insert "<tr><th>Package</th><th>Version</th><th>Description</th></tr>\n")
- (dolist (pkg pkgs)
- (insert (format "<tr><td><a
href=\"%s.html\">%s</a></td><td>%s</td><td>%s</td></tr>\n"
- (car pkg) (car pkg)
- (package-version-join (aref (cdr pkg) 0))
- (aref (cdr pkg) 2))))
- (insert " </table>
- </div>
- <div class=\"push\"></div>
- </div>
-
- <div class=\"footer\">
- <div class=\"container\">
- <p>Copyright 2016 <a href=\"https://fsf.org\">Free Software
Foundation</a>, Inc.</p>
- <p>Design provided by <a
href=\"http://nicolas.petton.fr\">Nicolas Petton</a></p>
- <p>
- This website is licensed under the
- <a
href=\"https://creativecommons.org/licenses/by-nd/3.0/us/\">CC BY-ND 3.0</a>
- US License.
- </p>
- </div>
- </div>
-
-</body>\n")
- (write-region (point-min) (point-max) "index.html")))
-
-(defun batch-html-make-index ()
- (let ((packages (make-hash-table :test #'equal))
- (specs (archive--form-from-file-contents "externals-list"))
- (archive-contents
- ;; Skip the first element which is a version number.
- (cdr (archive--form-from-file-contents "archive-contents"))))
- (dolist (subdir (directory-files "../../build/packages" nil))
- (cond
- ((member subdir '("." ".." "elpa.rss" "index.html" "archive-contents")))
- (t (puthash subdir nil packages))))
- (dolist (file (directory-files default-directory nil))
- (cond
- ((member file '("." ".." "elpa.rss" "index.html" "archive-contents")))
- ((string-match "\\.html\\'" file))
- ((string-match "\\.sig\\'" file))
- ((string-match "-readme\\.txt\\'" file)
- (let ((name (substring file 0 (match-beginning 0))))
- (puthash name (gethash name packages) packages)))
- ((string-match "-\\([0-9][^-]*\\)\\.\\(tar\\|el\\)\\'" file)
- (let ((name (substring file 0 (match-beginning 0)))
- (version (match-string 1 file)))
- (push (cons version file) (gethash name packages))))
- (t (message "Unknown file %S" file))))
- (maphash (lambda (pkg-name files)
- (archive--html-make-pkg
- (let ((pkg (intern pkg-name)))
- (or (assq pkg archive-contents)
- ;; Add entries for packages that are either not yet
- ;; released or not released any more.
- ;; FIXME: Get actual description!
- (let ((entry (cons pkg (vector nil nil "" nil nil))))
- (setq archive-contents
- ;; Add entry at the end.
- (nconc archive-contents (list entry)))
- entry)))
- (assoc pkg-name specs)
- files))
- packages)
- (archive--html-make-index archive-contents)))
-
-(defun archive--pull (dirname)
- (let ((default-directory (archive--dirname dirname)))
- (with-temp-buffer
- ;; Undo any local changes to `<pkg>-pkg.el', in case it's under
- ;; version control.
- (archive--call t "git" "checkout" "--"
- (concat (file-name-nondirectory dirname) "-pkg.el"))
- (erase-buffer) ;Throw away the error message we usually get.
- (cond
- ((file-directory-p ".git")
- (message "Running git pull in %S" default-directory)
- (archive--call t "git" "pull"))
- ((file-exists-p ".git")
- (if (with-temp-buffer
- (archive--call t "git" "status" "--branch" "--porcelain=2")
- (goto-char (point-min))
- ;; Nothing to pull (nor push, actually).
- (search-forward "\n# branch.ab +0 -0" nil t))
- (message "%s up-to-date" dirname)
- (message "Updating worktree in %S" default-directory)
- (archive--call t "git" "merge")))
- (t (error "No .git in %S" default-directory)))
- (unless (and (eobp) (bobp))
- (message "Updated %s:%s%s" dirname
- (if (and (eobp) (bolp)
- (eq (line-beginning-position 0) (point-min)))
- " " "\n")
- (buffer-string))))))
-
-;;; Maintain external packages.
-
-(defconst archive--elpa-git-url "git://git.sv.gnu.org/emacs/elpa")
-(defconst archive--emacs-git-url "git://git.sv.gnu.org/emacs.git")
-
-(defun archive--sync-emacs-repo ()
- "Sync Emacs repository, if applicable.
-Return non-nil if there's an \"emacs\" repository present."
- ;; Support for :core packages is important for elpa.gnu.org, but for other
- ;; cases such as "in-place installation", it's rather secondary since
- ;; those users can just as well use a development version of Emacs to get
- ;; those packages.
- ;; So make the handling of :core packages depend on whether or not the user
- ;; has setup a clone of Emacs under the "emacs" subdirectory.
- (let ((emacs-repo-root (expand-file-name "emacs")))
- (if (not (file-directory-p emacs-repo-root))
- (progn (message "No \"emacs\" subdir: will skip :core packages")
- nil)
- (archive--pull emacs-repo-root)
- t)))
-
-(defun archive--find-non-trivial-file (dir)
- (catch 'found-important-file
- (dolist (file (directory-files-recursively dir ".*"))
- (unless (or (member file '("." ".."))
- (string-match "\\.elc\\'" file)
- (string-match "-autoloads.el\\'" file)
- (string-match "-pkg.el\\'" file)
- (file-symlink-p file))
- (throw 'found-important-file file)))
- nil))
-
-(defun archive--cleanup-packages (externals-list with-core)
- "Remove unknown subdirectories of `packages/'.
-This is any subdirectory inside `packages/' that's not under
-version control nor listed in EXTERNALS-LIST.
-If WITH-CORE is non-nil, it means we manage :core packages as well."
- (when (file-directory-p (expand-file-name "packages/"))
- (let ((default-directory (expand-file-name "packages/")))
- (dolist (dir (directory-files "."))
- (cond
- ((file-symlink-p dir)
- ;; There are normally no such thing, but the user may elect to
- ;; add symlinks to other projects. If so, update them, as if they
- ;; were "externals".
- (when (file-directory-p (expand-file-name ".git" dir))
- (archive--pull dir)))
- ((or (not (file-directory-p dir)) )
- ;; We only add/remove plain directories in elpa/packages (not
- ;; symlinks).
- nil)
- ((member dir '("." "..")) nil)
- ((assoc dir externals-list) nil)
- ((file-directory-p (expand-file-name (format "%s/.git" dir)))
- (let ((status
- (with-temp-buffer
- (let ((default-directory (archive--dirname dir)))
- (archive--call t "git" "status" "--porcelain")
- (buffer-string)))))
- (if (zerop (length status))
- (progn (delete-directory dir 'recursive t)
- (message "Deleted all of %s" dir))
- (message "Keeping leftover unclean %s:\n%s" dir status))))
- ;; Check if `dir' is under version control.
- ((and with-core
- (not (zerop (archive--call nil "git" "ls-files"
- "--error-unmatch" dir))))
- ;; Not under version control. Check if it only contains
- ;; symlinks and generated files, in which case it is probably
- ;; a leftover :core package that can safely be deleted.
- ;; (let ((file (archive--find-non-trivial-file dir)))
- ;; (if file
- ;; (message "Keeping %s for non-trivial file \"%s\"" dir file)
- ;; (progn
- ;; (message "Deleted untracked package %s" dir)
- ;; (delete-directory dir 'recursive t))))
- ))))))
-
-
-(defun archive--external-package-sync (pkg-spec)
- "Sync external package named PKG-SPEC."
- (let ((name (car pkg-spec))
- (default-directory (expand-file-name "packages/")))
- (unless (file-directory-p default-directory)
- (make-directory default-directory))
- (cond ((not (file-exists-p name))
- (let* ((branch (concat "externals/" name))
- (output
- (with-temp-buffer
- (cond
- ((archive--git-branch-p (archive--ortb pkg-spec))
- (archive--call t "git" "worktree" "add"
- "-B" branch
- name (archive--ortb pkg-spec)))
- ((archive--git-branch-p branch)
- (archive--call t "git" "worktree" "add" name branch))
- ((archive--git-branch-p (archive--urtb pkg-spec))
- (archive--call t "git" "worktree" "add"
- "-B" branch "--no-track"
- name (archive--urtb pkg-spec)))
- (t (error "No branch %s for the worktree of %s"
- branch name)))
- (buffer-string))))
- (message "Cloning branch %s:\n%s" name output)))
- ((not (file-exists-p (concat name "/.git")))
- (message "%s is in the way of an external, please remove!" name))
- (t (archive--pull name)))))
-
-(defun archive--core-package-empty-dest-p (dest)
- "Return non-nil if DEST is an empty variant."
- (member dest (list "" "." nil)))
-
-(defun archive--core-package-link-file
- (source dest emacs-repo-root package-root exclude-regexp)
- "Link file from SOURCE to DEST ensuring subdirectories."
- (unless (string-match-p exclude-regexp source)
- (let* ((absolute-package-file-name
- (if (equal "" dest)
- ;; Calling expand-file-name would remove the trailing / !
- package-root
- (expand-file-name dest package-root)))
- (absolute-core-file-name
- (expand-file-name source emacs-repo-root))
- (directory (file-name-directory absolute-package-file-name)))
- (when (fboundp 'file-name-quote) ;Not yet available on elpa.gnu.org
- (setq directory (file-name-quote directory)))
- (unless (file-directory-p directory)
- (make-directory directory t))
- (condition-case err
- (make-symbolic-link absolute-core-file-name
- absolute-package-file-name t)
- (file-error
- (message "Error: can't symlink to %S from %S:\n %S"
- absolute-core-file-name absolute-package-file-name err)
- (copy-file absolute-core-file-name
- (if (file-directory-p absolute-package-file-name)
- (file-name-as-directory absolute-package-file-name)
- absolute-package-file-name)))))
- (message " %s -> %s" source (if (archive--core-package-empty-dest-p dest)
- (file-name-nondirectory source)
- dest))))
-
-(defun archive--core-package-link-directory
- (source dest emacs-repo-root package-root exclude-regexp)
- "Link directory files from SOURCE to DEST ensuring subdirectories."
- (let ((stack (list source))
- (base source)
- (absolute-source))
- (while stack
- (setq source (pop stack)
- absolute-source (expand-file-name source emacs-repo-root))
- (if (file-directory-p absolute-source)
- (dolist (file (directory-files absolute-source))
- (unless (member file (list "." ".."))
- (push (concat (file-name-as-directory source) file) stack)))
- (let* ((base (file-name-as-directory base))
- (source-sans-base (substring source (length base)))
- (package-file-name
- (if (archive--core-package-empty-dest-p dest)
- ;; Link to root with its original filename.
- source-sans-base
- (concat
- ;; Prepend the destination, allowing for directory rename.
- (file-name-as-directory dest) source-sans-base))))
- (archive--core-package-link-file
- source package-file-name
- emacs-repo-root package-root exclude-regexp))))))
-
-(defun archive--core-package-sync (definition)
- "Sync core package from DEFINITION."
- (pcase-let*
- ((`(,name . (:core ,file-patterns :excludes ,excludes)) definition)
- (emacs-repo-root (expand-file-name "emacs"))
- (package-root (archive--dirname name "packages"))
- (default-directory package-root)
- (exclude-regexp
- (mapconcat #'identity
- (mapcar #'wildcard-to-regexp
- (append '("*.elc" "*~") excludes nil))
- "\\|"))
- (file-patterns
- (mapcar
- (lambda (file-pattern)
- (pcase file-pattern
- ((pred (stringp)) (cons file-pattern ""))
- (`(,file ,dest . ,_) (cons file dest))
- (_ (error "Unrecognized file format for package %s: %S"
- name file-pattern))))
- (if (stringp file-patterns)
- ;; Files may be just a string, normalize.
- (list file-patterns)
- file-patterns))))
- (message "Linking files for package: %s" name)
- (when (file-directory-p package-root)
- (delete-directory package-root t))
- (make-directory package-root t)
- (dolist (file-pattern file-patterns)
- (pcase-let* ((`(,file . ,dest) file-pattern))
- (if (file-directory-p (expand-file-name file emacs-repo-root))
- (archive--core-package-link-directory
- file dest emacs-repo-root package-root exclude-regexp)
- (archive--core-package-link-file
- file dest emacs-repo-root package-root exclude-regexp))))))
-
-(defun archive-add/remove/update-externals ()
- "Remove non-package directories and fetch external packages."
- (let ((command-line-args-left '("-")))
- (batch-archive-update-worktrees)))
-
-(defun batch-archive-update-worktrees (&rest _)
- (let ((specs (archive--form-from-file-contents "externals-list"))
- (pkgs command-line-args-left)
- (with-core (archive--sync-emacs-repo)))
- (setq command-line-args-left nil)
- (if (equal pkgs '("-")) (setq pkgs (mapcar #'car specs)))
- (dolist (pkg pkgs)
- (let* ((pkg-spec (assoc pkg specs))
- (kind (nth 1 pkg-spec)))
- (pcase kind
- (`:external (archive--external-package-sync pkg-spec))
- (`:core (when with-core (archive--core-package-sync pkg-spec)))
- (_ (if pkg-spec
- (message "Unknown package kind `%S' for %s" kind pkg)
- (message "Unknown package %s" pkg))))))))
-
-;;; Fetch updates from upstream
-
-(defun archive--branch (pkg-spec)
- (or (plist-get (cdr pkg-spec) :branch) "master"))
-
-(defun archive--urtb (pkg-spec)
- "Return our upstream remote tracking branch for PKG-SPEC."
- (format "refs/remotes/upstream/%s/%s" (car pkg-spec)
- (archive--branch pkg-spec)))
-
-(defun archive--ortb (pkg-spec)
- "Return our origin remote tracking branch for PKG-SPEC."
- ;; We can't use the shorthand "origin/externals/%s" when we pass it to
- ;; `git-show-ref'.
- (format "refs/remotes/origin/externals/%s" (car pkg-spec)))
-
-(defun archive--git-branch-p (branch)
- "Return non-nil iff BRANCH is an existing branch."
- (equal 0 (archive--call t "git" "show-ref" "--verify" "--quiet" branch)))
-
-(defun archive--fetch (pkg-spec &optional k)
- (let* ((pkg (car pkg-spec))
- (url (plist-get (cdr pkg-spec) :external))
- (branch (archive--branch pkg-spec))
- (urtb (archive--urtb pkg-spec))
- (refspec (format "refs/heads/%s:%s" branch urtb)))
- (if (not url)
- (message "Missing upstream URL in externals-list for %s" pkg)
- (message "Fetching updates for %s..." pkg)
- (with-temp-buffer
- (cond
- ((not (equal 0 (archive--call t "git" "fetch" "--no-tags"
- url refspec)))
- (message "Fetch error for %s:\n%s" pkg (buffer-string)))
- ((let* ((ortb (archive--ortb pkg-spec))
- (exists (archive--git-branch-p ortb)))
- (not (equal 0 (archive--call t "git" "log"
- (if exists
- (format "%s...%s" ortb urtb)
- urtb)))))
- (message "Log error for %s:\n%s" pkg (buffer-string)))
- ((eq (point-min) (point-max))
- (message "No pending upstream changes for %s" pkg))
- (t (message "%s" (buffer-string))
- (when k (funcall k pkg-spec))))))))
-
-(defun archive--push (pkg-spec)
- (let* ((pkg (car pkg-spec))
- ;; (url (plist-get (cdr pkg-spec) :external))
- ;; (branch (archive--branch pkg-spec))
- (ortb (archive--ortb pkg-spec))
- (urtb (archive--urtb pkg-spec)))
- ;; FIXME: Arrange to merge if it's not a fast-forward.
- (with-temp-buffer
- (cond
- ((zerop (archive--call t "git" "merge-base" "--is-ancestor" urtb ortb))
- (message "Nothing to push for %s" pkg))
- ((and
- (not (zerop (archive--call t "git" "merge-base" "--is-ancestor"
- ortb urtb)))
- (archive--git-branch-p ortb))
- (message "Can't push %s: not a fast-forward" pkg))
- ((not (equal 0 (archive--call t "git" "push" "--set-upstream"
- "origin"
- (format "%s:refs/heads/externals/%s"
- urtb pkg))))
- (message "Fetch error for %s:\n%s" pkg (buffer-string)))
- (t
- (message "Pushed %s successfully:\n%s" pkg (buffer-string))
- (archive--external-package-sync pkg-spec))))))
-
-(defun archive--batch-fetch-and (k)
- (let ((specs (archive--form-from-file-contents "externals-list"))
- (pkgs command-line-args-left))
- (setq command-line-args-left nil)
- (if (equal pkgs '("-")) (setq pkgs (mapcar #'car specs)))
- (dolist (pkg pkgs)
- (let* ((pkg-spec (assoc pkg specs)))
- (if (not pkg-spec) (message "Unknown package: %s" pkg)
- ;; (unless (file-directory-p (expand-file-name pkg "packages"))
- ;; (archive--external-package-sync pkg-spec))
- (archive--fetch pkg-spec k))))))
-
-(defun batch-fetch-and-show (&rest _)
- (archive--batch-fetch-and #'ignore))
-
-(defun batch-fetch-and-push (&rest _)
- (archive--batch-fetch-and #'archive--push))
-
-(provide 'archive-contents)
-;;; archive-contents.el ends here
diff --git a/admin/ert-support.el b/admin/ert-support.el
deleted file mode 100644
index a0ff9ab..0000000
--- a/admin/ert-support.el
+++ /dev/null
@@ -1,55 +0,0 @@
-;; The contents of this file are subject to the GPL License, Version 3.0.
-
-;; Copyright (C) 2016-2017, Free Software Foundation, Inc.
-
-;; This program 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 program 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.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-(defun ert-support-package-install (top-directory package)
- ;; blitz default value and set up from elpa.
- (setq package-archives
- `(("local-elpa"
- . ,(expand-file-name "archive/packages" top-directory)))
- package-user-dir (make-temp-file "elpa-test" t))
- (package-initialize)
- (package-refresh-contents)
- (package-install package))
-
-(defun ert-support-test-find-tests (package-directory package)
- (append
- `(,(expand-file-name
- (concat (symbol-name package) "-autoloads.el") package-directory))
- (or
- (directory-files package-directory t ".*-test.el$")
- (directory-files package-directory t ".*-tests.el$")
- (let ((dir-test (expand-file-name "test" package-directory)))
- (when (file-directory-p dir-test)
- (directory-files dir-test t directory-files-no-dot-files-regexp)))
- (let ((dir-tests (expand-file-name "tests" package-directory)))
- (when (file-directory-p dir-tests)
- (directory-files dir-tests t directory-files-no-dot-files-regexp))))))
-
-(defun ert-support-load-tests (package-directory package)
- (mapc
- (lambda (file)
- (let ((force-load-messages t))
- (load-file file)))
- (ert-support-test-find-tests package-directory package)))
-
-(defun ert-support-test-package (top-directory package)
- (ert-support-package-install top-directory package)
- (ert-support-load-tests
- (expand-file-name (concat "packages/" (symbol-name package)) top-directory)
- package)
-
- (ert-run-tests-batch-and-exit t))
diff --git a/admin/forward-diffs.py b/admin/forward-diffs.py
deleted file mode 100755
index c0c330d..0000000
--- a/admin/forward-diffs.py
+++ /dev/null
@@ -1,438 +0,0 @@
-#!/usr/bin/python
-### forward-diffs.py --- forward emacs-diffs mails to maintainers
-
-## Copyright (C) 2012-2014 Free Software Foundation, Inc.
-
-## Author: Glenn Morris <rgm@gnu.org>
-## Maintainer: emacs-devel@gnu.org
-
-## This program 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 program 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.
-
-## You should have received a copy of the GNU General Public License
-## along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-### Commentary:
-
-## Forward emails from an emacs-diffs style mailing list to the
-## maintainer(s) of the modified files.
-
-## Two modes of operation:
-
-## 1) Create the maintfile (really this is just an optimization):
-## forward-diffs.py --create -p packagesdir -m maintfile
-
-## You can start with an empty maintfile and normal operation in 2)
-## will append information as needed.
-
-## 2) Call from eg procmail to forward diffs. Example usage:
-
-## :0c
-## * ^TO_emacs-elpa-diffs@gnu\.org
-## | forward-diffs.py -p packagedir -m maintfile -l logfile \
-## -o overmaint -s sender
-
-## where
-
-## packagedir = /path/to/packages
-## sender = your email address
-## logfile = file to write log to (you might want to rotate/compress/examine
it)
-## maintfile = file listing files and their maintainers, with format:
-##
-## package1/file1 email1
-## package2/file2 email2,email3
-## package3 email4
-##
-## Use "nomail" for the email field to not send a mail.
-## An entry that is a directory applies to all files in that directory
-## that do not have specific maintainers.
-##
-## overmaint = like maintfile, but takes precedence over it.
-
-### Code:
-
-import optparse
-import sys
-import re
-import email
-import smtplib
-import datetime
-import os
-
-
-## Scan FILE for Author or Maintainer (preferred) headers.
-## Return a list of all email addresses found in MAINTS.
-def scan_file(file, maints):
-
- try:
- fd = open( file, 'r')
- except Exception as err:
- lfile.write('Error opening file %s: %s\n' % (file, str(err)))
- return 1
-
- ## Max number of lines to scan looking for a maintainer.
- ## (20 seems to be the highest at present).
- max_lines = 50
- nline = 0
- cont = 0
- type = ""
-
- for line in fd:
-
- nline += 1
-
- if ( nline > max_lines ): break
-
- ## Try and de-obfuscate. Worth it?
- line = re.sub( '(?i) AT ', '@', line )
- line = re.sub( '(?i) DOT ', '.', line )
-
- if cont: # continued header?
- reg = re.match( ('%s[ \t]+[^:]*?<?([\w.-]+@[\w.-]+)>?' % prefix),
line, re.I )
- if not reg: # not a continued header
- cont = 0
- prefix = ""
- if ( type == "maint" ): break
- type = ""
-
- ## Check for one header immediately after another.
- if not cont:
- reg = re.match( '([^ ]+)? *(Author|Maintainer)s?:
.*?<?([\w.-]+@[\w.-]+)>?', line, re.I )
-
-
- if not reg: continue
-
- if cont:
- email = reg.group(1)
- maints.append(email)
- else:
- cont = 1
- prefix = reg.group(1) or ""
- type = reg.group(2)
- email = reg.group(3)
- type = "maint" if re.search( 'Maintainer', type, re.I ) else "auth"
- ## maints = [] does the wrong thing.
- if type == "maint": del maints[:]
- maints.append(email)
-
- fd.close()
-
-
-## Scan all the files under dir for maintainer information.
-## Write to stdout, or optional argument outfile (which is overwritten).
-def scan_dir(dir, outfile=None):
-
- dir = re.sub( '/+$', '', dir) + '/' # ensure trailing /
-
- if not os.path.isdir(dir):
- sys.stderr.write('No such directory: %s\n' % dir)
- sys.exit(1)
-
- fd = 0
- if outfile:
- try:
- fd = open( outfile, 'w' )
- except Exception as err:
- sys.stderr.write("Error opening `%s': %s\n" % (outfile, str(err)))
- sys.exit(1)
-
-
- for dirpath, dirnames, filenames in os.walk(dir):
- for file in filenames:
- path = os.path.join(dirpath, file)
- maints = []
- scan_file(path, maints)
- ## This would skip printing empty maints.
- ## That would mean we would scan the file each time for no reason.
- ## But empty maintainers are an error at present.
- if not maints: continue
- path = re.sub( '^%s' % dir, '', path )
- string = "%-50s %s\n" % (path, ",".join(maints))
- if fd:
- fd.write(string)
- else:
- print string,
-
- if fd: fd.close()
-
-
-usage="""usage: %prog <-p /path/to/packages> <-m maintfile>
- <-l logfile -s sender|--create> [-o overmaintfile] [--prefix prefix]
- [--sendmail] [--debug]
-Take an emacs-diffs mail on stdin, and forward it to the maintainer(s)."""
-
-parser = optparse.OptionParser()
-parser.set_usage ( usage )
-parser.add_option( "-m", dest="maintfile", default=None,
- help="file listing packages and maintainers")
-parser.add_option( "-l", dest="logfile", default=None,
- help="file to append output to")
-parser.add_option( "-o", dest="overmaintfile", default=None,
- help="override file listing packages and maintainers")
-parser.add_option( "-p", dest="packagedir", default=None,
- help="path to packages directory")
-parser.add_option( "-s", dest="sender", default=None,
- help="sender address for forwards")
-parser.add_option( "--create", dest="create", default=False,
- action="store_true", help="create maintfile")
-parser.add_option( "--no-scan", dest="noscan", default=True,
- action="store_true",
- help="don't scan for maintainers; implies --no-update")
-parser.add_option( "--no-update", dest="noupdate", default=False,
- action="store_true",
- help="do not update the maintfile")
-parser.add_option( "--prefix", dest="prefix", default="packages/",
- help="prefix to remove from modified file name [default:
%default]")
-parser.add_option( "--sendmail", dest="sendmail", default=False,
- action="store_true", help="use sendmail rather than smtp")
-parser.add_option( "--debug", dest="debug", default=False,
- action="store_true", help="debug only, do not send mail")
-
-
-( opts, args ) = parser.parse_args()
-
-
-if not opts.maintfile:
- parser.error('No maintfile specified')
-
-if not opts.packagedir:
- parser.error('No packagedir specified')
-
-if not os.path.isdir(opts.packagedir):
- sys.stderr.write('No such directory: %s\n' % opts.packagedir)
- sys.exit(1)
-
-
-if not opts.create:
- if not opts.logfile:
- parser.error('No logfile specified')
-
- if not opts.sender:
- parser.error('No sender specified')
-
-
-try:
- lfile = open( opts.logfile, 'a' )
-except Exception as err:
- sys.stderr.write('Error opening logfile: %s\n' % str(err))
- sys.exit(1)
-
-
-try:
- mfile = open( opts.maintfile, 'r' )
-except Exception as err:
- lfile.write('Error opening maintfile: %s\n' % str(err))
- sys.exit(1)
-
-## Create the maintfile.
-if opts.create:
- scan_dir( opts.packagedir, opts.maintfile )
- sys.exit()
-
-
-## Each element is package/file: maint1, maint2, ...
-maints = {}
-
-for line in mfile:
- if re.match( '#| *$', line ): continue
- ## FIXME error here if empty maintainer.
- (pfile, maint) = line.split()
- maints[pfile] = maint.split(',')
-
-mfile.close()
-
-
-if opts.overmaintfile:
- try:
- ofile = open( opts.overmaintfile, 'r' )
- except Exception as err:
- lfile.write('Error opening overmaintfile: %s\n' % str(err))
- sys.exit(1)
-
- for line in ofile:
- if re.match( '#| *$', line ): continue
- (pfile, maint) = line.split()
- maints[pfile] = maint.split(',')
-
- ofile.close()
-
-
-stdin = sys.stdin
-
-text = stdin.read()
-
-
-resent_via = 'GNU Emacs diff forwarder'
-
-message = email.message_from_string( text )
-
-(msg_name, msg_from) = email.utils.parseaddr( message['from'] )
-
-lfile.write('\nDate: %s\n' % str(datetime.datetime.now()))
-lfile.write('Message-ID: %s\n' % message['message-id'])
-lfile.write('From: %s\n' % msg_from)
-
-if resent_via == message['x-resent-via']:
- lfile.write('Mail loop; aborting\n')
- sys.exit(1)
-
-
-start = False
-pfiles_seen = []
-maints_seen = []
-
-for line in text.splitlines():
-
- # Look for and process things that look like (Git):
- #
- # Summary of changes:
- # packages/vlf/vlf.el | 2 +-
- # 1 files changed, 1 insertions(+), 1 deletions(-)
- #
- # or things that look like (Git):
- #
- # ---
- # packages/vlf/vlf.el | 2 +-
- # 1 files changed, 1 insertions(+), 1 deletions(-)
-
- #BZR: if re.match( 'modified:$', line ):
- if re.match( '---|Summary of changes:$', line ):
- start = True
- continue
-
- if not start: continue
-
- ## An empty line or a line with non-empty first character.
- if re.match( '( *$|[^ ])', line ): break
- # Any line that doesn't match the diffstat format (Git).
- if not re.match( ' [^ ]+ +\| ', line ):
- lfile.write('Stop scanning at: %s\n' % line)
- break
-
- if opts.prefix:
- #BZR: reg = re.match( '%s([^ ]+)' % opts.prefix, line.strip() )
- reg = re.match( ' %s([^ ]+)' % opts.prefix, line )
- if not reg:
- lfile.write('Skip: %s\n' % line)
- continue
- pfile = reg.group(1)
- else:
- pfile = line.strip()
-
-
- lfile.write('File: %s\n' % pfile)
-
- ## Should not be possible for files (rather than packages)...
- if pfile in pfiles_seen:
- lfile.write('Already seen this file\n')
- continue
-
- pfiles_seen.append(pfile)
-
-
- if not pfile in maints:
-
- lfile.write('Unknown maintainer\n')
-
- if not opts.noscan:
-
- lfile.write('Scanning file...\n')
- thismaint = []
- thisfile = os.path.join( opts.packagedir, pfile )
- # scan_file( thisfile, thismaint )
-
- if thismaint:
- maints[pfile] = thismaint
-
- ## Append maintainer to file.
- if not opts.noupdate:
- try:
- mfile = open( opts.maintfile, 'a' )
- string = "%-50s %s\n" % (pfile, ",".join(thismaint))
- mfile.write(string)
- mfile.close()
- lfile.write('Appended to maintfile\n')
- except Exception as err:
- lfile.write('Error appending to maintfile: %s\n' %
- str(err))
-
- ## Didn't scan, or scanning did not work.
- ## Look for a directory maintainer.
- if not pfile in maints:
- lfile.write('No file maintainer, trying directories...\n')
- while True:
- (pfile, tail) = os.path.split(pfile)
- if not pfile: break
- if pfile in maints: break
-
-
- if not pfile in maints:
- lfile.write('No maintainer, skipping\n')
- continue
-
-
- for maint in maints[pfile]:
-
- lfile.write('Maint: %s\n' % maint)
-
-
- if maint in maints_seen:
- lfile.write('Already seen this maintainer\n')
- continue
-
- maints_seen.append(maint)
-
-
- if maint == "nomail":
- lfile.write('Not resending, no mail is requested\n')
- continue
-
-
- if maint == msg_from:
- lfile.write('Not resending, since maintainer = committer\n')
- continue
-
-
- forward = message
- forward.add_header('X-Resent-Via', resent_via)
- forward.add_header('Resent-To', maint)
- forward.add_header('Resent-From', opts.sender)
-
- lfile.write('Resending via %s...\n' % ('sendmail'
- if opts.sendmail else 'smtp') )
-
-
- if opts.debug: continue
-
-
- if opts.sendmail:
- s = os.popen("/usr/sbin/sendmail -i -f %s %s" %
- (opts.sender, maint), "w")
- s.write(forward.as_string())
- status = s.close()
- if status:
- lfile.write('Sendmail exit status: %s\n' % status)
-
- else:
-
- try:
- s = smtplib.SMTP('localhost')
- except Exception as err:
- lfile.write('Error opening smtp: %s\n' % str(err))
- sys.exit(1)
-
- try:
- s.sendmail(opts.sender, maint, forward.as_string())
- except Exception as err:
- lfile.write('Error sending smtp: %s\n' % str(err))
-
- s.quit()
-
-### forward-diffs.py ends here
diff --git a/admin/hv.sh b/admin/hv.sh
deleted file mode 100644
index 9a45c92..0000000
--- a/admin/hv.sh
+++ /dev/null
@@ -1,47 +0,0 @@
-# hv.sh
-#
-# Author: Thien-Thi Nguyen <ttn@gnu.org>
-# License: Public Domain
-##
-# Usage: version=VERSION ; . hv.sh
-#
-# This file is not executable. Instead, it is meant
-# to be sourced (i.e., "." in sh, or "source" in bash).
-#
-# It sets shell variable ‘me’ to the basename(1) of $0,
-# then checks $1 for either ‘--help’ or ‘--version’.
-#
-# If ‘--help’, it scans $0 for the flush-left comment block w/ form:
-# ##
-# # HELP-TEXT
-# # ...
-# ##
-# formats it to stdout, and exits successfully (status 0). More precisely,
-# the first and last comment lines are ‘##’ (double-hash) and are omitted,
-# as are the ‘#’ (hash) at the beginning of each line. HELP-TEXT can be
-# multiline, including blank lines. It's customary to start HELP-TEXT w/
-# "Usage:" or "Synopsis:", like a manpage, but that is not required.
-#
-# If $1 is ‘--version’, this file displays to stdout
-# PROGNAME VERSION
-# and exits successfully (status 0). PROGNAME and VERSION are the values
-# of the ‘me’ and ‘version’ shell variables, respectively. This is why
-# ‘version’ must be set prior to sourcing the file. If ‘version’ is not
-# set or is the empty string, display "VERSION UNKNOWN" for VERSION.
-#
-# Any other value of $1 is silently ignored.
-##
-
-me=`basename "$0"`
-
-if [ x"$1" = x--help ] ; then
- sed '/^##/,/^##/!d;/^##/d;s/^# //g;s/^#$//g' "$0"
- exit 0
-fi
-
-if [ x"$1" = x--version ] ; then
- echo "$me" "${version:-VERSION UNKNOWN}"
- exit 0
-fi
-
-# hv.sh ends here
diff --git a/admin/update-archive.sh b/admin/update-archive.sh
deleted file mode 100755
index 6560748..0000000
--- a/admin/update-archive.sh
+++ /dev/null
@@ -1,235 +0,0 @@
-#!/bin/sh
-
-# TODO: Author
-
-# This program 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 program 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.
-
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-##
-# Usage: update-archive.sh [options]
-#
-# Update the archive. This involves several steps,
-# some performed in the "buildir" (cwd at invocation),
-# which should be a sibling of the elpa/ dir.
-#
-# Options:
-# --announce EMAIL -- also send announcement to EMAIL address
-# --batch -- write std{out,err} to make.log (in buildir)
-#
-# Preconditions:
-# - Installed software: /usr/sbin/sendmail, git, rsync, make, emacs.
-# - Internet connection (for ‘git pull’, sending mail).
-# - There should be a sibling directory of elpa/: staging/.
-#
-# Gory operation details follow (for maintainers).
-#
-# * Flow (see Cahoots for ‘[N]’)
-#
-# First, in sibling dir ../elpa, fetch changes (via ‘git pull’),
-# set up and update external packages[1], and check copyrights[2].
-# Signal error if any sub-step fails.
-#
-# Back in $buildir, snapshot ../elpa/packages/* as packages/*,
-# excluding some files such as ChangeLog, .git/, *.elc, and so on;
-# refresh the ChangeLog files[3]; wipe and recreate dir archive/[4].
-# Some of these sub-steps signal error on failure.
-#
-# In $buildir/archive/, make emacs-packages-latest.tgz from subdir
-# $buildir/archive/packages/ (unpacking creates ./package/*).
-#
-# In parent dir of $buildir, ensure existence of directories
-# staging/packages/ and staging-old/ -- that is, $buildir has
-# two sibling dirs staging/ and staging-old/ -- and then snapshot
-# staging/* to staging-old/* [which all kind of implies that
-# staging/ is persistent (is not a temporary dir), right? --ttn].
-# To populate staging/packages/ (here, called ‘dst’), iterate over
-# $buildir/archive/packages/* (here, called ‘src’) and do one of:
-# (a) for */archive-contents, *-readme.txt, mv directly
-# (b) if $dst/PV already exists, delete $src/PV
-# (c) mv $src/PV $dst/PV and announce it (if ‘--announce’)
-# Afterwards, mv $buildir/archive/emacs-packages-latest.tgz to staging/
-# and delete $buildir/archive/ (and all its subdirs).
-#
-# Lastly, in ../staging/packages/, make the HTML and readme.txt files[5].
-#
-# * Cahoots
-#
-# These programs are in cahoots w/ update-archive.sh -- here,
-# "lisp" means Emacs Lisp function found in archive-contents.el,
-# and "make" means makefile target found in ../GNUmakefile.
-# [1] lisp ‘archive-add/remove/update-externals’
-# [2] make ‘check_copyrights’
-# [3] lisp ‘archive-prepare-packages’
-# [4] make ‘archive-full’
-# [5] lisp ‘batch-html-make-index’
-#
-# * Miscellaneous
-#
-# "Signal error" means report an error and exit w/ status 1.
-# If invoked w/ ‘--batch’, reporting means mailing the log file
-# to emacs-elpa-diffs (a gnu dot org mailing list) using the
-# error message as title. Otherwise, reporting means displaying
-# the error message to stdout.
-#
-# Mail sender (From) is "ELPA update" w/ bogus address.
-#
-# "Snapshot" means use ‘rsync -av’ (plus other options).
-##
-# [NB: I inferred these from VCS logs. Corrections welcome! --ttn]
-# 0.x -- release from the previous VCS
-# 1.0 -- initial release from this VCS (Git)
-# 1.1 -- add ‘--announce EMAIL’ support
-# 1.2 -- fix externals maintenance
-# 1.3 -- fix ‘--announce EMAIL’ support
-# 1.4 -- use sendmail(8) and rsync(1)
-# 1.5 -- make staging operations less brittle
-# 1.6 -- support ‘--help’, ‘--version’
-# 1.7 -- fix DANGEROUS bug; make less noisy; name bash explicitly
-# 1.8 -- revert "name bash explicitly"
-version='1.8'
-# If $0 is a symlink, `dirname $0`/hv.sh might not be available,
-# and even if it IS available, how can we be sure it's bonafide?
-test -L "$0" || { hv=`dirname "$0"`/hv.sh ; test -r "$hv" && . "$hv" ; }
-
-# TODO: (here) Validate args.
-
-set -x
-
-makelog=""
-buildir="$(pwd)"
-
-announce=no
-a_email="" #info-gnu-emacs@gnu.org
-
-export LANG=C
-while [ $# -gt 0 ]; do
- case "$1" in
- "--announce") announce=yes; a_email="$2"; shift ;;
- "--batch")
- makelog="$(pwd)/make.log"
- exec >"$makelog" 2>&1
- ;;
- esac
- shift
-done
-
-send_mail () {
- to="$1"; shift
- title="$*"
- (cat <<ENDDOC
-From: ELPA update <do.not.reply@elpa.gnu.org>
-To: $to
-Subject: $title
-
-ENDDOC
- cat -) | /usr/sbin/sendmail "$to"
-}
-
-# Send an email to warn about a problem.
-signal_error () {
- title="$*"
- if [ "" = "$makelog" ]; then
- echo "Error: $title"
- else
- send_mail "emacs-elpa-diffs@gnu.org" "$title" <"$makelog"
- fi
- exit 1
-}
-
-announce_new () {
- if [ "yes" != "$announce" ]; then return; fi
- pv="$1"
- pkg="$(echo "$pv" | sed -e 's/^\(.*\)-\([^-]*\)\.[^-.]*$/\1/')"
- ver="$(echo "$pv" | sed -e 's/^\(.*\)-\([^-]*\)\.[^-.]*$/\2/')"
- if [ -z "$pkg" ] || [ -z "$ver" ]; then signal_error "bad PKG-VER: $pv"; fi
- send_mail "$a_email" "[GNU ELPA] $pkg version $ver" <<ENDDOC
-Version $ver of GNU ELPA package $pkg has just been released.
-You can now find it in M-x package-list RET.
-
-More at http://elpa.gnu.org/packages/$pkg.html
-ENDDOC
-}
-
-cd ../elpa || exit
-
-# Fetch changes.
-git pull || signal_error "git pull failed"
-
-# Remember we're inside the "elpa" branch which we don't want to trust,
-# So always refer to the makefile and admins files from $builddir".
-
-# Setup and update externals.
-emacs --batch -l "$buildir/admin/archive-contents.el" \
- -f archive-add/remove/update-externals
-
-make -f "$buildir/GNUmakefile" check_copyrights ||
- signal_error "check_copyright failed"
-
-cd "$buildir" || exit
-
-rsync -av --delete \
- --exclude=ChangeLog \
- --exclude=.git \
- --exclude='*.elc' \
- --exclude='*~' \
- --exclude='/*/*/*-autoloads.el' \
- ../elpa/packages ./
-
-# Refresh the ChangeLog files. This needs to be done in
-# the source tree, because it needs the VCS data!
-emacs -batch -l admin/archive-contents.el \
- -eval '(archive-prepare-packages "../elpa")'
-
-
-rm -rf archive # In case there's one left over!
-make archive-full || {
- signal_error "make archive-full failed"
-}
-latest="emacs-packages-latest.tgz"
-(cd archive || exit
- GZIP=--best tar zcf "$latest" packages)
-(cd ../
- mkdir -p staging/packages
- # Not sure why we have `staging-old', but let's keep it for now.
- mkdir -p staging-old
- rsync -av --inplace --delete staging/. staging-old/.
- # Move new files into place but don't throw out old package versions.
- for f in "$buildir"/archive/packages/*; do
- # PKG-VER
- pv=$(basename "$f")
- dst="staging/packages/$pv"
- # Actually, let's never overwrite an existing version. So changes can
- # be installed without causing a new package to be built until the
- # version field is changed. Some files need to be excluded from the
- # "immutable" policy, most importantly "archive-contents"
- # and "*-readme.txt".
- case $dst in
- */archive-contents | *-readme.txt ) mv "$f" "$dst" ;;
- * ) if [ -r "$dst" ]
- then rm "$f"
- else
- mv "$f" "$dst"
- # FIXME: Add a tag to remember the precise code used.
- announce_new "$pv"
- fi ;;
- esac
- done
- mv "$buildir"/archive/"$latest" staging/
- rm -rf "$buildir"/archive)
-
-# Make the HTML and readme.txt files.
-(cd ../staging/packages || exit
- emacs --batch -l "$buildir"/admin/archive-contents.el \
- --eval '(batch-html-make-index)')
-
-# update-archive.sh ends here