diff options
| author | Chong Yidong | 2011-03-06 15:19:39 -0500 |
|---|---|---|
| committer | Chong Yidong | 2011-03-06 15:19:39 -0500 |
| commit | 5c69cb2ce354d499609c202ff3ad48240202bb15 (patch) | |
| tree | 7273206acac51f594517aaaf8cc4f1f0b86ccaf9 | |
| parent | 78f5433f6ba4f787c766342b6ac68f79425bc685 (diff) | |
| download | emacs-5c69cb2ce354d499609c202ff3ad48240202bb15.tar.gz emacs-5c69cb2ce354d499609c202ff3ad48240202bb15.zip | |
Usability improvements to commands in package-x.el.
* lisp/emacs-lisp/package-x.el (package-archive-upload-base): Make it a
defcustom.
(package--update-file): Doc fix. Accept relative file names.
(package--archive-contents-from-file): Remove the argument, since
it's necessarily always "archive-contents".
(package-maint-add-news-item): Pass relative file name args to
package--update-file.
(package-upload-buffer-internal): Prompt for a destination if
package-archive-upload-base is invalid. Create the directory if
it does not exist.
(package-upload-buffer, package-upload-file): Doc fix.
| -rw-r--r-- | lisp/ChangeLog | 14 | ||||
| -rw-r--r-- | lisp/emacs-lisp/package-x.el | 253 |
2 files changed, 159 insertions, 108 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e4d402afa76..5e9e134e746 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,5 +1,19 @@ | |||
| 1 | 2011-03-06 Chong Yidong <cyd@stupidchicken.com> | 1 | 2011-03-06 Chong Yidong <cyd@stupidchicken.com> |
| 2 | 2 | ||
| 3 | * emacs-lisp/package-x.el (package-archive-upload-base): Make it a | ||
| 4 | defcustom. | ||
| 5 | (package--update-file): Doc fix. Accept relative file names. | ||
| 6 | (package--archive-contents-from-file): Remove the argument, since | ||
| 7 | it's necessarily always "archive-contents". | ||
| 8 | (package-maint-add-news-item): Pass relative file name args to | ||
| 9 | package--update-file. | ||
| 10 | (package-upload-buffer-internal): Prompt for a destination if | ||
| 11 | package-archive-upload-base is invalid. Create the directory if | ||
| 12 | it does not exist. | ||
| 13 | (package-upload-buffer, package-upload-file): Doc fix. | ||
| 14 | |||
| 15 | 2011-03-06 Chong Yidong <cyd@stupidchicken.com> | ||
| 16 | |||
| 3 | * isearch.el (isearch-mode-map): Bind C-y to isearch-yank-kill, | 17 | * isearch.el (isearch-mode-map): Bind C-y to isearch-yank-kill, |
| 4 | and move isearch-yank-line to M-s C-e (Bug#8183). | 18 | and move isearch-yank-line to M-s C-e (Bug#8183). |
| 5 | 19 | ||
diff --git a/lisp/emacs-lisp/package-x.el b/lisp/emacs-lisp/package-x.el index 61f23abf0a7..4de95f65702 100644 --- a/lisp/emacs-lisp/package-x.el +++ b/lisp/emacs-lisp/package-x.el | |||
| @@ -27,21 +27,41 @@ | |||
| 27 | 27 | ||
| 28 | ;;; Commentary: | 28 | ;;; Commentary: |
| 29 | 29 | ||
| 30 | ;; This file currently contains parts of the package system most | 30 | ;; This file currently contains parts of the package system that many |
| 31 | ;; people won't need, such as package uploading. | 31 | ;; won't need, such as package uploading. |
| 32 | |||
| 33 | ;; To upload to an archive, first set `package-archive-upload-base' to | ||
| 34 | ;; some desired directory. For testing purposes, you can specify any | ||
| 35 | ;; directory you want, but if you want the archive to be accessible to | ||
| 36 | ;; others via http, this is typically a directory in the /var/www tree | ||
| 37 | ;; (possibly one on a remote machine, accessed via Tramp). | ||
| 38 | |||
| 39 | ;; Then call M-x package-upload-file, which prompts for a file to | ||
| 40 | ;; upload. Alternatively, M-x package-upload-buffer uploads the | ||
| 41 | ;; current buffer, if it's visiting a package file. | ||
| 42 | |||
| 43 | ;; Once a package is uploaded, users can access it via the Package | ||
| 44 | ;; Menu, by adding the archive to `package-archives'. | ||
| 32 | 45 | ||
| 33 | ;;; Code: | 46 | ;;; Code: |
| 34 | 47 | ||
| 35 | (require 'package) | 48 | (require 'package) |
| 36 | (defvar gnus-article-buffer) | 49 | (defvar gnus-article-buffer) |
| 37 | 50 | ||
| 38 | ;; Note that this only works if you have the password, which you | 51 | (defcustom package-archive-upload-base "/path/to/archive" |
| 39 | ;; probably don't :-). | 52 | "The base location of the archive to which packages are uploaded. |
| 40 | (defvar package-archive-upload-base nil | 53 | This should be an absolute directory name. If the archive is on |
| 41 | "Base location for uploading to package archive.") | 54 | another machine, you may specify a remote name in the usual way, |
| 55 | e.g. \"/ssh:foo@example.com:/var/www/packages/\". | ||
| 56 | See Info node `(emacs)Remote Files'. | ||
| 57 | |||
| 58 | Unlike `package-archives', you can't specify a HTTP URL." | ||
| 59 | :type 'directory | ||
| 60 | :group 'package | ||
| 61 | :version "24.1") | ||
| 42 | 62 | ||
| 43 | (defvar package-update-news-on-upload nil | 63 | (defvar package-update-news-on-upload nil |
| 44 | "Whether package upload should also update NEWS and RSS feeds.") | 64 | "Whether uploading a package should also update NEWS and RSS feeds.") |
| 45 | 65 | ||
| 46 | (defun package--encode (string) | 66 | (defun package--encode (string) |
| 47 | "Encode a string by replacing some characters with XML entities." | 67 | "Encode a string by replacing some characters with XML entities." |
| @@ -75,13 +95,18 @@ | |||
| 75 | title " - " (package--encode text) | 95 | title " - " (package--encode text) |
| 76 | " </li>\n")) | 96 | " </li>\n")) |
| 77 | 97 | ||
| 78 | (defun package--update-file (file location text) | 98 | (defun package--update-file (file tag text) |
| 99 | "Update the package archive file named FILE. | ||
| 100 | FILE should be relative to `package-archive-upload-base'. | ||
| 101 | TAG is a string that can be found within the file; TEXT is | ||
| 102 | inserted after its first occurrence in the file." | ||
| 103 | (setq file (expand-file-name file package-archive-upload-base)) | ||
| 79 | (save-excursion | 104 | (save-excursion |
| 80 | (let ((old-buffer (find-buffer-visiting file))) | 105 | (let ((old-buffer (find-buffer-visiting file))) |
| 81 | (with-current-buffer (let ((find-file-visit-truename t)) | 106 | (with-current-buffer (let ((find-file-visit-truename t)) |
| 82 | (or old-buffer (find-file-noselect file))) | 107 | (or old-buffer (find-file-noselect file))) |
| 83 | (goto-char (point-min)) | 108 | (goto-char (point-min)) |
| 84 | (search-forward location) | 109 | (search-forward tag) |
| 85 | (forward-line) | 110 | (forward-line) |
| 86 | (insert text) | 111 | (insert text) |
| 87 | (let ((file-precious-flag t)) | 112 | (let ((file-precious-flag t)) |
| @@ -105,30 +130,31 @@ Return the file contents, as a string, or nil if unsuccessful." | |||
| 105 | (buffer-substring-no-properties (point-min) (point-max))) | 130 | (buffer-substring-no-properties (point-min) (point-max))) |
| 106 | (kill-buffer buffer)))))) | 131 | (kill-buffer buffer)))))) |
| 107 | 132 | ||
| 108 | (defun package--archive-contents-from-file (file) | 133 | (defun package--archive-contents-from-file () |
| 109 | "Parse the given archive-contents file." | 134 | "Parse the archive-contents at `package-archive-upload-base'" |
| 110 | (if (not (file-exists-p file)) | 135 | (let ((file (expand-file-name "archive-contents" |
| 111 | ;; no existing archive-contents, possibly a new ELPA repo. | 136 | package-archive-upload-base))) |
| 112 | (list package-archive-version) | 137 | (if (not (file-exists-p file)) |
| 113 | (let ((dont-kill (find-buffer-visiting file))) | 138 | ;; No existing archive-contents means a new archive. |
| 114 | (with-current-buffer (let ((find-file-visit-truename t)) | 139 | (list package-archive-version) |
| 115 | (find-file-noselect file)) | 140 | (let ((dont-kill (find-buffer-visiting file))) |
| 116 | (prog1 | 141 | (with-current-buffer (let ((find-file-visit-truename t)) |
| 117 | (package-read-from-string | 142 | (find-file-noselect file)) |
| 118 | (buffer-substring-no-properties (point-min) (point-max))) | 143 | (prog1 |
| 119 | (unless dont-kill | 144 | (package-read-from-string |
| 120 | (kill-buffer (current-buffer)))))))) | 145 | (buffer-substring-no-properties (point-min) (point-max))) |
| 146 | (unless dont-kill | ||
| 147 | (kill-buffer (current-buffer))))))))) | ||
| 121 | 148 | ||
| 122 | (defun package-maint-add-news-item (title description archive-url) | 149 | (defun package-maint-add-news-item (title description archive-url) |
| 123 | "Add a news item to the ELPA web pages. | 150 | "Add a news item to the webpages associated with the package archive. |
| 124 | TITLE is the title of the news item. | 151 | TITLE is the title of the news item. |
| 125 | DESCRIPTION is the text of the news item. | 152 | DESCRIPTION is the text of the news item." |
| 126 | You need administrative access to ELPA to use this." | ||
| 127 | (interactive "sTitle: \nsText: ") | 153 | (interactive "sTitle: \nsText: ") |
| 128 | (package--update-file (concat package-archive-upload-base "elpa.rss") | 154 | (package--update-file "elpa.rss" |
| 129 | "<description>" | 155 | "<description>" |
| 130 | (package--make-rss-entry title description archive-url)) | 156 | (package--make-rss-entry title description archive-url)) |
| 131 | (package--update-file (concat package-archive-upload-base "news.html") | 157 | (package--update-file "news.html" |
| 132 | "New entries go here" | 158 | "New entries go here" |
| 133 | (package--make-html-entry title description))) | 159 | (package--make-html-entry title description))) |
| 134 | 160 | ||
| @@ -144,8 +170,8 @@ PKG-INFO is the package info, see `package-buffer-info'. | |||
| 144 | EXTENSION is the file extension, a string. It can be either | 170 | EXTENSION is the file extension, a string. It can be either |
| 145 | \"el\" or \"tar\". | 171 | \"el\" or \"tar\". |
| 146 | 172 | ||
| 147 | The variable `package-archive-upload-base' specifies the upload | 173 | The upload destination is given by `package-archive-upload-base'. |
| 148 | destination. If this is nil, signal an error. | 174 | If its value is invalid, prompt for a directory. |
| 149 | 175 | ||
| 150 | Optional arg ARCHIVE-URL is the URL of the destination archive. | 176 | Optional arg ARCHIVE-URL is the URL of the destination archive. |
| 151 | If it is non-nil, compute the new \"archive-contents\" file | 177 | If it is non-nil, compute the new \"archive-contents\" file |
| @@ -156,85 +182,97 @@ addition, if `package-update-news-on-upload' is non-nil, call | |||
| 156 | If ARCHIVE-URL is nil, compute the new \"archive-contents\" file | 182 | If ARCHIVE-URL is nil, compute the new \"archive-contents\" file |
| 157 | from the \"archive-contents\" at `package-archive-upload-base', | 183 | from the \"archive-contents\" at `package-archive-upload-base', |
| 158 | if it exists." | 184 | if it exists." |
| 159 | (unless package-archive-upload-base | 185 | (let ((package-archive-upload-base package-archive-upload-base)) |
| 160 | (error "No destination specified in `package-archive-upload-base'")) | 186 | ;; Check if `package-archive-upload-base' is valid. |
| 161 | (save-excursion | 187 | (when (or (not (stringp package-archive-upload-base)) |
| 162 | (save-restriction | 188 | (eq package-archive-upload-base |
| 163 | (let* ((file-type (cond | 189 | (car-safe |
| 164 | ((equal extension "el") 'single) | 190 | (get 'package-archive-upload-base 'standard-value)))) |
| 165 | ((equal extension "tar") 'tar) | 191 | (setq package-archive-upload-base |
| 166 | (t (error "Unknown extension `%s'" extension)))) | 192 | (read-directory-name |
| 167 | (file-name (aref pkg-info 0)) | 193 | "Base directory for package archive: "))) |
| 168 | (pkg-name (intern file-name)) | 194 | (unless (file-directory-p package-archive-upload-base) |
| 169 | (requires (aref pkg-info 1)) | 195 | (if (y-or-n-p (format "%s does not exist; create it? " |
| 170 | (desc (if (string= (aref pkg-info 2) "") | 196 | package-archive-upload-base)) |
| 171 | (read-string "Description of package: ") | 197 | (make-directory package-archive-upload-base t) |
| 172 | (aref pkg-info 2))) | 198 | (error "Aborted"))) |
| 173 | (pkg-version (aref pkg-info 3)) | 199 | (save-excursion |
| 174 | (commentary (aref pkg-info 4)) | 200 | (save-restriction |
| 175 | (split-version (version-to-list pkg-version)) | 201 | (let* ((file-type (cond |
| 176 | (pkg-buffer (current-buffer))) | 202 | ((equal extension "el") 'single) |
| 177 | 203 | ((equal extension "tar") 'tar) | |
| 178 | ;; Get archive-contents from ARCHIVE-URL if it's non-nil, or | 204 | (t (error "Unknown extension `%s'" extension)))) |
| 179 | ;; from `package-archive-upload-base' otherwise. | 205 | (file-name (aref pkg-info 0)) |
| 180 | (let ((contents (or (package--archive-contents-from-url archive-url) | 206 | (pkg-name (intern file-name)) |
| 181 | (package--archive-contents-from-file | 207 | (requires (aref pkg-info 1)) |
| 182 | (concat package-archive-upload-base | 208 | (desc (if (string= (aref pkg-info 2) "") |
| 183 | "archive-contents")))) | 209 | (read-string "Description of package: ") |
| 184 | (new-desc (vector split-version requires desc file-type))) | 210 | (aref pkg-info 2))) |
| 185 | (if (> (car contents) package-archive-version) | 211 | (pkg-version (aref pkg-info 3)) |
| 186 | (error "Unrecognized archive version %d" (car contents))) | 212 | (commentary (aref pkg-info 4)) |
| 187 | (let ((elt (assq pkg-name (cdr contents)))) | 213 | (split-version (version-to-list pkg-version)) |
| 188 | (if elt | 214 | (pkg-buffer (current-buffer))) |
| 189 | (if (version-list-<= split-version | 215 | |
| 190 | (package-desc-vers (cdr elt))) | 216 | ;; Get archive-contents from ARCHIVE-URL if it's non-nil, or |
| 191 | (error "New package has smaller version: %s" pkg-version) | 217 | ;; from `package-archive-upload-base' otherwise. |
| 192 | (setcdr elt new-desc)) | 218 | (let ((contents (or (package--archive-contents-from-url archive-url) |
| 193 | (setq contents (cons (car contents) | 219 | (package--archive-contents-from-file))) |
| 194 | (cons (cons pkg-name new-desc) | 220 | (new-desc (vector split-version requires desc file-type))) |
| 195 | (cdr contents)))))) | 221 | (if (> (car contents) package-archive-version) |
| 196 | 222 | (error "Unrecognized archive version %d" (car contents))) | |
| 197 | ;; Now CONTENTS is the updated archive contents. Upload | 223 | (let ((elt (assq pkg-name (cdr contents)))) |
| 198 | ;; this and the package itself. For now we assume ELPA is | 224 | (if elt |
| 199 | ;; writable via file primitives. | 225 | (if (version-list-<= split-version |
| 200 | (let ((print-level nil) | 226 | (package-desc-vers (cdr elt))) |
| 201 | (print-length nil)) | 227 | (error "New package has smaller version: %s" pkg-version) |
| 202 | (write-region (concat (pp-to-string contents) "\n") | 228 | (setcdr elt new-desc)) |
| 203 | nil | 229 | (setq contents (cons (car contents) |
| 204 | (concat package-archive-upload-base | 230 | (cons (cons pkg-name new-desc) |
| 205 | "archive-contents"))) | 231 | (cdr contents)))))) |
| 206 | 232 | ||
| 207 | ;; If there is a commentary section, write it. | 233 | ;; Now CONTENTS is the updated archive contents. Upload |
| 208 | (when commentary | 234 | ;; this and the package itself. For now we assume ELPA is |
| 209 | (write-region commentary nil | 235 | ;; writable via file primitives. |
| 210 | (concat package-archive-upload-base | 236 | (let ((print-level nil) |
| 211 | (symbol-name pkg-name) "-readme.txt"))) | 237 | (print-length nil)) |
| 212 | 238 | (write-region (concat (pp-to-string contents) "\n") | |
| 213 | (set-buffer pkg-buffer) | 239 | nil |
| 214 | (write-region (point-min) (point-max) | 240 | (expand-file-name "archive-contents" |
| 215 | (concat package-archive-upload-base | 241 | package-archive-upload-base))) |
| 216 | file-name "-" pkg-version | 242 | |
| 217 | "." extension) | 243 | ;; If there is a commentary section, write it. |
| 218 | nil nil nil 'excl) | 244 | (when commentary |
| 219 | 245 | (write-region commentary nil | |
| 220 | ;; Write a news entry. | 246 | (expand-file-name |
| 221 | (and package-update-news-on-upload | 247 | (concat (symbol-name pkg-name) "-readme.txt") |
| 222 | archive-url | 248 | package-archive-upload-base))) |
| 223 | (package--update-news (concat file-name "." extension) | 249 | |
| 224 | pkg-version desc archive-url)) | 250 | (set-buffer pkg-buffer) |
| 225 | 251 | (write-region (point-min) (point-max) | |
| 226 | ;; special-case "package": write a second copy so that the | 252 | (expand-file-name |
| 227 | ;; installer can easily find the latest version. | 253 | (concat file-name "-" pkg-version "." extension) |
| 228 | (if (string= file-name "package") | 254 | package-archive-upload-base) |
| 229 | (write-region (point-min) (point-max) | 255 | nil nil nil 'excl) |
| 230 | (concat package-archive-upload-base | 256 | |
| 231 | file-name "." extension) | 257 | ;; Write a news entry. |
| 232 | nil nil nil 'ask))))))) | 258 | (and package-update-news-on-upload |
| 259 | archive-url | ||
| 260 | (package--update-news (concat file-name "." extension) | ||
| 261 | pkg-version desc archive-url)) | ||
| 262 | |||
| 263 | ;; special-case "package": write a second copy so that the | ||
| 264 | ;; installer can easily find the latest version. | ||
| 265 | (if (string= file-name "package") | ||
| 266 | (write-region (point-min) (point-max) | ||
| 267 | (expand-file-name | ||
| 268 | (concat file-name "." extension) | ||
| 269 | package-archive-upload-base) | ||
| 270 | nil nil nil 'ask)))))))) | ||
| 233 | 271 | ||
| 234 | (defun package-upload-buffer () | 272 | (defun package-upload-buffer () |
| 235 | "Upload the current buffer as a single-file Emacs Lisp package. | 273 | "Upload the current buffer as a single-file Emacs Lisp package. |
| 236 | The variable `package-archive-upload-base' specifies the upload | 274 | If `package-archive-upload-base' does not specify a valid upload |
| 237 | destination." | 275 | destination, prompt for one." |
| 238 | (interactive) | 276 | (interactive) |
| 239 | (save-excursion | 277 | (save-excursion |
| 240 | (save-restriction | 278 | (save-restriction |
| @@ -247,9 +285,8 @@ destination." | |||
| 247 | Interactively, prompt for FILE. The package is considered a | 285 | Interactively, prompt for FILE. The package is considered a |
| 248 | single-file package if FILE ends in \".el\", and a multi-file | 286 | single-file package if FILE ends in \".el\", and a multi-file |
| 249 | package if FILE ends in \".tar\". | 287 | package if FILE ends in \".tar\". |
| 250 | 288 | If `package-archive-upload-base' does not specify a valid upload | |
| 251 | The variable `package-archive-upload-base' specifies the upload | 289 | destination, prompt for one." |
| 252 | destination." | ||
| 253 | (interactive "fPackage file name: ") | 290 | (interactive "fPackage file name: ") |
| 254 | (with-temp-buffer | 291 | (with-temp-buffer |
| 255 | (insert-file-contents-literally file) | 292 | (insert-file-contents-literally file) |