Mercurial > hg > xemacs-beta
comparison lisp/package-get.el @ 375:a300bb07d72d r21-2b3
Import from CVS: tag r21-2b3
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:04:51 +0200 |
parents | 6240c7796c7a |
children | d883f39b8495 |
comparison
equal
deleted
inserted
replaced
374:4ebeb1a5388b | 375:a300bb07d72d |
---|---|
95 ;;; Change Log | 95 ;;; Change Log |
96 | 96 |
97 ;;; Code: | 97 ;;; Code: |
98 | 98 |
99 (require 'package-admin) | 99 (require 'package-admin) |
100 (require 'package-get-base) | 100 ;; (require 'package-get-base) |
101 | 101 |
102 (defgroup package-tools nil | |
103 "Tools to manipulate packages." | |
104 :group 'emacs) | |
105 | |
106 (defgroup package-get nil | |
107 "Automatic Package Fetcher and Installer." | |
108 :prefix "package-get" | |
109 :group 'package-tools) | |
110 | |
102 (defvar package-get-base nil | 111 (defvar package-get-base nil |
103 "List of packages that are installed at this site. | 112 "List of packages that are installed at this site. |
104 For each element in the alist, car is the package name and the cdr is | 113 For each element in the alist, car is the package name and the cdr is |
105 a plist containing information about the package. Typical fields | 114 a plist containing information about the package. Typical fields |
106 kept in the plist are: | 115 kept in the plist are: |
143 For version information, it is assumed things are listed in most | 152 For version information, it is assumed things are listed in most |
144 recent to least recent -- in other words, the version names don't have to | 153 recent to least recent -- in other words, the version names don't have to |
145 be lexically ordered. It is debatable if it makes sense to have more than | 154 be lexically ordered. It is debatable if it makes sense to have more than |
146 one version of a package available.") | 155 one version of a package available.") |
147 | 156 |
148 (defvar package-get-dir (temp-directory) | 157 (defcustom package-get-dir (temp-directory) |
149 "*Where to store temporary files for staging.") | 158 "*Where to store temporary files for staging." |
150 | 159 :tag "Temporary directory" |
151 (defvar package-get-remote | 160 :type 'directory |
161 :group 'package-get) | |
162 | |
163 ;; JV Any Custom expert know to get "Host" and "Dir" for the remote option | |
164 (defcustom package-get-remote | |
152 '(("ftp.xemacs.org" "/pub/xemacs/packages")) | 165 '(("ftp.xemacs.org" "/pub/xemacs/packages")) |
153 "*List of remote sites to contact for downloading packages. | 166 "*List of remote sites to contact for downloading packages. |
154 List format is '(site-name directory-on-site). Each site is tried in | 167 List format is '(site-name directory-on-site). Each site is tried in |
155 order until the package is found. As a special case, `site-name' can be | 168 order until the package is found. As a special case, `site-name' can be |
156 `nil', in which case `directory-on-site' is treated as a local directory.") | 169 `nil', in which case `directory-on-site' is treated as a local directory." |
157 | 170 :tag "Package repository" |
158 (defvar package-get-remove-copy nil | 171 :type '(repeat (choice (list :tag "Local" (const :tag "Local" nil) directory ) |
172 (list :tag "Remote" string string) )) | |
173 :group 'package-get) | |
174 | |
175 (defcustom package-get-remove-copy nil | |
159 "*After copying and installing a package, if this is T, then remove the | 176 "*After copying and installing a package, if this is T, then remove the |
160 copy. Otherwise, keep it around.") | 177 copy. Otherwise, keep it around." |
178 :type 'boolean | |
179 :group 'package-get) | |
180 | |
181 (defcustom package-get-base-filename | |
182 "/ftp.xemacs.org:/pub/xemacs/packages/package-index.LATEST" | |
183 "*Name of the default package database file, usually on ftp.xemacs.org." | |
184 :type 'file | |
185 :group 'package-get) | |
186 | |
187 ;;;###autoload | |
188 (defun package-get-require-base () | |
189 "Require that a package-get database has been loaded." | |
190 (when (or (not (boundp 'package-get-base)) | |
191 (not package-get-base)) | |
192 (package-get-update-base)) | |
193 (when (or (not (boundp 'package-get-base)) | |
194 (not package-get-base)) | |
195 (error "Package-get database not loaded"))) | |
196 | |
197 (defconst package-get-pgp-signed-begin-line "^-----BEGIN PGP SIGNED MESSAGE-----" | |
198 "Text for start of PGP signed messages.") | |
199 (defconst package-get-pgp-signature-begin-line "^-----BEGIN PGP SIGNATURE-----" | |
200 "Text for beginning of PGP signature.") | |
201 (defconst package-get-pgp-signature-end-line "^-----END PGP SIGNATURE-----" | |
202 "Text for end of PGP signature.") | |
203 | |
204 ;;;###autoload | |
205 (defun package-get-update-base-entry (entry) | |
206 "Update an entry in `package-get-base'." | |
207 (let ((existing (assoc (car entry) package-get-base))) | |
208 (if existing | |
209 (setcdr existing (cdr entry)) | |
210 (setq package-get-base (cons entry package-get-base))))) | |
211 | |
212 ;;;###autoload | |
213 (defun package-get-update-base (&optional db-file) | |
214 "Update the package-get database file with entries from DB-FILE." | |
215 (interactive (list | |
216 (read-file-name "Load package-get database: " | |
217 (file-name-directory package-get-base-filename) | |
218 package-get-base-filename | |
219 t | |
220 (file-name-nondirectory package-get-base-filename)))) | |
221 (setq db-file (expand-file-name (or db-file package-get-base-filename))) | |
222 (if (not (file-exists-p db-file)) | |
223 (error "Package-get database file `%s' does not exist" db-file)) | |
224 (if (not (file-readable-p db-file)) | |
225 (error "Package-get database file `%s' not readable" db-file)) | |
226 (let ((buf (get-buffer-create "*package database*"))) | |
227 (unwind-protect | |
228 (save-excursion | |
229 (set-buffer buf) | |
230 (erase-buffer buf) | |
231 (insert-file-contents-internal db-file) | |
232 (package-get-update-base-from-buffer buf)) | |
233 (kill-buffer buf)))) | |
234 | |
235 ;;;###autoload | |
236 (defun package-get-update-base-from-buffer (&optional buf) | |
237 "Update the package-get database with entries from BUFFER. | |
238 BUFFER defaults to the current buffer. This command can be | |
239 used interactively, for example from a mail or news buffer." | |
240 (interactive) | |
241 (setq buf (or buf (current-buffer))) | |
242 (let (content-beg content-end beg end) | |
243 (save-excursion | |
244 (set-buffer buf) | |
245 (goto-char (point-min)) | |
246 (setq content-beg (point)) | |
247 (setq content-end (save-excursion (goto-char (point-max)) (point))) | |
248 (when (re-search-forward package-get-pgp-signed-begin-line nil t) | |
249 (setq beg (match-beginning 0)) | |
250 (setq content-beg (match-end 0))) | |
251 (when (re-search-forward package-get-pgp-signature-begin-line nil t) | |
252 (setq content-end (match-beginning 0))) | |
253 (when (re-search-forward package-get-pgp-signature-end-line nil t) | |
254 (setq end (point))) | |
255 (if (not (and content-beg content-end beg end)) | |
256 (or (yes-or-no-p "Package-get entries not PGP signed, continue? ") | |
257 (error "Package-get database not updated"))) | |
258 (if (and content-beg content-end beg end) | |
259 (if (not (condition-case nil | |
260 (or (fboundp 'mc-pgp-verify-region) | |
261 (load-library "mc-pgp") | |
262 (fboundp 'mc-pgp-verify-region)) | |
263 (error nil))) | |
264 (or (yes-or-no-p | |
265 "No mailcrypt; can't verify package-get DB signature, continue? ") | |
266 (error "Package-get database not updated")))) | |
267 (if (and beg end | |
268 (fboundp 'mc-pgp-verify-region) | |
269 (or (not | |
270 (condition-case err | |
271 (mc-pgp-verify-region beg end) | |
272 (file-error | |
273 (and (string-match "No such file" (nth 2 err)) | |
274 (yes-or-no-p | |
275 "Can't find PGP, continue without package-get DB verification? "))) | |
276 (t nil))))) | |
277 (error "Package-get PGP signature failed to verify")) | |
278 (package-get-update-base-entries content-beg content-end) | |
279 (message "Updated package-get database")))) | |
280 | |
281 (defun package-get-update-base-entries (beg end) | |
282 "Update the package-get database with the entries found between | |
283 BEG and END in the current buffer." | |
284 (save-excursion | |
285 (goto-char beg) | |
286 (if (not (re-search-forward "^(package-get-update-base-entry" nil t)) | |
287 (error "Buffer does not contain package-get database entries")) | |
288 (beginning-of-line) | |
289 (let ((count 0)) | |
290 (while (and (< (point) end) | |
291 (re-search-forward "^(package-get-update-base-entry" nil t)) | |
292 (beginning-of-line) | |
293 (let ((entry (read (current-buffer)))) | |
294 (if (or (not (consp entry)) | |
295 (not (eq (car entry) 'package-get-update-base-entry))) | |
296 (error "Invalid package-get database entry found")) | |
297 (package-get-update-base-entry | |
298 (car (cdr (car (cdr entry))))) | |
299 (setq count (1+ count)))) | |
300 (message "Got %d package-get database entries" count)))) | |
161 | 301 |
162 (defun package-get-interactive-package-query (get-version package-symbol) | 302 (defun package-get-interactive-package-query (get-version package-symbol) |
163 "Perform interactive querying for package and optional version. | 303 "Perform interactive querying for package and optional version. |
164 Query for a version if GET-VERSION is non-nil. Return package name as | 304 Query for a version if GET-VERSION is non-nil. Return package name as |
165 a symbol instead of a string if PACKAGE-SYMBOL is non-nil. | 305 a symbol instead of a string if PACKAGE-SYMBOL is non-nil. |
166 The return value is suitable for direct passing to `interactive'." | 306 The return value is suitable for direct passing to `interactive'." |
307 (package-get-require-base) | |
167 (let ( (table (mapcar '(lambda (item) | 308 (let ( (table (mapcar '(lambda (item) |
168 (let ( (name (symbol-name (car item))) ) | 309 (let ( (name (symbol-name (car item))) ) |
169 (cons name name) | 310 (cons name name) |
170 )) | 311 )) |
171 package-get-base)) | 312 package-get-base)) |
204 | 345 |
205 ;;;###autoload | 346 ;;;###autoload |
206 (defun package-get-update-all () | 347 (defun package-get-update-all () |
207 "Fetch and install the latest versions of all currently installed packages." | 348 "Fetch and install the latest versions of all currently installed packages." |
208 (interactive) | 349 (interactive) |
350 (package-get-require-base) | |
209 ;; Load a fresh copy | 351 ;; Load a fresh copy |
210 (catch 'exit | 352 (catch 'exit |
211 (mapcar (lambda (pkg) | 353 (mapcar (lambda (pkg) |
212 (if (not (package-get (car pkg) nil 'never)) | 354 (if (not (package-get (car pkg) nil 'never)) |
213 (throw 'exit nil) ;; Bail out if error detected | 355 (throw 'exit nil) ;; Bail out if error detected |
214 )) | 356 )) |
215 packages-package-list))) | 357 packages-package-list))) |
216 | 358 |
217 ;;;###autoload | 359 ;;;###autoload |
218 (defun package-get-all (package version &optional fetched-packages) | 360 (defun package-get-all (package version &optional fetched-packages install-dir) |
219 "Fetch PACKAGE with VERSION and all other required packages. | 361 "Fetch PACKAGE with VERSION and all other required packages. |
220 Uses `package-get-base' to determine just what is required and what | 362 Uses `package-get-base' to determine just what is required and what |
221 package provides that functionality. If VERSION is nil, retrieves | 363 package provides that functionality. If VERSION is nil, retrieves |
222 latest version. Optional argument FETCHED-PACKAGES is used to keep | 364 latest version. Optional argument FETCHED-PACKAGES is used to keep |
223 track of packages already fetched. | 365 track of packages already fetched. Optional argument INSTALL-DIR, |
366 if non-nil, specifies the package directory where fetched packages | |
367 should be installed. | |
224 | 368 |
225 Returns nil upon error." | 369 Returns nil upon error." |
226 (interactive (package-get-interactive-package-query t nil)) | 370 (interactive (package-get-interactive-package-query t nil)) |
227 (let* ((the-package (package-get-info-find-package package-get-base | 371 (let* ((the-package (package-get-info-find-package package-get-base |
228 package)) | 372 package)) |
231 (this-requires (package-get-info-prop this-package 'requires)) | 375 (this-requires (package-get-info-prop this-package 'requires)) |
232 ) | 376 ) |
233 (catch 'exit | 377 (catch 'exit |
234 (setq version (package-get-info-prop this-package 'version)) | 378 (setq version (package-get-info-prop this-package 'version)) |
235 (unless (package-get-installedp package version) | 379 (unless (package-get-installedp package version) |
236 (if (not (package-get package version)) | 380 (if (not (package-get package version nil install-dir)) |
237 (progn | 381 (progn |
238 (setq fetched-packages nil) | 382 (setq fetched-packages nil) |
239 (throw 'exit nil)))) | 383 (throw 'exit nil)))) |
240 (setq fetched-packages | 384 (setq fetched-packages |
241 (append (list package) | 385 (append (list package) |
254 (if (null reqd-name) | 398 (if (null reqd-name) |
255 (error "Unable to find a provider for %s" | 399 (error "Unable to find a provider for %s" |
256 (car this-requires))) | 400 (car this-requires))) |
257 (if (not (setq fetched-packages | 401 (if (not (setq fetched-packages |
258 (package-get-all reqd-name reqd-version | 402 (package-get-all reqd-name reqd-version |
259 fetched-packages))) | 403 fetched-packages |
404 install-dir))) | |
260 (throw 'exit nil))) | 405 (throw 'exit nil))) |
261 ) | 406 ) |
262 (setq this-requires (cdr this-requires))) | 407 (setq this-requires (cdr this-requires))) |
263 ) | 408 ) |
264 fetched-packages | 409 fetched-packages |
265 )) | 410 )) |
411 | |
412 ;;;###autoload | |
413 (defun package-get-dependencies (packages) | |
414 "Compute dependencies for PACKAGES. | |
415 Uses `package-get-base' to determine just what is required and what | |
416 package provides that functionality. Returns the list of packages | |
417 required by PACKAGES." | |
418 (package-get-require-base) | |
419 (let ((orig-packages packages) | |
420 dependencies provided) | |
421 (while packages | |
422 (let* ((package (car packages)) | |
423 (the-package (package-get-info-find-package | |
424 package-get-base package)) | |
425 (this-package (package-get-info-version | |
426 the-package nil)) | |
427 (this-requires (package-get-info-prop this-package 'requires)) | |
428 (new-depends (set-difference | |
429 (mapcar | |
430 #'(lambda (reqd) | |
431 (let* ((reqd-package (package-get-package-provider reqd)) | |
432 (reqd-version (cadr reqd-package)) | |
433 (reqd-name (car reqd-package))) | |
434 (if (null reqd-name) | |
435 (error "Unable to find a provider for %s" reqd)) | |
436 reqd-name)) | |
437 this-requires) | |
438 dependencies)) | |
439 (this-provides (package-get-info-prop this-package 'provides))) | |
440 (setq dependencies | |
441 (union dependencies new-depends)) | |
442 (setq provided | |
443 (union provided (union (list package) this-provides))) | |
444 (setq packages | |
445 (union new-depends (cdr packages))))) | |
446 (set-difference dependencies orig-packages))) | |
266 | 447 |
267 (defun package-get-load-package-file (lispdir file) | 448 (defun package-get-load-package-file (lispdir file) |
268 (let (pathname) | 449 (let (pathname) |
269 (setq pathname (expand-file-name file lispdir)) | 450 (setq pathname (expand-file-name file lispdir)) |
270 (condition-case err | 451 (condition-case err |
330 (interactive (package-get-interactive-package-query nil t)) | 511 (interactive (package-get-interactive-package-query nil t)) |
331 (let* ((this-package | 512 (let* ((this-package |
332 (package-get-info-version | 513 (package-get-info-version |
333 (package-get-info-find-package package-get-base | 514 (package-get-info-find-package package-get-base |
334 package) version)) | 515 package) version)) |
516 (this-requires (package-get-info-prop this-package 'requires)) | |
335 (found nil) | 517 (found nil) |
336 (search-dirs package-get-remote) | 518 (search-dirs package-get-remote) |
337 (base-filename (package-get-info-prop this-package 'filename)) | 519 (base-filename (package-get-info-prop this-package 'filename)) |
338 (package-status t) | 520 (package-status t) |
339 filenames full-package-filename) | 521 filenames full-package-filename) |
341 (error "Couldn't find package %s with version %s" | 523 (error "Couldn't find package %s with version %s" |
342 package version)) | 524 package version)) |
343 (if (null base-filename) | 525 (if (null base-filename) |
344 (error "No filename associated with package %s, version %s" | 526 (error "No filename associated with package %s, version %s" |
345 package version)) | 527 package version)) |
346 (if (null install-dir) | 528 (setq install-dir |
347 (setq install-dir (package-admin-get-install-dir nil))) | 529 (package-admin-get-install-dir package install-dir |
530 (or (eq package 'mule-base) (memq 'mule-base this-requires)))) | |
348 | 531 |
349 ;; Contrive a list of possible package filenames. | 532 ;; Contrive a list of possible package filenames. |
350 ;; Ugly. Is there a better way to do this? | 533 ;; Ugly. Is there a better way to do this? |
351 (setq filenames (cons base-filename nil)) | 534 (setq filenames (cons base-filename nil)) |
352 (if (string-match "^\\(..*\\)\.tar\.gz$" base-filename) | 535 (if (string-match "^\\(..*\\)\.tar\.gz$" base-filename) |
579 "Search for a package that provides SYM and return the name and | 762 "Search for a package that provides SYM and return the name and |
580 version. Searches in `package-get-base' for SYM. If SYM is a | 763 version. Searches in `package-get-base' for SYM. If SYM is a |
581 consp, then it must match a corresponding (provide (SYM VERSION)) from | 764 consp, then it must match a corresponding (provide (SYM VERSION)) from |
582 the package." | 765 the package." |
583 (interactive "SSymbol: ") | 766 (interactive "SSymbol: ") |
767 (package-get-require-base) | |
584 (let ((packages package-get-base) | 768 (let ((packages package-get-base) |
585 (done nil) | 769 (done nil) |
586 (found nil)) | 770 (found nil)) |
587 (while (and (not done) packages) | 771 (while (and (not done) packages) |
588 (let* ((this-name (caar packages)) | 772 (let* ((this-name (caar packages)) |
610 | 794 |
611 ;;;###autoload | 795 ;;;###autoload |
612 (defun package-get-custom () | 796 (defun package-get-custom () |
613 "Fetch and install the latest versions of all customized packages." | 797 "Fetch and install the latest versions of all customized packages." |
614 (interactive) | 798 (interactive) |
799 (package-get-require-base) | |
615 ;; Load a fresh copy | 800 ;; Load a fresh copy |
616 (load "package-get-custom.el") | 801 (load "package-get-custom.el") |
617 (mapcar (lambda (pkg) | 802 (mapcar (lambda (pkg) |
618 (if (eval (intern (concat (symbol-name (car pkg)) "-package"))) | 803 (if (eval (intern (concat (symbol-name (car pkg)) "-package"))) |
619 (package-get-all (car pkg) nil)) | 804 (package-get-all (car pkg) nil)) |
688 | 873 |
689 ;; need this first to avoid infinite dependency loops | 874 ;; need this first to avoid infinite dependency loops |
690 (provide 'package-get) | 875 (provide 'package-get) |
691 | 876 |
692 ;; potentially update the custom dependencies every time we load this | 877 ;; potentially update the custom dependencies every time we load this |
878 (when nil ;; #### disable for now... -gk | |
879 (unless noninteractive | |
693 (let ((custom-file (package-get-file-installed-p "package-get-custom.el")) | 880 (let ((custom-file (package-get-file-installed-p "package-get-custom.el")) |
694 (package-file (package-get-file-installed-p "package-get-base.el"))) | 881 (package-file (package-get-file-installed-p "package-get-base.el"))) |
695 ;; update custom file if it doesn't exist | 882 ;; update custom file if it doesn't exist |
696 (if (or (not custom-file) | 883 (if (or (not custom-file) |
697 (and (< (car (nth 5 (file-attributes custom-file))) | 884 (and (< (car (nth 5 (file-attributes custom-file))) |
701 (save-excursion | 888 (save-excursion |
702 (message "generating package customizations...") | 889 (message "generating package customizations...") |
703 (set-buffer (package-get-create-custom)) | 890 (set-buffer (package-get-create-custom)) |
704 (save-buffer) | 891 (save-buffer) |
705 (message "generating package customizations...done"))) | 892 (message "generating package customizations...done"))) |
706 (load "package-get-custom.el")) | 893 (load "package-get-custom.el"))) |
894 ) | |
707 | 895 |
708 ;;; package-get.el ends here | 896 ;;; package-get.el ends here |