> I guess we need to reverse the list of directories, since
> directory-files sorts using string-lessp as the predicate?
Unfortunately, `directory-files` order in `package-load-all-descriptors` is later overlapped by `package--get-activatable-pkg` order which sorts `package-alist` in-place.
> What does "broken" mean in this case? I fear that your patch just
> changes what is necessary to resolve the issue in your case, but the
> underlying problem (the destructive modification of `package-list')
> still persists?
"Broken" means wrong order of versions.
As you can see in `package-process-define-package`
(old-pkgs (assq name package-alist)))
...
(push new-pkg-desc (cdr old-pkgs))
gives destructive modification of `package-alist` too.
We can put this destructive modification in one place, as Stefan noted, like this
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index ba0e3618f28..c184625d754 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -686,7 +686,7 @@ Convert EXP into a `package-desc' object using the
If there already exists a package by the same name in
`package-alist', insert this object there such that the packages
-are sorted with the highest version first."
+are sorted with VC and builtin packages first and the highest version second."
(when (eq (car-safe exp) 'define-package)
(let* ((new-pkg-desc (apply #'package-desc-from-define (cdr exp)))
(name (package-desc-name new-pkg-desc))
@@ -696,13 +696,29 @@ are sorted with the highest version first."
;; If there's no old package, just add this to `package-alist'.
(push (list name new-pkg-desc) package-alist)
;; If there is, insert the new package at the right place in the list.
- (while
- (if (and (cdr old-pkgs)
- (version-list-< version
- (package-desc-version (cadr old-pkgs))))
- (setq old-pkgs (cdr old-pkgs))
- (push new-pkg-desc (cdr old-pkgs))
- nil)))
+ (progn
+ ;; Prefer newer packages
+ (while
+ (if (and (cdr old-pkgs)
+ (version-list-< version
+ (package-desc-version (cadr old-pkgs))))
+ (setq old-pkgs (cdr old-pkgs))
+ (push new-pkg-desc (cdr old-pkgs))
+ nil))
+ (let ((pkg-desc (sort (cdr (assq name package-alist))
+ (lambda (p1 p2)
+ (let ((v1 (package-desc-version p1))
+ (v2 (package-desc-version p2)))
+ (or
+ (and
+ ;; Prefer VC packages.
+ (package-vc-p p1)
+ (not (package-vc-p p2)))
+ ;; Prefer builtin packages.
+ (and
+ (package-built-in-p p1 v1)
+ (not (package-built-in-p p2 v2)))))))))
+ (setq new-pkg-desc (car pkg-desc)))))
new-pkg-desc)))
(declare-function package-vc-commit "package-vc" (pkg))
@@ -916,17 +932,7 @@ correspond to previously loaded files."
(defun package--get-activatable-pkg (pkg-name)
;; Is "activatable" a word?
- (let ((pkg-descs (sort (cdr (assq pkg-name package-alist))
- (lambda (p1 p2)
- (let ((v1 (package-desc-version p1))
- (v2 (package-desc-version p2)))
- (or
- ;; Prefer VC packages.
- (package-vc-p p1)
- (package-vc-p p2)
- ;; Prefer builtin packages.
- (package-disabled-p p1 v1)
- (not (package-disabled-p p2 v2))))))))
+ (let ((pkg-descs (cdr (assq pkg-name package-alist))))
;; Check if PACKAGE is available in `package-alist'.
(while
(when pkg-descs