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

From: Spencer Baugh <[email-masked]>
Date: Thu, 03 Apr 2025 09:24:19 -0400

Stefan Monnier <[email-masked]> writes:

>> Makes sense.  How about this?
>
> See comments below.
>
>> diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
>> index b9a8dacab15..1269a9c95e7 100644
>> --- a/lisp/emacs-lisp/package.el
>> +++ b/lisp/emacs-lisp/package.el
>> @@ -4591,6 +4591,14 @@ package--quickstart-maybe-refresh
>>      (delete-file (concat package-quickstart-file "c"))
>>      (delete-file package-quickstart-file)))
>>  
>> +(defun package--quickstart-relative (load-name file)
>> +  "Return an expression which evaluates to FILE while loading LOAD-NAME."
>> +  (let* ((dir (file-name-directory (expand-file-name load-name)))
>> +         (relname (file-relative-name file dir)))
>> +    (if (string-prefix-p ".." relname)
>> +        file
>> +      `(file-name-concat (file-name-directory load-file-name) ,relname))))
>
> I think I'd test "../" just in case of dirnames that start with "..".

Good catch... actually I think I should just use file-in-directory-p,
that's more self-explanatory.

> 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.

>>  (defun package-quickstart-refresh ()
>>    "(Re)Generate the `package-quickstart-file'."
>>    (interactive)
>> @@ -4605,7 +4613,8 @@ package-quickstart-refresh
>>          ;; aren't truncated.
>>          (print-length nil)
>>          (print-level nil)
>> -        (Info-directory-list '("")))
>> +        (Info-directory-list '(""))
>> +        (qs-dir (file-name-directory (expand-file-name package-quickstart-file))))
>
> AFAICT `qs-dir` is not used.

Fixed.

>> @@ -4622,7 +4631,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-relative package-quickstart-file file))))
>>            (insert "(let* ((load-file-name " pfile ")\
>>  \(load-true-file-name load-file-name))\n")
>>            (insert-file-contents file)
>
> I think this needs wrapping to fit within 80 columns.

Fixed.

>> @@ -4638,7 +4647,10 @@ 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 (lambda (info-dir)
>> +                       (package--quickstart-relative package-quickstart-file info-dir))
>> +                     (butlast Info-directory-list))))
>>          (when info-dirs
>>            (pp `(progn (require 'info)
>>                        (info-initialize)
>
> I think this won't work because the rest of the code does:
>
>                       (setq Info-directory-list
>                             (append ',info-dirs Info-directory-list)))
>
> so the `file-name-concat`s won't be evaluated.

Oops... I guess I didn't run info when testing this.  Fixed.

>From e25d657cbe01b6fb1162c17c8d344eff63621131 Mon Sep 17 00:00:00 2001
From: Spencer Baugh <[email-masked]>
Date: Wed, 2 Apr 2025 17:21:24 -0400
Subject: [PATCH] Use relative names where possible in package-quickstart.el

package-quickstart.el hardcodes many absolute file names, which
makes it break if user-emacs-directory moves, or in other
situations.  To be slightly more robust to this, use relative
file names to packages that are located in the same directory as
package-quickstart.el.

* lisp/emacs-lisp/package.el (package--quickstart-rel): Add.
(package-quickstart-refresh): Use package--quickstart-rel on
file names.  (bug#77468)
---
 lisp/emacs-lisp/package.el | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index b9a8dacab15..a575dea7b92 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -4591,6 +4591,14 @@ package--quickstart-maybe-refresh
     (delete-file (concat package-quickstart-file "c"))
     (delete-file package-quickstart-file)))
 
+(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))
+
 (defun package-quickstart-refresh ()
   "(Re)Generate the `package-quickstart-file'."
   (interactive)
@@ -4605,7 +4613,8 @@ package-quickstart-refresh
         ;; aren't truncated.
         (print-length nil)
         (print-level nil)
-        (Info-directory-list '("")))
+        (Info-directory-list '(""))
+        (qs-dir (file-name-directory (expand-file-name package-quickstart-file))))
     (dolist (elt package-alist)
       (condition-case err
           (package-activate (car elt))
@@ -4622,7 +4631,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 qs-dir file))))
           (insert "(let* ((load-file-name " pfile ")\
 \(load-true-file-name load-file-name))\n")
           (insert-file-contents file)
@@ -4638,12 +4647,15 @@ 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 (lambda (info-dir)
+                       (package--quickstart-rel qs-dir info-dir))
+                     (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.
-- 
2.39.3