Function: package-compute-transaction
package-compute-transaction is a byte-compiled function defined in
package.el.gz.
Signature
(package-compute-transaction PACKAGES REQUIREMENTS &optional SEEN)
Documentation
Return a list of packages to be installed, including PACKAGES.
PACKAGES should be a list of package-desc.
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.
This function recursively computes the requirements of the packages in REQUIREMENTS, and returns a list of all the packages that must be installed. Packages that are already installed are not included in this list.
SEEN is used internally to detect infinite recursion.
Source Code
;; Defined in /usr/src/emacs/lisp/emacs-lisp/package.el.gz
;;; Dependency Management
;; Calculating the full transaction necessary for an installation,
;; keeping track of which packages were installed strictly as
;; dependencies, and determining which packages cannot be removed
;; because they are dependencies.
(defun package-compute-transaction (packages requirements &optional seen)
"Return a list of packages to be installed, including PACKAGES.
PACKAGES should be a list of `package-desc'.
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.
This function recursively computes the requirements of the
packages in REQUIREMENTS, and returns a list of all the packages
that must be installed. Packages that are already installed are
not included in this list.
SEEN is used internally to detect infinite recursion."
;; FIXME: We really should use backtracking to explore the whole
;; search space (e.g. if foo require bar-1.3, and bar-1.4 requires toto-1.1
;; whereas bar-1.3 requires toto-1.0 and the user has put a hold on toto-1.0:
;; the current code might fail to see that it could install foo by using the
;; older bar-1.3).
(dolist (elt requirements)
(let* ((next-pkg (car elt))
(next-version (cadr elt))
(already ()))
(dolist (pkg packages)
(if (eq next-pkg (package-desc-name pkg))
(setq already pkg)))
(when already
(if (version-list-<= next-version (package-desc-version already))
;; `next-pkg' is already in `packages', but its position there
;; means it might be installed too late: remove it from there, so
;; we re-add it (along with its dependencies) at an earlier place
;; below (bug#16994).
(if (memq already seen) ;Avoid inf-loop on dependency cycles.
(message "Dependency cycle going through %S"
(package-desc-full-name already))
(setq packages (delq already packages))
(setq already nil))
(error "Need package `%s-%s', but only %s is being installed"
next-pkg (package-version-join next-version)
(package-version-join (package-desc-version already)))))
(cond
(already nil)
((package-installed-p next-pkg next-version) nil)
(t
;; A package is required, but not installed. It might also be
;; blocked via `package-load-list'.
(let ((pkg-descs (cdr (assq next-pkg package-archive-contents)))
(found nil)
(found-something nil)
(problem nil))
(while (and pkg-descs (not found))
(let* ((pkg-desc (pop pkg-descs))
(version (package-desc-version pkg-desc))
(disabled (package-disabled-p next-pkg version)))
(cond
((version-list-< version next-version)
;; pkg-descs is sorted by priority, not version, so
;; don't error just yet.
(unless found-something
(setq found-something (package-version-join version))))
(disabled
(unless problem
(setq problem
(if (stringp disabled)
(format-message
"Package `%s' held at version %s, but version %s required"
next-pkg disabled
(package-version-join next-version))
(format-message "Required package `%s' is disabled"
next-pkg)))))
(t (setq found pkg-desc)))))
(unless found
(cond
(problem (error "%s" problem))
(found-something
(error "Need package `%s-%s', but only %s is available"
next-pkg (package-version-join next-version)
found-something))
(t (error "Package `%s-%s' is unavailable"
next-pkg (package-version-join next-version)))))
(setq packages
(package-compute-transaction (cons found packages)
(package-desc-reqs found)
(cons found seen))))))))
packages)