branch: elpa/package-lint
commit 84ba63ca9668f6a1ffd8fa7e66792037a19e5d81
Author: Steve Purcell <st...@sanityinc.com>
Commit: Steve Purcell <st...@sanityinc.com>

    Support multi-line headers, and report errors at the header value loc, not 
eol
---
 package-lint-test.el |  6 ++--
 package-lint.el      | 99 ++++++++++++++++++++++++++++------------------------
 2 files changed, 56 insertions(+), 49 deletions(-)

diff --git a/package-lint-test.el b/package-lint-test.el
index daf631e79a..d01c3b18a9 100644
--- a/package-lint-test.el
+++ b/package-lint-test.el
@@ -153,7 +153,7 @@ headers and provide form."
 (ert-deftest package-lint-test-warn-no-standard-keyword ()
   (should
    (equal
-    '((6 3 warning "You should include standard keywords: see the variable 
`finder-known-keywords'."))
+    '((6 13 warning "You should include standard keywords: see the variable 
`finder-known-keywords'."))
     (package-lint-test--run ";; Keywords: foo"))))
 
 (ert-deftest package-lint-test-no-warning-if-at-least-one-standard-keyword ()
@@ -342,11 +342,11 @@ Alternatively, depend on (emacs \"24.3\") or greater, in 
which cl-lib is bundled
 (ert-deftest package-lint-test-warning-cl-lib-not-needed ()
   (should
    (member
-    '(6 52 warning "An explicit dependency on cl-lib <= 1.0 is not needed on 
Emacs >= 24.3.")
+    '(6 21 warning "An explicit dependency on cl-lib <= 1.0 is not needed on 
Emacs >= 24.3.")
     (package-lint-test--run ";; Package-Requires: ((emacs \"25.1\") (cl-lib 
\"1.0\"))")))
   (should
    (member
-    '(6 52 warning "An explicit dependency on cl-lib <= 1.0 is not needed on 
Emacs >= 24.3.")
+    '(6 21 warning "An explicit dependency on cl-lib <= 1.0 is not needed on 
Emacs >= 24.3.")
     (package-lint-test--run ";; Package-Requires: ((emacs \"24.3\") (cl-lib 
\"0.5\"))"))))
 
 (ert-deftest package-lint-test-warning-cl ()
diff --git a/package-lint.el b/package-lint.el
index 23a96a5dca..1d87188b51 100644
--- a/package-lint.el
+++ b/package-lint.el
@@ -392,7 +392,7 @@ Instead it should use `user-emacs-directory' or 
`locate-user-emacs-file'."
 (defun package-lint--check-keywords-list ()
   "Verify that package keywords are listed in `finder-known-keywords'."
   (when (package-lint--goto-header "Keywords")
-    (let ((err-pos (match-beginning 2)))
+    (let ((err-pos (point)))
       (let ((keywords (lm-keywords-list)))
         (unless (cl-some (lambda (keyword) (assoc (intern keyword) 
finder-known-keywords)) keywords)
           (package-lint--error-at-point
@@ -403,18 +403,15 @@ Instead it should use `user-emacs-directory' or 
`locate-user-emacs-file'."
 (defun package-lint--check-url-header ()
   "Verify that the package has an HTTPS or HTTP Homepage/URL header."
   (if (package-lint--goto-header "\\(?:URL\\|Homepage\\)")
-      (let ((url (match-string 3))
-            (url-start (match-beginning 3)))
-        (when (string-match-p "^<.*>$" url)
-          (setq url (substring url 1 -1)
-                url-start (1+ url-start))
-          (backward-char 1))
-        (unless (and (equal (thing-at-point 'url) url)
-                     (string-match-p "^https?://" url))
-          (package-lint--error-at-point
-           'error
-           "Package URLs should be a single HTTPS or HTTP URL."
-           url-start)))
+      (progn
+        (when (looking-at "<.*>$")
+          (forward-char 1))
+        (let ((url (thing-at-point 'url)))
+          (unless (and url (string-match-p "^https?://" url))
+            (package-lint--error-at-point
+             'error
+             "Package URLs should be a single HTTPS or HTTP URL."
+             (point)))))
     (package-lint--error-at-bob
      'error
      "Package should have a Homepage or URL header.")))
@@ -423,27 +420,27 @@ Instead it should use `user-emacs-directory' or 
`locate-user-emacs-file'."
   "Check the contents of the \"Package-Requires\" header.
 Return a list of well-formed dependencies, same as
 `package-lint--check-well-formed-dependencies'."
-  (when (package-lint--goto-header "Package-Requires")
-    (let ((position (match-beginning 3))
-          (deps (match-string 3)))
-      (condition-case err
-          (pcase-let ((`(,parsed-deps . ,parse-end-pos) (read-from-string 
deps)))
-            (unless (= parse-end-pos (length deps))
-              (package-lint--error-at-bol
-               'error
-               "More than one expression provided."))
-            (let ((deps (package-lint--check-well-formed-dependencies position 
parsed-deps)))
-              (package-lint--check-emacs-version deps)
-              (package-lint--check-packages-installable deps)
-              (package-lint--check-deps-use-non-snapshot-version deps)
-              (package-lint--check-deps-do-not-use-zero-versions deps)
-              (package-lint--check-cl-lib-version deps)
-              deps))
-        (error
-         (package-lint--error-at-bol
-          'error
-          (format "Couldn't parse \"Package-Requires\" header: %s" 
(error-message-string err)))
-         nil)))))
+  (let ((deps (package-lint--goto-header "Package-Requires")))
+    (when deps
+      (let ((position (point)))
+        (condition-case err
+            (pcase-let ((`(,parsed-deps . ,parse-end-pos) (read-from-string 
deps)))
+              (unless (= parse-end-pos (length deps))
+                (package-lint--error-at-bol
+                 'error
+                 "More than one expression provided."))
+              (let ((deps (package-lint--check-well-formed-dependencies 
position parsed-deps)))
+                (package-lint--check-emacs-version deps)
+                (package-lint--check-packages-installable deps)
+                (package-lint--check-deps-use-non-snapshot-version deps)
+                (package-lint--check-deps-do-not-use-zero-versions deps)
+                (package-lint--check-cl-lib-version deps)
+                deps))
+          (error
+           (package-lint--error-at-bol
+            'error
+            (format "Couldn't parse \"Package-Requires\" header: %s" 
(error-message-string err)))
+           nil))))))
 
 (defun package-lint--check-well-formed-dependencies (position parsed-deps)
   "Check that dependencies listed at POSITION are well-formed.
@@ -848,7 +845,7 @@ Alternatively, depend on (emacs \"24.3\") or greater, in 
which cl-lib is bundled
           (package-lint--error-at-point
            'warning
            (format "\"%s\" is not a valid version. MELPA will handle this, but 
other archives will not." version)
-           (match-beginning 3)))
+           (point)))
       (package-lint--error-at-bob
        'warning
        "\"Version:\" or \"Package-Version:\" header is missing. MELPA will 
handle this, but other archives will not."))))
@@ -1153,18 +1150,28 @@ Lines consisting only of whitespace or empty comments 
are considered empty."
                    (lambda (v1 v2) (not (version-list-< v1 v2)))))
       (aref descriptors 0))))
 
-(defun package-lint--goto-header (header-name)
+(defun package-lint--goto-header (header-name &optional multiline)
   "Move to the first occurrence of HEADER-NAME in the file.
-If the return value is non-nil, then point will be at the end of
-the file, and the second and third match groups will contain the name and
-value of the header with any leading or trailing whitespace removed."
-  (let ((initial-point (point)))
-    (goto-char (point-min))
-    (let ((case-fold-search t))
-      (if (re-search-forward (concat (lm-get-header-re header-name) "\\(.*?\\) 
*$") nil t)
-          (match-string-no-properties 3)
-        (goto-char initial-point)
-        nil))))
+If the return value is non-nil, then point will be at the
+beginning of the header's value, and the second and third match
+groups will contain the name and value of the header with any
+leading or trailing whitespace removed.
+
+If MULTILINE is non-nil, allow the header value to span lines, and return
+them as a list of strings."
+  (goto-char (point-min))
+  (when (re-search-forward (concat (lm-get-header-re header-name) "\\(.*?\\) 
*$") (lm-code-mark) t)
+    (let ((start-pos (match-beginning 3))
+          (val (match-string-no-properties 3)))
+      (when multiline
+        (setq val (list val))
+        (forward-line 1)
+        (while (looking-at "^;+\\(\t\\|[\t\s]\\{2,\\}\\)\\(.+\\)")
+          (push (match-string-no-properties 2) val)
+          (forward-line 1))
+        (nreverse val))
+      (goto-char start-pos)
+      val)))
 
 (defun package-lint--update-or-insert-version (version)
   "Ensure current buffer has a \"Version: VERSION\" header."

Reply via email to