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

From: Xiyue Deng <[email-masked]>
Date: Fri, 27 Jun 2025 17:25:41 -0700

Hi Eli,

Eli Zaretskii <[email-masked]> writes:

>> Cc: [email-masked], Stefan Monnier <[email-masked]>
>> From: Xiyue Deng <[email-masked]>
>> Date: Fri, 27 Jun 2025 03:34:25 -0700
>> 
>> > and see if these packages need documentation in the Elisp manual (they
>> > may or may not).
>> >
>> 
>> 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.

>> +(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 return value is a list of names of built-in packages represented
>   as symbols.
>
> I don't see a need to mention that the list is not sorted, because not
> saying it's sorted should be enough for users not to rely on that.

Indeed, this seems to be an unnecessary detail to call out.

> (As a matter of fact, I think the list will be sorted, because
> package--builtin-versions is sorted.)
>

In fact, in 30.1 (which I'm using) it's almost sorted in descending
alphabetic order except that the last item is "emacs" and the second to
last is "all-out".  Anyway, as you mentioned, not mentioning the
ordering in the docstring should indicate that a caller should not make
any assumptions.

>> +(defun package-builtin-package-version (package)
>> +  "Return the version-list of PACKAGE (symbol).
>
> This uses "version-list", which is not accepted terminology in Emacs.
> I suggest
>
>     Return the version of a built-in PACKAGE given by its symbol.
>   Value is a list of integers representing the version of PACKAGE,
>   in the format returned by `version-to-list', or nil if PACKAGE
>   has no version or is not a built-in package.
>

Adapted.

>> diff --git a/etc/NEWS b/etc/NEWS
>> index eb85baae341..e940b5fce17 100644
>> --- a/etc/NEWS
>> +++ b/etc/NEWS
>> @@ -2607,6 +2607,13 @@ sleep state.
>>  and set the top-level buffer-local value of a variable.  A top-level
>>  value is the one that variable has outside of any let-bindings.
>>  
>> ++++
>> +** New functions to query builtin package information.
>> +'package-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.
>
> This should go under the "Package" section in NEWS.
>

Moved there.

> Thanks.

PTAL.

-- 
Regards,
Xiyue Deng
From 78ab8909c3550a8bf1cbb39b0abdf433946aa307 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   | 24 ++++++++++++++++++++++++
 etc/NEWS                   |  7 +++++++
 lisp/emacs-lisp/package.el | 15 +++++++++++++++
 3 files changed, 46 insertions(+)

diff --git a/doc/lispref/package.texi b/doc/lispref/package.texi
index c96c2f5d234..b65b70843b1 100644
--- a/doc/lispref/package.texi
+++ b/doc/lispref/package.texi
@@ -424,3 +424,27 @@ 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 a list of built-in packages which may also be packaged
+externally on ELPA.  Who likes to know which packages are built-in and
+their versions can use the following functions.  These functions are
+useful for external tools to query built-in package information.
+
+@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