diff options
| author | Artur Malabarba | 2015-11-14 15:44:44 +0000 |
|---|---|---|
| committer | Artur Malabarba | 2015-11-14 16:06:01 +0000 |
| commit | e7f2c91bd112306c96643cd9e57b53527742a8db (patch) | |
| tree | 6d45d754f8ad52b899b69af3f43d3dacc7f1a56e | |
| parent | ca947054e25fbc11bf8783166153567dcafdbe6c (diff) | |
| download | emacs-e7f2c91bd112306c96643cd9e57b53527742a8db.tar.gz emacs-e7f2c91bd112306c96643cd9e57b53527742a8db.zip | |
Backport: * lisp/emacs-lisp/package.el: Refactor -with-work-buffer-async.
(package--with-work-buffer-async): Reimplement as
`package--with-response-buffer'.
(package--with-work-buffer): Mark obsolete.
(package--with-response-buffer): New macro. This is a more self
contained and less contrived version of
`package--with-work-buffer-async'. It uses keyword arguments,
doesn't have async on the name, doesn't fallback on
`package--with-work-buffer', and has _much_ simpler error
handling. On master, this macro will soon be part of another
library (either standalone or inside url.el), which is why this
commit is not to be merged back.
(package--check-signature, package--download-one-archive)
(package-install-from-archive, describe-package-1): Use it.
(package--download-and-read-archives): Let
`package--download-one-archive' take care of calling
`package--update-downloads-in-progress'.
| -rw-r--r-- | lisp/emacs-lisp/package.el | 158 |
1 files changed, 76 insertions, 82 deletions
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 2962da5a917..fba07a6801e 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el | |||
| @@ -1124,7 +1124,8 @@ FILE is the name of a file relative to that base location. | |||
| 1124 | This macro retrieves FILE from LOCATION into a temporary buffer, | 1124 | This macro retrieves FILE from LOCATION into a temporary buffer, |
| 1125 | and evaluates BODY while that buffer is current. This work | 1125 | and evaluates BODY while that buffer is current. This work |
| 1126 | buffer is killed afterwards. Return the last value in BODY." | 1126 | buffer is killed afterwards. Return the last value in BODY." |
| 1127 | (declare (indent 2) (debug t)) | 1127 | (declare (indent 2) (debug t) |
| 1128 | (obsolete package--with-response-buffer "25.1")) | ||
| 1128 | `(with-temp-buffer | 1129 | `(with-temp-buffer |
| 1129 | (if (string-match-p "\\`https?:" ,location) | 1130 | (if (string-match-p "\\`https?:" ,location) |
| 1130 | (url-insert-file-contents (concat ,location ,file)) | 1131 | (url-insert-file-contents (concat ,location ,file)) |
| @@ -1134,47 +1135,52 @@ buffer is killed afterwards. Return the last value in BODY." | |||
| 1134 | (insert-file-contents (expand-file-name ,file ,location))) | 1135 | (insert-file-contents (expand-file-name ,file ,location))) |
| 1135 | ,@body)) | 1136 | ,@body)) |
| 1136 | 1137 | ||
| 1137 | (defmacro package--with-work-buffer-async (location file async &rest body) | 1138 | (cl-defmacro package--with-response-buffer (url &rest body &key async file error-form noerror &allow-other-keys) |
| 1138 | "Run BODY in a buffer containing the contents of FILE at LOCATION. | 1139 | "Access URL and run BODY in a buffer containing the response. |
| 1139 | If ASYNC is non-nil, and if it is possible, run BODY | 1140 | Point is after the headers when BODY runs. |
| 1140 | asynchronously. If an error is encountered and ASYNC is a | 1141 | FILE, if provided, is added to URL. |
| 1141 | function, call it with no arguments (instead of executing BODY). | 1142 | URL can be a local file name, which must be absolute. |
| 1142 | If it returns non-nil, or if it wasn't a function, propagate the | 1143 | ASYNC, if non-nil, runs the request asynchronously. |
| 1143 | error. | 1144 | ERROR-FORM is run only if an error occurs. If NOERROR is |
| 1144 | 1145 | non-nil, don't propagate errors caused by the connection or by | |
| 1145 | For a description of the other arguments see | 1146 | BODY (does not apply to errors signaled by ERROR-FORM). |
| 1146 | `package--with-work-buffer'." | 1147 | |
| 1147 | (declare (indent 3) (debug t)) | 1148 | \(fn URL &key ASYNC FILE ERROR-FORM NOERROR &rest BODY)" |
| 1148 | (macroexp-let2* macroexp-copyable-p | 1149 | (declare (indent defun) (debug t)) |
| 1149 | ((async-1 async) | 1150 | (while (keywordp (car body)) |
| 1150 | (file-1 file) | 1151 | (setq body (cdr (cdr body)))) |
| 1151 | (location-1 location)) | 1152 | (macroexp-let2* nil ((url-1 url)) |
| 1152 | `(if (or (not ,async-1) | 1153 | `(cl-macrolet ((wrap-errors (&rest bodyforms) |
| 1153 | (not (string-match-p "\\`https?:" ,location-1))) | 1154 | (let ((err (make-symbol "err"))) |
| 1154 | (package--with-work-buffer ,location-1 ,file-1 ,@body) | 1155 | `(condition-case ,err |
| 1155 | ;; This `condition-case' is to catch connection errors. | 1156 | ,(macroexp-progn bodyforms) |
| 1156 | (condition-case error-signal | 1157 | ,(list 'error ',error-form |
| 1157 | (url-retrieve (concat ,location-1 ,file-1) | 1158 | (list 'unless ',noerror |
| 1158 | ;; This is to catch execution errors. | 1159 | `(signal (car ,err) (cdr ,err)))))))) |
| 1159 | (lambda (status) | 1160 | (if (string-match-p "\\`https?:" ,url-1) |
| 1160 | (condition-case error-signal | 1161 | (let* ((url (concat ,url-1 ,file)) |
| 1161 | (progn | 1162 | (callback (lambda (status) |
| 1162 | (when-let ((er (plist-get status :error))) | 1163 | (let ((b (current-buffer))) |
| 1163 | (error "Error retrieving: %s %S" (concat ,location-1 ,file-1) er)) | 1164 | (unwind-protect (wrap-errors |
| 1164 | (goto-char (point-min)) | 1165 | (when-let ((er (plist-get status :error))) |
| 1165 | (unless (search-forward "\n\n" nil 'noerror) | 1166 | (error "Error retrieving: %s %S" url er)) |
| 1166 | (error "Invalid url response in buffer %s" | 1167 | (unless (search-forward-regexp "^\r?\n\r?" nil 'noerror) |
| 1167 | (current-buffer))) | 1168 | (rest-error 'rest-unintelligible-result)) |
| 1168 | (delete-region (point-min) (point)) | 1169 | (delete-region (point-min) (point)) |
| 1169 | ,@body | 1170 | ,@body) |
| 1170 | (kill-buffer (current-buffer))) | 1171 | (when (buffer-live-p b) |
| 1171 | (error (when (if (functionp ,async-1) (funcall ,async-1) t) | 1172 | (kill-buffer b))))))) |
| 1172 | (signal (car error-signal) (cdr error-signal)))))) | 1173 | (if ,async |
| 1173 | nil | 1174 | (wrap-errors (url-retrieve url callback nil 'silent)) |
| 1174 | 'silent) | 1175 | (let ((buffer (wrap-errors (url-retrieve-synchronously url 'silent)))) |
| 1175 | (error (when (if (functionp ,async-1) (funcall ,async-1) t) | 1176 | (with-current-buffer buffer |
| 1176 | (message "Error contacting: %s" (concat ,location-1 ,file-1)) | 1177 | (funcall callback nil))))) |
| 1177 | (signal (car error-signal) (cdr error-signal)))))))) | 1178 | (wrap-errors (with-temp-buffer |
| 1179 | (let ((url (expand-file-name ,file ,url-1))) | ||
| 1180 | (unless (file-name-absolute-p url) | ||
| 1181 | (error "Location %s is not a url nor an absolute file name" url)) | ||
| 1182 | (insert-file-contents url)) | ||
| 1183 | ,@body)))))) | ||
| 1178 | 1184 | ||
| 1179 | (defun package--check-signature-content (content string &optional sig-file) | 1185 | (defun package--check-signature-content (content string &optional sig-file) |
| 1180 | "Check signature CONTENT against STRING. | 1186 | "Check signature CONTENT against STRING. |
| @@ -1220,15 +1226,12 @@ list can be empty). If the signatures file is not found, | |||
| 1220 | CALLBACK is called with no arguments." | 1226 | CALLBACK is called with no arguments." |
| 1221 | (let ((sig-file (concat file ".sig")) | 1227 | (let ((sig-file (concat file ".sig")) |
| 1222 | (string (or string (buffer-string)))) | 1228 | (string (or string (buffer-string)))) |
| 1223 | (condition-case nil | 1229 | (package--with-response-buffer location :file sig-file |
| 1224 | (package--with-work-buffer-async | 1230 | :async async :noerror t |
| 1225 | location sig-file (when async (or callback t)) | 1231 | :error-form (when callback (funcall callback nil)) |
| 1226 | (let ((sig (package--check-signature-content | 1232 | (let ((sig (package--check-signature-content (buffer-substring (point) (point-max)) string sig-file))) |
| 1227 | (buffer-string) string sig-file))) | 1233 | (when callback (funcall callback sig)) |
| 1228 | (when callback (funcall callback sig)) | 1234 | sig)))) |
| 1229 | sig)) | ||
| 1230 | (file-error (funcall callback))))) | ||
| 1231 | |||
| 1232 | 1235 | ||
| 1233 | ;;; Packages on Archives | 1236 | ;;; Packages on Archives |
| 1234 | ;; The following variables store information about packages available | 1237 | ;; The following variables store information about packages available |
| @@ -1470,7 +1473,9 @@ Once it's empty, run `package--post-download-archives-hook'." | |||
| 1470 | ARCHIVE should be a cons cell of the form (NAME . LOCATION), | 1473 | ARCHIVE should be a cons cell of the form (NAME . LOCATION), |
| 1471 | similar to an entry in `package-alist'. Save the cached copy to | 1474 | similar to an entry in `package-alist'. Save the cached copy to |
| 1472 | \"archives/NAME/FILE\" in `package-user-dir'." | 1475 | \"archives/NAME/FILE\" in `package-user-dir'." |
| 1473 | (package--with-work-buffer-async (cdr archive) file async | 1476 | (package--with-response-buffer (cdr archive) :file file |
| 1477 | :async async | ||
| 1478 | :error-form (package--update-downloads-in-progress archive) | ||
| 1474 | (let* ((location (cdr archive)) | 1479 | (let* ((location (cdr archive)) |
| 1475 | (name (car archive)) | 1480 | (name (car archive)) |
| 1476 | (content (buffer-string)) | 1481 | (content (buffer-string)) |
| @@ -1494,17 +1499,14 @@ similar to an entry in `package-alist'. Save the cached copy to | |||
| 1494 | ;; remove it from the in-progress list. | 1499 | ;; remove it from the in-progress list. |
| 1495 | (package--update-downloads-in-progress archive) | 1500 | (package--update-downloads-in-progress archive) |
| 1496 | (error "Unsigned archive `%s'" name)) | 1501 | (error "Unsigned archive `%s'" name)) |
| 1502 | ;; Either everything worked or we don't mind not signing. | ||
| 1497 | ;; Write out the archives file. | 1503 | ;; Write out the archives file. |
| 1498 | (write-region content nil local-file nil 'silent) | 1504 | (write-region content nil local-file nil 'silent) |
| 1499 | ;; Write out good signatures into archive-contents.signed file. | 1505 | ;; Write out good signatures into archive-contents.signed file. |
| 1500 | (when good-sigs | 1506 | (when good-sigs |
| 1501 | (write-region (mapconcat #'epg-signature-to-string good-sigs "\n") | 1507 | (write-region (mapconcat #'epg-signature-to-string good-sigs "\n") |
| 1502 | nil (concat local-file ".signed") nil 'silent)) | 1508 | nil (concat local-file ".signed") nil 'silent)) |
| 1503 | (package--update-downloads-in-progress archive) | 1509 | (package--update-downloads-in-progress archive)))))))) |
| 1504 | ;; If we got this far, either everything worked or we don't mind | ||
| 1505 | ;; not signing, so tell `package--with-work-buffer-async' to not | ||
| 1506 | ;; propagate errors. | ||
| 1507 | nil))))))) | ||
| 1508 | 1510 | ||
| 1509 | (defun package--download-and-read-archives (&optional async) | 1511 | (defun package--download-and-read-archives (&optional async) |
| 1510 | "Download descriptions of all `package-archives' and read them. | 1512 | "Download descriptions of all `package-archives' and read them. |
| @@ -1517,12 +1519,7 @@ perform the downloads asynchronously." | |||
| 1517 | :test #'equal)) | 1519 | :test #'equal)) |
| 1518 | (dolist (archive package-archives) | 1520 | (dolist (archive package-archives) |
| 1519 | (condition-case-unless-debug nil | 1521 | (condition-case-unless-debug nil |
| 1520 | (package--download-one-archive | 1522 | (package--download-one-archive archive "archive-contents" async) |
| 1521 | archive "archive-contents" | ||
| 1522 | ;; Called if the async download fails | ||
| 1523 | (when async | ||
| 1524 | ;; The t at the end means to propagate connection errors. | ||
| 1525 | (lambda () (package--update-downloads-in-progress archive) t))) | ||
| 1526 | (error (message "Failed to download `%s' archive." | 1523 | (error (message "Failed to download `%s' archive." |
| 1527 | (car archive)))))) | 1524 | (car archive)))))) |
| 1528 | 1525 | ||
| @@ -1777,7 +1774,7 @@ if all the in-between dependencies are also in PACKAGE-LIST." | |||
| 1777 | (let* ((location (package-archive-base pkg-desc)) | 1774 | (let* ((location (package-archive-base pkg-desc)) |
| 1778 | (file (concat (package-desc-full-name pkg-desc) | 1775 | (file (concat (package-desc-full-name pkg-desc) |
| 1779 | (package-desc-suffix pkg-desc)))) | 1776 | (package-desc-suffix pkg-desc)))) |
| 1780 | (package--with-work-buffer location file | 1777 | (package--with-response-buffer location :file file |
| 1781 | (if (or (not package-check-signature) | 1778 | (if (or (not package-check-signature) |
| 1782 | (member (package-desc-archive pkg-desc) | 1779 | (member (package-desc-archive pkg-desc) |
| 1783 | package-unsigned-archives)) | 1780 | package-unsigned-archives)) |
| @@ -2368,26 +2365,23 @@ Otherwise no newline is inserted." | |||
| 2368 | (replace-match "")) | 2365 | (replace-match "")) |
| 2369 | (while (re-search-forward "^\\(;+ ?\\)" nil t) | 2366 | (while (re-search-forward "^\\(;+ ?\\)" nil t) |
| 2370 | (replace-match "")))) | 2367 | (replace-match "")))) |
| 2371 | (let ((readme (expand-file-name (format "%s-readme.txt" name) | 2368 | (let* ((basename (format "%s-readme.txt" name)) |
| 2372 | package-user-dir)) | 2369 | (readme (expand-file-name basename package-user-dir)) |
| 2373 | readme-string) | 2370 | readme-string) |
| 2374 | ;; For elpa packages, try downloading the commentary. If that | 2371 | ;; For elpa packages, try downloading the commentary. If that |
| 2375 | ;; fails, try an existing readme file in `package-user-dir'. | 2372 | ;; fails, try an existing readme file in `package-user-dir'. |
| 2376 | (cond ((condition-case nil | 2373 | (cond ((and (package-desc-archive desc) |
| 2377 | (save-excursion | 2374 | (package--with-response-buffer (package-archive-base desc) |
| 2378 | (package--with-work-buffer | 2375 | :file basename :noerror t |
| 2379 | (package-archive-base desc) | 2376 | (save-excursion |
| 2380 | (format "%s-readme.txt" name) | 2377 | (goto-char (point-max)) |
| 2381 | (save-excursion | 2378 | (unless (bolp) |
| 2382 | (goto-char (point-max)) | 2379 | (insert ?\n))) |
| 2383 | (unless (bolp) | 2380 | (write-region nil nil |
| 2384 | (insert ?\n))) | 2381 | (expand-file-name readme package-user-dir) |
| 2385 | (write-region nil nil | 2382 | nil 'silent) |
| 2386 | (expand-file-name readme package-user-dir) | 2383 | (setq readme-string (buffer-string)) |
| 2387 | nil 'silent) | 2384 | t)) |
| 2388 | (setq readme-string (buffer-string)) | ||
| 2389 | t)) | ||
| 2390 | (error nil)) | ||
| 2391 | (insert readme-string)) | 2385 | (insert readme-string)) |
| 2392 | ((file-readable-p readme) | 2386 | ((file-readable-p readme) |
| 2393 | (insert-file-contents readme) | 2387 | (insert-file-contents readme) |