Subject: bug#77468: 30.1.50; package-quickstart file is not relocatable

From: Spencer Baugh <[email-masked]>
Date: Mon, 07 Apr 2025 13:02:41 -0400

Stefan Monnier <[email-masked]> writes:

>>> Also, could we compute (file-name-directory load-file-name)
>>> once at the beginning of the quickstart file instead of once per
>>> inlined file?
>> Done.
>
> I don't see it:
>
>> +(defun package--quickstart-rel (dir file)
>> +  "Return an expression which evaluates to FILE while loading a file in DIR."
>> +  (if (file-in-directory-p file dir)
>> +      ;; Use a relative name so we can still find FILE if DIR is moved.
>> +      `(file-name-concat (file-name-directory load-file-name)
>> +                         ,(file-relative-name file dir))
>> +    file))
>
> We still generate code that computes `(file-name-directory
> load-file-name)` N times, AFAICT.

Oh, I misunderstood what you were asking for, I see now.

I guess file-name-directory can be slow due to find-file-name-handler...
that's sad since it's otherwise just a trivial string operation.

I guess I could wrap the entire file in a let binding, but that's mildly
annoying and ugly...

How about putting the let binding outside the file?  Like this:

diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index b9a8dacab15..d65d3baa7fa 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -1699,7 +1699,10 @@ package-activate-all
   (let* ((elc (concat package-quickstart-file "c"))
          (qs (if (file-readable-p elc) elc
                (if (file-readable-p package-quickstart-file)
-                   package-quickstart-file))))
+                   package-quickstart-file)))
+         (default-directory
+          ;; For expressions produced by `package--quickstart-rel'.
+          (file-name-directory (expand-file-name package-quickstart-file))))
     ;; The quickstart file presumes that it has a blank slate,
     ;; so don't use it if we already activated some packages.
     (or (and qs (not (bound-and-true-p package-activated-list))
@@ -4591,6 +4594,16 @@ package--quickstart-maybe-refresh
     (delete-file (concat package-quickstart-file "c"))
     (delete-file package-quickstart-file)))
 
+(defun package--quickstart-rel (file)
+  "Return an expression which evaluates to FILE.
+
+If FILE is in `default-directory', returns an expression that is
+relative to `default-directory', so if that directory is moved we can
+still find FILE."
+  (if (file-in-directory-p file default-directory)
+      `(file-name-concat default-directory ,(file-relative-name file))
+    file))
+
 (defun package-quickstart-refresh ()
   "(Re)Generate the `package-quickstart-file'."
   (interactive)
@@ -4605,7 +4618,10 @@ package-quickstart-refresh
         ;; aren't truncated.
         (print-length nil)
         (print-level nil)
-        (Info-directory-list '("")))
+        (Info-directory-list '(""))
+        (default-directory
+         ;; So `package--quickstart-rel' produces relative expressions.
+         (file-name-directory (expand-file-name package-quickstart-file))))
     (dolist (elt package-alist)
       (condition-case err
           (package-activate (car elt))
@@ -4622,7 +4638,7 @@ package-quickstart-refresh
                 ;; Prefer uncompiled files (and don't accept .so files).
                 (let ((load-suffixes '(".el" ".elc")))
                   (locate-library (package--autoloads-file-name pkg))))
-               (pfile (prin1-to-string file)))
+               (pfile (prin1-to-string (package--quickstart-rel file))))
           (insert "(let* ((load-file-name " pfile ")\
 \(load-true-file-name load-file-name))\n")
           (insert-file-contents file)
@@ -4638,12 +4654,13 @@ package-quickstart-refresh
                   (append ',(mapcar #'package-desc-name package--quickstart-pkgs)
                           package-activated-list)))
           (current-buffer))
-      (let ((info-dirs (butlast Info-directory-list)))
+      (let ((info-dirs
+             (mapcar #'package--quickstart-rel (butlast Info-directory-list))))
         (when info-dirs
           (pp `(progn (require 'info)
                       (info-initialize)
                       (setq Info-directory-list
-                            (append ',info-dirs Info-directory-list)))
+                            (append (list . ,info-dirs) Info-directory-list)))
               (current-buffer))))
       ;; Use `\s' instead of a space character, so this code chunk is not
       ;; mistaken for an actual file-local section of package.el.