scripts: style: Add 'alphabetical-sort' option.

* guix/scripts/style.scm (show-help): Describe option.
(order-packages): Add procedure.
(format-whole-file): Add 'order?' argument.
(%options): Add 'alphabetical-sort' option.
(guix-style): Alphabetically order packages in files.
* tests/guix-style.sh: Test alphabetical ordering.
* doc/guix.texi (Invoking guix style): Document option.

Change-Id: I4aa7c0bd0b6d42529ae7d304587ffb10bf5f4006
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
This commit is contained in:
Herman Rimm 2024-09-02 20:58:05 +02:00 committed by Ludovic Courtès
parent 52681a036a
commit c4ce313052
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
3 changed files with 100 additions and 6 deletions

View file

@ -15227,6 +15227,13 @@ configuration (you need write permissions for the file):
guix style -f /etc/config.scm guix style -f /etc/config.scm
@end example @end example
@item --alphabetical-sort
@itemx -A
Place the top-level package definitions in the given files in
alphabetical order. Package definitions with matching names are placed
with versions in descending order. This option only has an effect in
combination with @option{--whole-file}.
@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:

View file

@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2021-2024 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2021-2024 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2024 Herman Rimm <herman@rimm.ee>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -29,6 +30,7 @@
(define-module (guix scripts style) (define-module (guix scripts style)
#:autoload (gnu packages) (specification->package fold-packages) #:autoload (gnu packages) (specification->package fold-packages)
#:use-module (guix combinators)
#:use-module (guix scripts) #:use-module (guix scripts)
#:use-module ((guix scripts build) #:select (%standard-build-options)) #:use-module ((guix scripts build) #:select (%standard-build-options))
#:use-module (guix ui) #:use-module (guix ui)
@ -494,11 +496,62 @@ (define (package-location<? p1 p2)
;;; Whole-file formatting. ;;; Whole-file formatting.
;;; ;;;
(define* (format-whole-file file #:rest rest) (define (order-packages lst)
"Reformat all of FILE." "Return LST, a list of top-level expressions and blanks, with
top-level package definitions in alphabetical order. Packages which
share a name are placed with versions in descending order."
(define (package-name pkg)
(match pkg
((('define-public _ expr) _ ...)
(match expr
((or ('package _ ('name name) _ ...)
('package ('name name) _ ...))
name)
(_ #f)))
(_ #f)))
(define (package-version pkg)
(match pkg
((('define-public _ expr) _ ...)
(match expr
((or ('package _ _ ('version version) _ ...)
('package _ ('version version) _ ...))
version)
(_ #f)))
(_ #f)))
(define (package>? lst1 lst2)
(let ((name1 (package-name lst1))
(name2 (package-name lst2))
(version1 (package-version lst1))
(version2 (package-version lst2)))
(and name1 name2 (or (string>? name1 name2)
(and (string=? name1 name2)
version1
version2
(version>? version2 version1))))))
;; Group define-public with preceding blanks and defines.
(let ((lst (fold2 (lambda (expr tail head)
(let ((head (cons expr head)))
(match expr
((? blank?)
(values tail head))
(('define _ ...)
(values tail head))
(_ (values (cons head tail) '())))))
'() '() lst)))
(reverse (concatenate (sort! lst package>?)))))
(define* (format-whole-file file order? #:rest rest)
"Reformat all of FILE. When ORDER? is true, top-level package definitions
are put in alphabetical order."
(with-fluids ((%default-port-encoding "UTF-8")) (with-fluids ((%default-port-encoding "UTF-8"))
(let ((lst (call-with-input-file file read-with-comments/sequence (let* ((lst (call-with-input-file file read-with-comments/sequence
#:guess-encoding #t))) #:guess-encoding #t))
(lst (if order?
(order-packages lst)
lst)))
(with-atomic-file-output file (with-atomic-file-output file
(lambda (port) (lambda (port)
(apply pretty-print-with-comments/splice port lst (apply pretty-print-with-comments/splice port lst
@ -526,6 +579,9 @@ (define %options
(option '(#\f "whole-file") #f #f (option '(#\f "whole-file") #f #f
(lambda (opt name arg result) (lambda (opt name arg result)
(alist-cons 'whole-file? #t result))) (alist-cons 'whole-file? #t result)))
(option '(#\A "--alphabetical-sort") #f #f
(lambda (opt name arg result)
(alist-cons 'order? #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
@ -569,7 +625,7 @@ (define (show-help)
(display (G_ " (display (G_ "
-S, --styling=RULE apply RULE, a styling rule")) -S, --styling=RULE apply RULE, a styling rule"))
(display (G_ " (display (G_ "
-l, --list-stylings display the list of available style rules")) -l, --list-stylings display the list of available style rules"))
(newline) (newline)
(display (G_ " (display (G_ "
-n, --dry-run display files that would be edited but do nothing")) -n, --dry-run display files that would be edited but do nothing"))
@ -584,6 +640,9 @@ (define (show-help)
(newline) (newline)
(display (G_ " (display (G_ "
-f, --whole-file format the entire contents of the given file(s)")) -f, --whole-file format the entire contents of the given file(s)"))
(display (G_ "
-A, --alphabetical-sort
place the contents in alphabetical order as well"))
(newline) (newline)
(display (G_ " (display (G_ "
-h, --help display this help and exit")) -h, --help display this help and exit"))
@ -627,7 +686,9 @@ (define (parse-options)
(warning (G_ "'--styling' option has no effect in whole-file mode~%"))) (warning (G_ "'--styling' option has no effect in whole-file mode~%")))
(when (null? files) (when (null? files)
(warning (G_ "no files specified, nothing to do~%"))) (warning (G_ "no files specified, nothing to do~%")))
(for-each format-whole-file files)) (for-each
(cute format-whole-file <> (assoc-ref opts 'order?))
files))
(let ((packages (filter-map (match-lambda (let ((packages (filter-map (match-lambda
(('argument . spec) (('argument . spec)
(specification->package spec)) (specification->package spec))

View file

@ -58,6 +58,24 @@ cat > "$tmpfile" <<EOF
;; The services. ;; The services.
(services (services
(cons (service mcron-service-type) %base-services))) (cons (service mcron-service-type) %base-services)))
;; Incomplete package definitions in alphabetical order.
(define-public pkg
(package
(name "bar")
(version "2")))
;; The comment below belongs to the foo package.
(define-public pkg
(package
(name "bar")
(version "1")))
;; Incomplete package definitions in alphabetical order.
(define-public pkg
(package
(name "foo")
(version "2")))
EOF EOF
cp "$tmpfile" "$tmpfile.bak" cp "$tmpfile" "$tmpfile.bak"
@ -78,3 +96,11 @@ test "$initial_hash" != "$(guix hash "$tmpfile")"
guix style -f "$tmpfile" guix style -f "$tmpfile"
test "$initial_hash" = "$(guix hash "$tmpfile")" test "$initial_hash" = "$(guix hash "$tmpfile")"
# Swap foo and bar packages.
sed -i "$tmpfile" -e 's/"foo"/"bar"/g'
sed -i "$tmpfile" -e '0,/"bar"/{s//"foo"/}'
test "$initial_hash" != "$(guix hash "$tmpfile")"
guix style -fA "$tmpfile"
test "$initial_hash" = "$(guix hash "$tmpfile")"