diff options
| author | Chong Yidong | 2011-03-05 22:22:06 -0500 |
|---|---|---|
| committer | Chong Yidong | 2011-03-05 22:22:06 -0500 |
| commit | f561e49a25cace5e6d3cf3b222d87fa483226f76 (patch) | |
| tree | dac80a926beb01ee9465369e617944640cfdd79e | |
| parent | ad7d6ecb162a8154cc865a4c3514f5753208c3d1 (diff) | |
| download | emacs-f561e49a25cace5e6d3cf3b222d87fa483226f76.tar.gz emacs-f561e49a25cace5e6d3cf3b222d87fa483226f76.zip | |
Allow specifying local ELPA mirrors in package-archives.
* emacs-lisp/package.el (package-archives): Accept either ordinary
directory names, in addition to HTTP URLs.
(package--with-work-buffer): New macro. Handle normal directories.
(package-handle-response): Don't display the failing buffer.
(package-download-single, package-download-tar)
(package--download-one-archive): Use package--with-work-buffer.
(package-archive-base): Rename from package-archive-url.
| -rw-r--r-- | lisp/ChangeLog | 10 | ||||
| -rw-r--r-- | lisp/emacs-lisp/package.el | 124 |
2 files changed, 77 insertions, 57 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index a3646cc5a47..380d12443da 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,13 @@ | |||
| 1 | 2011-03-06 Chong Yidong <cyd@stupidchicken.com> | ||
| 2 | |||
| 3 | * emacs-lisp/package.el (package-archives): Accept either ordinary | ||
| 4 | directory names, in addition to HTTP URLs. | ||
| 5 | (package--with-work-buffer): New macro. Handle normal directories. | ||
| 6 | (package-handle-response): Don't display the failing buffer. | ||
| 7 | (package-download-single, package-download-tar) | ||
| 8 | (package--download-one-archive): Use package--with-work-buffer. | ||
| 9 | (package-archive-base): Rename from package-archive-url. | ||
| 10 | |||
| 1 | 2011-03-06 Glenn Morris <rgm@gnu.org> | 11 | 2011-03-06 Glenn Morris <rgm@gnu.org> |
| 2 | 12 | ||
| 3 | * generic-x.el (generic-unix-modes): Add xmodmap-generic-mode. | 13 | * generic-x.el (generic-unix-modes): Add xmodmap-generic-mode. |
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index ab5ba1bea56..2552ad4eb68 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el | |||
| @@ -220,10 +220,15 @@ If VERSION is nil, the package is not loaded (it is \"disabled\")." | |||
| 220 | (defcustom package-archives '(("gnu" . "http://elpa.gnu.org/packages/")) | 220 | (defcustom package-archives '(("gnu" . "http://elpa.gnu.org/packages/")) |
| 221 | "An alist of archives from which to fetch. | 221 | "An alist of archives from which to fetch. |
| 222 | The default value points to the GNU Emacs package repository. | 222 | The default value points to the GNU Emacs package repository. |
| 223 | Each element has the form (ID . URL), where ID is an identifier | 223 | |
| 224 | string for an archive and URL is a http: URL (a string)." | 224 | Each element has the form (ID . LOCATION). |
| 225 | ID is an archive name, as a string. | ||
| 226 | LOCATION specifies the base location for the archive. | ||
| 227 | If it starts with \"http:\", it is treated as a HTTP URL; | ||
| 228 | otherwise it should be an absolute directory name. | ||
| 229 | (Other types of URL are currently not supported.)" | ||
| 225 | :type '(alist :key-type (string :tag "Archive name") | 230 | :type '(alist :key-type (string :tag "Archive name") |
| 226 | :value-type (string :tag "Archive URL")) | 231 | :value-type (string :tag "URL or directory name")) |
| 227 | :risky t | 232 | :risky t |
| 228 | :group 'package | 233 | :group 'package |
| 229 | :version "24.1") | 234 | :version "24.1") |
| @@ -617,8 +622,36 @@ Otherwise it uses an external `tar' program. | |||
| 617 | (let ((load-path (cons pkg-dir load-path))) | 622 | (let ((load-path (cons pkg-dir load-path))) |
| 618 | (byte-recompile-directory pkg-dir 0 t))))) | 623 | (byte-recompile-directory pkg-dir 0 t))))) |
| 619 | 624 | ||
| 625 | (defmacro package--with-work-buffer (location file &rest body) | ||
| 626 | "Run BODY in a buffer containing the contents of FILE at LOCATION. | ||
| 627 | LOCATION is the base location of a package archive, and should be | ||
| 628 | one of the URLs (or file names) specified in `package-archives'. | ||
| 629 | FILE is the name of a file relative to that base location. | ||
| 630 | |||
| 631 | This macro retrieves FILE from LOCATION into a temporary buffer, | ||
| 632 | and evaluates BODY while that buffer is current. This work | ||
| 633 | buffer is killed afterwards. Return the last value in BODY." | ||
| 634 | `(let* ((http (string-match "\\`http:" ,location)) | ||
| 635 | (buffer | ||
| 636 | (if http | ||
| 637 | (url-retrieve-synchronously (concat ,location ,file)) | ||
| 638 | (generate-new-buffer "*package work buffer*")))) | ||
| 639 | (prog1 | ||
| 640 | (with-current-buffer buffer | ||
| 641 | (if http | ||
| 642 | (progn (package-handle-response) | ||
| 643 | (re-search-forward "^$" nil 'move) | ||
| 644 | (forward-char) | ||
| 645 | (delete-region (point-min) (point))) | ||
| 646 | (unless (file-name-absolute-p ,location) | ||
| 647 | (error "Archive location %s is not an absolute file name" | ||
| 648 | ,location)) | ||
| 649 | (insert-file-contents (expand-file-name ,file ,location))) | ||
| 650 | ,@body) | ||
| 651 | (kill-buffer buffer)))) | ||
| 652 | |||
| 620 | (defun package-handle-response () | 653 | (defun package-handle-response () |
| 621 | "Handle the response from the server. | 654 | "Handle the response from a `url-retrieve-synchronously' call. |
| 622 | Parse the HTTP response and throw if an error occurred. | 655 | Parse the HTTP response and throw if an error occurred. |
| 623 | The url package seems to require extra processing for this. | 656 | The url package seems to require extra processing for this. |
| 624 | This should be called in a `save-excursion', in the download buffer. | 657 | This should be called in a `save-excursion', in the download buffer. |
| @@ -627,7 +660,6 @@ It will move point to somewhere in the headers." | |||
| 627 | (require 'url-http) | 660 | (require 'url-http) |
| 628 | (let ((response (url-http-parse-response))) | 661 | (let ((response (url-http-parse-response))) |
| 629 | (when (or (< response 200) (>= response 300)) | 662 | (when (or (< response 200) (>= response 300)) |
| 630 | (display-buffer (current-buffer)) | ||
| 631 | (error "Error during download request:%s" | 663 | (error "Error during download request:%s" |
| 632 | (buffer-substring-no-properties (point) (progn | 664 | (buffer-substring-no-properties (point) (progn |
| 633 | (end-of-line) | 665 | (end-of-line) |
| @@ -635,28 +667,17 @@ It will move point to somewhere in the headers." | |||
| 635 | 667 | ||
| 636 | (defun package-download-single (name version desc requires) | 668 | (defun package-download-single (name version desc requires) |
| 637 | "Download and install a single-file package." | 669 | "Download and install a single-file package." |
| 638 | (let ((buffer (url-retrieve-synchronously | 670 | (let ((location (package-archive-base name)) |
| 639 | (concat (package-archive-url name) | 671 | (file (concat (symbol-name name) "-" version ".el"))) |
| 640 | (symbol-name name) "-" version ".el")))) | 672 | (package--with-work-buffer location file |
| 641 | (with-current-buffer buffer | 673 | (package-unpack-single (symbol-name name) version desc requires)))) |
| 642 | (package-handle-response) | ||
| 643 | (re-search-forward "^$" nil 'move) | ||
| 644 | (forward-char) | ||
| 645 | (delete-region (point-min) (point)) | ||
| 646 | (package-unpack-single (symbol-name name) version desc requires) | ||
| 647 | (kill-buffer buffer)))) | ||
| 648 | 674 | ||
| 649 | (defun package-download-tar (name version) | 675 | (defun package-download-tar (name version) |
| 650 | "Download and install a tar package." | 676 | "Download and install a tar package." |
| 651 | (let ((tar-buffer (url-retrieve-synchronously | 677 | (let ((location (package-archive-base name)) |
| 652 | (concat (package-archive-url name) | 678 | (file (concat (symbol-name name) "-" version ".tar"))) |
| 653 | (symbol-name name) "-" version ".tar")))) | 679 | (package--with-work-buffer location file |
| 654 | (with-current-buffer tar-buffer | 680 | (package-unpack name version)))) |
| 655 | (package-handle-response) | ||
| 656 | (re-search-forward "^$" nil 'move) | ||
| 657 | (forward-char) | ||
| 658 | (package-unpack name version) | ||
| 659 | (kill-buffer tar-buffer)))) | ||
| 660 | 681 | ||
| 661 | (defun package-installed-p (package &optional min-version) | 682 | (defun package-installed-p (package &optional min-version) |
| 662 | "Return true if PACKAGE, of VERSION or newer, is installed. | 683 | "Return true if PACKAGE, of VERSION or newer, is installed. |
| @@ -987,31 +1008,26 @@ The file can either be a tar file or an Emacs Lisp file." | |||
| 987 | (error "Package `%s-%s' is a system package, not deleting" | 1008 | (error "Package `%s-%s' is a system package, not deleting" |
| 988 | name version)))) | 1009 | name version)))) |
| 989 | 1010 | ||
| 990 | (defun package-archive-url (name) | 1011 | (defun package-archive-base (name) |
| 991 | "Return the archive containing the package NAME." | 1012 | "Return the archive containing the package NAME." |
| 992 | (let ((desc (cdr (assq (intern-soft name) package-archive-contents)))) | 1013 | (let ((desc (cdr (assq (intern-soft name) package-archive-contents)))) |
| 993 | (cdr (assoc (aref desc (- (length desc) 1)) package-archives)))) | 1014 | (cdr (assoc (aref desc (- (length desc) 1)) package-archives)))) |
| 994 | 1015 | ||
| 995 | (defun package--download-one-archive (archive file) | 1016 | (defun package--download-one-archive (archive file) |
| 996 | "Download an archive file FILE from ARCHIVE, and cache it locally." | 1017 | "Retrieve an archive file FILE from ARCHIVE, and cache it. |
| 997 | (let* ((archive-name (car archive)) | 1018 | ARCHIVE should be a cons cell of the form (NAME . LOCATION), |
| 998 | (archive-url (cdr archive)) | 1019 | similar to an entry in `package-alist'. Save the cached copy to |
| 999 | (dir (expand-file-name "archives" package-user-dir)) | 1020 | \"archives/NAME/archive-contents\" in `package-user-dir'." |
| 1000 | (dir (expand-file-name archive-name dir)) | 1021 | (let* ((dir (expand-file-name "archives" package-user-dir)) |
| 1001 | (buffer (url-retrieve-synchronously (concat archive-url file)))) | 1022 | (dir (expand-file-name (car archive) dir))) |
| 1002 | (with-current-buffer buffer | 1023 | (package--with-work-buffer (cdr archive) file |
| 1003 | (package-handle-response) | ||
| 1004 | (re-search-forward "^$" nil 'move) | ||
| 1005 | (forward-char) | ||
| 1006 | (delete-region (point-min) (point)) | ||
| 1007 | ;; Read the retrieved buffer to make sure it is valid (e.g. it | 1024 | ;; Read the retrieved buffer to make sure it is valid (e.g. it |
| 1008 | ;; may fetch a URL redirect page). | 1025 | ;; may fetch a URL redirect page). |
| 1009 | (when (listp (read buffer)) | 1026 | (when (listp (read buffer)) |
| 1010 | (make-directory dir t) | 1027 | (make-directory dir t) |
| 1011 | (setq buffer-file-name (expand-file-name file dir)) | 1028 | (setq buffer-file-name (expand-file-name file dir)) |
| 1012 | (let ((version-control 'never)) | 1029 | (let ((version-control 'never)) |
| 1013 | (save-buffer)))) | 1030 | (save-buffer)))))) |
| 1014 | (kill-buffer buffer))) | ||
| 1015 | 1031 | ||
| 1016 | (defun package-refresh-contents () | 1032 | (defun package-refresh-contents () |
| 1017 | "Download the ELPA archive description if needed. | 1033 | "Download the ELPA archive description if needed. |
| @@ -1176,27 +1192,21 @@ If optional arg NO-ACTIVATE is non-nil, don't activate packages." | |||
| 1176 | (while (re-search-forward "^\\(;+ ?\\)" nil t) | 1192 | (while (re-search-forward "^\\(;+ ?\\)" nil t) |
| 1177 | (replace-match "")))) | 1193 | (replace-match "")))) |
| 1178 | (let ((readme (expand-file-name (concat package-name "-readme.txt") | 1194 | (let ((readme (expand-file-name (concat package-name "-readme.txt") |
| 1179 | package-user-dir))) | 1195 | package-user-dir)) |
| 1196 | readme-string) | ||
| 1180 | ;; For elpa packages, try downloading the commentary. If that | 1197 | ;; For elpa packages, try downloading the commentary. If that |
| 1181 | ;; fails, try an existing readme file in `package-user-dir'. | 1198 | ;; fails, try an existing readme file in `package-user-dir'. |
| 1182 | (cond ((let ((buffer (ignore-errors | 1199 | (cond ((condition-case nil |
| 1183 | (url-retrieve-synchronously | 1200 | (package--with-work-buffer (package-archive-base package) |
| 1184 | (concat (package-archive-url package) | 1201 | (concat package-name "-readme.txt") |
| 1185 | package-name "-readme.txt")))) | 1202 | (setq buffer-file-name |
| 1186 | response) | 1203 | (expand-file-name readme package-user-dir)) |
| 1187 | (when buffer | 1204 | (let ((version-control 'never)) |
| 1188 | (with-current-buffer buffer | 1205 | (save-buffer)) |
| 1189 | (setq response (url-http-parse-response)) | 1206 | (setq readme-string (buffer-string)) |
| 1190 | (if (or (< response 200) (>= response 300)) | 1207 | t) |
| 1191 | (setq response nil) | 1208 | (error nil)) |
| 1192 | (setq buffer-file-name | 1209 | (insert readme-string)) |
| 1193 | (expand-file-name readme package-user-dir)) | ||
| 1194 | (delete-region (point-min) (1+ url-http-end-of-headers)) | ||
| 1195 | (save-buffer))) | ||
| 1196 | (when response | ||
| 1197 | (insert-buffer-substring buffer) | ||
| 1198 | (kill-buffer buffer) | ||
| 1199 | t)))) | ||
| 1200 | ((file-readable-p readme) | 1210 | ((file-readable-p readme) |
| 1201 | (insert-file-contents readme) | 1211 | (insert-file-contents readme) |
| 1202 | (goto-char (point-max)))))))) | 1212 | (goto-char (point-max)))))))) |