Add 'guix style'.
* guix/scripts/style.scm, tests/style.scm: New files. * Makefile.am (MODULES, SCM_TESTS): Add them. * po/guix/POTFILES.in: Add 'guix/scripts/style.scm'. * doc/guix.texi (Invoking guix style): New node. (package Reference): Reference it. (Invoking guix lint): Likewise.master
parent
73b08ad1a3
commit
f23803af20
|
@ -286,6 +286,7 @@ MODULES = \
|
||||||
guix/scripts/refresh.scm \
|
guix/scripts/refresh.scm \
|
||||||
guix/scripts/repl.scm \
|
guix/scripts/repl.scm \
|
||||||
guix/scripts/describe.scm \
|
guix/scripts/describe.scm \
|
||||||
|
guix/scripts/style.scm \
|
||||||
guix/scripts/system.scm \
|
guix/scripts/system.scm \
|
||||||
guix/scripts/system/search.scm \
|
guix/scripts/system/search.scm \
|
||||||
guix/scripts/system/reconfigure.scm \
|
guix/scripts/system/reconfigure.scm \
|
||||||
|
@ -500,6 +501,7 @@ SCM_TESTS = \
|
||||||
tests/swh.scm \
|
tests/swh.scm \
|
||||||
tests/syscalls.scm \
|
tests/syscalls.scm \
|
||||||
tests/system.scm \
|
tests/system.scm \
|
||||||
|
tests/style.scm \
|
||||||
tests/texlive.scm \
|
tests/texlive.scm \
|
||||||
tests/transformations.scm \
|
tests/transformations.scm \
|
||||||
tests/ui.scm \
|
tests/ui.scm \
|
||||||
|
|
100
doc/guix.texi
100
doc/guix.texi
|
@ -286,6 +286,7 @@ Utilities
|
||||||
* Invoking guix hash:: Computing the cryptographic hash of a file.
|
* Invoking guix hash:: Computing the cryptographic hash of a file.
|
||||||
* Invoking guix import:: Importing package definitions.
|
* Invoking guix import:: Importing package definitions.
|
||||||
* Invoking guix refresh:: Updating package definitions.
|
* Invoking guix refresh:: Updating package definitions.
|
||||||
|
* Invoking guix style:: Styling package definitions.
|
||||||
* Invoking guix lint:: Finding errors in package definitions.
|
* Invoking guix lint:: Finding errors in package definitions.
|
||||||
* Invoking guix size:: Profiling disk usage.
|
* Invoking guix size:: Profiling disk usage.
|
||||||
* Invoking guix graph:: Visualizing the graph of packages.
|
* Invoking guix graph:: Visualizing the graph of packages.
|
||||||
|
@ -6722,7 +6723,8 @@ the one above, but using the @dfn{old input style}:
|
||||||
|
|
||||||
This style is now deprecated; it is still supported but support will be
|
This style is now deprecated; it is still supported but support will be
|
||||||
removed in a future version. It should not be used for new package
|
removed in a future version. It should not be used for new package
|
||||||
definitions.
|
definitions. @xref{Invoking guix style}, on how to migrate to the new
|
||||||
|
style.
|
||||||
@end quotation
|
@end quotation
|
||||||
|
|
||||||
@cindex cross compilation, package dependencies
|
@cindex cross compilation, package dependencies
|
||||||
|
@ -10254,6 +10256,7 @@ the Scheme programming interface of Guix in a convenient way.
|
||||||
* Invoking guix hash:: Computing the cryptographic hash of a file.
|
* Invoking guix hash:: Computing the cryptographic hash of a file.
|
||||||
* Invoking guix import:: Importing package definitions.
|
* Invoking guix import:: Importing package definitions.
|
||||||
* Invoking guix refresh:: Updating package definitions.
|
* Invoking guix refresh:: Updating package definitions.
|
||||||
|
* Invoking guix style:: Styling package definitions.
|
||||||
* Invoking guix lint:: Finding errors in package definitions.
|
* Invoking guix lint:: Finding errors in package definitions.
|
||||||
* Invoking guix size:: Profiling disk usage.
|
* Invoking guix size:: Profiling disk usage.
|
||||||
* Invoking guix graph:: Visualizing the graph of packages.
|
* Invoking guix graph:: Visualizing the graph of packages.
|
||||||
|
@ -12076,6 +12079,98 @@ token procured from @uref{https://github.com/settings/tokens} or
|
||||||
otherwise.
|
otherwise.
|
||||||
|
|
||||||
|
|
||||||
|
@node Invoking guix style
|
||||||
|
@section Invoking @command{guix style}
|
||||||
|
|
||||||
|
The @command{guix style} command helps packagers style their package
|
||||||
|
definitions according to the latest fashionable trends. The command
|
||||||
|
currently focuses on one aspect: the style of package inputs. It may
|
||||||
|
eventually be extended to handle other stylistic matters.
|
||||||
|
|
||||||
|
The way package inputs are written is going through a transition
|
||||||
|
(@pxref{package Reference}, for more on package inputs). Until version
|
||||||
|
1.3.0, package inputs were written using the ``old style'', where each
|
||||||
|
input was given an explicit label, most of the time the package name:
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
(package
|
||||||
|
;; @dots{}
|
||||||
|
;; The "old style" (deprecated).
|
||||||
|
(inputs `(("libunistring" ,libunistring)
|
||||||
|
("libffi" ,libffi))))
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
Today, the old style is deprecated and the preferred style looks like
|
||||||
|
this:
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
(package
|
||||||
|
;; @dots{}
|
||||||
|
;; The "new style".
|
||||||
|
(inputs (list libunistring libffi)))
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
Likewise, uses of @code{alist-delete} and friends to manipulate inputs
|
||||||
|
is now deprecated in favor of @code{modify-inputs} (@pxref{Defining
|
||||||
|
Package Variants}, for more info on @code{modify-inputs}).
|
||||||
|
|
||||||
|
In the vast majority of cases, this is a purely mechanical change on the
|
||||||
|
surface syntax that does not even incur a package rebuild. Running
|
||||||
|
@command{guix style} can do that for you, whether you're working on
|
||||||
|
packages in Guix proper or in an external channel.
|
||||||
|
|
||||||
|
The general syntax is:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix style [@var{options}] @var{package}@dots{}
|
||||||
|
@end example
|
||||||
|
|
||||||
|
This causes @command{guix style} to analyze and rewrite the definition
|
||||||
|
of @var{package}@dots{}. It does so in a conservative way: preserving
|
||||||
|
comments and bailing out if it cannot make sense of the code that
|
||||||
|
appears in an inputs field. The available options are listed below.
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item --load-path=@var{directory}
|
||||||
|
@itemx -L @var{directory}
|
||||||
|
Add @var{directory} to the front of the package module search path
|
||||||
|
(@pxref{Package Modules}).
|
||||||
|
|
||||||
|
@item --expression=@var{expr}
|
||||||
|
@itemx -e @var{expr}
|
||||||
|
Style the package @var{expr} evaluates to.
|
||||||
|
|
||||||
|
For example, running:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix style -e '(@@ (gnu packages gcc) gcc-5)'
|
||||||
|
@end example
|
||||||
|
|
||||||
|
styles the @code{gcc-5} package definition.
|
||||||
|
|
||||||
|
@item --input-simplification=@var{policy}
|
||||||
|
Specify the package input simplification policy for cases where an input
|
||||||
|
label does not match the corresponding package name. @var{policy} may
|
||||||
|
be one of the following:
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item silent
|
||||||
|
Simplify inputs only when the change is ``silent'', meaning that the
|
||||||
|
package does not need to be rebuilt (its derivation is unchanged).
|
||||||
|
|
||||||
|
@item safe
|
||||||
|
Simplify inputs only when that is ``safe'' to do: the package might need
|
||||||
|
to be rebuilt, but the change is known to have no observable effect.
|
||||||
|
|
||||||
|
@item always
|
||||||
|
Simplify inputs even when input labels do not match package names, and
|
||||||
|
even if that might have an observable effect.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
The default is @code{silent}, meaning that input simplifications do not
|
||||||
|
trigger any package rebuild.
|
||||||
|
@end table
|
||||||
|
|
||||||
@node Invoking guix lint
|
@node Invoking guix lint
|
||||||
@section Invoking @command{guix lint}
|
@section Invoking @command{guix lint}
|
||||||
|
|
||||||
|
@ -12209,7 +12304,8 @@ use of tabulations, etc.
|
||||||
Report old-style input labels that do not match the name of the
|
Report old-style input labels that do not match the name of the
|
||||||
corresponding package. This aims to help migrate from the ``old input
|
corresponding package. This aims to help migrate from the ``old input
|
||||||
style''. @xref{package Reference}, for more information on package
|
style''. @xref{package Reference}, for more information on package
|
||||||
inputs and input styles.
|
inputs and input styles. @xref{Invoking guix style}, on how to migrate
|
||||||
|
to the new style.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
The general syntax is:
|
The general syntax is:
|
||||||
|
|
|
@ -0,0 +1,527 @@
|
||||||
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
|
;;; Copyright © 2021 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/>.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;;;
|
||||||
|
;;; This script updates package definitions so they use the "simplified" style
|
||||||
|
;;; for input lists, as in:
|
||||||
|
;;;
|
||||||
|
;;; (package
|
||||||
|
;;; ;; ...
|
||||||
|
;;; (inputs (list foo bar baz)))
|
||||||
|
;;;
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define-module (guix scripts style)
|
||||||
|
#:autoload (gnu packages) (specification->package fold-packages)
|
||||||
|
#:use-module (guix scripts)
|
||||||
|
#:use-module ((guix scripts build) #:select (%standard-build-options))
|
||||||
|
#:use-module (guix combinators)
|
||||||
|
#:use-module (guix ui)
|
||||||
|
#:use-module (guix packages)
|
||||||
|
#:use-module (guix utils)
|
||||||
|
#:use-module (guix i18n)
|
||||||
|
#:use-module (guix diagnostics)
|
||||||
|
#:use-module (ice-9 control)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
|
#:use-module (ice-9 rdelim)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (srfi srfi-9)
|
||||||
|
#:use-module (srfi srfi-26)
|
||||||
|
#:use-module (srfi srfi-37)
|
||||||
|
#:export (guix-style))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Comment-preserving reader.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
;; A comment.
|
||||||
|
(define-record-type <comment>
|
||||||
|
(comment str margin?)
|
||||||
|
comment?
|
||||||
|
(str comment->string)
|
||||||
|
(margin? comment-margin?))
|
||||||
|
|
||||||
|
(define (read-with-comments port)
|
||||||
|
"Like 'read', but include <comment> objects when they're encountered."
|
||||||
|
;; Note: Instead of implementing this functionality in 'read' proper, which
|
||||||
|
;; is the best approach long-term, this code is a later on top of 'read',
|
||||||
|
;; such that we don't have to rely on a specific Guile version.
|
||||||
|
(let loop ((blank-line? #t)
|
||||||
|
(return (const 'unbalanced)))
|
||||||
|
(match (read-char port)
|
||||||
|
((? eof-object? eof)
|
||||||
|
eof) ;oops!
|
||||||
|
(chr
|
||||||
|
(cond ((eqv? chr #\newline)
|
||||||
|
(loop #t return))
|
||||||
|
((char-set-contains? char-set:whitespace chr)
|
||||||
|
(loop blank-line? return))
|
||||||
|
((memv chr '(#\( #\[))
|
||||||
|
(let/ec return
|
||||||
|
(let liip ((lst '()))
|
||||||
|
(liip (cons (loop (match lst
|
||||||
|
(((? comment?) . _) #t)
|
||||||
|
(_ #f))
|
||||||
|
(lambda ()
|
||||||
|
(return (reverse lst))))
|
||||||
|
lst)))))
|
||||||
|
((memv chr '(#\) #\]))
|
||||||
|
(return))
|
||||||
|
((eq? chr #\')
|
||||||
|
(list 'quote (loop #f return)))
|
||||||
|
((eq? chr #\`)
|
||||||
|
(list 'quasiquote (loop #f return)))
|
||||||
|
((eq? chr #\,)
|
||||||
|
(list (match (peek-char port)
|
||||||
|
(#\@
|
||||||
|
(read-char port)
|
||||||
|
'unquote-splicing)
|
||||||
|
(_
|
||||||
|
'unquote))
|
||||||
|
(loop #f return)))
|
||||||
|
((eqv? chr #\;)
|
||||||
|
(unread-char chr port)
|
||||||
|
(comment (read-line port 'concat)
|
||||||
|
(not blank-line?)))
|
||||||
|
(else
|
||||||
|
(unread-char chr port)
|
||||||
|
(read port)))))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Comment-preserving pretty-printer.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define* (pretty-print-with-comments port obj
|
||||||
|
#:key
|
||||||
|
(indent 0)
|
||||||
|
(max-width 78)
|
||||||
|
(long-list 5))
|
||||||
|
(let loop ((indent indent)
|
||||||
|
(column indent)
|
||||||
|
(delimited? #t) ;true if comes after a delimiter
|
||||||
|
(obj obj))
|
||||||
|
(match obj
|
||||||
|
((? comment? comment)
|
||||||
|
(if (comment-margin? comment)
|
||||||
|
(begin
|
||||||
|
(display " " port)
|
||||||
|
(display (comment->string comment) port))
|
||||||
|
(begin
|
||||||
|
;; When already at the beginning of a line, for example because
|
||||||
|
;; COMMENT follows a margin comment, no need to emit a newline.
|
||||||
|
(unless (= column indent)
|
||||||
|
(newline port)
|
||||||
|
(display (make-string indent #\space) port))
|
||||||
|
(display (comment->string comment) port)))
|
||||||
|
(display (make-string indent #\space) port)
|
||||||
|
indent)
|
||||||
|
(('quote lst)
|
||||||
|
(unless delimited? (display " " port))
|
||||||
|
(display "'" port)
|
||||||
|
(loop indent (+ column (if delimited? 1 2)) #t lst))
|
||||||
|
(('quasiquote lst)
|
||||||
|
(unless delimited? (display " " port))
|
||||||
|
(display "`" port)
|
||||||
|
(loop indent (+ column (if delimited? 1 2)) #t lst))
|
||||||
|
(('unquote lst)
|
||||||
|
(unless delimited? (display " " port))
|
||||||
|
(display "," port)
|
||||||
|
(loop indent (+ column (if delimited? 1 2)) #t lst))
|
||||||
|
(('modify-inputs inputs clauses ...)
|
||||||
|
;; Special-case 'modify-inputs' to have one clause per line and custom
|
||||||
|
;; indentation.
|
||||||
|
(let ((head "(modify-inputs "))
|
||||||
|
(display head port)
|
||||||
|
(loop (+ indent 4)
|
||||||
|
(+ column (string-length head))
|
||||||
|
#t
|
||||||
|
inputs)
|
||||||
|
(let* ((indent (+ indent 2))
|
||||||
|
(column (fold (lambda (clause column)
|
||||||
|
(newline port)
|
||||||
|
(display (make-string indent #\space)
|
||||||
|
port)
|
||||||
|
(loop indent indent #t clause))
|
||||||
|
indent
|
||||||
|
clauses)))
|
||||||
|
(display ")" port)
|
||||||
|
(+ column 1))))
|
||||||
|
((head tail ...)
|
||||||
|
(unless delimited? (display " " port))
|
||||||
|
(display "(" port)
|
||||||
|
(let* ((new-column (loop indent (+ 1 column) #t head))
|
||||||
|
(indent (+ indent (- new-column column)))
|
||||||
|
(long? (> (length tail) long-list)))
|
||||||
|
(define column
|
||||||
|
(fold2 (lambda (item column first?)
|
||||||
|
(define newline?
|
||||||
|
;; Insert a newline if ITEM is itself a list, or if TAIL
|
||||||
|
;; is long, but only if ITEM is not the first item.
|
||||||
|
(and (or (pair? item) long?)
|
||||||
|
(not first?) (not (comment? item))))
|
||||||
|
|
||||||
|
(when newline?
|
||||||
|
(newline port)
|
||||||
|
(display (make-string indent #\space) port))
|
||||||
|
(let ((column (if newline? indent column)))
|
||||||
|
(values (loop indent
|
||||||
|
column
|
||||||
|
(= column indent)
|
||||||
|
item)
|
||||||
|
(comment? item))))
|
||||||
|
(+ 1 new-column)
|
||||||
|
#t ;first
|
||||||
|
tail))
|
||||||
|
(display ")" port)
|
||||||
|
(+ column 1)))
|
||||||
|
(_
|
||||||
|
(let* ((str (object->string obj))
|
||||||
|
(len (string-length str)))
|
||||||
|
(if (> (+ column 1 len) max-width)
|
||||||
|
(begin
|
||||||
|
(newline port)
|
||||||
|
(display (make-string indent #\space) port)
|
||||||
|
(display str port)
|
||||||
|
(+ indent len))
|
||||||
|
(begin
|
||||||
|
(unless delimited? (display " " port))
|
||||||
|
(display str port)
|
||||||
|
(+ column (if delimited? 1 2) len))))))))
|
||||||
|
|
||||||
|
(define (object->string* obj indent)
|
||||||
|
(call-with-output-string
|
||||||
|
(lambda (port)
|
||||||
|
(pretty-print-with-comments port obj
|
||||||
|
#:indent indent))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Simplifying input expressions.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define (label-matches? label name)
|
||||||
|
"Return true if LABEL matches NAME, a package name."
|
||||||
|
(or (string=? label name)
|
||||||
|
(and (string-prefix? "python-" label)
|
||||||
|
(string-prefix? "python2-" name)
|
||||||
|
(string=? (string-drop label (string-length "python-"))
|
||||||
|
(string-drop name (string-length "python2-"))))))
|
||||||
|
|
||||||
|
(define* (simplify-inputs location package str inputs
|
||||||
|
#:key (label-matches? label-matches?))
|
||||||
|
"Simplify the inputs field of PACKAGE (a string) at LOCATION; its current
|
||||||
|
value is INPUTS the corresponding source code is STR. Return a string to
|
||||||
|
replace STR."
|
||||||
|
(define (simplify-input-expression return)
|
||||||
|
(match-lambda
|
||||||
|
((label ('unquote symbol)) symbol)
|
||||||
|
((label ('unquote symbol) output)
|
||||||
|
(list 'quasiquote
|
||||||
|
(list (list 'unquote symbol) output)))
|
||||||
|
(_
|
||||||
|
;; Expression doesn't look like a simple input.
|
||||||
|
(warning location (G_ "~a: complex expression, \
|
||||||
|
bailing out~%")
|
||||||
|
package)
|
||||||
|
(return str))))
|
||||||
|
|
||||||
|
(define (simplify-input exp input return)
|
||||||
|
(define package* package)
|
||||||
|
|
||||||
|
(match input
|
||||||
|
((or ((? string? label) (? package? package))
|
||||||
|
((? string? label) (? package? package)
|
||||||
|
(? string?)))
|
||||||
|
;; If LABEL doesn't match PACKAGE's name, then simplifying would incur
|
||||||
|
;; a rebuild, and perhaps it would break build-side code relying on
|
||||||
|
;; this specific label.
|
||||||
|
(if (label-matches? label (package-name package))
|
||||||
|
((simplify-input-expression return) exp)
|
||||||
|
(begin
|
||||||
|
(warning location (G_ "~a: input label \
|
||||||
|
'~a' does not match package name, bailing out~%")
|
||||||
|
package* label)
|
||||||
|
(return str))))
|
||||||
|
(_
|
||||||
|
(warning location (G_ "~a: non-trivial input, \
|
||||||
|
bailing out~%")
|
||||||
|
package*)
|
||||||
|
(return str))))
|
||||||
|
|
||||||
|
(define (simplify-expressions exp inputs return)
|
||||||
|
;; Simplify the expressions in EXP, which correspond to INPUTS, and return
|
||||||
|
;; a list of expressions. Call RETURN with a string when bailing out.
|
||||||
|
(let loop ((result '())
|
||||||
|
(exp exp)
|
||||||
|
(inputs inputs))
|
||||||
|
(match exp
|
||||||
|
(((? comment? head) . rest)
|
||||||
|
(loop (cons head result) rest inputs))
|
||||||
|
((head . rest)
|
||||||
|
(match inputs
|
||||||
|
((input . inputs)
|
||||||
|
;; HEAD (an sexp) and INPUT (an input tuple) are correlated.
|
||||||
|
(loop (cons (simplify-input head input return) result)
|
||||||
|
rest inputs))
|
||||||
|
(()
|
||||||
|
;; If EXP and INPUTS have a different length, that
|
||||||
|
;; means EXP is a non-trivial input list, for example
|
||||||
|
;; with input-splicing, conditionals, etc.
|
||||||
|
(warning location (G_ "~a: input expression is too short~%")
|
||||||
|
package)
|
||||||
|
(return str))))
|
||||||
|
(()
|
||||||
|
;; It's possible for EXP to contain fewer elements than INPUTS, for
|
||||||
|
;; example in the case of input splicing. No bailout here. (XXX)
|
||||||
|
(reverse result)))))
|
||||||
|
|
||||||
|
(define inputs-exp
|
||||||
|
(call-with-input-string str read-with-comments))
|
||||||
|
|
||||||
|
(match inputs-exp
|
||||||
|
(('list _ ...) ;already done
|
||||||
|
str)
|
||||||
|
(('modify-inputs _ ...) ;already done
|
||||||
|
str)
|
||||||
|
(('quasiquote ;prepending inputs
|
||||||
|
(exp ...
|
||||||
|
('unquote-splicing
|
||||||
|
((and symbol (or 'package-inputs 'package-native-inputs
|
||||||
|
'package-propagated-inputs))
|
||||||
|
arg))))
|
||||||
|
(let/ec return
|
||||||
|
(object->string*
|
||||||
|
(let ((things (simplify-expressions exp inputs return)))
|
||||||
|
`(modify-inputs (,symbol ,arg)
|
||||||
|
(prepend ,@things)))
|
||||||
|
(location-column location))))
|
||||||
|
(('quasiquote ;replacing an input
|
||||||
|
((and exp ((? string? to-delete) ('unquote replacement)))
|
||||||
|
('unquote-splicing
|
||||||
|
('alist-delete (? string? to-delete)
|
||||||
|
((and symbol
|
||||||
|
(or 'package-inputs 'package-native-inputs
|
||||||
|
'package-propagated-inputs))
|
||||||
|
arg)))))
|
||||||
|
(let/ec return
|
||||||
|
(object->string*
|
||||||
|
(let ((things (simplify-expressions (list exp)
|
||||||
|
(list (car inputs))
|
||||||
|
return)))
|
||||||
|
`(modify-inputs (,symbol ,arg)
|
||||||
|
(replace ,to-delete ,replacement)))
|
||||||
|
(location-column location))))
|
||||||
|
|
||||||
|
(('quasiquote ;removing an input
|
||||||
|
(exp ...
|
||||||
|
('unquote-splicing
|
||||||
|
('alist-delete (? string? to-delete)
|
||||||
|
((and symbol
|
||||||
|
(or 'package-inputs 'package-native-inputs
|
||||||
|
'package-propagated-inputs))
|
||||||
|
arg)))))
|
||||||
|
(let/ec return
|
||||||
|
(object->string*
|
||||||
|
(let ((things (simplify-expressions exp inputs return)))
|
||||||
|
`(modify-inputs (,symbol ,arg)
|
||||||
|
(delete ,to-delete)
|
||||||
|
(prepend ,@things)))
|
||||||
|
(location-column location))))
|
||||||
|
(('fold 'alist-delete ;removing several inputs
|
||||||
|
((and symbol
|
||||||
|
(or 'package-inputs 'package-native-inputs
|
||||||
|
'package-propagated-inputs))
|
||||||
|
arg)
|
||||||
|
('quote ((? string? to-delete) ...)))
|
||||||
|
(object->string*
|
||||||
|
`(modify-inputs (,symbol ,arg)
|
||||||
|
(delete ,@to-delete))
|
||||||
|
(location-column location)))
|
||||||
|
(('quasiquote ;removing several inputs and adding others
|
||||||
|
(exp ...
|
||||||
|
('unquote-splicing
|
||||||
|
('fold 'alist-delete
|
||||||
|
((and symbol
|
||||||
|
(or 'package-inputs 'package-native-inputs
|
||||||
|
'package-propagated-inputs))
|
||||||
|
arg)
|
||||||
|
('quote ((? string? to-delete) ...))))))
|
||||||
|
(let/ec return
|
||||||
|
(object->string*
|
||||||
|
(let ((things (simplify-expressions exp inputs return)))
|
||||||
|
`(modify-inputs (,symbol ,arg)
|
||||||
|
(delete ,@to-delete)
|
||||||
|
(prepend ,@things)))
|
||||||
|
(location-column location))))
|
||||||
|
(('quasiquote (exp ...))
|
||||||
|
(let/ec return
|
||||||
|
(object->string*
|
||||||
|
`(list ,@(simplify-expressions exp inputs return))
|
||||||
|
(location-column location))))
|
||||||
|
(_
|
||||||
|
(warning location (G_ "~a: unsupported input style, \
|
||||||
|
bailing out~%")
|
||||||
|
package)
|
||||||
|
str)))
|
||||||
|
|
||||||
|
(define* (simplify-package-inputs package
|
||||||
|
#:key (policy 'silent))
|
||||||
|
"Edit the source code of PACKAGE to simplify its inputs field if needed.
|
||||||
|
POLICY is a symbol that defines whether to simplify inputs; it can one of
|
||||||
|
'silent (change only if the resulting derivation is the same), 'safe (change
|
||||||
|
only if semantics are known to be unaffected), and 'always (fearlessly
|
||||||
|
simplify inputs!)."
|
||||||
|
(for-each (lambda (field-name field)
|
||||||
|
(match (field package)
|
||||||
|
(()
|
||||||
|
#f)
|
||||||
|
(inputs
|
||||||
|
(match (package-field-location package field-name)
|
||||||
|
(#f
|
||||||
|
;; If the location of FIELD-NAME is not found, it may be
|
||||||
|
;; that PACKAGE inherits from another package.
|
||||||
|
#f)
|
||||||
|
(location
|
||||||
|
(edit-expression
|
||||||
|
(location->source-properties location)
|
||||||
|
(lambda (str)
|
||||||
|
(define matches?
|
||||||
|
(match policy
|
||||||
|
('silent
|
||||||
|
;; Simplify inputs only when the label matches
|
||||||
|
;; perfectly, such that the resulting derivation
|
||||||
|
;; is unchanged.
|
||||||
|
label-matches?)
|
||||||
|
('safe
|
||||||
|
;; If PACKAGE has no arguments, labels are known
|
||||||
|
;; to have no effect: this is a "safe" change, but
|
||||||
|
;; it may change the derivation.
|
||||||
|
(if (null? (package-arguments package))
|
||||||
|
(const #t)
|
||||||
|
label-matches?))
|
||||||
|
('always
|
||||||
|
;; Assume it's gonna be alright.
|
||||||
|
(const #f))))
|
||||||
|
|
||||||
|
(simplify-inputs location
|
||||||
|
(package-name package)
|
||||||
|
str inputs
|
||||||
|
#:label-matches? matches?))))))))
|
||||||
|
'(inputs native-inputs propagated-inputs)
|
||||||
|
(list package-inputs package-native-inputs
|
||||||
|
package-propagated-inputs)))
|
||||||
|
|
||||||
|
(define (package-location<? p1 p2)
|
||||||
|
"Return true if P1's location is \"before\" P2's."
|
||||||
|
(let ((loc1 (package-location p1))
|
||||||
|
(loc2 (package-location p2)))
|
||||||
|
(and loc1 loc2
|
||||||
|
(if (string=? (location-file loc1) (location-file loc2))
|
||||||
|
(< (location-line loc1) (location-line loc2))
|
||||||
|
(string<? (location-file loc1) (location-file loc2))))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Options.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define %options
|
||||||
|
;; Specification of the command-line options.
|
||||||
|
(list (find (lambda (option)
|
||||||
|
(member "load-path" (option-names option)))
|
||||||
|
%standard-build-options)
|
||||||
|
|
||||||
|
(option '(#\e "expression") #t #f
|
||||||
|
(lambda (opt name arg result)
|
||||||
|
(alist-cons 'expression arg result)))
|
||||||
|
(option '("input-simplification") #t #f
|
||||||
|
(lambda (opt name arg result)
|
||||||
|
(let ((symbol (string->symbol arg)))
|
||||||
|
(unless (memq symbol '(silent safe always))
|
||||||
|
(leave (G_ "~a: invalid input simplification policy~%")
|
||||||
|
arg))
|
||||||
|
(alist-cons 'input-simplification-policy symbol
|
||||||
|
result))))
|
||||||
|
|
||||||
|
(option '(#\h "help") #f #f
|
||||||
|
(lambda args
|
||||||
|
(show-help)
|
||||||
|
(exit 0)))
|
||||||
|
(option '(#\V "version") #f #f
|
||||||
|
(lambda args
|
||||||
|
(show-version-and-exit "guix style")))))
|
||||||
|
|
||||||
|
(define (show-help)
|
||||||
|
(display (G_ "Usage: guix style [OPTION]... [PACKAGE]...
|
||||||
|
Update package definitions to the latest style.\n"))
|
||||||
|
(display (G_ "
|
||||||
|
-L, --load-path=DIR prepend DIR to the package module search path"))
|
||||||
|
(display (G_ "
|
||||||
|
-e, --expression=EXPR consider the package EXPR evaluates to"))
|
||||||
|
(display (G_ "
|
||||||
|
--input-simplification=POLICY
|
||||||
|
follow POLICY for package input simplification, one
|
||||||
|
of 'silent', 'safe', or 'always'"))
|
||||||
|
(newline)
|
||||||
|
(display (G_ "
|
||||||
|
-h, --help display this help and exit"))
|
||||||
|
(display (G_ "
|
||||||
|
-V, --version display version information and exit"))
|
||||||
|
(newline)
|
||||||
|
(show-bug-report-information))
|
||||||
|
|
||||||
|
(define %default-options
|
||||||
|
;; Alist of default option values.
|
||||||
|
'((input-simplification-policy . silent)))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Entry point.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define-command (guix-style . args)
|
||||||
|
(category packaging)
|
||||||
|
(synopsis "update the style of package definitions")
|
||||||
|
|
||||||
|
(define (parse-options)
|
||||||
|
;; Return the alist of option values.
|
||||||
|
(parse-command-line args %options (list %default-options)
|
||||||
|
#:build-options? #f))
|
||||||
|
|
||||||
|
(let* ((opts (parse-options))
|
||||||
|
(packages (filter-map (match-lambda
|
||||||
|
(('argument . spec)
|
||||||
|
(specification->package spec))
|
||||||
|
(('expression . str)
|
||||||
|
(read/eval str))
|
||||||
|
(_ #f))
|
||||||
|
opts))
|
||||||
|
(policy (assoc-ref opts 'input-simplification-policy)))
|
||||||
|
(for-each (lambda (package)
|
||||||
|
(simplify-package-inputs package #:policy policy))
|
||||||
|
;; 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<?)))))
|
|
@ -115,5 +115,6 @@ guix/scripts/offload.scm
|
||||||
guix/scripts/perform-download.scm
|
guix/scripts/perform-download.scm
|
||||||
guix/scripts/refresh.scm
|
guix/scripts/refresh.scm
|
||||||
guix/scripts/repl.scm
|
guix/scripts/repl.scm
|
||||||
|
guix/scripts/style.scm
|
||||||
guix/scripts/system/reconfigure.scm
|
guix/scripts/system/reconfigure.scm
|
||||||
nix/nix-daemon/guix-daemon.cc
|
nix/nix-daemon/guix-daemon.cc
|
||||||
|
|
|
@ -0,0 +1,366 @@
|
||||||
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
|
;;; Copyright © 2021 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/>.
|
||||||
|
|
||||||
|
(define-module (tests-style)
|
||||||
|
#:use-module (guix packages)
|
||||||
|
#:use-module (guix scripts style)
|
||||||
|
#:use-module ((guix utils) #:select (call-with-temporary-directory))
|
||||||
|
#:use-module ((guix build utils) #:select (substitute*))
|
||||||
|
#:use-module (guix diagnostics)
|
||||||
|
#:use-module (gnu packages acl)
|
||||||
|
#:use-module (gnu packages multiprecision)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (srfi srfi-64)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
|
#:use-module (ice-9 rdelim)
|
||||||
|
#:use-module (ice-9 pretty-print))
|
||||||
|
|
||||||
|
(define (call-with-test-package inputs proc)
|
||||||
|
(call-with-temporary-directory
|
||||||
|
(lambda (directory)
|
||||||
|
(call-with-output-file (string-append directory "/my-packages.scm")
|
||||||
|
(lambda (port)
|
||||||
|
(pretty-print
|
||||||
|
`(begin
|
||||||
|
(define-module (my-packages)
|
||||||
|
#:use-module (guix)
|
||||||
|
#:use-module (guix licenses)
|
||||||
|
#:use-module (gnu packages acl)
|
||||||
|
#:use-module (gnu packages base)
|
||||||
|
#:use-module (gnu packages multiprecision)
|
||||||
|
#:use-module (srfi srfi-1))
|
||||||
|
|
||||||
|
(define base
|
||||||
|
(package
|
||||||
|
(inherit coreutils)
|
||||||
|
(inputs '())
|
||||||
|
(native-inputs '())
|
||||||
|
(propagated-inputs '())))
|
||||||
|
|
||||||
|
(define (sdl-union . lst)
|
||||||
|
(package
|
||||||
|
(inherit base)
|
||||||
|
(name "sdl-union")))
|
||||||
|
|
||||||
|
(define-public my-coreutils
|
||||||
|
(package
|
||||||
|
(inherit base)
|
||||||
|
,@inputs
|
||||||
|
(name "my-coreutils"))))
|
||||||
|
port)))
|
||||||
|
|
||||||
|
(proc directory))))
|
||||||
|
|
||||||
|
(define test-directory
|
||||||
|
;; Directory where the package definition lives.
|
||||||
|
(make-parameter #f))
|
||||||
|
|
||||||
|
(define-syntax-rule (with-test-package fields exp ...)
|
||||||
|
(call-with-test-package fields
|
||||||
|
(lambda (directory)
|
||||||
|
(define file
|
||||||
|
(string-append directory "/my-packages.scm"))
|
||||||
|
|
||||||
|
;; Run as a separate process to make sure FILE is reloaded.
|
||||||
|
(system* "guix" "style" "-L" directory "my-coreutils")
|
||||||
|
(system* "cat" file)
|
||||||
|
|
||||||
|
(load file)
|
||||||
|
(parameterize ((test-directory directory))
|
||||||
|
exp ...))))
|
||||||
|
|
||||||
|
(define* (read-lines port line #:optional (count 1))
|
||||||
|
"Read COUNT lines from PORT, starting from LINE."
|
||||||
|
(let loop ((lines '())
|
||||||
|
(count count))
|
||||||
|
(cond ((< (port-line port) (- line 1))
|
||||||
|
(read-char port)
|
||||||
|
(loop lines count))
|
||||||
|
((zero? count)
|
||||||
|
(string-concatenate-reverse lines))
|
||||||
|
(else
|
||||||
|
(match (read-line port 'concat)
|
||||||
|
((? eof-object?)
|
||||||
|
(loop lines 0))
|
||||||
|
(line
|
||||||
|
(loop (cons line lines) (- count 1))))))))
|
||||||
|
|
||||||
|
(define* (read-package-field package field #:optional (count 1))
|
||||||
|
(let* ((location (package-field-location package field))
|
||||||
|
(file (location-file location))
|
||||||
|
(line (location-line location)))
|
||||||
|
(call-with-input-file (if (string-prefix? "/" file)
|
||||||
|
file
|
||||||
|
(string-append (test-directory) "/"
|
||||||
|
file))
|
||||||
|
(lambda (port)
|
||||||
|
(read-lines port line count)))))
|
||||||
|
|
||||||
|
|
||||||
|
(test-begin "style")
|
||||||
|
|
||||||
|
(test-equal "nothing to rewrite"
|
||||||
|
'()
|
||||||
|
(with-test-package '()
|
||||||
|
(package-direct-inputs (@ (my-packages) my-coreutils))))
|
||||||
|
|
||||||
|
(test-equal "input labels, mismatch"
|
||||||
|
(list `(("foo" ,gmp) ("bar" ,acl))
|
||||||
|
" (inputs `((\"foo\" ,gmp) (\"bar\" ,acl)))\n")
|
||||||
|
(with-test-package '((inputs `(("foo" ,gmp) ("bar" ,acl))))
|
||||||
|
(list (package-direct-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs))))
|
||||||
|
|
||||||
|
(test-equal "input labels, simple"
|
||||||
|
(list `(("gmp" ,gmp) ("acl" ,acl))
|
||||||
|
" (inputs (list gmp acl))\n")
|
||||||
|
(with-test-package '((inputs `(("gmp" ,gmp) ("acl" ,acl))))
|
||||||
|
(list (package-direct-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs))))
|
||||||
|
|
||||||
|
(test-equal "input labels, long list with one item per line"
|
||||||
|
(list (concatenate (make-list 4 `(("gmp" ,gmp) ("acl" ,acl))))
|
||||||
|
"\
|
||||||
|
(list gmp
|
||||||
|
acl
|
||||||
|
gmp
|
||||||
|
acl
|
||||||
|
gmp
|
||||||
|
acl
|
||||||
|
gmp
|
||||||
|
acl))\n")
|
||||||
|
(with-test-package '((inputs `(("gmp" ,gmp) ("acl" ,acl)
|
||||||
|
("gmp" ,gmp) ("acl" ,acl)
|
||||||
|
("gmp" ,gmp) ("acl" ,acl)
|
||||||
|
("gmp" ,gmp) ("acl" ,acl))))
|
||||||
|
(list (package-direct-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs 8))))
|
||||||
|
|
||||||
|
(test-equal "input labels, sdl-union"
|
||||||
|
"\
|
||||||
|
(list gmp acl
|
||||||
|
(sdl-union 1 2 3 4)))\n"
|
||||||
|
(with-test-package '((inputs `(("gmp" ,gmp) ("acl" ,acl)
|
||||||
|
("sdl-union" ,(sdl-union 1 2 3 4)))))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs 2)))
|
||||||
|
|
||||||
|
(test-equal "input labels, output"
|
||||||
|
(list `(("gmp" ,gmp "debug") ("acl" ,acl))
|
||||||
|
" (inputs (list `(,gmp \"debug\") acl))\n")
|
||||||
|
(with-test-package '((inputs `(("gmp" ,gmp "debug") ("acl" ,acl))))
|
||||||
|
(list (package-direct-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs))))
|
||||||
|
|
||||||
|
(test-equal "input labels, prepend"
|
||||||
|
(list `(("gmp" ,gmp) ("acl" ,acl))
|
||||||
|
"\
|
||||||
|
(modify-inputs (package-propagated-inputs coreutils)
|
||||||
|
(prepend gmp acl)))\n")
|
||||||
|
(with-test-package '((inputs `(("gmp" ,gmp) ("acl" ,acl)
|
||||||
|
,@(package-propagated-inputs coreutils))))
|
||||||
|
(list (package-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs 2))))
|
||||||
|
|
||||||
|
(test-equal "input labels, prepend + delete"
|
||||||
|
(list `(("gmp" ,gmp) ("acl" ,acl))
|
||||||
|
"\
|
||||||
|
(modify-inputs (package-propagated-inputs coreutils)
|
||||||
|
(delete \"gmp\")
|
||||||
|
(prepend gmp acl)))\n")
|
||||||
|
(with-test-package '((inputs `(("gmp" ,gmp)
|
||||||
|
("acl" ,acl)
|
||||||
|
,@(alist-delete "gmp"
|
||||||
|
(package-propagated-inputs coreutils)))))
|
||||||
|
(list (package-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs 3))))
|
||||||
|
|
||||||
|
(test-equal "input labels, prepend + delete multiple"
|
||||||
|
(list `(("gmp" ,gmp) ("acl" ,acl))
|
||||||
|
"\
|
||||||
|
(modify-inputs (package-propagated-inputs coreutils)
|
||||||
|
(delete \"foo\" \"bar\" \"baz\")
|
||||||
|
(prepend gmp acl)))\n")
|
||||||
|
(with-test-package '((inputs `(("gmp" ,gmp)
|
||||||
|
("acl" ,acl)
|
||||||
|
,@(fold alist-delete
|
||||||
|
(package-propagated-inputs coreutils)
|
||||||
|
'("foo" "bar" "baz")))))
|
||||||
|
(list (package-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs 3))))
|
||||||
|
|
||||||
|
(test-equal "input labels, replace"
|
||||||
|
(list '() ;there's no "gmp" input to replace
|
||||||
|
"\
|
||||||
|
(modify-inputs (package-propagated-inputs coreutils)
|
||||||
|
(replace \"gmp\" gmp)))\n")
|
||||||
|
(with-test-package '((inputs `(("gmp" ,gmp)
|
||||||
|
,@(alist-delete "gmp"
|
||||||
|
(package-propagated-inputs coreutils)))))
|
||||||
|
(list (package-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs 2))))
|
||||||
|
|
||||||
|
(test-equal "input labels, 'safe' policy"
|
||||||
|
(list `(("gmp" ,gmp) ("acl" ,acl))
|
||||||
|
"\
|
||||||
|
(inputs (list gmp acl))\n")
|
||||||
|
(call-with-test-package '((inputs `(("GMP" ,gmp) ("ACL" ,acl)))
|
||||||
|
(arguments '())) ;no build system arguments
|
||||||
|
(lambda (directory)
|
||||||
|
(define file
|
||||||
|
(string-append directory "/my-packages.scm"))
|
||||||
|
|
||||||
|
(system* "guix" "style" "-L" directory "my-coreutils"
|
||||||
|
"--input-simplification=safe")
|
||||||
|
|
||||||
|
(load file)
|
||||||
|
(list (package-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs)))))
|
||||||
|
|
||||||
|
(test-equal "input labels, 'safe' policy, nothing changed"
|
||||||
|
(list `(("GMP" ,gmp) ("ACL" ,acl))
|
||||||
|
"\
|
||||||
|
(inputs `((\"GMP\" ,gmp) (\"ACL\" ,acl)))\n")
|
||||||
|
(call-with-test-package '((inputs `(("GMP" ,gmp) ("ACL" ,acl)))
|
||||||
|
;; Non-empty argument list, so potentially unsafe
|
||||||
|
;; input simplification.
|
||||||
|
(arguments
|
||||||
|
'(#:configure-flags
|
||||||
|
(assoc-ref %build-inputs "GMP"))))
|
||||||
|
(lambda (directory)
|
||||||
|
(define file
|
||||||
|
(string-append directory "/my-packages.scm"))
|
||||||
|
|
||||||
|
(system* "guix" "style" "-L" directory "my-coreutils"
|
||||||
|
"--input-simplification=safe")
|
||||||
|
|
||||||
|
(load file)
|
||||||
|
(list (package-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs)))))
|
||||||
|
|
||||||
|
(test-equal "input labels, margin comment"
|
||||||
|
(list `(("gmp" ,gmp))
|
||||||
|
`(("acl" ,acl))
|
||||||
|
" (inputs (list gmp)) ;margin comment\n"
|
||||||
|
" (native-inputs (list acl)) ;another one\n")
|
||||||
|
(call-with-test-package '((inputs `(("gmp" ,gmp)))
|
||||||
|
(native-inputs `(("acl" ,acl))))
|
||||||
|
(lambda (directory)
|
||||||
|
(define file
|
||||||
|
(string-append directory "/my-packages.scm"))
|
||||||
|
|
||||||
|
(substitute* file
|
||||||
|
(("\"gmp\"(.*)$" _ rest)
|
||||||
|
(string-append "\"gmp\"" (string-trim-right rest)
|
||||||
|
" ;margin comment\n"))
|
||||||
|
(("\"acl\"(.*)$" _ rest)
|
||||||
|
(string-append "\"acl\"" (string-trim-right rest)
|
||||||
|
" ;another one\n")))
|
||||||
|
(system* "cat" file)
|
||||||
|
|
||||||
|
(system* "guix" "style" "-L" directory "my-coreutils")
|
||||||
|
|
||||||
|
(load file)
|
||||||
|
(list (package-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(package-native-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs)
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'native-inputs)))))
|
||||||
|
|
||||||
|
(test-equal "input labels, margin comment on long list"
|
||||||
|
(list (concatenate (make-list 4 `(("gmp" ,gmp) ("acl" ,acl))))
|
||||||
|
"\
|
||||||
|
(list gmp ;margin comment
|
||||||
|
acl
|
||||||
|
gmp ;margin comment
|
||||||
|
acl
|
||||||
|
gmp ;margin comment
|
||||||
|
acl
|
||||||
|
gmp ;margin comment
|
||||||
|
acl))\n")
|
||||||
|
(call-with-test-package '((inputs `(("gmp" ,gmp) ("acl" ,acl)
|
||||||
|
("gmp" ,gmp) ("acl" ,acl)
|
||||||
|
("gmp" ,gmp) ("acl" ,acl)
|
||||||
|
("gmp" ,gmp) ("acl" ,acl))))
|
||||||
|
(lambda (directory)
|
||||||
|
(define file
|
||||||
|
(string-append directory "/my-packages.scm"))
|
||||||
|
|
||||||
|
(substitute* file
|
||||||
|
(("\"gmp\"(.*)$" _ rest)
|
||||||
|
(string-append "\"gmp\"" (string-trim-right rest)
|
||||||
|
" ;margin comment\n")))
|
||||||
|
(system* "cat" file)
|
||||||
|
|
||||||
|
(system* "guix" "style" "-L" directory "my-coreutils")
|
||||||
|
|
||||||
|
(load file)
|
||||||
|
(list (package-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs 8)))))
|
||||||
|
|
||||||
|
(test-equal "input labels, line comment"
|
||||||
|
(list `(("gmp" ,gmp) ("acl" ,acl))
|
||||||
|
"\
|
||||||
|
(inputs (list gmp
|
||||||
|
;; line comment!
|
||||||
|
acl))\n")
|
||||||
|
(call-with-test-package '((inputs `(("gmp" ,gmp) ("acl" ,acl))))
|
||||||
|
(lambda (directory)
|
||||||
|
(define file
|
||||||
|
(string-append directory "/my-packages.scm"))
|
||||||
|
|
||||||
|
(substitute* file
|
||||||
|
((",gmp\\)(.*)$" _ rest)
|
||||||
|
(string-append ",gmp)\n ;; line comment!\n" rest)))
|
||||||
|
|
||||||
|
(system* "guix" "style" "-L" directory "my-coreutils")
|
||||||
|
|
||||||
|
(load file)
|
||||||
|
(list (package-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs 3)))))
|
||||||
|
|
||||||
|
(test-equal "input labels, modify-inputs and margin comment"
|
||||||
|
(list `(("gmp" ,gmp) ("acl" ,acl) ("mpfr" ,mpfr))
|
||||||
|
"\
|
||||||
|
(modify-inputs (package-propagated-inputs coreutils)
|
||||||
|
(prepend gmp ;margin comment
|
||||||
|
acl ;another one
|
||||||
|
mpfr)))\n")
|
||||||
|
(call-with-test-package '((inputs
|
||||||
|
`(("gmp" ,gmp) ("acl" ,acl) ("mpfr" ,mpfr)
|
||||||
|
,@(package-propagated-inputs coreutils))))
|
||||||
|
(lambda (directory)
|
||||||
|
(define file
|
||||||
|
(string-append directory "/my-packages.scm"))
|
||||||
|
|
||||||
|
(substitute* file
|
||||||
|
((",gmp\\)(.*)$" _ rest)
|
||||||
|
(string-append ",gmp) ;margin comment\n" rest))
|
||||||
|
((",acl\\)(.*)$" _ rest)
|
||||||
|
(string-append ",acl) ;another one\n" rest)))
|
||||||
|
|
||||||
|
(system* "guix" "style" "-L" directory "my-coreutils")
|
||||||
|
|
||||||
|
(load file)
|
||||||
|
(list (package-inputs (@ (my-packages) my-coreutils))
|
||||||
|
(read-package-field (@ (my-packages) my-coreutils) 'inputs 4)))))
|
||||||
|
|
||||||
|
(test-end)
|
||||||
|
|
||||||
|
;; Local Variables:
|
||||||
|
;; eval: (put 'with-test-package 'scheme-indent-function 1)
|
||||||
|
;; eval: (put 'call-with-test-package 'scheme-indent-function 1)
|
||||||
|
;; End:
|
Reference in New Issue