emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] elpa-admin 7e5b75b 1/2: * elpa-admin.el: Add support for checking


From: Stefan Monnier
Subject: [elpa] elpa-admin 7e5b75b 1/2: * elpa-admin.el: Add support for checking copyright notices
Date: Fri, 11 Dec 2020 13:50:51 -0500 (EST)

branch: elpa-admin
commit 7e5b75b0b0807f914ccecb8265d6e3d005dd4dc2
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>

    * elpa-admin.el: Add support for checking copyright notices
    
    (elpaa--copyright-file): New variable.
    (elpaa--copyright-check): New function.
    (elpaa--make-one-tarball): Use it.
    (elpaa--copyright-filter, elpaa--copyright-collect)
    (elpaa--copyright-files, elpaa-batch-copyright-check): New functions.
---
 GNUmakefile   | 47 +++++-------------------------
 README        |  6 +++-
 elpa-admin.el | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 103 insertions(+), 43 deletions(-)

diff --git a/GNUmakefile b/GNUmakefile
index 3f02588..d9fe616 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -3,50 +3,16 @@
 
 EMACS=emacs --batch
 
-.PHONY: archive-tmp changelogs process-archive archive-full org-fetch clean 
all do-it
-
+.PHONY: all
 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)~"
-
-.PHONY: check/%
+.PHONY: check/% check-all
+check-all: check/-
 check/%:
-       @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;                                                      \
-       cat ../$(CR_EXCEPTIONS) ../$(CR_EXCEPTIONS)) | sort | uniq -u
+       $(EMACS) -l $(CURDIR)/admin/elpa-admin.el       \
+                -f elpaa-batch-copyright-check $*
 
+.PHONY: build/% build-all
 build/%:
        $(EMACS) -l $(CURDIR)/admin/elpa-admin.el       \
                 -f elpaa-batch-make-one-package $*
@@ -55,6 +21,7 @@ build-all:
        $(EMACS) -l $(CURDIR)/admin/elpa-admin.el       \
                 -f elpaa-batch-make-all-packages
 
+.PHONY: clean
 clean:
 #      rm -rf archive $(ARCHIVE_TMP)
        rm -f packages/*/*-autoloads.el
diff --git a/README b/README
index 6dcf846..0cc8fd9 100644
--- a/README
+++ b/README
@@ -19,7 +19,11 @@ This code expects to be used in a directory that has the 
following layout:
 - =admin/=              -- Directory containing a copy of the here files
 - =GNUmakefile=         -- A copy of or symlink to =admin/GNUmakefile=
 - =externals-list=      -- The specifications of the packages
-  
+- =copyright_exceptions= -- List of exceptions for the copyright-notices checks
+
+The =copyright_exceptions= file can be absent, in which case copyright notices
+will simply not be checked.
+
 Additionally to the above, this code will then add to that directory
 the following elements:
 
diff --git a/elpa-admin.el b/elpa-admin.el
index e8918ee..9e99ae0 100644
--- a/elpa-admin.el
+++ b/elpa-admin.el
@@ -22,7 +22,6 @@
 ;;;; TODO
 
 ;; 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
@@ -37,7 +36,7 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl-lib))
+(require 'cl-lib)
 (require 'lisp-mnt)
 (require 'package)
 
@@ -54,6 +53,7 @@
 (defconst elpaa--release-branch-prefix "externals-release/")
 
 (defconst elpaa--specs-file "externals-list")
+(defconst elpaa--copyright-file "copyright_exceptions")
 
 (defvar elpaa--debug t)
 (defun elpaa--message (&rest args)
@@ -256,6 +256,7 @@ Return non-nil if a new tarball was created."
       (delete-file (expand-file-name (format "%s-pkg.el" pkgname) dir))
       (when revision-function
         (elpaa--select-revision dir pkg-spec (funcall revision-function)))
+      (elpaa--copyright-check)
       ;; FIXME: Build Info files and corresponding `dir' file.
       (elpaa--write-pkg-file dir pkgname metadata)
       ;; FIXME: Allow renaming files or selecting a subset of the files!
@@ -1121,6 +1122,94 @@ If WITH-CORE is non-nil, it means we manage :core 
packages as well."
                  (message "Unknown package kind `%S' for %s" kind pkg)
                (message "Unknown package %s" pkg))))))))
 
+;;; Check copyrights
+
+(defun elpaa--copyright-files (pkg-spec)
+  "Return the list of ELisp files in the package PKG-SPEC."
+  (let* ((pkgname (car pkg-spec))
+         (default-directory (elpaa--dirname pkgname "packages"))
+         (ignores (elpaa--spec-get pkg-spec :ignored-files))
+         (all-ignores '("." ".." ".git" "test" ".dir-locals.el"))
+         (dir-files (lambda (d)
+                      (cl-set-difference (directory-files d)
+                                         all-ignores :test #'equal)))
+         (pending (cl-set-difference
+                   (funcall dir-files ".")
+                   (list (concat pkgname "-pkg.el")
+                         (concat pkgname "-autoloads.el"))
+                   :test #'equal))
+         (files '()))
+    (while pending
+      (pcase (pop pending)
+        ((pred (lambda (f) (member f ignores))))
+        ((pred file-symlink-p))
+        ((and (pred file-directory-p) d)
+         (setq pending (nconc (mapcar (lambda (f) (concat d "/" f))
+                                      (funcall dir-files d))
+                              pending)))
+        ((and (pred (string-match "\\.el\\'")) f)
+         (push f files))))
+    files))
+
+(defun elpaa--copyright-collect (pkg-spec)
+  ;; This is crude but is only meant to catch the all too common mistakes where
+  ;; we forget to update the copyright information after transferring the
+  ;; copyright to the FSF.
+  (with-temp-buffer
+    (let* ((pkgname (car pkg-spec))
+           (files (mapcar (lambda (f) (concat pkgname "/" f))
+                          (elpaa--copyright-files pkg-spec)))
+           (default-directory (elpaa--dirname "packages")))
+      ;; Look for ELisp files which omit a copyright line for the FSF.
+      (apply #'elpaa--call t "grep" "-L" "Free Software Foundation, Inc" files)
+      ;; Look for *other* lines attributing copyright to someone else.
+      (dolist (file files)
+        (elpaa--call t "sed" "-n"
+                     "-e" "/[Cc]opyright.*, *[1-9][-0-9]*,\\?$/N"
+                     "-e" "/Free Software Foundation/d"
+                     ;; FIXME: This tends to suffer from misc false positives.
+                     "-e" (format "s|^\\(.*;.*[Cc]opyright\\)|%s:\\1|p"
+                                  (replace-regexp-in-string "|" "_" file))
+                     file)))
+    (sort-lines nil (point-min) (point-max))
+    (buffer-string)))
+
+(defun elpaa--copyright-filter (collected)
+  (let ((res '()))
+    (with-current-buffer (find-file-noselect elpaa--copyright-file)
+      (dolist (line (split-string collected "\n" t))
+        (goto-char (point-min))
+        (unless (re-search-forward (concat "^" (regexp-quote line) "$") nil t)
+          (push line res))))
+    res))
+
+(defun elpaa--copyright-check (pkg-name)
+  "Check the copyright notices, if applicable."
+  (when (file-readable-p elpaa--copyright-file)
+    (let* ((collected (elpaa--copyright-collect pkg-name))
+           (filtered (elpaa--copyright-filter collected)))
+      (when filtered
+        (message "Problem with copyright notices:\n%s"
+                 (mapconcat (lambda (line)
+                              (if (string-match ":" line) line
+                                (concat "Missing copyright notice in " line)))
+                            filtered "\n"))
+        (error "Abort")))))
+
+(defun elpaa-batch-copyright-check (&rest _)
+  (let ((specs (elpaa--get-specs))
+        (pkgs command-line-args-left))
+    (setq command-line-args-left nil)
+    (when (equal pkgs '("-"))
+      (setq pkgs (delq nil (mapcar (lambda (spec)
+                                     (when (file-directory-p
+                                            (elpaa--dirname (car spec)
+                                                            "packages"))
+                                       (car spec)))
+                                   specs))))
+    (dolist (pkg pkgs)
+      (elpaa--copyright-check (assoc pkg specs)))))
+
 ;;; Fetch updates from upstream
 
 (defun elpaa--branch (pkg-spec)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]