Mercurial > hg > xemacs-beta
comparison lisp/package-get.el @ 373:6240c7796c7a r21-2b2
Import from CVS: tag r21-2b2
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:04:06 +0200 |
parents | cc15677e0335 |
children | a300bb07d72d |
comparison
equal
deleted
inserted
replaced
372:49e1ed2d7ed8 | 373:6240c7796c7a |
---|---|
147 | 147 |
148 (defvar package-get-dir (temp-directory) | 148 (defvar package-get-dir (temp-directory) |
149 "*Where to store temporary files for staging.") | 149 "*Where to store temporary files for staging.") |
150 | 150 |
151 (defvar package-get-remote | 151 (defvar package-get-remote |
152 '( | 152 '(("ftp.xemacs.org" "/pub/xemacs/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") | |
155 ("ftp.xemacs.org" "/pub/xemacs/package")) | |
156 "*List of remote sites to contact for downloading packages. | 153 "*List of remote sites to contact for downloading packages. |
157 List format is '(site-name directory-on-site). Each site is tried in | 154 List format is '(site-name directory-on-site). Each site is tried in |
158 order until the package is found.") | 155 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.") | |
159 | 157 |
160 (defvar package-get-remove-copy nil | 158 (defvar package-get-remove-copy nil |
161 "*After copying and installing a package, if this is T, then remove the | 159 "*After copying and installing a package, if this is T, then remove the |
162 copy. Otherwise, keep it around.") | 160 copy. Otherwise, keep it around.") |
161 | |
162 (defun package-get-interactive-package-query (get-version package-symbol) | |
163 "Perform interactive querying for package and optional version. | |
164 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. | |
166 The return value is suitable for direct passing to `interactive'." | |
167 (let ( (table (mapcar '(lambda (item) | |
168 (let ( (name (symbol-name (car item))) ) | |
169 (cons name name) | |
170 )) | |
171 package-get-base)) | |
172 package package-symbol default-version version) | |
173 (save-window-excursion | |
174 (setq package (completing-read "Package: " table nil t)) | |
175 (setq package-symbol (intern package)) | |
176 (if get-version | |
177 (progn | |
178 (setq default-version | |
179 (package-get-info-prop | |
180 (package-get-info-version | |
181 (package-get-info-find-package package-get-base | |
182 package-symbol) nil) | |
183 'version)) | |
184 (while (string= | |
185 (setq version (read-string "Version: " default-version)) | |
186 "") | |
187 ) | |
188 (if package-symbol | |
189 (list package-symbol version) | |
190 (list package version)) | |
191 ) | |
192 (if package-symbol | |
193 (list package-symbol) | |
194 (list package))) | |
195 ))) | |
196 | |
197 ;;;###autoload | |
198 (defun package-get-delete-package (package &optional pkg-topdir) | |
199 "Delete an installation of PACKAGE below directory PKG-TOPDIR. | |
200 PACKAGE is a symbol, not a string. | |
201 This is just an interactive wrapper for `package-admin-delete-binary-package'." | |
202 (interactive (package-get-interactive-package-query nil t)) | |
203 (package-admin-delete-binary-package package pkg-topdir)) | |
163 | 204 |
164 ;;;###autoload | 205 ;;;###autoload |
165 (defun package-get-update-all () | 206 (defun package-get-update-all () |
166 "Fetch and install the latest versions of all currently installed packages." | 207 "Fetch and install the latest versions of all currently installed packages." |
167 (interactive) | 208 (interactive) |
168 ;; Load a fresh copy | 209 ;; Load a fresh copy |
169 (mapcar (lambda (pkg) | 210 (catch 'exit |
170 (package-get-all | 211 (mapcar (lambda (pkg) |
171 (car pkg) nil)) | 212 (if (not (package-get (car pkg) nil 'never)) |
172 packages-package-list)) | 213 (throw 'exit nil) ;; Bail out if error detected |
214 )) | |
215 packages-package-list))) | |
173 | 216 |
174 ;;;###autoload | 217 ;;;###autoload |
175 (defun package-get-all (package version &optional fetched-packages) | 218 (defun package-get-all (package version &optional fetched-packages) |
176 "Fetch PACKAGE with VERSION and all other required packages. | 219 "Fetch PACKAGE with VERSION and all other required packages. |
177 Uses `package-get-base' to determine just what is required and what | 220 Uses `package-get-base' to determine just what is required and what |
178 package provides that functionality. If VERSION is nil, retrieves | 221 package provides that functionality. If VERSION is nil, retrieves |
179 latest version. Optional argument FETCHED-PACKAGES is used to keep | 222 latest version. Optional argument FETCHED-PACKAGES is used to keep |
180 track of packages already fetched." | 223 track of packages already fetched. |
181 (interactive "sPackage: \nsVersion: ") | 224 |
225 Returns nil upon error." | |
226 (interactive (package-get-interactive-package-query t nil)) | |
182 (let* ((the-package (package-get-info-find-package package-get-base | 227 (let* ((the-package (package-get-info-find-package package-get-base |
183 package)) | 228 package)) |
184 (this-package (package-get-info-version | 229 (this-package (package-get-info-version |
185 the-package version)) | 230 the-package version)) |
186 (this-requires (package-get-info-prop this-package 'requires)) | 231 (this-requires (package-get-info-prop this-package 'requires)) |
187 ) | 232 ) |
188 (setq version (package-get-info-prop this-package 'version)) | 233 (catch 'exit |
189 (unless (package-get-installedp package version) | 234 (setq version (package-get-info-prop this-package 'version)) |
190 (package-get package version)) | 235 (unless (package-get-installedp package version) |
191 (setq fetched-packages | 236 (if (not (package-get package version)) |
192 (append (list package) | 237 (progn |
193 (package-get-info-prop this-package 'provides) | 238 (setq fetched-packages nil) |
194 fetched-packages)) | 239 (throw 'exit nil)))) |
195 ;; grab everything that this package requires plus recursively | 240 (setq fetched-packages |
196 ;; grab everything that the requires require. Keep track | 241 (append (list package) |
197 ;; in `fetched-packages' the list of things provided -- this | 242 (package-get-info-prop this-package 'provides) |
198 ;; keeps us from going into a loop | 243 fetched-packages)) |
199 (while this-requires | 244 ;; grab everything that this package requires plus recursively |
200 (if (not (member (car this-requires) fetched-packages)) | 245 ;; grab everything that the requires require. Keep track |
201 (let* ((reqd-package (package-get-package-provider | 246 ;; in `fetched-packages' the list of things provided -- this |
202 (car this-requires))) | 247 ;; keeps us from going into a loop |
203 (reqd-version (cadr reqd-package)) | 248 (while this-requires |
204 (reqd-name (car reqd-package))) | 249 (if (not (member (car this-requires) fetched-packages)) |
205 (if (null reqd-name) | 250 (let* ((reqd-package (package-get-package-provider |
206 (error "Unable to find a provider for %s" (car this-requires))) | 251 (car this-requires))) |
207 (setq fetched-packages | 252 (reqd-version (cadr reqd-package)) |
208 (package-get-all reqd-name reqd-version fetched-packages))) | 253 (reqd-name (car reqd-package))) |
209 ) | 254 (if (null reqd-name) |
210 (setq this-requires (cdr this-requires))) | 255 (error "Unable to find a provider for %s" |
256 (car this-requires))) | |
257 (if (not (setq fetched-packages | |
258 (package-get-all reqd-name reqd-version | |
259 fetched-packages))) | |
260 (throw 'exit nil))) | |
261 ) | |
262 (setq this-requires (cdr this-requires))) | |
263 ) | |
211 fetched-packages | 264 fetched-packages |
212 )) | 265 )) |
213 | 266 |
267 (defun package-get-load-package-file (lispdir file) | |
268 (let (pathname) | |
269 (setq pathname (expand-file-name file lispdir)) | |
270 (condition-case err | |
271 (progn | |
272 (load pathname t) | |
273 t) | |
274 (t | |
275 (message "Error loading package file \"%s\" %s!" pathname err) | |
276 nil)) | |
277 )) | |
278 | |
279 (defun package-get-init-package (lispdir) | |
280 "Initialize the package. | |
281 This really assumes that the package has never been loaded. Updating | |
282 a newer package can cause problems, due to old, obsolete functions in | |
283 the old package. | |
284 | |
285 Return `t' upon complete success, `nil' if any errors occurred." | |
286 (progn | |
287 (if (and lispdir | |
288 (file-accessible-directory-p lispdir)) | |
289 (progn | |
290 ;; Add lispdir to load-path if it doesn't already exist. | |
291 ;; NOTE: this does not take symlinks, etc., into account. | |
292 (if (let ( (dirs load-path) ) | |
293 (catch 'done | |
294 (while dirs | |
295 (if (string-equal (car dirs) lispdir) | |
296 (throw 'done nil)) | |
297 (setq dirs (cdr dirs)) | |
298 ) | |
299 t)) | |
300 (setq load-path (cons lispdir load-path))) | |
301 (if (not (package-get-load-package-file lispdir "auto-autoloads")) | |
302 (package-get-load-package-file lispdir "_pkg")) | |
303 t) | |
304 nil) | |
305 )) | |
306 | |
214 ;;;###autoload | 307 ;;;###autoload |
215 (defun package-get (package &optional version conflict) | 308 (defun package-get (package &optional version conflict install-dir) |
216 "Fetch PACKAGE from remote site. | 309 "Fetch PACKAGE from remote site. |
217 Optional arguments VERSION indicates which version to retrieve, nil | 310 Optional arguments VERSION indicates which version to retrieve, nil |
218 means most recent version. CONFLICT indicates what happens if the | 311 means most recent version. CONFLICT indicates what happens if the |
219 package is already installed. Valid values for CONFLICT are: | 312 package is already installed. Valid values for CONFLICT are: |
220 'always always retrieve the package even if it is already installed | 313 'always always retrieve the package even if it is already installed |
221 'never do not retrieve the package if it is installed. | 314 'never do not retrieve the package if it is installed. |
315 INSTALL-DIR, if non-nil, specifies the package directory where | |
316 fetched packages should be installed. | |
222 | 317 |
223 The value of `package-get-base' is used to determine what files should | 318 The value of `package-get-base' is used to determine what files should |
224 be retrieved. The value of `package-get-remote' is used to determine | 319 be retrieved. The value of `package-get-remote' is used to determine |
225 where a package should be retrieved from. The sites are tried in | 320 where a package should be retrieved from. The sites are tried in |
226 order so one is better off listing easily reached sites first. | 321 order so one is better off listing easily reached sites first. |
227 | 322 |
228 Once the package is retrieved, its md5 checksum is computed. If that | 323 Once the package is retrieved, its md5 checksum is computed. If that |
229 sum does not match that stored in `package-get-base' for this version | 324 sum does not match that stored in `package-get-base' for this version |
230 of the package, an error is signalled." | 325 of the package, an error is signalled. |
231 (interactive "xPackage List: ") | 326 |
327 Returns `t' upon success, the symbol `error' if the package was | |
328 successfully installed but errors occurred during initialization, or | |
329 `nil' upon error." | |
330 (interactive (package-get-interactive-package-query nil t)) | |
232 (let* ((this-package | 331 (let* ((this-package |
233 (package-get-info-version | 332 (package-get-info-version |
234 (package-get-info-find-package package-get-base | 333 (package-get-info-find-package package-get-base |
235 package) version)) | 334 package) version)) |
236 (found nil) | 335 (found nil) |
237 (search-dirs package-get-remote) | 336 (search-dirs package-get-remote) |
238 (filename (package-get-info-prop this-package 'filename))) | 337 (base-filename (package-get-info-prop this-package 'filename)) |
338 (package-status t) | |
339 filenames full-package-filename) | |
239 (if (null this-package) | 340 (if (null this-package) |
240 (error "Couldn't find package %s with version %s" | 341 (error "Couldn't find package %s with version %s" |
241 package version)) | 342 package version)) |
242 (if (null filename) | 343 (if (null base-filename) |
243 (error "No filename associated with package %s, version %s" | 344 (error "No filename associated with package %s, version %s" |
244 package version)) | 345 package version)) |
346 (if (null install-dir) | |
347 (setq install-dir (package-admin-get-install-dir nil))) | |
348 | |
349 ;; Contrive a list of possible package filenames. | |
350 ;; Ugly. Is there a better way to do this? | |
351 (setq filenames (cons base-filename nil)) | |
352 (if (string-match "^\\(..*\\)\.tar\.gz$" base-filename) | |
353 (setq filenames (append filenames | |
354 (list (concat (match-string 1 base-filename) | |
355 ".tgz"))))) | |
356 | |
245 (setq version (package-get-info-prop this-package 'version)) | 357 (setq version (package-get-info-prop this-package 'version)) |
246 (unless (and (eq conflict 'never) | 358 (unless (and (eq conflict 'never) |
247 (package-get-installedp package version)) | 359 (package-get-installedp package version)) |
248 ;; Find the package from search list in package-get-remote | 360 ;; Find the package from the search list in package-get-remote |
249 ;; and copy it into the staging directory. Then validate | 361 ;; and copy it into the staging directory. Then validate |
250 ;; the checksum. Finally, install the package. | 362 ;; the checksum. Finally, install the package. |
251 (while (and search-dirs | 363 (catch 'done |
252 (not (file-exists-p (package-get-staging-dir filename)))) | 364 (let (search-filenames current-dir-entry host dir current-filename |
253 (if (file-exists-p (package-get-remote-filename | 365 dest-filename) |
254 (car search-dirs) filename)) | 366 ;; In each search directory ... |
255 (copy-file (package-get-remote-filename (car search-dirs) filename) | 367 (while search-dirs |
256 (package-get-staging-dir filename)) | 368 (setq current-dir-entry (car search-dirs) |
257 (setq search-dirs (cdr search-dirs)) | 369 host (car current-dir-entry) |
370 dir (car (cdr current-dir-entry)) | |
371 search-filenames filenames | |
372 ) | |
373 | |
374 ;; Look for one of the possible package filenames ... | |
375 (while search-filenames | |
376 (setq current-filename (car search-filenames) | |
377 dest-filename (package-get-staging-dir current-filename)) | |
378 (cond | |
379 ;; No host means look on the current system. | |
380 ( (null host) | |
381 (setq full-package-filename | |
382 (substitute-in-file-name | |
383 (expand-file-name current-filename | |
384 (file-name-as-directory dir)))) | |
385 ) | |
386 | |
387 ;; If it's already on the disk locally, and the size is | |
388 ;; greater than zero ... | |
389 ( (and (file-exists-p dest-filename) | |
390 (let (attrs) | |
391 ;; file-attributes could return -1 for LARGE files, | |
392 ;; but, hopefully, packages won't be that large. | |
393 (and (setq attrs (file-attributes dest-filename)) | |
394 (> (nth 7 attrs) 0)))) | |
395 (setq full-package-filename dest-filename) | |
396 ) | |
397 | |
398 ;; If the file exists on the remote system ... | |
399 ( (file-exists-p (package-get-remote-filename | |
400 current-dir-entry current-filename)) | |
401 ;; Get it | |
402 (setq full-package-filename dest-filename) | |
403 (message "Retrieving package `%s' ..." | |
404 current-filename) | |
405 (sit-for 0) | |
406 (copy-file (package-get-remote-filename current-dir-entry | |
407 current-filename) | |
408 full-package-filename t) | |
409 ) | |
410 ) | |
411 | |
412 ;; If we found it, we're done. | |
413 (if (and full-package-filename | |
414 (file-exists-p full-package-filename)) | |
415 (throw 'done nil)) | |
416 ;; Didn't find it. Try the next possible filename. | |
417 (setq search-filenames (cdr search-filenames)) | |
418 ) | |
419 ;; Try looking in the next possible directory ... | |
420 (setq search-dirs (cdr search-dirs)) | |
421 ) | |
258 )) | 422 )) |
259 (if (not (file-exists-p (package-get-staging-dir filename))) | 423 |
260 (error "Unable to find file %s" filename)) | 424 (if (or (not full-package-filename) |
425 (not (file-exists-p full-package-filename))) | |
426 (error "Unable to find file %s" base-filename)) | |
261 ;; Validate the md5 checksum | 427 ;; Validate the md5 checksum |
262 ;; Doing it with XEmacs removes the need for an external md5 program | 428 ;; Doing it with XEmacs removes the need for an external md5 program |
429 (message "Validating checksum for `%s'..." package) (sit-for 0) | |
263 (with-temp-buffer | 430 (with-temp-buffer |
264 ;; What ever happened to i-f-c-literally | 431 ;; What ever happened to i-f-c-literally |
265 (let (file-name-handler-alist) | 432 (let (file-name-handler-alist) |
266 (insert-file-contents-internal (package-get-staging-dir filename))) | 433 (insert-file-contents-internal full-package-filename)) |
267 (if (not (string= (md5 (current-buffer)) | 434 (if (not (string= (md5 (current-buffer)) |
268 (package-get-info-prop this-package | 435 (package-get-info-prop this-package |
269 'md5sum))) | 436 'md5sum))) |
270 (error "Package %s does not match md5 checksum" filename))) | 437 (error "Package %s does not match md5 checksum" base-filename))) |
271 (message "Retrieved package %s" filename) (sit-for 0) | 438 |
439 (package-admin-delete-binary-package package install-dir) | |
440 | |
441 (message "Installing package `%s' ..." package) (sit-for 0) | |
272 (let ((status | 442 (let ((status |
273 (package-admin-add-binary-package | 443 (package-admin-add-binary-package full-package-filename |
274 (package-get-staging-dir filename)))) | 444 install-dir))) |
275 (when (not (= status 0)) | 445 (if (= status 0) |
276 (message "Package failed.") | 446 (progn |
277 (switch-to-buffer package-admin-temp-buffer))) | 447 ;; clear messages so that only messages from |
278 (sit-for 0) | 448 ;; package-get-init-package are seen, below. |
279 (message "Added package") (sit-for 0) | 449 (clear-message) |
450 (if (package-get-init-package (package-admin-get-lispdir | |
451 install-dir package)) | |
452 (progn | |
453 (message "Added package `%s'" package) | |
454 (sit-for 0) | |
455 ) | |
456 (progn | |
457 ;; display message only if there isn't already one. | |
458 (if (not (current-message)) | |
459 (progn | |
460 (message "Added package `%s' (errors occurred)" | |
461 package) | |
462 (sit-for 0) | |
463 )) | |
464 (if package-status | |
465 (setq package-status 'errors)) | |
466 )) | |
467 ) | |
468 (message "Installation of package %s failed." base-filename) | |
469 (sit-for 0) | |
470 (switch-to-buffer package-admin-temp-buffer) | |
471 (setq package-status nil) | |
472 )) | |
280 (setq found t)) | 473 (setq found t)) |
281 (if (and found package-get-remove-copy) | 474 (if (and found package-get-remove-copy) |
282 (delete-file (package-get-staging-dir filename))) | 475 (delete-file full-package-filename)) |
476 package-status | |
283 )) | 477 )) |
284 | 478 |
285 (defun package-get-info-find-package (which name) | 479 (defun package-get-info-find-package (which name) |
286 "Look in WHICH for the package called NAME and return all the info | 480 "Look in WHICH for the package called NAME and return all the info |
287 associated with it. See `package-get-base' for info on the format | 481 associated with it. See `package-get-base' for info on the format |
302 "In PACKAGE, return the plist associated with a particular VERSION of the | 496 "In PACKAGE, return the plist associated with a particular VERSION of the |
303 package. PACKAGE is typically as returned by | 497 package. PACKAGE is typically as returned by |
304 `package-get-info-find-package'. If VERSION is nil, then return the | 498 `package-get-info-find-package'. If VERSION is nil, then return the |
305 first (aka most recent) version. Use `package-get-info-find-prop' | 499 first (aka most recent) version. Use `package-get-info-find-prop' |
306 to retrieve a particular property from the value returned by this." | 500 to retrieve a particular property from the value returned by this." |
307 (interactive "xPackage Info: \nsVersion: ") | 501 (interactive (package-get-interactive-package-query t t)) |
308 (while (and version package (not (string= (plist-get (car package) 'version) version))) | 502 (while (and version package (not (string= (plist-get (car package) 'version) version))) |
309 (setq package (cdr package))) | 503 (setq package (cdr package))) |
310 (if package (car package))) | 504 (if package (car package))) |
311 | 505 |
312 (defun package-get-info-prop (package-version property) | 506 (defun package-get-info-prop (package-version property) |
343 Use `package-get-dir' for directory to store stuff. | 537 Use `package-get-dir' for directory to store stuff. |
344 Creates `package-get-dir' it it doesn't exist." | 538 Creates `package-get-dir' it it doesn't exist." |
345 (interactive "FPackage filename: ") | 539 (interactive "FPackage filename: ") |
346 (if (not (file-exists-p package-get-dir)) | 540 (if (not (file-exists-p package-get-dir)) |
347 (make-directory package-get-dir)) | 541 (make-directory package-get-dir)) |
348 (concat | 542 (expand-file-name |
349 (file-name-as-directory package-get-dir) | 543 (file-name-nondirectory (or (and (fboundp 'efs-ftp-path) |
350 (file-name-nondirectory (or (nth 2 (efs-ftp-path filename)) filename)))) | 544 (nth 2 (efs-ftp-path filename))) |
351 | 545 filename)) |
546 (file-name-as-directory package-get-dir))) | |
352 | 547 |
353 (defun package-get-remote-filename (search filename) | 548 (defun package-get-remote-filename (search filename) |
354 "Return FILENAME as a remote filename. | 549 "Return FILENAME as a remote filename. |
355 It first checks if FILENAME already is a remote filename. If it is | 550 It first checks if FILENAME already is a remote filename. If it is |
356 not, then it uses the (car search) as the remote site-name and the (cadr | 551 not, then it uses the (car search) as the remote site-name and the (cadr |
456 (interactive) | 651 (interactive) |
457 ;; Load a fresh copy | 652 ;; Load a fresh copy |
458 (let ((custom-buffer (find-file-noselect | 653 (let ((custom-buffer (find-file-noselect |
459 (or (package-get-file-installed-p | 654 (or (package-get-file-installed-p |
460 "package-get-custom.el") | 655 "package-get-custom.el") |
461 (concat (file-name-directory | 656 (expand-file-name |
462 (package-get-file-installed-p | 657 "package-get-custom.el" |
463 "package-get-base.el")) | 658 (file-name-directory |
464 "package-get-custom.el")))) | 659 (package-get-file-installed-p |
660 "package-get-base.el")) | |
661 )))) | |
465 (pkg-groups nil)) | 662 (pkg-groups nil)) |
466 | 663 |
467 ;; clear existing stuff | 664 ;; clear existing stuff |
468 (delete-region (point-min custom-buffer) | 665 (delete-region (point-min custom-buffer) |
469 (point-max custom-buffer) custom-buffer) | 666 (point-max custom-buffer) custom-buffer) |