comparison lisp/package-get.el @ 314:341dac730539 r21-0b55

Import from CVS: tag r21-0b55
author cvs
date Mon, 13 Aug 2007 10:44:22 +0200
parents 9ea74add5d37
children 512e409c26a2
comparison
equal deleted inserted replaced
313:2905de29931f 314:341dac730539
153 ("ftp.xemacs.org" "/pub/xemacs/beta/xemacs-21.0/packages/binary-packages") 153 ("ftp.xemacs.org" "/pub/xemacs/beta/xemacs-21.0/packages/binary-packages")
154 ("ftp.xemacs.org" "/pub/xemacs/beta/xemacs-21.0/packages/single-file-packages") 154 ("ftp.xemacs.org" "/pub/xemacs/beta/xemacs-21.0/packages/single-file-packages")
155 ("ftp.xemacs.org" "/pub/xemacs/package")) 155 ("ftp.xemacs.org" "/pub/xemacs/package"))
156 "*List of remote sites to contact for downloading packages. 156 "*List of remote sites to contact for downloading packages.
157 List format is '(site-name directory-on-site). Each site is tried in 157 List format is '(site-name directory-on-site). Each site is tried in
158 order until the package is found.") 158 order until the package is found. As a special case, `site-name' can be
159 `nil', in which case `directory-on-site' is treated as a local directory.")
159 160
160 (defvar package-get-remove-copy nil 161 (defvar package-get-remove-copy nil
161 "*After copying and installing a package, if this is T, then remove the 162 "*After copying and installing a package, if this is T, then remove the
162 copy. Otherwise, keep it around.") 163 copy. Otherwise, keep it around.")
164
165 (defun package-get-rmtree (directory)
166 "Delete a directory and all of its contents, recursively.
167 This is a feeble attempt at making a portable rmdir."
168 (let ( (orig-default-directory default-directory) files dirs dir)
169 (unwind-protect
170 (progn
171 (setq directory (file-name-as-directory directory))
172 (setq files (directory-files directory nil nil nil t))
173 (setq dirs (directory-files directory nil nil nil 'dirs))
174 (while dirs
175 (setq dir (car dirs))
176 (if (file-symlink-p dir) ;; just in case, handle symlinks
177 (delete-file dir)
178 (if (not (or (string-equal dir ".") (string-equal dir "..")))
179 (package-get-rmtree (expand-file-name dir directory))))
180 (setq dirs (cdr dirs))
181 )
182 (setq default-directory directory)
183 (condition-case err
184 (progn
185 (while files
186 (delete-file (car files))
187 (setq files (cdr files))
188 )
189 (delete-directory directory)
190 )
191 (file-error
192 (message "%s: %s: \"%s\"" (nth 1 err) (nth 2 err) (nth 3 err)))
193 )
194 )
195 (progn
196 (setq default-directory orig-default-directory)
197 ))
198 ))
163 199
164 ;;;###autoload 200 ;;;###autoload
165 (defun package-get-update-all () 201 (defun package-get-update-all ()
166 "Fetch and install the latest versions of all currently installed packages." 202 "Fetch and install the latest versions of all currently installed packages."
167 (interactive) 203 (interactive)
168 ;; Load a fresh copy 204 ;; Load a fresh copy
169 (mapcar (lambda (pkg) 205 (catch 'exit
170 (package-get (car pkg) nil 'never)) 206 (mapcar (lambda (pkg)
171 packages-package-list)) 207 (if (not (package-get (car pkg) nil 'never))
208 (throw 'exit nil) ;; Bail out if error detected
209 ))
210 packages-package-list)))
211
212 (defun package-get-interactive-package-query (get-version package-symbol)
213 "Perform interactive querying for package and optional version.
214 Query for a version if GET-VERSION is non-nil. Return package name as
215 a symbol instead of a string if PACKAGE-SYMBOL is non-nil.
216 The return value is suitable for direct passing to `interactive'."
217 (let ( (table (mapcar '(lambda (item)
218 (let ( (name (symbol-name (car item))) )
219 (cons name name)
220 ))
221 package-get-base))
222 package package-symbol default-version version)
223 (save-window-excursion
224 (setq package (completing-read "Package: " table nil t))
225 (setq package-symbol (intern package))
226 (if get-version
227 (progn
228 (setq default-version
229 (package-get-info-prop
230 (package-get-info-version
231 (package-get-info-find-package package-get-base
232 package-symbol) nil)
233 'version))
234 (while (string=
235 (setq version (read-string "Version: " default-version))
236 "")
237 )
238 (if package-symbol
239 (list package-symbol version)
240 (list package version))
241 )
242 (if package-symbol
243 (list package-symbol)
244 (list package)))
245 )))
172 246
173 ;;;###autoload 247 ;;;###autoload
174 (defun package-get-all (package version &optional fetched-packages) 248 (defun package-get-all (package version &optional fetched-packages)
175 "Fetch PACKAGE with VERSION and all other required packages. 249 "Fetch PACKAGE with VERSION and all other required packages.
176 Uses `package-get-base' to determine just what is required and what 250 Uses `package-get-base' to determine just what is required and what
177 package provides that functionality. If VERSION is nil, retrieves 251 package provides that functionality. If VERSION is nil, retrieves
178 latest version. Optional argument FETCHED-PACKAGES is used to keep 252 latest version. Optional argument FETCHED-PACKAGES is used to keep
179 track of packages already fetched." 253 track of packages already fetched.
180 (interactive "sPackage: \nsVersion: ") 254
255 Returns nil upon error."
256 (interactive (package-get-interactive-package-query t nil))
181 (let* ((the-package (package-get-info-find-package package-get-base 257 (let* ((the-package (package-get-info-find-package package-get-base
182 package)) 258 package))
183 (this-package (package-get-info-version 259 (this-package (package-get-info-version
184 the-package version)) 260 the-package version))
185 (this-requires (package-get-info-prop this-package 'requires)) 261 (this-requires (package-get-info-prop this-package 'requires))
186 ) 262 )
187 (setq version (package-get-info-prop this-package 'version)) 263 (catch 'exit
188 (unless (package-get-installedp package version) 264 (setq version (package-get-info-prop this-package 'version))
189 (package-get package version)) 265 (unless (package-get-installedp package version)
190 (setq fetched-packages 266 (if (not (package-get package version))
191 (append (list package) 267 (progn
192 (package-get-info-prop this-package 'provides) 268 (setq fetched-packages nil)
193 fetched-packages)) 269 (throw 'exit nil))))
194 ;; grab everything that this package requires plus recursively 270 (setq fetched-packages
195 ;; grab everything that the requires require. Keep track 271 (append (list package)
196 ;; in `fetched-packages' the list of things provided -- this 272 (package-get-info-prop this-package 'provides)
197 ;; keeps us from going into a loop 273 fetched-packages))
198 (while this-requires 274 ;; grab everything that this package requires plus recursively
199 (if (not (member (car this-requires) fetched-packages)) 275 ;; grab everything that the requires require. Keep track
200 (let* ((reqd-package (package-get-package-provider 276 ;; in `fetched-packages' the list of things provided -- this
201 (car this-requires))) 277 ;; keeps us from going into a loop
202 (reqd-version (cadr reqd-package)) 278 (while this-requires
203 (reqd-name (car reqd-package))) 279 (if (not (member (car this-requires) fetched-packages))
204 (if (null reqd-name) 280 (let* ((reqd-package (package-get-package-provider
205 (error "Unable to find a provider for %s" (car this-requires))) 281 (car this-requires)))
206 (setq fetched-packages 282 (reqd-version (cadr reqd-package))
207 (package-get-all reqd-name reqd-version fetched-packages))) 283 (reqd-name (car reqd-package)))
208 ) 284 (if (null reqd-name)
209 (setq this-requires (cdr this-requires))) 285 (error "Unable to find a provider for %s"
286 (car this-requires)))
287 (if (not (setq fetched-packages
288 (package-get-all reqd-name reqd-version
289 fetched-packages)))
290 (throw 'exit nil)))
291 )
292 (setq this-requires (cdr this-requires)))
293 )
210 fetched-packages 294 fetched-packages
295 ))
296
297 (defun package-get-load-package-file (lispdir file)
298 (let (pathname)
299 (setq pathname (expand-file-name file lispdir))
300 (condition-case err
301 (progn
302 (load pathname t)
303 t)
304 (t
305 (message "Error loading package file \"%s\" %s!" pathname err)
306 nil))
307 ))
308
309 (defun package-get-init-package (lispdir)
310 "Initialize the package.
311 This really assumes that the package has never been loaded. Updating
312 a newer package can cause problems, due to old, obsolete functions in
313 the old package.
314
315 Return `t' upon complete success, `nil' if any errors occurred."
316 (progn
317 (if (and lispdir
318 (file-accessible-directory-p lispdir))
319 (progn
320 ;; Add lispdir to load-path if it doesn't already exist.
321 ;; NOTE: this does not take symlinks, etc., into account.
322 (if (let ( (dirs load-path) )
323 (catch 'done
324 (while dirs
325 (if (string-equal (car dirs) lispdir)
326 (throw 'done nil))
327 (setq dirs (cdr dirs))
328 )
329 t))
330 (setq load-path (cons lispdir load-path)))
331 (package-get-load-package-file lispdir "auto-autoloads")
332 t)
333 nil)
211 )) 334 ))
212 335
213 ;;;###autoload 336 ;;;###autoload
214 (defun package-get (package &optional version conflict install-dir) 337 (defun package-get (package &optional version conflict install-dir)
215 "Fetch PACKAGE from remote site. 338 "Fetch PACKAGE from remote site.
226 where a package should be retrieved from. The sites are tried in 349 where a package should be retrieved from. The sites are tried in
227 order so one is better off listing easily reached sites first. 350 order so one is better off listing easily reached sites first.
228 351
229 Once the package is retrieved, its md5 checksum is computed. If that 352 Once the package is retrieved, its md5 checksum is computed. If that
230 sum does not match that stored in `package-get-base' for this version 353 sum does not match that stored in `package-get-base' for this version
231 of the package, an error is signalled." 354 of the package, an error is signalled.
232 (interactive "xPackage List: ") 355
356 Returns `t' upon success, the symbol `error' if the package was
357 successfully installed but errors occurred during initialization, or
358 `nil' upon error."
359 (interactive (package-get-interactive-package-query nil t))
233 (let* ((this-package 360 (let* ((this-package
234 (package-get-info-version 361 (package-get-info-version
235 (package-get-info-find-package package-get-base 362 (package-get-info-find-package package-get-base
236 package) version)) 363 package) version))
237 (found nil) 364 (found nil)
238 (search-dirs package-get-remote) 365 (search-dirs package-get-remote)
239 (filename (package-get-info-prop this-package 'filename))) 366 (base-filename (package-get-info-prop this-package 'filename))
367 (package-status t)
368 filenames full-package-filename package-lispdir)
240 (if (null this-package) 369 (if (null this-package)
241 (error "Couldn't find package %s with version %s" 370 (error "Couldn't find package %s with version %s"
242 package version)) 371 package version))
243 (if (null filename) 372 (if (null base-filename)
244 (error "No filename associated with package %s, version %s" 373 (error "No filename associated with package %s, version %s"
245 package version)) 374 package version))
375 (if (null install-dir)
376 (setq install-dir (package-admin-get-install-dir nil)))
377
378 ;; Contrive a list of possible package filenames.
379 ;; Ugly. Is there a better way to do this?
380 (setq filenames (cons base-filename nil))
381 (if (string-match "^\\(..*\\)\.tar\.gz$" base-filename)
382 (setq filenames (cons (concat (match-string 1 base-filename) ".tgz")
383 filenames)))
384
246 (setq version (package-get-info-prop this-package 'version)) 385 (setq version (package-get-info-prop this-package 'version))
247 (unless (and (eq conflict 'never) 386 (unless (and (eq conflict 'never)
248 (package-get-installedp package version)) 387 (package-get-installedp package version))
249 ;; Find the package from search list in package-get-remote 388 ;; Find the package from the search list in package-get-remote
250 ;; and copy it into the staging directory. Then validate 389 ;; and copy it into the staging directory. Then validate
251 ;; the checksum. Finally, install the package. 390 ;; the checksum. Finally, install the package.
252 (while (and search-dirs 391 (catch 'done
253 (not (file-exists-p (package-get-staging-dir filename)))) 392 (let (search-filenames current-dir-entry host dir current-filename)
254 (if (file-exists-p (package-get-remote-filename 393 ;; In each search directory ...
255 (car search-dirs) filename)) 394 (while search-dirs
256 (copy-file (package-get-remote-filename (car search-dirs) filename) 395 (setq current-dir-entry (car search-dirs)
257 (package-get-staging-dir filename)) 396 host (car current-dir-entry)
258 (setq search-dirs (cdr search-dirs)) 397 dir (car (cdr current-dir-entry))
398 search-filenames filenames)
399
400 ;; Look for one of the possible package filenames ...
401 (while search-filenames
402 (setq current-filename (car search-filenames))
403 (if (null host)
404 (progn
405 ;; No host means look on the current system.
406 (setq full-package-filename
407 (substitute-in-file-name
408 (expand-file-name current-filename
409 (file-name-as-directory dir))))
410 )
411 ;; If the file exists on the remote system ...
412 (if (file-exists-p (package-get-remote-filename
413 current-dir-entry current-filename))
414 (progn
415 ;; Get it
416 (setq full-package-filename
417 (package-get-staging-dir current-filename))
418 (message "Retrieving package `%s' ..."
419 current-filename)
420 (sit-for 0)
421 (copy-file (package-get-remote-filename current-dir-entry
422 current-filename)
423 ))))
424 ;; If we found it, we're done.
425 (if (file-exists-p full-package-filename)
426 (throw 'done nil))
427 ;; Didn't find it. Try the next possible filename.
428 (setq search-filenames (cdr search-filenames))
429 )
430 ;; Try looking in the next possible directory ...
431 (setq search-dirs (cdr search-dirs))
432 )
259 )) 433 ))
260 (if (not (file-exists-p (package-get-staging-dir filename))) 434
261 (error "Unable to find file %s" filename)) 435 (if (or (not full-package-filename)
436 (not (file-exists-p full-package-filename)))
437 (error "Unable to find file %s" base-filename))
262 ;; Validate the md5 checksum 438 ;; Validate the md5 checksum
263 ;; Doing it with XEmacs removes the need for an external md5 program 439 ;; Doing it with XEmacs removes the need for an external md5 program
440 (message "Validating checksum for `%s'..." package) (sit-for 0)
264 (with-temp-buffer 441 (with-temp-buffer
265 ;; What ever happened to i-f-c-literally 442 ;; What ever happened to i-f-c-literally
266 (let (file-name-handler-alist) 443 (let (file-name-handler-alist)
267 (insert-file-contents-internal (package-get-staging-dir filename))) 444 (insert-file-contents-internal full-package-filename))
268 (if (not (string= (md5 (current-buffer)) 445 (if (not (string= (md5 (current-buffer))
269 (package-get-info-prop this-package 446 (package-get-info-prop this-package
270 'md5sum))) 447 'md5sum)))
271 (error "Package %s does not match md5 checksum" filename))) 448 (error "Package %s does not match md5 checksum" base-filename)))
272 (message "Retrieved package %s" filename) (sit-for 0) 449
450 ;; Now delete old lisp directory, if any
451 ;;
452 ;; Gads, this is ugly. However, we're not supposed to use `concat'
453 ;; in the name of portability.
454 (if (and (setq package-lispdir (expand-file-name "lisp" install-dir))
455 (setq package-lispdir (expand-file-name (symbol-name package)
456 package-lispdir))
457 (file-accessible-directory-p package-lispdir))
458 (progn
459 (message "Removing old lisp directory \"%s\" ..." package-lispdir)
460 (sit-for 0)
461 (package-get-rmtree package-lispdir)
462 ))
463
464 (message "Installing package `%s' ..." package) (sit-for 0)
273 (let ((status 465 (let ((status
274 (package-admin-add-binary-package 466 (package-admin-add-binary-package full-package-filename
275 (package-get-staging-dir filename) 467 install-dir)))
276 install-dir))) 468 (if (= status 0)
277 (when (not (= status 0)) 469 (progn
278 (message "Package failed.") 470 ;; clear messages so that only messages from
279 (switch-to-buffer package-admin-temp-buffer))) 471 ;; package-get-init-package are seen, below.
280 (sit-for 0) 472 (clear-message)
281 (message "Added package") (sit-for 0) 473 (if (package-get-init-package package-lispdir)
474 (progn
475 (message "Added package `%s'" package)
476 (sit-for 0)
477 )
478 (progn
479 ;; display message only if there isn't already one.
480 (if (not (current-message))
481 (progn
482 (message "Added package `%s' (errors occurred)"
483 package)
484 (sit-for 0)
485 ))
486 (if package-status
487 (setq package-status 'errors))
488 ))
489 )
490 (message "Installation of package %s failed." base-filename)
491 (sit-for 0)
492 (switch-to-buffer package-admin-temp-buffer)
493 (setq package-status nil)
494 ))
282 (setq found t)) 495 (setq found t))
283 (if (and found package-get-remove-copy) 496 (if (and found package-get-remove-copy)
284 (delete-file (package-get-staging-dir filename))) 497 (delete-file full-package-filename))
498 package-status
285 )) 499 ))
286 500
287 (defun package-get-info-find-package (which name) 501 (defun package-get-info-find-package (which name)
288 "Look in WHICH for the package called NAME and return all the info 502 "Look in WHICH for the package called NAME and return all the info
289 associated with it. See `package-get-base' for info on the format 503 associated with it. See `package-get-base' for info on the format
304 "In PACKAGE, return the plist associated with a particular VERSION of the 518 "In PACKAGE, return the plist associated with a particular VERSION of the
305 package. PACKAGE is typically as returned by 519 package. PACKAGE is typically as returned by
306 `package-get-info-find-package'. If VERSION is nil, then return the 520 `package-get-info-find-package'. If VERSION is nil, then return the
307 first (aka most recent) version. Use `package-get-info-find-prop' 521 first (aka most recent) version. Use `package-get-info-find-prop'
308 to retrieve a particular property from the value returned by this." 522 to retrieve a particular property from the value returned by this."
309 (interactive "xPackage Info: \nsVersion: ") 523 (interactive (package-get-interactive-package-query t t))
310 (while (and version package (not (string= (plist-get (car package) 'version) version))) 524 (while (and version package (not (string= (plist-get (car package) 'version) version)))
311 (setq package (cdr package))) 525 (setq package (cdr package)))
312 (if package (car package))) 526 (if package (car package)))
313 527
314 (defun package-get-info-prop (package-version property) 528 (defun package-get-info-prop (package-version property)
345 Use `package-get-dir' for directory to store stuff. 559 Use `package-get-dir' for directory to store stuff.
346 Creates `package-get-dir' it it doesn't exist." 560 Creates `package-get-dir' it it doesn't exist."
347 (interactive "FPackage filename: ") 561 (interactive "FPackage filename: ")
348 (if (not (file-exists-p package-get-dir)) 562 (if (not (file-exists-p package-get-dir))
349 (make-directory package-get-dir)) 563 (make-directory package-get-dir))
350 (concat 564 (expand-file-name
351 (file-name-as-directory package-get-dir) 565 (file-name-nondirectory (or (nth 2 (efs-ftp-path filename)) filename))
352 (file-name-nondirectory (or (nth 2 (efs-ftp-path filename)) filename)))) 566 (file-name-as-directory package-get-dir)))
353 567
354 568
355 (defun package-get-remote-filename (search filename) 569 (defun package-get-remote-filename (search filename)
356 "Return FILENAME as a remote filename. 570 "Return FILENAME as a remote filename.
357 It first checks if FILENAME already is a remote filename. If it is 571 It first checks if FILENAME already is a remote filename. If it is
458 (interactive) 672 (interactive)
459 ;; Load a fresh copy 673 ;; Load a fresh copy
460 (let ((custom-buffer (find-file-noselect 674 (let ((custom-buffer (find-file-noselect
461 (or (package-get-file-installed-p 675 (or (package-get-file-installed-p
462 "package-get-custom.el") 676 "package-get-custom.el")
463 (concat (file-name-directory 677 (expand-file-name
464 (package-get-file-installed-p 678 "package-get-custom.el"
465 "package-get-base.el")) 679 (file-name-directory
466 "package-get-custom.el")))) 680 (package-get-file-installed-p
681 "package-get-base.el"))
682 ))))
467 (pkg-groups nil)) 683 (pkg-groups nil))
468 684
469 ;; clear existing stuff 685 ;; clear existing stuff
470 (delete-region (point-min custom-buffer) 686 (delete-region (point-min custom-buffer)
471 (point-max custom-buffer) custom-buffer) 687 (point-max custom-buffer) custom-buffer)