[PATCH 0/2] Add a function to parse emacs elisp's package header

  • Done
  • quality assurance status badge
Details
3 participants
  • Ludovic Courtès
  • Maxime Devos
  • Fredrik Salomonsson
Owner
unassigned
Submitted by
Fredrik Salomonsson
Severity
normal
F
F
Fredrik Salomonsson wrote on 15 May 2022 01:00
(address . guix-patches@gnu.org)(name . Fredrik Salomonsson)(address . plattfot@posteo.net)
20220514230017.27372-1-plattfot@posteo.net
When writing a guix.scm file for an emacs packages, I wanted a way to fetch
the version I specify in the header of the elisp file. I found that I could do
that with the lisp-mnt library in emacs. Unfortunately none of the emacs
utility functions in guix/build/emacs-utils.scm return the output of an
elisp expression.

With these two patches I aim to add that functionality.

I spilt it in two functions:

emacs-batch-script: Run an arbitrary elisp expression and return the output as
a string.

emacs-header-parse: Given a header section and a file it will return the value
of that section.

For example (emacs-header-parse "version" "path/to/an/elisp/package.el")

Reason for the spilt is that people might want to run other elisp snippets.

Fredrik Salomonsson (2):
guix: emacs-utils: Add emacs-batch-script.
guix: emacs-utils: Add emacs-header-parse.

guix/build/emacs-utils.scm | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)


base-commit: 3935451f63c078cae9a928d87c6838ec3138abc0
--
2.36.0
F
F
Fredrik Salomonsson wrote on 15 May 2022 01:05
[PATCH 1/2] guix: emacs-utils: Add emacs-batch-script.
(address . 55420@debbugs.gnu.org)(name . Fredrik Salomonsson)(address . plattfot@posteo.net)
20220514230508.27885-1-plattfot@posteo.net
* guix/build/emacs-utils.scm (emacs-batch-script): New procedure.
---
guix/build/emacs-utils.scm | 13 +++++++++++++
1 file changed, 13 insertions(+)

Toggle diff (44 lines)
diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm
index 60a754b9e9..8d40b9e139 100644
--- a/guix/build/emacs-utils.scm
+++ b/guix/build/emacs-utils.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2014 Alex Kost <alezost@gmail.com>
;;; Copyright © 2018, 2020, 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2019 Liliana Marie Prikler <liliana.prikler@gmail.com>
+;;; Copyright © 2022 Fredrik Salomonsson <plattfot@posteo.net>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -22,10 +23,13 @@
(define-module (guix build emacs-utils)
#:use-module (guix build utils)
#:use-module (ice-9 format)
+ #:use-module (ice-9 popen)
+ #:use-module (ice-9 rdelim)
#:export (%emacs
emacs-batch-eval
emacs-batch-edit-file
emacs-batch-disable-compilation
+ emacs-batch-script
emacs-generate-autoloads
emacs-byte-compile-directory
@@ -69,6 +73,15 @@ (define (emacs-batch-disable-compilation file)
(add-file-local-variable 'no-byte-compile t)
(basic-save-buffer))))
+(define (emacs-batch-script expr)
+ "Execute the Elisp code EXPR in Emacs batch mode and return output."
+ (call-with-port
+ (open-pipe*
+ OPEN_READ
+ (%emacs) "--quick" "--batch"
+ (string-append "--eval=" (expr->string expr)))
+ read-string))
+
(define (emacs-generate-autoloads name directory)
"Generate autoloads for Emacs package NAME placed in DIRECTORY."
(let* ((file (string-append directory "/" name "-autoloads.el"))
--
2.36.0
F
F
Fredrik Salomonsson wrote on 15 May 2022 01:05
[PATCH 2/2] guix: emacs-utils: Add emacs-header-parse.
(address . 55420@debbugs.gnu.org)(name . Fredrik Salomonsson)(address . plattfot@posteo.net)
20220514230508.27885-2-plattfot@posteo.net
* guix/build/emacs-utils.scm (emacs-header-parse): New procedure.
---
guix/build/emacs-utils.scm | 9 +++++++++
1 file changed, 9 insertions(+)

Toggle diff (29 lines)
diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm
index 8d40b9e139..76d9464806 100644
--- a/guix/build/emacs-utils.scm
+++ b/guix/build/emacs-utils.scm
@@ -32,6 +32,7 @@ (define-module (guix build emacs-utils)
emacs-batch-script
emacs-generate-autoloads
emacs-byte-compile-directory
+ emacs-header-parse
as-display
emacs-substitute-sexps
@@ -97,6 +98,14 @@ (define* (emacs-byte-compile-directory dir)
(byte-recompile-directory (file-name-as-directory ,dir) 0 1))))
(emacs-batch-eval expr)))
+(define (emacs-header-parse section file)
+ "Parse the header SECTION in FILE and return it as a string."
+ (emacs-batch-script
+ `(progn
+ (require 'lisp-mnt)
+ (find-file ,file)
+ (princ (lm-header ,section)))))
+
(define as-display ;syntactic keyword for 'emacs-substitute-sexps'
'(as display))
--
2.36.0
L
L
Ludovic Courtès wrote on 1 Jun 2022 22:38
Re: bug#55420: [PATCH 0/2] Add a function to parse emacs elisp's package header
(name . Fredrik Salomonsson)(address . plattfot@posteo.net)(address . 55420@debbugs.gnu.org)
87ee08t8z5.fsf_-_@gnu.org
Hi Fredrik,

The patches LGTM modulo cosmetic issues:

Fredrik Salomonsson <plattfot@posteo.net> skribis:

Toggle quote (2 lines)
> * guix/build/emacs-utils.scm (emacs-batch-script): New procedure.

[...]

Toggle quote (9 lines)
> +(define (emacs-batch-script expr)
> + "Execute the Elisp code EXPR in Emacs batch mode and return output."
> + (call-with-port
> + (open-pipe*
> + OPEN_READ
> + (%emacs) "--quick" "--batch"
> + (string-append "--eval=" (expr->string expr)))
> + read-string))

I suggest something like:

(let* ((pipe (open-pipe* …))
(output (read-string pipe))
(status (close-pipe pipe)))
(unless (zero? status)
;; Use SRFI-34 + either a &message condition or (better)
;; a dedicate SRFI-35 condition type for the error.
(raise (condition …)))
output)

That way, execution failures would be caught and reported.

Ludo’.
L
L
Ludovic Courtès wrote on 1 Jun 2022 22:39
(name . Fredrik Salomonsson)(address . plattfot@posteo.net)(address . 55420@debbugs.gnu.org)
87a6awt8y8.fsf_-_@gnu.org
Fredrik Salomonsson <plattfot@posteo.net> skribis:

Toggle quote (2 lines)
> * guix/build/emacs-utils.scm (emacs-header-parse): New procedure.

LGTM!

Could you send a v2 of these patches?

Thanks in advance,
Ludo’.
F
F
Fredrik Salomonsson wrote on 2 Jun 2022 04:53
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 55420@debbugs.gnu.org)
87zgivai89.fsf@d2.com
Hi Ludo,

Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (32 lines)
> Hi Fredrik,
>
> The patches LGTM modulo cosmetic issues:
>
> Fredrik Salomonsson <plattfot@posteo.net> skribis:
>
>> * guix/build/emacs-utils.scm (emacs-batch-script): New procedure.
>
> [...]
>
>> +(define (emacs-batch-script expr)
>> + "Execute the Elisp code EXPR in Emacs batch mode and return output."
>> + (call-with-port
>> + (open-pipe*
>> + OPEN_READ
>> + (%emacs) "--quick" "--batch"
>> + (string-append "--eval=" (expr->string expr)))
>> + read-string))
>
> I suggest something like:
>
> (let* ((pipe (open-pipe* …))
> (output (read-string pipe))
> (status (close-pipe pipe)))
> (unless (zero? status)
> ;; Use SRFI-34 + either a &message condition or (better)
> ;; a dedicate SRFI-35 condition type for the error.
> (raise (condition …)))
> output)
>
> That way, execution failures would be caught and reported.

Thank you for the feedback. I update the procedure to use a dedicated
SRFI-35 condition type. But I cannot figure out how to capture the error
message from emacs, as I want the condition type to contain both the
expression as well as the error you get from emacs.

Here is what I have so far:

(define-condition-type &emacs-batch-error &error
emacs-batch-error?
(expression emacs-batch-error-expression)
(message emacs-batch-error-message))
(define (emacs-batch-script expr)
"Execute the Elisp code EXPR in Emacs batch mode and return output."
(let* ((error-pipe (open-output-string))
(pipe (with-error-to-port error-pipe
(lambda ()
(open-pipe*
OPEN_READ
(%emacs) "--quick" "--batch"
(string-append "--eval=" (expr->string expr))))))
(output (read-string pipe))
(error (get-output-string error-pipe))
(status (close-pipe pipe)))
(unless (zero? status)
(raise (condition (&emacs-batch-error
(expression expr)
(message error)))))
output))

Here is the output when I test it out in the guix repl:
--------------------------------------------------------------------------------
scheme@(guix-user)> (use-modules (guix build emacs-utils))
(use-modules (guix build emacs-utils))
scheme@(guix-user)> (emacs-batch-script '(prog (princ "hello")))
(emacs-batch-script '(prog (princ "hello")))
ice-9/boot-9.scm:1685:16: In procedure raise-exception:
Wrong type (expecting exact integer): #<&emacs-batch-error expression: (prog (princ "hello")) message: "">

Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
scheme@(guix-user) [1]>
--------------------------------------------------------------------------------

Note the message is empty in #<&emacs-batch-error…>. It should contain:

Debugger entered--Lisp error: (void-function prog)
(prog (princ "hello"))
command-line-1(("--eval=(prog (princ \"hello\"))"))
command-line()
normal-top-level()

Any idea what I'm doing wrong?

Thanks

--
s/Fred[re]+i[ck]+/Fredrik/g
L
L
Ludovic Courtès wrote on 2 Jun 2022 15:44
(name . Fredrik Salomonsson)(address . plattfot@posteo.net)(address . 55420@debbugs.gnu.org)
87fsknp4bu.fsf@gnu.org
Hi,

Fredrik Salomonsson <plattfot@posteo.net> skribis:

Toggle quote (25 lines)
> Here is what I have so far:
>
> (define-condition-type &emacs-batch-error &error
> emacs-batch-error?
> (expression emacs-batch-error-expression)
> (message emacs-batch-error-message))
>
> (define (emacs-batch-script expr)
> "Execute the Elisp code EXPR in Emacs batch mode and return output."
> (let* ((error-pipe (open-output-string))
> (pipe (with-error-to-port error-pipe
> (lambda ()
> (open-pipe*
> OPEN_READ
> (%emacs) "--quick" "--batch"
> (string-append "--eval=" (expr->string expr))))))
> (output (read-string pipe))
> (error (get-output-string error-pipe))
> (status (close-pipe pipe)))
> (unless (zero? status)
> (raise (condition (&emacs-batch-error
> (expression expr)
> (message error)))))
> output))

Unfortunately ‘open-pipe*’ is not smart enough to redirect stderr to a
non-file port (a string port in this case).

One way around it would be to merge stdout and stderr, like so:

(parameterize ((current-error-port (current-output-port)))
(open-pipe* …))

but then you get both on the same stream, which could be a problem for
instance if Emacs emits warnings and such.

You could work around it by establishing a second pipe:

(match (pipe)
((stderr-input . stderr-output)
(parameterize ((current-error-port stderr-output))
(open-pipe* …))))

Here you should be able to read, in the parent process, from
‘stderr-input’.

Another option is to not try to capture stderr: after all, that’ll get
printed on the screen anyway.

HTH,
Ludo’.
F
F
Fredrik Salomonsson wrote on 5 Jun 2022 02:19
[PATCH v2 1/2] guix: emacs-utils: Add emacs-batch-script.
(address . 55420@debbugs.gnu.org)(name . Fredrik Salomonsson)(address . plattfot@posteo.net)
20220605001924.184934-1-plattfot@posteo.net
* guix/build/emacs-utils.scm (emacs-batch-script): New procedure.

* tests/build-emacs-utils.scm: New file.

* Makefile.am (TESTS): Add `tests/build-emacs-utils.scm'.
---
Makefile.am | 1 +
guix/build/emacs-utils.scm | 30 +++++++++++++++++++++++++++
tests/build-emacs-utils.scm | 41 +++++++++++++++++++++++++++++++++++++
3 files changed, 72 insertions(+)
create mode 100644 tests/build-emacs-utils.scm

Toggle diff (122 lines)
diff --git a/Makefile.am b/Makefile.am
index e8d4b7ef8a..4a8514ea3a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -469,6 +469,7 @@ SCM_TESTS = \
tests/boot-parameters.scm \
tests/bournish.scm \
tests/builders.scm \
+ tests/build-emacs-utils.scm \
tests/build-utils.scm \
tests/cache.scm \
tests/challenge.scm \
diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm
index 60a754b9e9..1684bf3262 100644
--- a/guix/build/emacs-utils.scm
+++ b/guix/build/emacs-utils.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2014 Alex Kost <alezost@gmail.com>
;;; Copyright © 2018, 2020, 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2019 Liliana Marie Prikler <liliana.prikler@gmail.com>
+;;; Copyright © 2022 Fredrik Salomonsson <plattfot@posteo.net>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -22,10 +23,19 @@
(define-module (guix build emacs-utils)
#:use-module (guix build utils)
#:use-module (ice-9 format)
+ #:use-module (ice-9 popen)
+ #:use-module (ice-9 rdelim)
+ #:use-module (srfi srfi-34)
+ #:use-module (srfi srfi-35)
#:export (%emacs
emacs-batch-eval
emacs-batch-edit-file
emacs-batch-disable-compilation
+ emacs-batch-script
+
+ emacs-batch-error?
+ emacs-batch-error-message
+
emacs-generate-autoloads
emacs-byte-compile-directory
@@ -69,6 +79,26 @@ (define (emacs-batch-disable-compilation file)
(add-file-local-variable 'no-byte-compile t)
(basic-save-buffer))))
+(define-condition-type &emacs-batch-error &error
+ emacs-batch-error?
+ (message emacs-batch-error-message))
+
+(define (emacs-batch-script expr)
+ "Execute the Elisp code EXPR in Emacs batch mode and return output."
+ (let* ((error-pipe (pipe))
+ (port (parameterize ((current-error-port (cdr error-pipe)))
+ (open-pipe*
+ OPEN_READ
+ (%emacs) "--quick" "--batch"
+ (string-append "--eval=" (expr->string expr)))))
+ (output (read-string port))
+ (status (close-pipe port)))
+ (close-port (cdr error-pipe))
+ (unless (zero? status)
+ (raise (condition (&emacs-batch-error
+ (message (read-string (car error-pipe)))))))
+ output))
+
(define (emacs-generate-autoloads name directory)
"Generate autoloads for Emacs package NAME placed in DIRECTORY."
(let* ((file (string-append directory "/" name "-autoloads.el"))
diff --git a/tests/build-emacs-utils.scm b/tests/build-emacs-utils.scm
new file mode 100644
index 0000000000..03b73b1fed
--- /dev/null
+++ b/tests/build-emacs-utils.scm
@@ -0,0 +1,41 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 Fredrik Salomonsson <plattfot@posteo.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+
+(define-module (test build-emacs-utils)
+ #:use-module (guix tests)
+ #:use-module (guix build emacs-utils)
+ #:use-module (guix build utils)
+ #:use-module ((guix utils)
+ #:select (call-with-temporary-directory))
+ #:use-module (srfi srfi-34)
+ #:use-module (srfi srfi-64))
+
+(test-begin "build-emacs-utils")
+
+(test-equal "print foo from emacs"
+ "foo"
+ (emacs-batch-script '(princ "foo")))
+
+(test-assert "emacs-batch-script: raise &emacs-batch-error on failure"
+ (guard (c ((emacs-batch-error? c)
+ (string-contains (emacs-batch-error-message c)
+ "Lisp error: (wrong-type-argument numberp \"three\")")))
+ (emacs-batch-script '(mapcar 'number-to-string (list 1 2 "three")))))
+
+(test-end "build-emacs-utils")

base-commit: 271736117e3f09b616a2dbd5d74c9595926c9297
--
2.36.1
F
F
Fredrik Salomonsson wrote on 5 Jun 2022 02:19
[PATCH v2 2/2] guix: emacs-utils: Add emacs-header-parse.
(address . 55420@debbugs.gnu.org)(name . Fredrik Salomonsson)(address . plattfot@posteo.net)
20220605001924.184934-2-plattfot@posteo.net
* guix/build/emacs-utils.scm (emacs-header-parse): New procedure.

* tests/build-emacs-utils.scm ("emacs-header-parse: fetch version",
"emacs-header-parse: fetch keywords", "emacs-header-parse: fetch
nonexistent author"): New tests.
---
guix/build/emacs-utils.scm | 9 +++++++++
tests/build-emacs-utils.scm | 30 ++++++++++++++++++++++++++++++
2 files changed, 39 insertions(+)

Toggle diff (68 lines)
diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm
index 1684bf3262..8ee547f2b3 100644
--- a/guix/build/emacs-utils.scm
+++ b/guix/build/emacs-utils.scm
@@ -38,6 +38,7 @@ (define-module (guix build emacs-utils)
emacs-generate-autoloads
emacs-byte-compile-directory
+ emacs-header-parse
as-display
emacs-substitute-sexps
@@ -114,6 +115,14 @@ (define* (emacs-byte-compile-directory dir)
(byte-recompile-directory (file-name-as-directory ,dir) 0 1))))
(emacs-batch-eval expr)))
+(define (emacs-header-parse section file)
+ "Parse the header SECTION in FILE and return it as a string."
+ (emacs-batch-script
+ `(progn
+ (require 'lisp-mnt)
+ (find-file ,file)
+ (princ (lm-header ,section)))))
+
(define as-display ;syntactic keyword for 'emacs-substitute-sexps'
'(as display))
diff --git a/tests/build-emacs-utils.scm b/tests/build-emacs-utils.scm
index 03b73b1fed..57647caaa2 100644
--- a/tests/build-emacs-utils.scm
+++ b/tests/build-emacs-utils.scm
@@ -38,4 +38,34 @@ (define-module (test build-emacs-utils)
"Lisp error: (wrong-type-argument numberp \"three\")")))
(emacs-batch-script '(mapcar 'number-to-string (list 1 2 "three")))))
+(define (test-emacs-header-parse section)
+ (call-with-temporary-directory
+ (lambda (directory)
+ (let ((mock-elisp-file (string-append directory "/foo.el")))
+ (call-with-output-file mock-elisp-file
+ (lambda (port)
+ (display ";;; foo --- mock emacs package -*- lexical-binding: t -*-
+
+;; Created: 4 Jun 2022
+;; Keywords: lisp test
+;; Version: 1.0.0
+;;; Commentary:
+;;; Code:
+;;; foo.el ends here
+"
+ port)))
+ (emacs-header-parse section mock-elisp-file)))))
+
+(test-equal "emacs-header-parse: fetch version"
+ "1.0.0"
+ (test-emacs-header-parse "version"))
+
+(test-equal "emacs-header-parse: fetch keywords"
+ "lisp test"
+ (test-emacs-header-parse "keywords"))
+
+(test-equal "emacs-header-parse: fetch nonexistent author"
+ "nil"
+ (test-emacs-header-parse "author"))
+
(test-end "build-emacs-utils")
--
2.36.1
F
F
Fredrik Salomonsson wrote on 5 Jun 2022 02:42
Re: bug#55420: [PATCH 0/2] Add a function to parse emacs elisp's package header
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 55420@debbugs.gnu.org)
87h750rldx.fsf@posteo.net
Hi Ludo,

Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (53 lines)
> Hi,
>
> Fredrik Salomonsson <plattfot@posteo.net> skribis:
>
>> Here is what I have so far:
>>
>> (define-condition-type &emacs-batch-error &error
>> emacs-batch-error?
>> (expression emacs-batch-error-expression)
>> (message emacs-batch-error-message))
>>
>> (define (emacs-batch-script expr)
>> "Execute the Elisp code EXPR in Emacs batch mode and return output."
>> (let* ((error-pipe (open-output-string))
>> (pipe (with-error-to-port error-pipe
>> (lambda ()
>> (open-pipe*
>> OPEN_READ
>> (%emacs) "--quick" "--batch"
>> (string-append "--eval=" (expr->string expr))))))
>> (output (read-string pipe))
>> (error (get-output-string error-pipe))
>> (status (close-pipe pipe)))
>> (unless (zero? status)
>> (raise (condition (&emacs-batch-error
>> (expression expr)
>> (message error)))))
>> output))
>
> Unfortunately ‘open-pipe*’ is not smart enough to redirect stderr to a
> non-file port (a string port in this case).
>
> One way around it would be to merge stdout and stderr, like so:
>
> (parameterize ((current-error-port (current-output-port)))
> (open-pipe* …))
>
> but then you get both on the same stream, which could be a problem for
> instance if Emacs emits warnings and such.
>
> You could work around it by establishing a second pipe:
>
> (match (pipe)
> ((stderr-input . stderr-output)
> (parameterize ((current-error-port stderr-output))
> (open-pipe* …))))
>
> Here you should be able to read, in the parent process, from
> ‘stderr-input’.
>
> Another option is to not try to capture stderr: after all, that’ll get
> printed on the screen anyway.

I just sent in v2 of the patches. Changes are:

- emacs-batch-script will now raise an &emacs-batch-error if emacs batch
script fails. I opted to capture the stderr and package that up in the
condition. Thank you for the pointers! I removed the expression slot I
had in my prototype. It felt redundant, emacs error message should be
enough.

- tests/build-emacs-utils.scm: I added tests for the two new procedures.

It was good that I added the tests as I had missed to use (srfi srfi-34)
in build/emacs-utils.scm during my prototyping and that generated the
cryptic error:

Wrong type (expecting exact integer): #<&emacs-batch-error…>

Took me a while to figure that one out. But now all is good. The tests
are passing.

Thanks again.

--
s/Fred[re]+i[ck]+/Fredrik/g
M
M
Maxime Devos wrote on 5 Jun 2022 11:52
Re: [bug#55420] [PATCH v2 1/2] guix: emacs-utils: Add emacs-batch-script.
38a5e03d835b2daa2dd1959048f1d03f6f5a48cd.camel@telenet.be
Fredrik Salomonsson schreef op zo 05-06-2022 om 00:19 [+0000]:
Toggle quote (4 lines)
> +(test-equal "print foo from emacs"
> +  "foo"
> +  (emacs-batch-script '(princ "foo")))

IIUC, this can only be run if emacs is in $PATH when running the tests,
so sometimes the test needs to be skipped. As an example on how to do
this, see the "pypi->guix-package, wheels" test in tests/pypi.scm.

Greetings,
Maxime.
-----BEGIN PGP SIGNATURE-----

iI0EABYKADUWIQTB8z7iDFKP233XAR9J4+4iGRcl7gUCYpx82xccbWF4aW1lZGV2
b3NAdGVsZW5ldC5iZQAKCRBJ4+4iGRcl7puYAQCWIg6YACUP+M/WyndYxWZjFjuT
Pg2TfhpjyXweT1h3KgD/fRMlo09wcX62XRhrHyua0WjZRhr0+qXm0UNWw40XPgg=
=Vv4M
-----END PGP SIGNATURE-----


F
F
Fredrik Salomonsson wrote on 5 Jun 2022 21:51
[PATCH v3 1/2] guix: emacs-utils: Add emacs-batch-script.
(address . 55420@debbugs.gnu.org)(name . Fredrik Salomonsson)(address . plattfot@posteo.net)
20220605195143.23591-1-plattfot@posteo.net
* guix/build/emacs-utils.scm (emacs-batch-script): New procedure.

* tests/build-emacs-utils.scm: New file.

* Makefile.am (TESTS): Add `tests/build-emacs-utils.scm'.
---
Makefile.am | 1 +
guix/build/emacs-utils.scm | 30 ++++++++++++++++++++++++++
tests/build-emacs-utils.scm | 43 +++++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+)
create mode 100644 tests/build-emacs-utils.scm

Toggle diff (124 lines)
diff --git a/Makefile.am b/Makefile.am
index e8d4b7ef8a..4a8514ea3a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -469,6 +469,7 @@ SCM_TESTS = \
tests/boot-parameters.scm \
tests/bournish.scm \
tests/builders.scm \
+ tests/build-emacs-utils.scm \
tests/build-utils.scm \
tests/cache.scm \
tests/challenge.scm \
diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm
index 60a754b9e9..1684bf3262 100644
--- a/guix/build/emacs-utils.scm
+++ b/guix/build/emacs-utils.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2014 Alex Kost <alezost@gmail.com>
;;; Copyright © 2018, 2020, 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2019 Liliana Marie Prikler <liliana.prikler@gmail.com>
+;;; Copyright © 2022 Fredrik Salomonsson <plattfot@posteo.net>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -22,10 +23,19 @@
(define-module (guix build emacs-utils)
#:use-module (guix build utils)
#:use-module (ice-9 format)
+ #:use-module (ice-9 popen)
+ #:use-module (ice-9 rdelim)
+ #:use-module (srfi srfi-34)
+ #:use-module (srfi srfi-35)
#:export (%emacs
emacs-batch-eval
emacs-batch-edit-file
emacs-batch-disable-compilation
+ emacs-batch-script
+
+ emacs-batch-error?
+ emacs-batch-error-message
+
emacs-generate-autoloads
emacs-byte-compile-directory
@@ -69,6 +79,26 @@ (define (emacs-batch-disable-compilation file)
(add-file-local-variable 'no-byte-compile t)
(basic-save-buffer))))
+(define-condition-type &emacs-batch-error &error
+ emacs-batch-error?
+ (message emacs-batch-error-message))
+
+(define (emacs-batch-script expr)
+ "Execute the Elisp code EXPR in Emacs batch mode and return output."
+ (let* ((error-pipe (pipe))
+ (port (parameterize ((current-error-port (cdr error-pipe)))
+ (open-pipe*
+ OPEN_READ
+ (%emacs) "--quick" "--batch"
+ (string-append "--eval=" (expr->string expr)))))
+ (output (read-string port))
+ (status (close-pipe port)))
+ (close-port (cdr error-pipe))
+ (unless (zero? status)
+ (raise (condition (&emacs-batch-error
+ (message (read-string (car error-pipe)))))))
+ output))
+
(define (emacs-generate-autoloads name directory)
"Generate autoloads for Emacs package NAME placed in DIRECTORY."
(let* ((file (string-append directory "/" name "-autoloads.el"))
diff --git a/tests/build-emacs-utils.scm b/tests/build-emacs-utils.scm
new file mode 100644
index 0000000000..27cff46c38
--- /dev/null
+++ b/tests/build-emacs-utils.scm
@@ -0,0 +1,43 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 Fredrik Salomonsson <plattfot@posteo.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+
+(define-module (test build-emacs-utils)
+ #:use-module (guix tests)
+ #:use-module (guix build emacs-utils)
+ #:use-module (guix build utils)
+ #:use-module ((guix utils)
+ #:select (call-with-temporary-directory))
+ #:use-module (srfi srfi-34)
+ #:use-module (srfi srfi-64))
+
+(test-begin "build-emacs-utils")
+;; Only run the following tests if emacs is present.
+(test-skip (if (which "emacs") 0 2))
+
+(test-equal "emacs-batch-script: print foo from emacs"
+ "foo"
+ (emacs-batch-script '(princ "foo")))
+
+(test-assert "emacs-batch-script: raise &emacs-batch-error on failure"
+ (guard (c ((emacs-batch-error? c)
+ (string-contains (emacs-batch-error-message c)
+ "Lisp error: (wrong-type-argument numberp \"three\")")))
+ (emacs-batch-script '(mapcar 'number-to-string (list 1 2 "three")))))
+
+(test-end "build-emacs-utils")

base-commit: 271736117e3f09b616a2dbd5d74c9595926c9297
--
2.36.1
F
F
Fredrik Salomonsson wrote on 5 Jun 2022 21:51
[PATCH v3 2/2] guix: emacs-utils: Add emacs-header-parse.
(address . 55420@debbugs.gnu.org)(name . Fredrik Salomonsson)(address . plattfot@posteo.net)
20220605195143.23591-2-plattfot@posteo.net
* guix/build/emacs-utils.scm (emacs-header-parse): New procedure.

* tests/build-emacs-utils.scm ("emacs-header-parse: fetch version",
"emacs-header-parse: fetch keywords", "emacs-header-parse: fetch
nonexistent author"): New tests.
---
guix/build/emacs-utils.scm | 9 +++++++++
tests/build-emacs-utils.scm | 27 ++++++++++++++++++++++++++-
2 files changed, 35 insertions(+), 1 deletion(-)

Toggle diff (72 lines)
diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm
index 1684bf3262..8ee547f2b3 100644
--- a/guix/build/emacs-utils.scm
+++ b/guix/build/emacs-utils.scm
@@ -38,6 +38,7 @@ (define-module (guix build emacs-utils)
emacs-generate-autoloads
emacs-byte-compile-directory
+ emacs-header-parse
as-display
emacs-substitute-sexps
@@ -114,6 +115,14 @@ (define* (emacs-byte-compile-directory dir)
(byte-recompile-directory (file-name-as-directory ,dir) 0 1))))
(emacs-batch-eval expr)))
+(define (emacs-header-parse section file)
+ "Parse the header SECTION in FILE and return it as a string."
+ (emacs-batch-script
+ `(progn
+ (require 'lisp-mnt)
+ (find-file ,file)
+ (princ (lm-header ,section)))))
+
(define as-display ;syntactic keyword for 'emacs-substitute-sexps'
'(as display))
diff --git a/tests/build-emacs-utils.scm b/tests/build-emacs-utils.scm
index 27cff46c38..081032285a 100644
--- a/tests/build-emacs-utils.scm
+++ b/tests/build-emacs-utils.scm
@@ -28,7 +28,7 @@ (define-module (test build-emacs-utils)
(test-begin "build-emacs-utils")
;; Only run the following tests if emacs is present.
-(test-skip (if (which "emacs") 0 2))
+(test-skip (if (which "emacs") 0 5))
(test-equal "emacs-batch-script: print foo from emacs"
"foo"
@@ -40,4 +40,29 @@ (define-module (test build-emacs-utils)
"Lisp error: (wrong-type-argument numberp \"three\")")))
(emacs-batch-script '(mapcar 'number-to-string (list 1 2 "three")))))
+(call-with-temporary-directory
+ (lambda (directory)
+ (let ((mock-elisp-file (string-append directory "/foo.el")))
+ (call-with-output-file mock-elisp-file
+ (lambda (port)
+ (display ";;; foo --- mock emacs package -*- lexical-binding: t -*-
+
+;; Created: 4 Jun 2022
+;; Keywords: lisp test
+;; Version: 1.0.0
+;;; Commentary:
+;;; Code:
+;;; foo.el ends here
+"
+ port)))
+ (test-equal "emacs-header-parse: fetch version"
+ "1.0.0"
+ (emacs-header-parse "version" mock-elisp-file))
+ (test-equal "emacs-header-parse: fetch keywords"
+ "lisp test"
+ (emacs-header-parse "keywords" mock-elisp-file))
+ (test-equal "emacs-header-parse: fetch nonexistent author"
+ "nil"
+ (emacs-header-parse "author" mock-elisp-file)))))
+
(test-end "build-emacs-utils")
--
2.36.1
F
F
Fredrik Salomonsson wrote on 5 Jun 2022 22:02
Re: [bug#55420] [PATCH v2 1/2] guix: emacs-utils: Add emacs-batch-script.
87v8teop3x.fsf@posteo.net
Hi Maxime,

Maxime Devos <maximedevos@telenet.be> writes:

Toggle quote (9 lines)
> Fredrik Salomonsson schreef op zo 05-06-2022 om 00:19 [+0000]:
>> +(test-equal "print foo from emacs"
>> +  "foo"
>> +  (emacs-batch-script '(princ "foo")))
>
> IIUC, this can only be run if emacs is in $PATH when running the tests,
> so sometimes the test needs to be skipped. As an example on how to do
> this, see the "pypi->guix-package, wheels" test in tests/pypi.scm.

Yes, you are correct. All my tests started to fail when I added `--pure`
to my test command.

I just sent in a v3 of the patches when I skip the tests if emacs is not
in the PATH.

I also changed the tests for the `emacs-header-parse` to be wrapped by
`call-with-temporary-directory`. It felt wasteful to create and destroy that
file for each test when the file is static.

I opted to just have one test-skip and skip all five of them. Although
that migth be too fragile. Would be great to have something like:

(unless (which "emacs")
(test-skip "emacs-batch-script:")
(test-skip "emacs-header-parse:"))

But the docs just mention a counter or the full name of a test.

--
s/Fred[re]+i[ck]+/Fredrik/g
L
L
Ludovic Courtès wrote on 17 Jun 2022 22:29
Re: bug#55420: [PATCH 0/2] Add a function to parse emacs elisp's package header
(name . Fredrik Salomonsson)(address . plattfot@posteo.net)(address . 55420-done@debbugs.gnu.org)
87czf7dofa.fsf_-_@gnu.org
Hi Fredrik,

Fredrik Salomonsson <plattfot@posteo.net> skribis:

Toggle quote (6 lines)
> * guix/build/emacs-utils.scm (emacs-batch-script): New procedure.
>
> * tests/build-emacs-utils.scm: New file.
>
> * Makefile.am (TESTS): Add `tests/build-emacs-utils.scm'.

[...]

Toggle quote (6 lines)
> * guix/build/emacs-utils.scm (emacs-header-parse): New procedure.
>
> * tests/build-emacs-utils.scm ("emacs-header-parse: fetch version",
> "emacs-header-parse: fetch keywords", "emacs-header-parse: fetch
> nonexistent author"): New tests.

Thanks, applied. Apologies for the delay!

Ludo’.
Closed
?