diff options
| author | Stephen Leake | 2018-12-13 14:45:05 -0800 |
|---|---|---|
| committer | Stephen Leake | 2018-12-13 14:45:05 -0800 |
| commit | d4fb2690702fbd348977fc94a9f7a99c00cc3010 (patch) | |
| tree | a55fa60e7401455bb75c91c21b2f7540dd5488f4 | |
| parent | 87bef630bf0f45e8da74e43ba614aa2292b296ef (diff) | |
| download | emacs-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.texi | 33 | ||||
| -rw-r--r-- | lisp/emacs-lisp/package.el | 85 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/package-tests.el | 19 |
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 |
| 252 | file is used as the long description. | 253 | file is used as the long description (overriding any @samp{;;; |
| 254 | Commentary:} 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 |
| 255 | assumed to be an Info directory file made with @command{install-info}. | 257 | assumed 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, |
| 313 | and associated files, are stored. If you want the archive to be | 315 | and associated files, are stored. If you want the archive to be |
| 314 | reachable via HTTP, this directory must be accessible to a web server. | 316 | reachable via HTTP, this directory must be accessible to a web server; |
| 315 | How 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 |
| 394 | with an interface to GNU Privacy Guard, @pxref{Top,, EasyPG, epa, | 396 | with an interface to GNU Privacy Guard, @pxref{Top,, EasyPG, epa, |
| 395 | Emacs EasyPG Assistant Manual}. | 397 | Emacs EasyPG Assistant Manual}. |
| 398 | |||
| 399 | @node Archive Web Server | ||
| 400 | @section Interfacing to an archive web server | ||
| 401 | @cindex archive web server | ||
| 402 | |||
| 403 | A web server providing access to a package archive must support the | ||
| 404 | following queries: | ||
| 405 | |||
| 406 | @table @asis | ||
| 407 | @item archive-contents | ||
| 408 | Return a lisp form describing the archive contents. The form is a list | ||
| 409 | of 'package-desc' structures (see @file{package.el}), except the first | ||
| 410 | element of the list is the archive version. | ||
| 411 | |||
| 412 | @item <package name>-readme.txt | ||
| 413 | Return the long description of the package. | ||
| 414 | |||
| 415 | @item <file name>.sig | ||
| 416 | Return the signature for the file. | ||
| 417 | |||
| 418 | @item <file name> | ||
| 419 | Return the file. This will be the tarball for a multi-file | ||
| 420 | package, 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. | ||
| 2241 | The 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 | ||