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.
parent
90ef692e9b
commit
a15542d26d
|
@ -580,6 +580,7 @@ SH_TESTS = \
|
||||||
tests/guix-package.sh \
|
tests/guix-package.sh \
|
||||||
tests/guix-package-aliases.sh \
|
tests/guix-package-aliases.sh \
|
||||||
tests/guix-package-net.sh \
|
tests/guix-package-net.sh \
|
||||||
|
tests/guix-style.sh \
|
||||||
tests/guix-system.sh \
|
tests/guix-system.sh \
|
||||||
tests/guix-home.sh \
|
tests/guix-home.sh \
|
||||||
tests/guix-archive.sh \
|
tests/guix-archive.sh \
|
||||||
|
|
|
@ -14058,9 +14058,12 @@ otherwise.
|
||||||
@node Invoking guix style
|
@node Invoking guix style
|
||||||
@section Invoking @command{guix style}
|
@section Invoking @command{guix style}
|
||||||
|
|
||||||
The @command{guix style} command helps packagers style their package
|
The @command{guix style} command helps users and packagers alike style
|
||||||
definitions according to the latest fashionable trends. The command
|
their package definitions and configuration files according to the
|
||||||
currently provides the following styling rules:
|
latest fashionable trends. It can either reformat whole files, with the
|
||||||
|
@option{--whole-file} option, or apply specific @dfn{styling rules} to
|
||||||
|
individual package definitions. The command currently provides the
|
||||||
|
following styling rules:
|
||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
@item
|
@item
|
||||||
|
@ -14115,6 +14118,12 @@ the packages. The @option{--styling} or @option{-S} option allows you
|
||||||
to select the style rule, the default rule being @code{format}---see
|
to select the style rule, the default rule being @code{format}---see
|
||||||
below.
|
below.
|
||||||
|
|
||||||
|
To reformat entire source files, the syntax is:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix style --whole-file @var{file}@dots{}
|
||||||
|
@end example
|
||||||
|
|
||||||
The available options are listed below.
|
The available options are listed below.
|
||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
|
@ -14122,6 +14131,19 @@ The available options are listed below.
|
||||||
@itemx -n
|
@itemx -n
|
||||||
Show source file locations that would be edited but do not modify them.
|
Show source file locations that would be edited but do not modify them.
|
||||||
|
|
||||||
|
@item --whole-file
|
||||||
|
@itemx -f
|
||||||
|
Reformat the given files in their entirety. In that case, subsequent
|
||||||
|
arguments are interpreted as file names (rather than package names), and
|
||||||
|
the @option{--styling} option has no effect.
|
||||||
|
|
||||||
|
As an example, here is how you might reformat your operating system
|
||||||
|
configuration (you need write permissions for the file):
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix style -f /etc/config.scm
|
||||||
|
@end example
|
||||||
|
|
||||||
@item --styling=@var{rule}
|
@item --styling=@var{rule}
|
||||||
@itemx -S @var{rule}
|
@itemx -S @var{rule}
|
||||||
Apply @var{rule}, one of the following styling rules:
|
Apply @var{rule}, one of the following styling rules:
|
||||||
|
|
|
@ -328,6 +328,21 @@ PACKAGE."
|
||||||
(< (location-line loc1) (location-line loc2))
|
(< (location-line loc1) (location-line loc2))
|
||||||
(string<? (location-file loc1) (location-file loc2))))))
|
(string<? (location-file loc1) (location-file loc2))))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Whole-file formatting.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define* (format-whole-file file #:rest rest)
|
||||||
|
"Reformat all of FILE."
|
||||||
|
(let ((lst (call-with-input-file file read-with-comments/sequence)))
|
||||||
|
(with-atomic-file-output file
|
||||||
|
(lambda (port)
|
||||||
|
(apply pretty-print-with-comments/splice port lst
|
||||||
|
#:format-comment canonicalize-comment
|
||||||
|
#:format-vertical-space canonicalize-vertical-space
|
||||||
|
rest)))))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; Options.
|
;;; Options.
|
||||||
|
@ -345,6 +360,9 @@ PACKAGE."
|
||||||
(option '(#\e "expression") #t #f
|
(option '(#\e "expression") #t #f
|
||||||
(lambda (opt name arg result)
|
(lambda (opt name arg result)
|
||||||
(alist-cons 'expression arg result)))
|
(alist-cons 'expression arg result)))
|
||||||
|
(option '(#\f "whole-file") #f #f
|
||||||
|
(lambda (opt name arg result)
|
||||||
|
(alist-cons 'whole-file? #t result)))
|
||||||
(option '(#\S "styling") #t #f
|
(option '(#\S "styling") #t #f
|
||||||
(lambda (opt name arg result)
|
(lambda (opt name arg result)
|
||||||
(alist-cons 'styling-procedure
|
(alist-cons 'styling-procedure
|
||||||
|
@ -400,6 +418,9 @@ Update package definitions to the latest style.\n"))
|
||||||
of 'silent', 'safe', or 'always'"))
|
of 'silent', 'safe', or 'always'"))
|
||||||
(newline)
|
(newline)
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
|
-f, --whole-file format the entire contents of the given file(s)"))
|
||||||
|
(newline)
|
||||||
|
(display (G_ "
|
||||||
-h, --help display this help and exit"))
|
-h, --help display this help and exit"))
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
-V, --version display version information and exit"))
|
-V, --version display version information and exit"))
|
||||||
|
@ -426,27 +447,35 @@ Update package definitions to the latest style.\n"))
|
||||||
#:build-options? #f))
|
#:build-options? #f))
|
||||||
|
|
||||||
(let* ((opts (parse-options))
|
(let* ((opts (parse-options))
|
||||||
(packages (filter-map (match-lambda
|
|
||||||
(('argument . spec)
|
|
||||||
(specification->package spec))
|
|
||||||
(('expression . str)
|
|
||||||
(read/eval str))
|
|
||||||
(_ #f))
|
|
||||||
opts))
|
|
||||||
(edit (if (assoc-ref opts 'dry-run?)
|
(edit (if (assoc-ref opts 'dry-run?)
|
||||||
edit-expression/dry-run
|
edit-expression/dry-run
|
||||||
edit-expression))
|
edit-expression))
|
||||||
(style (assoc-ref opts 'styling-procedure))
|
(style (assoc-ref opts 'styling-procedure))
|
||||||
(policy (assoc-ref opts 'input-simplification-policy)))
|
(policy (assoc-ref opts 'input-simplification-policy)))
|
||||||
(with-error-handling
|
(with-error-handling
|
||||||
(for-each (lambda (package)
|
(if (assoc-ref opts 'whole-file?)
|
||||||
(style package #:policy policy
|
(let ((files (filter-map (match-lambda
|
||||||
#:edit-expression edit))
|
(('argument . file) file)
|
||||||
;; Sort package by source code location so that we start editing
|
(_ #f))
|
||||||
;; files from the bottom and going upward. That way, the
|
opts)))
|
||||||
;; 'location' field of <package> records is not invalidated as
|
(unless (eq? format-package-definition style)
|
||||||
;; we modify files.
|
(warning (G_ "'--styling' option has no effect in whole-file mode~%")))
|
||||||
(sort (if (null? packages)
|
(for-each format-whole-file files))
|
||||||
(fold-packages cons '() #:select? (const #t))
|
(let ((packages (filter-map (match-lambda
|
||||||
packages)
|
(('argument . spec)
|
||||||
(negate package-location<?))))))
|
(specification->package spec))
|
||||||
|
(('expression . str)
|
||||||
|
(read/eval str))
|
||||||
|
(_ #f))
|
||||||
|
opts)))
|
||||||
|
(for-each (lambda (package)
|
||||||
|
(style package #:policy policy
|
||||||
|
#:edit-expression edit))
|
||||||
|
;; Sort package by source code location so that we start
|
||||||
|
;; editing files from the bottom and going upward. That
|
||||||
|
;; way, the 'location' field of <package> records is not
|
||||||
|
;; invalidated as we modify files.
|
||||||
|
(sort (if (null? packages)
|
||||||
|
(fold-packages cons '() #:select? (const #t))
|
||||||
|
packages)
|
||||||
|
(negate package-location<?))))))))
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
# GNU Guix --- Functional package management for GNU
|
||||||
|
# Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test 'guix style'.
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
guix style --version
|
||||||
|
|
||||||
|
tmpdir="guix-style-$$"
|
||||||
|
trap 'rm -r "$tmpdir"' EXIT
|
||||||
|
|
||||||
|
tmpfile="$tmpdir/os.scm"
|
||||||
|
mkdir "$tmpdir"
|
||||||
|
cat > "$tmpfile" <<EOF
|
||||||
|
;;; This is a header with three semicolons.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define-module (foo bar)
|
||||||
|
#:use-module (guix)
|
||||||
|
#:use-module (gnu))
|
||||||
|
|
||||||
|
;; One blank line and a page break.
|
||||||
|
|
||||||
|
|
||||||
|
;; And now, the OS.
|
||||||
|
(operating-system
|
||||||
|
(host-name "komputilo")
|
||||||
|
(locale "eo_EO.UTF-8")
|
||||||
|
|
||||||
|
;; User accounts.
|
||||||
|
(users (cons (user-account
|
||||||
|
(name "alice")
|
||||||
|
(comment "Bob's sister")
|
||||||
|
(group "users")
|
||||||
|
|
||||||
|
;; Groups fit on one line.
|
||||||
|
(supplementary-groups '("wheel" "audio" "video")))
|
||||||
|
%base-user-accounts))
|
||||||
|
|
||||||
|
;; The services.
|
||||||
|
(services
|
||||||
|
(cons (service mcron-service-type) %base-services)))
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cp "$tmpfile" "$tmpfile.bak"
|
||||||
|
|
||||||
|
initial_hash="$(guix hash "$tmpfile")"
|
||||||
|
|
||||||
|
guix style -f "$tmpfile"
|
||||||
|
if ! test "$initial_hash" = "$(guix hash "$tmpfile")"
|
||||||
|
then
|
||||||
|
cat "$tmpfile"
|
||||||
|
diff -u "$tmpfile.bak" "$tmpfile"
|
||||||
|
false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Introduce random changes and try again.
|
||||||
|
sed -i "$tmpfile" -e's/ +/ /g'
|
||||||
|
! test "$initial_hash" = "$(guix hash "$tmpfile")"
|
||||||
|
|
||||||
|
guix style -f "$tmpfile"
|
||||||
|
test "$initial_hash" = "$(guix hash "$tmpfile")"
|
Reference in New Issue