aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Leake2018-12-13 14:45:05 -0800
committerStephen Leake2018-12-13 14:45:05 -0800
commitd4fb2690702fbd348977fc94a9f7a99c00cc3010 (patch)
treea55fa60e7401455bb75c91c21b2f7540dd5488f4
parent87bef630bf0f45e8da74e43ba614aa2292b296ef (diff)
downloademacs-d4fb2690702fbd348977fc94a9f7a99c00cc3010.tar.gz
emacs-d4fb2690702fbd348977fc94a9f7a99c00cc3010.zip
Get long package description for installed packages from installed files
* doc/lispref/package.texi (Archive Web Server): New; document web server interface. * lisp/emacs-lisp/package.el (package--get-description): New; get long description from installed files. (describe-package-1): Use it, improve comments. No longer writing NAME-readme.txt. * test/lisp/emacs-lisp/package-tests.el: (package-test-describe-package): There is now a description for an installed package. (package-test-describe-installed-multi-file-package): New test.
-rw-r--r--doc/lispref/package.texi33
-rw-r--r--lisp/emacs-lisp/package.el85
-rw-r--r--test/lisp/emacs-lisp/package-tests.el19
3 files changed, 109 insertions, 28 deletions
diff --git a/doc/lispref/package.texi b/doc/lispref/package.texi
index 37c1ee6697d..730decc378d 100644
--- a/doc/lispref/package.texi
+++ b/doc/lispref/package.texi
@@ -22,6 +22,7 @@ user-level features of the packaging system.
22* Simple Packages:: How to package a single .el file. 22* Simple Packages:: How to package a single .el file.
23* Multi-file Packages:: How to package multiple files. 23* Multi-file Packages:: How to package multiple files.
24* Package Archives:: Maintaining package archives. 24* Package Archives:: Maintaining package archives.
25* Archive Web Server:: Interfacing to an archive web server.
25@end menu 26@end menu
26 27
27@node Packaging Basics 28@node Packaging Basics
@@ -249,7 +250,8 @@ dependency's version (a string).
249@end defun 250@end defun
250 251
251 If the content directory contains a file named @file{README}, this 252 If the content directory contains a file named @file{README}, this
252file is used as the long description. 253file is used as the long description (overriding any @samp{;;;
254Commentary:} section).
253 255
254 If the content directory contains a file named @file{dir}, this is 256 If the content directory contains a file named @file{dir}, this is
255assumed to be an Info directory file made with @command{install-info}. 257assumed to be an Info directory file made with @command{install-info}.
@@ -311,8 +313,8 @@ access. Such local archives are mainly useful for testing.
311 313
312 A package archive is simply a directory in which the package files, 314 A package archive is simply a directory in which the package files,
313and associated files, are stored. If you want the archive to be 315and associated files, are stored. If you want the archive to be
314reachable via HTTP, this directory must be accessible to a web server. 316reachable via HTTP, this directory must be accessible to a web server;
315How to accomplish this is beyond the scope of this manual. 317@xref{Archive Web Server}.
316 318
317 A convenient way to set up and update a package archive is via the 319 A convenient way to set up and update a package archive is via the
318@code{package-x} library. This is included with Emacs, but not loaded 320@code{package-x} library. This is included with Emacs, but not loaded
@@ -393,3 +395,28 @@ manual. For more information on cryptographic keys and signing,
393@pxref{Top,, GnuPG, gnupg, The GNU Privacy Guard Manual}. Emacs comes 395@pxref{Top,, GnuPG, gnupg, The GNU Privacy Guard Manual}. Emacs comes
394with an interface to GNU Privacy Guard, @pxref{Top,, EasyPG, epa, 396with an interface to GNU Privacy Guard, @pxref{Top,, EasyPG, epa,
395Emacs EasyPG Assistant Manual}. 397Emacs EasyPG Assistant Manual}.
398
399@node Archive Web Server
400@section Interfacing to an archive web server
401@cindex archive web server
402
403A web server providing access to a package archive must support the
404following queries:
405
406@table @asis
407@item archive-contents
408Return a lisp form describing the archive contents. The form is a list
409of 'package-desc' structures (see @file{package.el}), except the first
410element of the list is the archive version.
411
412@item <package name>-readme.txt
413Return the long description of the package.
414
415@item <file name>.sig
416Return the signature for the file.
417
418@item <file name>
419Return the file. This will be the tarball for a multi-file
420package, or the single file for a simple package.
421
422@end table
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index dcede1a5b27..1752c7e9fe0 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -2123,6 +2123,9 @@ If NOSAVE is non-nil, the package is not removed from
2123 (add-hook 'post-command-hook #'package-menu--post-refresh) 2123 (add-hook 'post-command-hook #'package-menu--post-refresh)
2124 (delete-directory dir t) 2124 (delete-directory dir t)
2125 ;; Remove NAME-VERSION.signed and NAME-readme.txt files. 2125 ;; Remove NAME-VERSION.signed and NAME-readme.txt files.
2126 ;;
2127 ;; NAME-readme.txt files are no longer created, but they
2128 ;; may be left around from an earlier install.
2126 (dolist (suffix '(".signed" "readme.txt")) 2129 (dolist (suffix '(".signed" "readme.txt"))
2127 (let* ((version (package-version-join (package-desc-version pkg-desc))) 2130 (let* ((version (package-version-join (package-desc-version pkg-desc)))
2128 (file (concat (if (string= suffix ".signed") 2131 (file (concat (if (string= suffix ".signed")
@@ -2233,6 +2236,45 @@ Otherwise no newline is inserted."
2233 2236
2234(declare-function lm-commentary "lisp-mnt" (&optional file)) 2237(declare-function lm-commentary "lisp-mnt" (&optional file))
2235 2238
2239(defun package--get-description (desc)
2240 "Return a string containing the long description of the package DESC.
2241The description is read from the installed package files."
2242 ;; Installed packages have nil for kind, so we look for README
2243 ;; first, then fall back to the Commentary header.
2244
2245 ;; We don’t include README.md here, because that is often the home
2246 ;; page on a site like github, and not suitable as the package long
2247 ;; description.
2248 (let ((files '("README-elpa" "README-elpa.md" "README" "README.rst" "README.org"))
2249 file
2250 (srcdir (package-desc-dir desc))
2251 result)
2252 (while (and files
2253 (not result))
2254 (setq file (pop files))
2255 (when (file-readable-p (expand-file-name file srcdir))
2256 ;; Found a README.
2257 (with-temp-buffer
2258 (insert-file-contents (expand-file-name file srcdir))
2259 (setq result (buffer-string)))))
2260
2261 (or
2262 result
2263
2264 ;; Look for Commentary header.
2265 (let ((mainsrcfile (expand-file-name (format "%s.el" (package-desc-name desc))
2266 srcdir)))
2267 (when (file-readable-p mainsrcfile)
2268 (with-temp-buffer
2269 (insert (or (lm-commentary mainsrcfile) ""))
2270 (goto-char (point-min))
2271 (when (re-search-forward "^;;; Commentary:\n" nil t)
2272 (replace-match ""))
2273 (while (re-search-forward "^\\(;+ ?\\)" nil t)
2274 (replace-match ""))
2275 (buffer-string))))
2276 )))
2277
2236(defun describe-package-1 (pkg) 2278(defun describe-package-1 (pkg)
2237 (require 'lisp-mnt) 2279 (require 'lisp-mnt)
2238 (let* ((desc (or 2280 (let* ((desc (or
@@ -2406,7 +2448,8 @@ Otherwise no newline is inserted."
2406 (insert "\n") 2448 (insert "\n")
2407 2449
2408 (if built-in 2450 (if built-in
2409 ;; For built-in packages, insert the commentary. 2451 ;; For built-in packages, get the description from the
2452 ;; Commentary header.
2410 (let ((fn (locate-file (format "%s.el" name) load-path 2453 (let ((fn (locate-file (format "%s.el" name) load-path
2411 load-file-rep-suffixes)) 2454 load-file-rep-suffixes))
2412 (opoint (point))) 2455 (opoint (point)))
@@ -2417,27 +2460,25 @@ Otherwise no newline is inserted."
2417 (replace-match "")) 2460 (replace-match ""))
2418 (while (re-search-forward "^\\(;+ ?\\)" nil t) 2461 (while (re-search-forward "^\\(;+ ?\\)" nil t)
2419 (replace-match "")))) 2462 (replace-match ""))))
2420 (let* ((basename (format "%s-readme.txt" name)) 2463
2421 (readme (expand-file-name basename package-user-dir)) 2464 (if (package-installed-p desc)
2422 readme-string) 2465 ;; For installed packages, get the description from the installed files.
2423 ;; For elpa packages, try downloading the commentary. If that 2466 (insert (package--get-description desc))
2424 ;; fails, try an existing readme file in `package-user-dir'. 2467
2425 (cond ((and (package-desc-archive desc) 2468 ;; For non-built-in, non-installed packages, get description from the archive.
2426 (package--with-response-buffer (package-archive-base desc) 2469 (let* ((basename (format "%s-readme.txt" name))
2427 :file basename :noerror t 2470 readme-string)
2428 (save-excursion 2471
2429 (goto-char (point-max)) 2472 (package--with-response-buffer (package-archive-base desc)
2430 (unless (bolp) 2473 :file basename :noerror t
2431 (insert ?\n))) 2474 (save-excursion
2432 (write-region nil nil 2475 (goto-char (point-max))
2433 (expand-file-name readme package-user-dir) 2476 (unless (bolp)
2434 nil 'silent) 2477 (insert ?\n)))
2435 (setq readme-string (buffer-string)) 2478 (setq readme-string (buffer-string))
2436 t)) 2479 t)
2437 (insert readme-string)) 2480 (insert readme-string))
2438 ((file-readable-p readme) 2481 ))))
2439 (insert-file-contents readme)
2440 (goto-char (point-max))))))))
2441 2482
2442(defun package-install-button-action (button) 2483(defun package-install-button-action (button)
2443 (let ((pkg-desc (button-get button 'package-desc))) 2484 (let ((pkg-desc (button-get button 'package-desc)))
diff --git a/test/lisp/emacs-lisp/package-tests.el b/test/lisp/emacs-lisp/package-tests.el
index f08bc92ff2a..17431f31f85 100644
--- a/test/lisp/emacs-lisp/package-tests.el
+++ b/test/lisp/emacs-lisp/package-tests.el
@@ -435,11 +435,24 @@ Must called from within a `tar-mode' buffer."
435 (save-excursion (should (search-forward "Summary: A single-file package with no dependencies" nil t))) 435 (save-excursion (should (search-forward "Summary: A single-file package with no dependencies" nil t)))
436 (save-excursion (should (search-forward "Homepage: http://doodles.au" nil t))) 436 (save-excursion (should (search-forward "Homepage: http://doodles.au" nil t)))
437 (save-excursion (should (re-search-forward "Keywords: \\[?frobnicate\\]?" nil t))) 437 (save-excursion (should (re-search-forward "Keywords: \\[?frobnicate\\]?" nil t)))
438 ;; No description, though. Because at this point we don't know 438 (save-excursion (should (search-forward "This package provides a minor mode to frobnicate"
439 ;; what archive the package originated from, and we don't have 439 nil t)))
440 ;; its readme file saved.
441 ))) 440 )))
442 441
442(ert-deftest package-test-describe-installed-multi-file-package ()
443 "Test displaying of the readme for installed multi-file package."
444
445 (with-package-test ()
446 (package-initialize)
447 (package-refresh-contents)
448 (package-install 'multi-file)
449 (with-fake-help-buffer
450 (describe-package 'multi-file)
451 (goto-char (point-min))
452 (should (search-forward "Homepage: http://puddles.li" nil t))
453 (should (search-forward "This is a bare-bones readme file for the multi-file"
454 nil t)))))
455
443(ert-deftest package-test-describe-non-installed-package () 456(ert-deftest package-test-describe-non-installed-package ()
444 "Test displaying of the readme for non-installed package." 457 "Test displaying of the readme for non-installed package."
445 458