Handle missing dependencies for source packages

* lisp/emacs-lisp/package-vc.el (package-vc-install-dependencies): Add
new function.
(package-vc--unpack-1): Call 'package-vc-install-dependencies' instead
of 'package-compute-transaction' and 'package-download-transaction'.

It is unreasonable to abort the installation, since we cannot expect
all dependencies to be available in the regular archives.  Instead we
note which packages couldn't be found, and warn the user that these
will be missing.
This commit is contained in:
Philip Kaludercic 2022-12-25 09:35:36 +01:00
parent 7bc7b6b4dd
commit b38e56d8a9

View file

@ -406,12 +406,59 @@ otherwise it's assumed to be an Info file."
(when clean-up
(delete-file file))))
(defun package-vc-install-dependencies (requirements)
"Install missing dependencies, and return missing ones.
The return value will be nil if everything was found, or a list
of (NAME VERSION) pairs of all packages that couldn't be found.
REQUIREMENTS should be a list of additional requirements; each
element in this list should have the form (PACKAGE VERSION-LIST),
where PACKAGE is a package name and VERSION-LIST is the required
version of that package."
(let ((to-install '()) (missing '()))
(cl-labels ((search (pkg)
"Attempt to find all dependencies for PKG."
(cond
((assq (car pkg) to-install)) ;inhibit cycles
((package-installed-p (car pkg)))
((let* ((pac package-archive-contents)
(desc (cadr (assoc (car pkg) pac))))
(if desc
(let ((reqs (package-desc-reqs pkg)))
(push pkg to-install)
(mapc #'search reqs))
(push pkg missing))))))
(version-order (a b)
"Predicate to sort packages in order."
(version-list-< (cadr b) (cadr a)))
(duplicate-p (a b)
"Are A and B the same package?"
(eq (car a) (car b)))
(depends-on-p (target package)
"Does PACKAGE depend on TARGET?"
(or (eq target package)
(let* ((pac package-archive-contents)
(desc (cadr (assoc package pac))))
(seq-some
(apply-partially #'depends-on-p target)
(package-desc-reqs desc)))))
(dependent-order (a b)
(or (not (depends-on-p (car b) (car a)))
(depends-on-p (car a) (car b)))))
(mapc #'search requirements)
(cl-callf sort to-install #'version-order)
(cl-callf seq-uniq to-install #'duplicate-p)
(cl-callf sort to-install #'dependent-order))
(mapc #'package-install-from-archive to-install)
missing))
(defun package-vc--unpack-1 (pkg-desc pkg-dir)
"Prepare PKG-DESC that is already checked-out in PKG-DIR.
This includes downloading missing dependencies, generating
autoloads, generating a package description file (used to
identify a package as a VC package later on), building
documentation and marking the package as installed."
(let (missing)
;; Remove any previous instance of PKG-DESC from `package-alist'
(let ((pkgs (assq (package-desc-name pkg-desc) package-alist)))
(when pkgs
@ -433,8 +480,10 @@ documentation and marking the package as installed."
(setq deps)))))
(dolist (dep deps)
(cl-callf version-to-list (cadr dep)))
(package-download-transaction
(package-compute-transaction nil (delete-dups deps))))
(setf missing (package-vc-install-dependencies (delete-dups deps)))
(setf missing (delq (assq (package-desc-name pkg-desc)
missing)
missing)))
(let ((default-directory (file-name-as-directory pkg-dir))
(pkg-file (expand-file-name (package--description-file pkg-dir) pkg-dir)))
@ -491,14 +540,22 @@ documentation and marking the package as installed."
;; Confirm that the installation was successful
(let ((main-file (package-vc--main-file pkg-desc)))
(message "VC package `%s' installed (Version %s, Revision %S)."
(message "VC package `%s' installed (Version %s, Revision %S).%s"
(package-desc-name pkg-desc)
(lm-with-file main-file
(package-strip-rcs-id
(or (lm-header "package-version")
(lm-header "version"))))
(vc-working-revision main-file)))
t)
(vc-working-revision main-file)
(if missing
(format
" Failed to install the following dependencies: %s"
(mapconcat
(lambda (p)
(format "%s (%s)" (car p) (cadr p)))
missing ", "))
"")))
t))
(defun package-vc--guess-backend (url)
"Guess the VC backend for URL.