diff options
Diffstat (limited to 'lisp/emacs-lisp/package.el')
-rw-r--r-- | lisp/emacs-lisp/package.el | 177 |
1 files changed, 102 insertions, 75 deletions
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 2552ad4eb68..5dc2938fe08 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -319,20 +319,39 @@ Like `package-alist', but maps package name to a second alist. The inner alist is keyed by version.") (put 'package-obsolete-alist 'risky-local-variable t) -(defconst package-subdirectory-regexp - "^\\([^.].*\\)-\\([0-9]+\\(?:[.][0-9]+\\)*\\)$" - "Regular expression matching the name of a package subdirectory. -The first subexpression is the package name. -The second subexpression is the version string.") - -(defun package-version-join (l) - "Turn a list of version numbers into a version string." - (mapconcat 'int-to-string l ".")) +(defun package-version-join (vlist) + "Return the version string corresponding to the list VLIST. +This is, approximately, the inverse of `version-to-list'. +\(Actually, it returns only one of the possible inverses, since +`version-to-list' is a many-to-one operation.)" + (if (null vlist) + "" + (let ((str-list (list "." (int-to-string (car vlist))))) + (dolist (num (cdr vlist)) + (cond + ((>= num 0) + (push (int-to-string num) str-list) + (push "." str-list)) + ((< num -3) + (error "Invalid version list `%s'" vlist)) + (t + ;; pre, or beta, or alpha + (cond ((equal "." (car str-list)) + (pop str-list)) + ((not (string-match "[0-9]+" (car str-list))) + (error "Invalid version list `%s'" vlist))) + (push (cond ((= num -1) "pre") + ((= num -2) "beta") + ((= num -3) "alpha")) + str-list)))) + (if (equal "." (car str-list)) + (pop str-list)) + (apply 'concat (nreverse str-list))))) (defun package-strip-version (dirname) "Strip the version from a combined package name and version. E.g., if given \"quux-23.0\", will return \"quux\"" - (if (string-match package-subdirectory-regexp dirname) + (if (string-match (concat "\\`" package-subdirectory-regexp "\\'") dirname) (match-string 1 dirname))) (defun package-load-descriptor (dir package) @@ -357,12 +376,13 @@ In each valid package subdirectory, this function loads the description file containing a call to `define-package', which updates `package-alist' and `package-obsolete-alist'." (let ((all (memq 'all package-load-list)) + (regexp (concat "\\`" package-subdirectory-regexp "\\'")) name version force) (dolist (dir (cons package-user-dir package-directory-list)) (when (file-directory-p dir) (dolist (subdir (directory-files dir)) (when (and (file-directory-p (expand-file-name subdir dir)) - (string-match package-subdirectory-regexp subdir)) + (string-match regexp subdir)) (setq name (intern (match-string 1 subdir)) version (match-string 2 subdir) force (assq name package-load-list)) @@ -554,30 +574,29 @@ EXTRA-PROPERTIES is currently unused." (package-autoload-ensure-default-file generated-autoload-file)) (update-directory-autoloads pkg-dir))) -(defun package-untar-buffer () +(defvar tar-parse-info) +(declare-function tar-untar-buffer "tar-mode" ()) + +(defun package-untar-buffer (dir) "Untar the current buffer. -This uses `tar-untar-buffer' if it is available. -Otherwise it uses an external `tar' program. -`default-directory' should be set by the caller." +This uses `tar-untar-buffer' from Tar mode. All files should +untar into a directory named DIR; otherwise, signal an error." (require 'tar-mode) - (if (fboundp 'tar-untar-buffer) - (progn - ;; tar-mode messes with narrowing, so we just let it have the - ;; whole buffer to play with. - (delete-region (point-min) (point)) - (tar-mode) - (tar-untar-buffer)) - ;; FIXME: check the result. - (call-process-region (point) (point-max) "tar" nil '(nil nil) nil - "xf" "-"))) + (tar-mode) + ;; Make sure everything extracts into DIR. + (let ((regexp (concat "\\`" (regexp-quote dir) "/"))) + (dolist (tar-data tar-parse-info) + (unless (string-match regexp (aref tar-data 2)) + (error "Package does not untar cleanly into directory %s/" dir)))) + (tar-untar-buffer)) (defun package-unpack (name version) - (let ((pkg-dir (expand-file-name (concat (symbol-name name) "-" version) - package-user-dir))) + (let* ((dirname (concat (symbol-name name) "-" version)) + (pkg-dir (expand-file-name dirname package-user-dir))) (make-directory package-user-dir t) ;; FIXME: should we delete PKG-DIR if it exists? (let* ((default-directory (file-name-as-directory package-user-dir))) - (package-untar-buffer) + (package-untar-buffer dirname) (package-generate-autoloads (symbol-name name) pkg-dir) (let ((load-path (cons pkg-dir load-path))) (byte-recompile-directory pkg-dir 0 t))))) @@ -592,7 +611,9 @@ Otherwise it uses an external `tar' program. (if (string= file-name "package") (package--write-file-no-coding (expand-file-name (concat file-name ".el") package-user-dir)) - (let* ((pkg-dir (expand-file-name (concat file-name "-" version) + (let* ((pkg-dir (expand-file-name (concat file-name "-" + (package-version-join + (version-to-list version))) package-user-dir)) (el-file (expand-file-name (concat file-name ".el") pkg-dir)) (pkg-file (expand-file-name (concat file-name "-pkg.el") pkg-dir))) @@ -848,15 +869,17 @@ The package is found on one of the archives in `package-archives'." ;; Try to activate it. (package-initialize)) -(defun package-strip-rcs-id (v-str) - "Strip RCS version ID from the version string. +(defun package-strip-rcs-id (str) + "Strip RCS version ID from the version string STR. If the result looks like a dotted numeric version, return it. Otherwise return nil." - (if v-str - (if (string-match "^[ \t]*[$]Revision:[ \t]\([0-9.]+\)[ \t]*[$]$" v-str) - (match-string 1 v-str) - (if (string-match "^[0-9.]*$" v-str) - v-str)))) + (when str + (when (string-match "\\`[ \t]*[$]Revision:[ \t]+" str) + (setq str (substring str (match-end 0)))) + (condition-case nil + (if (version-to-list str) + str) + (error nil)))) (defun package-buffer-info () "Return a vector describing the package in the current buffer. @@ -911,43 +934,47 @@ boundaries." "Find package information for a tar file. FILE is the name of the tar file to examine. The return result is a vector like `package-buffer-info'." - (unless (string-match "^\\(.+\\)-\\([0-9.]+\\)\\.tar$" file) - (error "Invalid package name `%s'" file)) - (let* ((pkg-name (file-name-nondirectory (match-string-no-properties 1 file))) - (pkg-version (match-string-no-properties 2 file)) - ;; Extract the package descriptor. - (pkg-def-contents (shell-command-to-string - ;; Requires GNU tar. - (concat "tar -xOf " file " " - pkg-name "-" pkg-version "/" - pkg-name "-pkg.el"))) - (pkg-def-parsed (package-read-from-string pkg-def-contents))) - (unless (eq (car pkg-def-parsed) 'define-package) - (error "No `define-package' sexp is present in `%s-pkg.el'" pkg-name)) - (let ((name-str (nth 1 pkg-def-parsed)) - (version-string (nth 2 pkg-def-parsed)) - (docstring (nth 3 pkg-def-parsed)) - (requires (nth 4 pkg-def-parsed)) - (readme (shell-command-to-string - ;; Requires GNU tar. - (concat "tar -xOf " file " " - pkg-name "-" pkg-version "/README")))) - (unless (equal pkg-version version-string) - (error "Package has inconsistent versions")) - (unless (equal pkg-name name-str) - (error "Package has inconsistent names")) - ;; Kind of a hack. - (if (string-match ": Not found in archive" readme) - (setq readme nil)) - ;; Turn string version numbers into list form. - (if (eq (car requires) 'quote) - (setq requires (car (cdr requires)))) - (setq requires - (mapcar (lambda (elt) - (list (car elt) - (version-to-list (cadr elt)))) - requires)) - (vector pkg-name requires docstring version-string readme)))) + (let ((default-directory (file-name-directory file)) + (file (file-name-nondirectory file))) + (unless (string-match (concat "\\`" package-subdirectory-regexp "\\.tar\\'") + file) + (error "Invalid package name `%s'" file)) + (let* ((pkg-name (match-string-no-properties 1 file)) + (pkg-version (match-string-no-properties 2 file)) + ;; Extract the package descriptor. + (pkg-def-contents (shell-command-to-string + ;; Requires GNU tar. + (concat "tar -xOf " file " " + + pkg-name "-" pkg-version "/" + pkg-name "-pkg.el"))) + (pkg-def-parsed (package-read-from-string pkg-def-contents))) + (unless (eq (car pkg-def-parsed) 'define-package) + (error "No `define-package' sexp is present in `%s-pkg.el'" pkg-name)) + (let ((name-str (nth 1 pkg-def-parsed)) + (version-string (nth 2 pkg-def-parsed)) + (docstring (nth 3 pkg-def-parsed)) + (requires (nth 4 pkg-def-parsed)) + (readme (shell-command-to-string + ;; Requires GNU tar. + (concat "tar -xOf " file " " + pkg-name "-" pkg-version "/README")))) + (unless (equal pkg-version version-string) + (error "Package has inconsistent versions")) + (unless (equal pkg-name name-str) + (error "Package has inconsistent names")) + ;; Kind of a hack. + (if (string-match ": Not found in archive" readme) + (setq readme nil)) + ;; Turn string version numbers into list form. + (if (eq (car requires) 'quote) + (setq requires (car (cdr requires)))) + (setq requires + (mapcar (lambda (elt) + (list (car elt) + (version-to-list (cadr elt)))) + requires)) + (vector pkg-name requires docstring version-string readme))))) ;;;###autoload (defun package-install-from-buffer (pkg-info type) @@ -1037,7 +1064,7 @@ makes them available for download." (unless (file-exists-p package-user-dir) (make-directory package-user-dir t)) (dolist (archive package-archives) - (condition-case nil + (condition-case-no-debug nil (package--download-one-archive archive "archive-contents") (error (message "Failed to download `%s' archive." (car archive))))) @@ -1465,7 +1492,7 @@ packages marked for deletion are removed." delete-list ", ")))) (dolist (elt delete-list) - (condition-case err + (condition-case-no-debug err (package-delete (car elt) (cdr elt)) (error (message (cadr err))))) (error "Aborted"))) |