summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2022-08-02 18:01:35 +0200
committerLudovic Courtès <ludo@gnu.org>2022-08-08 11:53:33 +0200
commita15542d26df42dabdb5e2f76d150ae200230c3b0 (patch)
treeb5c17cf1660c5fc800a3f3773025ad0201848790
parent90ef692e9b48732ae2e3921ff5d101e186506a85 (diff)
style: Add '--whole-file' option.
* guix/scripts/style.scm (format-whole-file): New procedure. (%options, show-help): Add '--whole-file'. (guix-style): Honor it. * tests/guix-style.sh: New file. * Makefile.am (SH_TESTS): Add it. * doc/guix.texi (Invoking guix style): Document it.
-rw-r--r--Makefile.am1
-rw-r--r--doc/guix.texi28
-rw-r--r--guix/scripts/style.scm65
-rw-r--r--tests/guix-style.sh80
4 files changed, 153 insertions, 21 deletions
diff --git a/Makefile.am b/Makefile.am
index 2cda20e61c1..f7c42e81533 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -580,6 +580,7 @@ SH_TESTS = \
580 tests/guix-package.sh \ 580 tests/guix-package.sh \
581 tests/guix-package-aliases.sh \ 581 tests/guix-package-aliases.sh \
582 tests/guix-package-net.sh \ 582 tests/guix-package-net.sh \
583 tests/guix-style.sh \
583 tests/guix-system.sh \ 584 tests/guix-system.sh \
584 tests/guix-home.sh \ 585 tests/guix-home.sh \
585 tests/guix-archive.sh \ 586 tests/guix-archive.sh \
diff --git a/doc/guix.texi b/doc/guix.texi
index d6460a785ff..9a6a5c307d3 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -14058,9 +14058,12 @@ otherwise.
14058@node Invoking guix style 14058@node Invoking guix style
14059@section Invoking @command{guix style} 14059@section Invoking @command{guix style}
14060 14060
14061The @command{guix style} command helps packagers style their package 14061The @command{guix style} command helps users and packagers alike style
14062definitions according to the latest fashionable trends. The command 14062their package definitions and configuration files according to the
14063currently provides the following styling rules: 14063latest fashionable trends. It can either reformat whole files, with the
14064@option{--whole-file} option, or apply specific @dfn{styling rules} to
14065individual package definitions. The command currently provides the
14066following styling rules:
14064 14067
14065@itemize 14068@itemize
14066@item 14069@item
@@ -14115,6 +14118,12 @@ the packages. The @option{--styling} or @option{-S} option allows you
14115to select the style rule, the default rule being @code{format}---see 14118to select the style rule, the default rule being @code{format}---see
14116below. 14119below.
14117 14120
14121To reformat entire source files, the syntax is:
14122
14123@example
14124guix style --whole-file @var{file}@dots{}
14125@end example
14126
14118The available options are listed below. 14127The available options are listed below.
14119 14128
14120@table @code 14129@table @code
@@ -14122,6 +14131,19 @@ The available options are listed below.
14122@itemx -n 14131@itemx -n
14123Show source file locations that would be edited but do not modify them. 14132Show source file locations that would be edited but do not modify them.
14124 14133
14134@item --whole-file
14135@itemx -f
14136Reformat the given files in their entirety. In that case, subsequent
14137arguments are interpreted as file names (rather than package names), and
14138the @option{--styling} option has no effect.
14139
14140As an example, here is how you might reformat your operating system
14141configuration (you need write permissions for the file):
14142
14143@example
14144guix style -f /etc/config.scm
14145@end example
14146
14125@item --styling=@var{rule} 14147@item --styling=@var{rule}
14126@itemx -S @var{rule} 14148@itemx -S @var{rule}
14127Apply @var{rule}, one of the following styling rules: 14149Apply @var{rule}, one of the following styling rules:
diff --git a/guix/scripts/style.scm b/guix/scripts/style.scm
index 2e14bc68fd0..c0b9ea1a282 100644
--- a/guix/scripts/style.scm
+++ b/guix/scripts/style.scm
@@ -330,6 +330,21 @@ PACKAGE."
330 330
331 331
332;;; 332;;;
333;;; Whole-file formatting.
334;;;
335
336(define* (format-whole-file file #:rest rest)
337 "Reformat all of FILE."
338 (let ((lst (call-with-input-file file read-with-comments/sequence)))
339 (with-atomic-file-output file
340 (lambda (port)
341 (apply pretty-print-with-comments/splice port lst
342 #:format-comment canonicalize-comment
343 #:format-vertical-space canonicalize-vertical-space
344 rest)))))
345
346
347;;;
333;;; Options. 348;;; Options.
334;;; 349;;;
335 350
@@ -345,6 +360,9 @@ PACKAGE."
345 (option '(#\e "expression") #t #f 360 (option '(#\e "expression") #t #f
346 (lambda (opt name arg result) 361 (lambda (opt name arg result)
347 (alist-cons 'expression arg result))) 362 (alist-cons 'expression arg result)))
363 (option '(#\f "whole-file") #f #f
364 (lambda (opt name arg result)
365 (alist-cons 'whole-file? #t result)))
348 (option '(#\S "styling") #t #f 366 (option '(#\S "styling") #t #f
349 (lambda (opt name arg result) 367 (lambda (opt name arg result)
350 (alist-cons 'styling-procedure 368 (alist-cons 'styling-procedure
@@ -400,6 +418,9 @@ Update package definitions to the latest style.\n"))
400 of 'silent', 'safe', or 'always'")) 418 of 'silent', 'safe', or 'always'"))
401 (newline) 419 (newline)
402 (display (G_ " 420 (display (G_ "
421 -f, --whole-file format the entire contents of the given file(s)"))
422 (newline)
423 (display (G_ "
403 -h, --help display this help and exit")) 424 -h, --help display this help and exit"))
404 (display (G_ " 425 (display (G_ "
405 -V, --version display version information and exit")) 426 -V, --version display version information and exit"))
@@ -426,27 +447,35 @@ Update package definitions to the latest style.\n"))
426 #:build-options? #f)) 447 #:build-options? #f))
427 448
428 (let* ((opts (parse-options)) 449 (let* ((opts (parse-options))
429 (packages (filter-map (match-lambda
430 (('argument . spec)
431 (specification->package spec))
432 (('expression . str)
433 (read/eval str))
434 (_ #f))
435 opts))
436 (edit (if (assoc-ref opts 'dry-run?) 450 (edit (if (assoc-ref opts 'dry-run?)
437 edit-expression/dry-run 451 edit-expression/dry-run
438 edit-expression)) 452 edit-expression))
439 (style (assoc-ref opts 'styling-procedure)) 453 (style (assoc-ref opts 'styling-procedure))
440 (policy (assoc-ref opts 'input-simplification-policy))) 454 (policy (assoc-ref opts 'input-simplification-policy)))
441 (with-error-handling 455 (with-error-handling
442 (for-each (lambda (package) 456 (if (assoc-ref opts 'whole-file?)
443 (style package #:policy policy 457 (let ((files (filter-map (match-lambda
444 #:edit-expression edit)) 458 (('argument . file) file)
445 ;; Sort package by source code location so that we start editing 459 (_ #f))
446 ;; files from the bottom and going upward. That way, the 460 opts)))
447 ;; 'location' field of <package> records is not invalidated as 461 (unless (eq? format-package-definition style)
448 ;; we modify files. 462 (warning (G_ "'--styling' option has no effect in whole-file mode~%")))
449 (sort (if (null? packages) 463 (for-each format-whole-file files))
450 (fold-packages cons '() #:select? (const #t)) 464 (let ((packages (filter-map (match-lambda
451 packages) 465 (('argument . spec)
452 (negate package-location<?)))))) 466 (specification->package spec))
467 (('expression . str)
468 (read/eval str))
469 (_ #f))
470 opts)))
471 (for-each (lambda (package)
472 (style package #:policy policy
473 #:edit-expression edit))
474 ;; Sort package by source code location so that we start
475 ;; editing files from the bottom and going upward. That
476 ;; way, the 'location' field of <package> records is not
477 ;; invalidated as we modify files.
478 (sort (if (null? packages)
479 (fold-packages cons '() #:select? (const #t))
480 packages)
481 (negate package-location<?))))))))
diff --git a/tests/guix-style.sh b/tests/guix-style.sh
new file mode 100644
index 00000000000..58f953a0ec1
--- /dev/null
+++ b/tests/guix-style.sh
@@ -0,0 +1,80 @@
1# GNU Guix --- Functional package management for GNU
2# Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
3#
4# This file is part of GNU Guix.
5#
6# GNU Guix is free software; you can redistribute it and/or modify it
7# under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3 of the License, or (at
9# your option) any later version.
10#
11# GNU Guix is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19#
20# Test 'guix style'.
21#
22
23set -e
24
25guix style --version
26
27tmpdir="guix-style-$$"
28trap 'rm -r "$tmpdir"' EXIT
29
30tmpfile="$tmpdir/os.scm"
31mkdir "$tmpdir"
32cat > "$tmpfile" <<EOF
33;;; This is a header with three semicolons.
34;;;
35
36(define-module (foo bar)
37 #:use-module (guix)
38 #:use-module (gnu))
39
40;; One blank line and a page break.
41
42
43;; And now, the OS.
44(operating-system
45 (host-name "komputilo")
46 (locale "eo_EO.UTF-8")
47
48 ;; User accounts.
49 (users (cons (user-account
50 (name "alice")
51 (comment "Bob's sister")
52 (group "users")
53
54 ;; Groups fit on one line.
55 (supplementary-groups '("wheel" "audio" "video")))
56 %base-user-accounts))
57
58 ;; The services.
59 (services
60 (cons (service mcron-service-type) %base-services)))
61EOF
62
63cp "$tmpfile" "$tmpfile.bak"
64
65initial_hash="$(guix hash "$tmpfile")"
66
67guix style -f "$tmpfile"
68if ! test "$initial_hash" = "$(guix hash "$tmpfile")"
69then
70 cat "$tmpfile"
71 diff -u "$tmpfile.bak" "$tmpfile"
72 false
73fi
74
75# Introduce random changes and try again.
76sed -i "$tmpfile" -e's/ +/ /g'
77! test "$initial_hash" = "$(guix hash "$tmpfile")"
78
79guix style -f "$tmpfile"
80test "$initial_hash" = "$(guix hash "$tmpfile")"