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