guix_mirror_bot pushed a commit to branch master
in repository guix.
commit a5ac56f8830928205ce5424082486d509f898dc7
Author: Ludovic Courtès <[email protected]>
AuthorDate: Thu Sep 4 14:28:42 2025 +0200
packages: ‘package-field-location’ returns a <location> for atoms.
Fixes guix/guix#1975.
When using ‘read’, ‘package-field-location’ would not get source location
for
atoms such as symbols, typically making it impossible to get the location of
the value of a field list (build-system gnu-build-system). This fixes that.
* guix/packages.scm (field-value-location): New procedure.
(package-field-location): Use it instead of inline code.
* tests/packages.scm ("package-field-location"): Test the ‘build-system’
field.
Reported-by: Nicolas Graves <[email protected]>
Change-Id: I98c694bb6f1999fa9ca80e145fa016640067af55
---
guix/packages.scm | 53 +++++++++++++++++++++++++++++++++++++----------------
tests/packages.scm | 3 +++
2 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/guix/packages.scm b/guix/packages.scm
index 1d5986c5f4..bba281b374 100644
--- a/guix/packages.scm
+++ b/guix/packages.scm
@@ -794,6 +794,42 @@ object."
(name old-name)
(properties `((superseded . ,p)))))
+(define* (field-value-location port field
+ #:optional (file (port-filename port)))
+ "Return the source location of the value of FIELD as read from PORT, or #f
+if FIELD could not be found."
+ (define (field-value lst field)
+ (syntax-case lst ()
+ (()
+ #f)
+ (((binding value) rest ...)
+ (eq? (syntax->datum #'binding) field)
+ #'value)
+ ((_ rest ...)
+ (field-value #'(rest ...) field))))
+
+ (define (extract inits)
+ (and=> (field-value inits field)
+ (lambda (value)
+ (let ((loc (and=> (syntax-source value)
+ source-properties->location)))
+ (and loc
+ ;; Preserve the original file name, which
+ ;; may be a relative file name.
+ (set-field loc (location-file) file))))))
+
+ ;; Use 'read-syntax', not 'read', to get location info on all the tokens,
+ ;; including symbols. Abuse 'syntax-case' for pattern matching on syntax
+ ;; objects.
+ (syntax-case (read-syntax port) ()
+ ((head inits ...)
+ (eq? (syntax->datum #'head) 'package)
+ (extract #'(inits ...)))
+ ((head _ inits ...)
+ (eq? (syntax->datum #'head) 'package/inherit)
+ (extract #'(inits ...)))
+ (x #f)))
+
(define (package-field-location package field)
"Return the source code location of the definition of FIELD for PACKAGE, or
#f if it could not be determined."
@@ -807,22 +843,7 @@ object."
(call-with-input-file file-found
(lambda (port)
(go-to-location port line column)
- (match (read port)
- ((or ('package inits ...)
- ('package/inherit _ inits ...))
- (let ((field (assoc field inits)))
- (match field
- ((_ value)
- (let ((loc (and=> (source-properties value)
- source-properties->location)))
- (and loc
- ;; Preserve the original file name, which may
be a
- ;; relative file name.
- (set-field loc (location-file) file))))
- (_
- #f))))
- (_
- #f)))))
+ (field-value-location port field file))))
(lambda _
#f)))
(#f
diff --git a/tests/packages.scm b/tests/packages.scm
index f56c63128d..78cb670815 100644
--- a/tests/packages.scm
+++ b/tests/packages.scm
@@ -292,6 +292,9 @@
(member (read-at (package-field-location %bootstrap-guile 'version))
(let ((version (package-version %bootstrap-guile)))
(list version `(version ,version))))
+ (member (read-at (package-field-location coreutils
+ 'build-system))
+ '(build-system gnu-build-system))
(not (package-field-location %bootstrap-guile 'does-not-exist)))))
;; Make sure we don't change the file name to an absolute file name.