diff options
| -rw-r--r-- | doc/guix.texi | 26 | ||||
| -rw-r--r-- | guix/scripts/lint.scm | 55 | ||||
| -rw-r--r-- | tests/guix-lint.sh | 20 |
3 files changed, 90 insertions, 11 deletions
diff --git a/doc/guix.texi b/doc/guix.texi index 209becd722a..30c91d0df9d 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -124,7 +124,7 @@ Copyright @copyright{} 2023 Thomas Ieong@* | |||
| 124 | Copyright @copyright{} 2023 Saku Laesvuori@* | 124 | Copyright @copyright{} 2023 Saku Laesvuori@* |
| 125 | Copyright @copyright{} 2023 Graham James Addis@* | 125 | Copyright @copyright{} 2023 Graham James Addis@* |
| 126 | Copyright @copyright{} 2023-2025 Tomas Volf@* | 126 | Copyright @copyright{} 2023-2025 Tomas Volf@* |
| 127 | Copyright @copyright{} 2024, 2025 Herman Rimm@* | 127 | Copyright @copyright{} 2024-2026 Herman Rimm@* |
| 128 | Copyright @copyright{} 2024 Matthew Trzcinski@* | 128 | Copyright @copyright{} 2024 Matthew Trzcinski@* |
| 129 | Copyright @copyright{} 2024 Richard Sent@* | 129 | Copyright @copyright{} 2024 Richard Sent@* |
| 130 | Copyright @copyright{} 2024 Dariqq@* | 130 | Copyright @copyright{} 2024 Dariqq@* |
| @@ -16710,6 +16710,12 @@ guix lint @var{options} @var{package}@dots{} | |||
| 16710 | @end example | 16710 | @end example |
| 16711 | 16711 | ||
| 16712 | If no package is given on the command line, then all packages are checked. | 16712 | If no package is given on the command line, then all packages are checked. |
| 16713 | To check packages in particular source files, the syntax is: | ||
| 16714 | |||
| 16715 | @example | ||
| 16716 | guix lint @var{options} --whole-file @var{file}@dots{} | ||
| 16717 | @end example | ||
| 16718 | |||
| 16713 | The @var{options} may be zero or more of the following: | 16719 | The @var{options} may be zero or more of the following: |
| 16714 | 16720 | ||
| 16715 | @table @code | 16721 | @table @code |
| @@ -16747,9 +16753,23 @@ Only enable the checkers that do not depend on Internet access. | |||
| 16747 | Add @var{directory} to the front of the package module search path | 16753 | Add @var{directory} to the front of the package module search path |
| 16748 | (@pxref{Package Modules}). | 16754 | (@pxref{Package Modules}). |
| 16749 | 16755 | ||
| 16750 | This allows users to define their own packages and make them visible to | 16756 | @item --whole-file |
| 16751 | the command-line tools. | 16757 | @itemx -f |
| 16758 | Check the top-level package definitions in the given files; subsequent | ||
| 16759 | arguments are treated as file names rather than package names. This | ||
| 16760 | option also enables a special checker which checks if a package | ||
| 16761 | alphabetically succeeds the one above it. | ||
| 16762 | |||
| 16763 | For example, to check if the packages in @file{gnu/packages/matrix.scm} | ||
| 16764 | are sorted alphabetically, and if the package names therein follow | ||
| 16765 | established conventions, run: | ||
| 16766 | |||
| 16767 | @example | ||
| 16768 | guix lint -c name -f gnu/packages/matrix.scm | ||
| 16769 | @end example | ||
| 16752 | 16770 | ||
| 16771 | The previous two options allow users to define their own packages and | ||
| 16772 | make them visible to the command-line tools. | ||
| 16753 | @end table | 16773 | @end table |
| 16754 | 16774 | ||
| 16755 | @node Invoking guix size | 16775 | @node Invoking guix size |
diff --git a/guix/scripts/lint.scm b/guix/scripts/lint.scm index ee3de51fb1a..6a317bf64d5 100644 --- a/guix/scripts/lint.scm +++ b/guix/scripts/lint.scm | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | ;;; Copyright © 2018, 2019 Arun Isaac <arunisaac@systemreboot.net> | 11 | ;;; Copyright © 2018, 2019 Arun Isaac <arunisaac@systemreboot.net> |
| 12 | ;;; Copyright © 2019, 2020 Simon Tournier <zimon.toutoune@gmail.com> | 12 | ;;; Copyright © 2019, 2020 Simon Tournier <zimon.toutoune@gmail.com> |
| 13 | ;;; Copyright © 2020 Brice Waegeneire <brice@waegenei.re> | 13 | ;;; Copyright © 2020 Brice Waegeneire <brice@waegenei.re> |
| 14 | ;;; Copyright © 2024, 2026 Herman Rimm <herman@rimm.ee> | ||
| 14 | ;;; | 15 | ;;; |
| 15 | ;;; This file is part of GNU Guix. | 16 | ;;; This file is part of GNU Guix. |
| 16 | ;;; | 17 | ;;; |
| @@ -28,8 +29,10 @@ | |||
| 28 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | 29 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. |
| 29 | 30 | ||
| 30 | (define-module (guix scripts lint) | 31 | (define-module (guix scripts lint) |
| 32 | #:use-module (guix diagnostics) | ||
| 31 | #:use-module (guix packages) | 33 | #:use-module (guix packages) |
| 32 | #:use-module (guix lint) | 34 | #:use-module (guix lint) |
| 35 | #:use-module (guix modules) | ||
| 33 | #:use-module (guix ui) | 36 | #:use-module (guix ui) |
| 34 | #:use-module (guix store) | 37 | #:use-module (guix store) |
| 35 | #:use-module (guix scripts) | 38 | #:use-module (guix scripts) |
| @@ -87,6 +90,28 @@ | |||
| 87 | checkers) | 90 | checkers) |
| 88 | (exit 0)) | 91 | (exit 0)) |
| 89 | 92 | ||
| 93 | (define* (process-whole-file file checkers #:key store) | ||
| 94 | "Run the given CHECKERS on packages in FILE and check that the | ||
| 95 | packages are sorted alphabetically." | ||
| 96 | (load* file '()) | ||
| 97 | (let* ((module (resolve-interface (file-name->module-name file))) | ||
| 98 | (packages (sort (fold-packages cons '() (list module)) | ||
| 99 | package-location<?))) | ||
| 100 | (fold (lambda (package previous) | ||
| 101 | (let ((line (location-line (package-location package))) | ||
| 102 | (name (package-name package))) | ||
| 103 | (run-checkers package checkers #:store store) | ||
| 104 | (and (string<? name previous) | ||
| 105 | (emit-warnings | ||
| 106 | (list (lint-warning | ||
| 107 | (package package) | ||
| 108 | (location (location file line 0)) | ||
| 109 | (message-text | ||
| 110 | (G_ "breaks from alphabetical order")) | ||
| 111 | (message-data '()))))) | ||
| 112 | name)) | ||
| 113 | "" packages))) | ||
| 114 | |||
| 90 | 115 | ||
| 91 | ;;; | 116 | ;;; |
| 92 | ;;; Command-line options. | 117 | ;;; Command-line options. |
| @@ -115,6 +140,9 @@ run the checkers on all packages.\n")) | |||
| 115 | -L, --load-path=DIR prepend DIR to the package module search path")) | 140 | -L, --load-path=DIR prepend DIR to the package module search path")) |
| 116 | (newline) | 141 | (newline) |
| 117 | (display (G_ " | 142 | (display (G_ " |
| 143 | -f, --whole-file check the packages defined in the given file(s)")) | ||
| 144 | (newline) | ||
| 145 | (display (G_ " | ||
| 118 | -h, --help display this help and exit")) | 146 | -h, --help display this help and exit")) |
| 119 | (display (G_ " | 147 | (display (G_ " |
| 120 | -l, --list-checkers display the list of available lint checkers")) | 148 | -l, --list-checkers display the list of available lint checkers")) |
| @@ -161,6 +189,9 @@ run the checkers on all packages.\n")) | |||
| 161 | (lambda args | 189 | (lambda args |
| 162 | (leave-on-EPIPE (show-help)) | 190 | (leave-on-EPIPE (show-help)) |
| 163 | (exit 0))) | 191 | (exit 0))) |
| 192 | (option '(#\f "whole-file") #f #f | ||
| 193 | (lambda (opt name arg result) | ||
| 194 | (alist-cons 'whole-file? #t result))) | ||
| 164 | (option '(#\l "list-checkers") #f #f | 195 | (option '(#\l "list-checkers") #f #f |
| 165 | (lambda (opt name arg result) | 196 | (lambda (opt name arg result) |
| 166 | (alist-cons 'list? #t result))) | 197 | (alist-cons 'list? #t result))) |
| @@ -187,12 +218,17 @@ run the checkers on all packages.\n")) | |||
| 187 | #:build-options? #f)) | 218 | #:build-options? #f)) |
| 188 | 219 | ||
| 189 | (let* ((opts (parse-options)) | 220 | (let* ((opts (parse-options)) |
| 190 | (args (filter-map (match-lambda | 221 | (whole-file? (assoc-ref opts 'whole-file?)) |
| 191 | (('argument . spec) | 222 | (args (filter-map (if whole-file? |
| 192 | (specification->package spec)) | 223 | (match-lambda |
| 193 | (('expression . exp) | 224 | (('argument . file) file) |
| 194 | (read/eval-package-expression exp)) | 225 | (_ #f)) |
| 195 | (_ #f)) | 226 | (match-lambda |
| 227 | (('argument . spec) | ||
| 228 | (specification->package spec)) | ||
| 229 | (('expression . exp) | ||
| 230 | (read/eval-package-expression exp)) | ||
| 231 | (_ #f))) | ||
| 196 | (reverse opts))) | 232 | (reverse opts))) |
| 197 | (no-checkers (or (assoc-ref opts 'exclude) '())) | 233 | (no-checkers (or (assoc-ref opts 'exclude) '())) |
| 198 | (the-checkers (filter (lambda (checker) | 234 | (the-checkers (filter (lambda (checker) |
| @@ -221,6 +257,13 @@ run the checkers on all packages.\n")) | |||
| 221 | (call-maybe-with-store | 257 | (call-maybe-with-store |
| 222 | (lambda (store) | 258 | (lambda (store) |
| 223 | (cond | 259 | (cond |
| 260 | (whole-file? | ||
| 261 | (when (null? args) | ||
| 262 | (warning (G_ "no files specified, nothing to do~%"))) | ||
| 263 | (for-each | ||
| 264 | (lambda (file) | ||
| 265 | (process-whole-file file checkers #:store store)) | ||
| 266 | args)) | ||
| 224 | ((null? args) | 267 | ((null? args) |
| 225 | (fold-packages (lambda (p r) (run-checkers p checkers | 268 | (fold-packages (lambda (p r) (run-checkers p checkers |
| 226 | #:store store)) '())) | 269 | #:store store)) '())) |
diff --git a/tests/guix-lint.sh b/tests/guix-lint.sh index 97c2ea83fef..4a77315b3a2 100644 --- a/tests/guix-lint.sh +++ b/tests/guix-lint.sh | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | # GNU Guix --- Functional package management for GNU | 1 | # GNU Guix --- Functional package management for GNU |
| 2 | # Copyright © 2014 Cyril Roelandt <tipecaml@gmail.com> | 2 | # Copyright © 2014 Cyril Roelandt <tipecaml@gmail.com> |
| 3 | # Copyright © 2026 Herman Rimm <herman@rimm.ee> | ||
| 3 | # | 4 | # |
| 4 | # This file is part of GNU Guix. | 5 | # This file is part of GNU Guix. |
| 5 | # | 6 | # |
| @@ -35,12 +36,20 @@ cat > "$module_dir/foo.scm"<<EOF | |||
| 35 | #:use-module (guix packages) | 36 | #:use-module (guix packages) |
| 36 | #:use-module (gnu packages base)) | 37 | #:use-module (gnu packages base)) |
| 37 | 38 | ||
| 39 | ;; This definition uses (the line number of) the hello package location | ||
| 40 | ;; instead of generating a new one. | ||
| 41 | (define-public hi hello) | ||
| 42 | |||
| 38 | (define-public dummy | 43 | (define-public dummy |
| 39 | (package (inherit hello) | 44 | (package (inherit hello) |
| 40 | (name "dummy") | 45 | (name "dummy") |
| 41 | (version "42") | 46 | (version "42") |
| 42 | (synopsis "dummy package") | 47 | (synopsis "dummy package") |
| 43 | (description "dummy package. Only used for testing purposes."))) | 48 | (description "dummy package. Only used for testing purposes."))) |
| 49 | |||
| 50 | (define-public bar | ||
| 51 | (package (inherit dummy) | ||
| 52 | (name "bar"))) | ||
| 44 | EOF | 53 | EOF |
| 45 | 54 | ||
| 46 | GUIX_PACKAGE_PATH="$module_dir" | 55 | GUIX_PACKAGE_PATH="$module_dir" |
| @@ -52,10 +61,11 @@ grep_warning () | |||
| 52 | echo $res | 61 | echo $res |
| 53 | } | 62 | } |
| 54 | 63 | ||
| 55 | # Three issues with the dummy package: | 64 | # Issues with the dummy package: |
| 56 | # 1) the synopsis starts with the package name; | 65 | # 1) the synopsis starts with the package name; |
| 57 | # 2) the synopsis starts with a lower-case letter; | 66 | # 2) the synopsis starts with a lower-case letter; |
| 58 | # 3) the description has a single space following the end-of-sentence period. | 67 | # 3) the description has a single space following the end-of-sentence period; |
| 68 | # 4) the alphabetically lesser bar package succeeds it. | ||
| 59 | 69 | ||
| 60 | out=`guix lint -c synopsis,description dummy 2>&1` | 70 | out=`guix lint -c synopsis,description dummy 2>&1` |
| 61 | test `grep_warning "$out"` -eq 3 | 71 | test `grep_warning "$out"` -eq 3 |
| @@ -69,6 +79,12 @@ test `grep_warning "$out"` -eq 1 | |||
| 69 | out=`guix lint -c description,synopsis dummy 2>&1` | 79 | out=`guix lint -c description,synopsis dummy 2>&1` |
| 70 | test `grep_warning "$out"` -eq 3 | 80 | test `grep_warning "$out"` -eq 3 |
| 71 | 81 | ||
| 82 | working_dir="$(pwd)" | ||
| 83 | cd "$module_dir" | ||
| 84 | out=`guix lint -c name -f foo.scm 2>&1` | ||
| 85 | cd "$working_dir" | ||
| 86 | test `echo "$out" | grep -E -c "breaks from alphabetical order"` -eq 1 | ||
| 87 | |||
| 72 | guix lint -c synopsis,invalid-checker dummy 2>&1 | \ | 88 | guix lint -c synopsis,invalid-checker dummy 2>&1 | \ |
| 73 | grep -q 'invalid-checker: invalid checker' | 89 | grep -q 'invalid-checker: invalid checker' |
| 74 | 90 | ||
