guix-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 1/2] scripts: add guix lint


From: Cyril Roelandt
Subject: [PATCH 1/2] scripts: add guix lint
Date: Tue, 22 Jul 2014 01:51:57 +0200

* guix/scripts/lint.scm: New file. Defines a 'lint' tool for Guix packages.
* Makefile.am (MODULES): Add it.
---
 Makefile.am           |   1 +
 guix/scripts/lint.scm | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+)
 create mode 100644 guix/scripts/lint.scm

diff --git a/Makefile.am b/Makefile.am
index 41e0e67..e6d2556 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -87,6 +87,7 @@ MODULES =                                     \
   guix/scripts/authenticate.scm                        \
   guix/scripts/refresh.scm                     \
   guix/scripts/system.scm                      \
+  guix/scripts/lint.scm                                \
   guix.scm                                     \
   $(GNU_SYSTEM_MODULES)
 
diff --git a/guix/scripts/lint.scm b/guix/scripts/lint.scm
new file mode 100644
index 0000000..f60718f
--- /dev/null
+++ b/guix/scripts/lint.scm
@@ -0,0 +1,188 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2014 Cyril Roelandt <address@hidden>
+;;;
+;;; 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 (guix scripts lint)
+  #:use-module (guix base32)
+  #:use-module (guix packages)
+  #:use-module (guix records)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (gnu packages)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-9)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:export (guix-lint))
+
+
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  ;; Alist of default option values.
+  `((format . , bytevector->nix-base32-string)))
+
+(define (show-help)
+  (display (_ "Usage: guix lint [OPTION]... [PACKAGE]
+Run a set of checkers on the specified package; if none is specified, run the 
checkers on all packages.\n"))
+  (display (_ "
+  -h, --help             display this help and exit"))
+  (display (_ "
+  -l, --list-checkers    display the list of available lint checkers"))
+  (display (_ "
+  -V, --version          display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specification of the command-line options.
+  ;; TODO: add some options:
+  ;; * --checkers=checker1,checker2...: only run the specified checkers
+  ;; * --certainty=[low,medium,high]: only run checkers that have at least this
+  ;;                                  'certainty'.
+  (list (option '(#\h "help") #f #f
+                (lambda args
+                  (show-help)
+                  (exit 0)))
+        (option '(#\l "list-checkers") #f #f
+                (lambda args
+                   (list-checkers-and-exit)))
+        (option '(#\V "version") #f #f
+                (lambda args
+                  (show-version-and-exit "guix lint")))))
+
+
+;;;
+;;; Helpers
+;;;
+(define (emit-warning package s)
+ (format #t "~a: ~a~%" (package-full-name package) s))
+
+
+;;;
+;;; Checkers
+;;;
+(define-record-type* <lint-checker>
+  lint-checker make-lint-checker
+  lint-checker?
+  ;; TODO: add a 'certainty' field that shows how confident we are in the
+  ;; checker. Then allow users to only run checkers that have a certain
+  ;; 'certainty' level.
+  (name        lint-checker-name)
+  (description lint-checker-description)
+  (check       lint-checker-check))
+
+(define (list-checkers-and-exit)
+ (format #t "Available checkers:~%")
+ (for-each (lambda (checker)
+             (format #t "- ~a: ~a~%"
+                     (lint-checker-name checker)
+                     (lint-checker-description checker)))
+           %checkers)
+ (exit 0))
+
+(define (check-inputs-should-be-native package)
+ (let ((inputs (package-inputs package)))
+   (if (member "pkg-config" (map car inputs))
+       (emit-warning package "pkg-config should probably be a native input"))))
+
+(define (check-synopsis-style package)
+  (define (check-final-period synopsis)
+    (if (string=? (string-take-right synopsis 1) ".")
+        (emit-warning package
+                      "No period allowed at the end of the synopsis.")))
+
+  (define (check-start-article synopsis)
+   (if (or (string=? (string-take synopsis 2) "A ")
+           (string=? (string-take synopsis 3) "An "))
+       (emit-warning package
+                     "No article allowed at the beginning of the synopsis.")))
+
+ (let ((synopsis (package-synopsis package)))
+   (if (string? synopsis)
+       (begin
+        (check-final-period synopsis)
+        (check-start-article synopsis)))))
+
+(define (check-patches package)
+ (let ((patches   (and=> (package-source package) origin-patches))
+       (name      (package-name package))
+       (full-name (package-full-name package)))
+   (if (and patches
+            (any (lambda (patch)
+                   (let ((filename (basename patch)))
+                     (not (or (eq? (string-contains filename name) 0)
+                              (eq? (string-contains filename full-name) 0)))))
+                 patches))
+       (emit-warning package
+         "Filenames of patches should start by the package name"))))
+
+(define %checkers
+  (list
+   (make-lint-checker "inputs-should-be-native"
+    "Identify inputs that should be native inputs"
+    check-inputs-should-be-native)
+   (make-lint-checker "patch-filenames"
+    "Validate filenames of patches"
+    check-patches)
+   (make-lint-checker "synopsis"
+    "Validate package synopsis"
+    check-synopsis-style)))
+
+(define (run-checkers package)
+ (for-each (lambda (checker)
+             ((lint-checker-check checker) package))
+           %checkers))
+
+
+;;;
+;;; Entry Point
+;;;
+
+(define (guix-lint . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (_ "~A: unrecognized option~%") name))
+                (lambda (arg result)
+                  (alist-cons 'argument arg result))
+                %default-options))
+
+  (let* ((opts (parse-options))
+         (args (filter-map (match-lambda
+                            (('argument . value)
+                             value)
+                            (_ #f))
+                           (reverse opts)))
+         (fmt  (assq-ref opts 'format)))
+
+ (if (null? args)
+     (fold-packages (lambda (p r) (run-checkers p)) '())
+     (for-each (lambda (name)
+                 (let*-values (((name version)
+                               (package-name->name+version name)))
+                  (let ((packages (find-packages-by-name name version)))
+                    (case (length packages)
+                        ((0) (format #t "No such package")); XXX
+                        ((1) (run-checkers (car packages)))
+                        (else (format #t
+                                      "More than one package found, be more 
precise")))))); XXX
+               args))))
-- 
1.8.4.rc3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]