Subject: bug#78844: 30.1; feature request: public interface for querying builtin packages and versions

From: Xiyue Deng <[email-masked]>
Date: Sat, 28 Jun 2025 01:29:15 -0700

Hi Eli,

Eli Zaretskii <[email-masked]> writes:

>> From: Xiyue Deng <[email-masked]>
>> Cc: [email-masked], [email-masked], [email-masked]
>> Date: Fri, 27 Jun 2025 17:25:41 -0700
>> 
>> >> I don't seem to find any Elisp manual for package.el (there is one in
>> >> the Emacs manual but only has documents for user facing interfaces for
>> >> the package buffer).  But do let me know if there is.
>> >
>> > There's the "Packaging" chapter in the ELisp manual.  Whether it is a
>> > suitable place to add these interfaces depends on who is the intended
>> > audience of the interfaces.  If that chapter is not suitable, maybe
>> > the "Loading" chapter is a better place.
>> >
>> 
>> Admittedly I tried to be lazy and want to just add the new functions to
>> an existing section but didn't find any good fit.  I just bit the bullet
>> and added a new section in package.texi for these functions.  Please
>> help proofread.
>
> Thanks, comments below.  However, packages.texi is not the right place
> for this stuff, because it's for the user manual, not for the ELisp
> reference manual.  Since these APIs are for Lisp programmers, they
> should be documented in the ELisp manual, and the chapters I mentioned
> are in that manual.
>

I'm a bit confused: the file I changed was doc/lispref/package.texi,
which I suppose is the ELisp manual, no?

>> >> +(defun package-builtin-packages ()
>> >> +  "Return a list of builtin package symbols.
>> >> +The returned list is not guaranteed to be sorted."
>> >
>> > This doc string is too biased towards implementation, IMO.  I would
>> > rephrase it as follows:
>> >
>> >     Return a list of all the built-in packages.
>> 
>> To be precise, package--builtin-versions doesn't have all the built-in
>> packages (which I think is a subset of the list populated by
>> package--builtins).  As here we are more interested in packages that do
>> have a version associated, I have renamed the function to
>> `package-versioned-builtin-packages' to hopefully better convey the
>> intention.  Let me know if this is desirable.
>
> The renaming could be fine if the intended users of this API will
> indeed only want to know about versioned built-in packages, and won't
> care about those who have no versions.  Is that in fact true?  If so,
> why aren't unversioned packages important?
>
> If we do want to return the built-in packages that have no versions,
> then the name should remain as it was, and we should instead amend the
> implementation to also return packages that have no versions.
>

The motivation for introducing those functions is to be able to check
whether a built-in package has higher version compared to the same
package in other packaging system, which, in my case, is Debian's APT,
and could be useful for other packaging systems.  See my first mail[1]
for a concrete motivating example and my reply[2] to Stefan's email for
a more explanations.

The current status quo is that most Emacs addons that are packaged in
Debian are in `package--builtin-versions', so this is sufficient for our
use case.  Plus, on testing I realized that `package--builtins' is not
populated by default until one loads `finder-inf', which means increased
loading time to use that information.

In summary, I think having `package-versioned-builtin-packages' is good
enough for now.  And if requirement changes in the future, we can still
introduce `package-builtin-packages' to query `package--builtins'.

>> +@node Package Information
>> +@section Get built-in packages and versions
>> +@cindex package information
>> +
>> +Emacs ships a list of built-in packages which may also be packaged
>    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Emacs ships the packages themselves, not a list of packages.

My English fails me often.  Revised the wording a bit.  PTAL.

[1] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=78844#5
[2] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=78844#23

-- 
Regards,
Xiyue Deng
From 270eb596aac5d7bea7cf6005655b2586a9a6648d Mon Sep 17 00:00:00 2001
From: Xiyue Deng <[email-masked]>
Date: Fri, 20 Jun 2025 21:34:45 -0700
Subject: [PATCH] Add public interfaces for accessing builtin package info
 (Bug#78844)

* lisp/emacs-lisp/package.el (package-builtin-packages)
(package-builtin-package-version): New functions.
* doc/lispref/package.texi: Add a section 'Package Information' with
documentation for the new functions.
* etc/NEWS: Add entry for 'package-versioned-builtin-packages' and
'package-builtin-package-version'.
---
 doc/lispref/package.texi   | 25 +++++++++++++++++++++++++
 etc/NEWS                   |  7 +++++++
 lisp/emacs-lisp/package.el | 15 +++++++++++++++
 3 files changed, 47 insertions(+)

diff --git a/doc/lispref/package.texi b/doc/lispref/package.texi
index c96c2f5d234..32da72094d4 100644
--- a/doc/lispref/package.texi
+++ b/doc/lispref/package.texi
@@ -424,3 +424,28 @@ Forwards-Compatibility
 the manual installed, you can also read the
 @url{https://elpa.gnu.org/packages/doc/compat.html#Usage, Online
 Compat manual}.
+
+@node Package Information
+@section Get built-in packages and versions
+@cindex package information
+
+Emacs ships built-in packages which may also be packaged externally on
+ELPA.  Knowing whether a built-in package has a higher version than on
+ELPA or other packaging systems may be useful for external packaging
+tools.  Those who would like to query such information can use the
+following functions.
+
+@defun package-versioned-builtin-packages
+This function returns the list of packages that are built-in to Emacs
+and have a version.  The returned list contains one symbol for each
+built-in package that has a version, which are likely also packaged
+externally on ELPA.
+@end defun
+
+@defun package-builtin-package-version package
+This function returns the version of a built-in @var{package}.
+@var{package} should be a symbol.  The returned value is a list of
+integers representing the version of PACKAGE in the format returned by
+the function @code{version-to-list}, or nil if @var{package} does not
+have a version or is not a buil-tin package.
+@end defun
diff --git a/etc/NEWS b/etc/NEWS
index eb85baae341..5ea5f5314a2 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1965,6 +1965,13 @@ installed, total number of packages from all the package archives, total
 number of packages to upgrade and total number of new packages
 available.
 
++++
+*** New functions to query builtin package information.
+'package-versioned-builtin-packages' returns a list of symbols of
+built-in packages; 'package-builtin-package-version' returns the
+version-list of a given package symbol.  These functions provide stable
+interfaces for external tools to query built-in package information.
+
 ** RCIRC
 
 +++
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 9bcffb1df0b..aca2ba558d9 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -669,6 +669,21 @@ package-alist
 loaded and/or activated, customize `package-load-list'.")
 (put 'package-alist 'risky-local-variable t)
 
+;;;; Public interfaces for accessing built-in package info
+
+(defun package-versioned-builtin-packages ()
+  "Return a list of all the versioned built-in packages.
+The return value is a list of names of built-in packages represented as
+symbols."
+  (mapcar #'car package--builtin-versions))
+
+(defun package-builtin-package-version (package)
+  "Return the version of a built-in PACKAGE given by its symbol.
+The return value is a list of integers representing the version of
+PACKAGE, in the format returned by `version-to-list', or nil if the
+package has no version or is not a built-in package."
+  (alist-get package package--builtin-versions))
+
 ;;;###autoload
 (defvar package-activated-list nil
   ;; FIXME: This should implicitly include all builtin packages.
-- 
2.47.2