emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

emacs-29 b38e56d8a9 2/2: Handle missing dependencies for source packages


From: Philip Kaludercic
Subject: emacs-29 b38e56d8a9 2/2: Handle missing dependencies for source packages
Date: Sun, 25 Dec 2022 03:40:22 -0500 (EST)

branch: emacs-29
commit b38e56d8a98d9488ed6ae16521334c25304153ca
Author: Philip Kaludercic <philipk@posteo.net>
Commit: Philip Kaludercic <philipk@posteo.net>

    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.
---
 lisp/emacs-lisp/package-vc.el | 231 ++++++++++++++++++++++++++----------------
 1 file changed, 144 insertions(+), 87 deletions(-)

diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 8f0eedd2f8..17c37aa517 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -406,99 +406,156 @@ 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."
-  ;; Remove any previous instance of PKG-DESC from `package-alist'
-  (let ((pkgs (assq (package-desc-name pkg-desc) package-alist)))
-    (when pkgs
-      (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
-
-  ;; In case the package was installed directly from source, the
-  ;; dependency list wasn't know beforehand, and they might have
-  ;; to be installed explicitly.
-  (let ((deps '()))
-    (dolist (file (directory-files pkg-dir t "\\.el\\'" t))
-      (with-temp-buffer
-        (insert-file-contents file)
-        (when-let* ((require-lines (lm-header-multiline "package-requires")))
-          (thread-last
-            (mapconcat #'identity require-lines " ")
-            package-read-from-string
-            package--prepare-dependencies
-            (nconc deps)
-            (setq deps)))))
-    (dolist (dep deps)
-      (cl-callf version-to-list (cadr dep)))
-    (package-download-transaction
-     (package-compute-transaction nil (delete-dups deps))))
-
-  (let ((default-directory (file-name-as-directory pkg-dir))
-        (pkg-file (expand-file-name (package--description-file pkg-dir) 
pkg-dir)))
-    ;; Generate autoloads
-    (let* ((name (package-desc-name pkg-desc))
-           (auto-name (format "%s-autoloads.el" name))
-           (extras (package-desc-extras pkg-desc))
-           (lisp-dir (alist-get :lisp-dir extras)))
-      (package-generate-autoloads
-       name (file-name-concat pkg-dir lisp-dir))
-      (when lisp-dir
-        (write-region
-         (with-temp-buffer
-           (insert ";; Autoload indirection for package-vc\n\n")
-           (prin1 `(load (expand-file-name
-                          ,(file-name-concat lisp-dir auto-name)
-                          (or (and load-file-name
-                                   (file-name-directory load-file-name))
-                              (car load-path))))
-                  (current-buffer))
-           (buffer-string))
-         nil (expand-file-name auto-name pkg-dir))))
-
-    ;; Generate package file
-    (package-vc--generate-description-file pkg-desc pkg-file)
-
-    ;; Detect a manual
-    (when-let ((pkg-spec (package-vc--desc->spec pkg-desc))
-               ((executable-find "install-info")))
-      (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
-        (package-vc--build-documentation pkg-desc doc-file))))
-
-  ;; Update package-alist.
-  (let ((new-desc (package-load-descriptor pkg-dir)))
-    ;; Activation has to be done before compilation, so that if we're
-    ;; upgrading and macros have changed we load the new definitions
-    ;; before compiling.
-    (when (package-activate-1 new-desc :reload :deps)
-      ;; FIXME: Compilation should be done as a separate, optional, step.
-      ;; E.g. for multi-package installs, we should first install all packages
-      ;; and then compile them.
-      (package--compile new-desc)
-      (when package-native-compile
-        (package--native-compile-async new-desc))
-      ;; After compilation, load again any files loaded by
-      ;; `activate-1', so that we use the byte-compiled definitions.
-      (package--reload-previously-loaded new-desc)))
-
-  ;; Mark package as selected
-  (package--save-selected-packages
-   (cons (package-desc-name pkg-desc)
-         package-selected-packages))
-  (package--quickstart-maybe-refresh)
-
-  ;; Confirm that the installation was successful
-  (let ((main-file (package-vc--main-file pkg-desc)))
-    (message "VC package `%s' installed (Version %s, Revision %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)
+  (let (missing)
+    ;; Remove any previous instance of PKG-DESC from `package-alist'
+    (let ((pkgs (assq (package-desc-name pkg-desc) package-alist)))
+      (when pkgs
+        (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
+
+    ;; In case the package was installed directly from source, the
+    ;; dependency list wasn't know beforehand, and they might have
+    ;; to be installed explicitly.
+    (let ((deps '()))
+      (dolist (file (directory-files pkg-dir t "\\.el\\'" t))
+        (with-temp-buffer
+          (insert-file-contents file)
+          (when-let* ((require-lines (lm-header-multiline "package-requires")))
+            (thread-last
+              (mapconcat #'identity require-lines " ")
+              package-read-from-string
+              package--prepare-dependencies
+              (nconc deps)
+              (setq deps)))))
+      (dolist (dep deps)
+        (cl-callf version-to-list (cadr dep)))
+      (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)))
+      ;; Generate autoloads
+      (let* ((name (package-desc-name pkg-desc))
+             (auto-name (format "%s-autoloads.el" name))
+             (extras (package-desc-extras pkg-desc))
+             (lisp-dir (alist-get :lisp-dir extras)))
+        (package-generate-autoloads
+         name (file-name-concat pkg-dir lisp-dir))
+        (when lisp-dir
+          (write-region
+           (with-temp-buffer
+             (insert ";; Autoload indirection for package-vc\n\n")
+             (prin1 `(load (expand-file-name
+                            ,(file-name-concat lisp-dir auto-name)
+                            (or (and load-file-name
+                                     (file-name-directory load-file-name))
+                                (car load-path))))
+                    (current-buffer))
+             (buffer-string))
+           nil (expand-file-name auto-name pkg-dir))))
+
+      ;; Generate package file
+      (package-vc--generate-description-file pkg-desc pkg-file)
+
+      ;; Detect a manual
+      (when-let ((pkg-spec (package-vc--desc->spec pkg-desc))
+                 ((executable-find "install-info")))
+        (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
+          (package-vc--build-documentation pkg-desc doc-file))))
+
+    ;; Update package-alist.
+    (let ((new-desc (package-load-descriptor pkg-dir)))
+      ;; Activation has to be done before compilation, so that if we're
+      ;; upgrading and macros have changed we load the new definitions
+      ;; before compiling.
+      (when (package-activate-1 new-desc :reload :deps)
+        ;; FIXME: Compilation should be done as a separate, optional, step.
+        ;; E.g. for multi-package installs, we should first install all 
packages
+        ;; and then compile them.
+        (package--compile new-desc)
+        (when package-native-compile
+          (package--native-compile-async new-desc))
+        ;; After compilation, load again any files loaded by
+        ;; `activate-1', so that we use the byte-compiled definitions.
+        (package--reload-previously-loaded new-desc)))
+
+    ;; Mark package as selected
+    (package--save-selected-packages
+     (cons (package-desc-name pkg-desc)
+           package-selected-packages))
+    (package--quickstart-maybe-refresh)
+
+    ;; Confirm that the installation was successful
+    (let ((main-file (package-vc--main-file pkg-desc)))
+      (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)
+               (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.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]