~ruther/guix-local

635af8628c096526e3a79348f484e641aa05f04a — Herman Rimm 2 years ago 50e514c
import: Insert packages into modules alphabetically.

* guix/scripts/import.scm (guix-import): Add 'insert' option.
(import-as-definitions): Add procedure.
* doc/guix.texi (Invoking guix import): Describe 'insert' option.

Change-Id: Id87ea707123630e12bcb6788599acac6895b26c4
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2 files changed, 65 insertions(+), 31 deletions(-)

M doc/guix.texi
M guix/scripts/import.scm
M doc/guix.texi => doc/guix.texi +12 -2
@@ 124,6 124,7 @@ Copyright @copyright{} 2023 Thomas Ieong@*
Copyright @copyright{} 2023 Saku Laesvuori@*
Copyright @copyright{} 2023 Graham James Addis@*
Copyright @copyright{} 2023 Tomas Volf@*
Copyright @copyright{} 2024 Herman Rimm@*

Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or


@@ 14186,12 14187,21 @@ is a package definition, or a template thereof, in the format we know
The general syntax is:

@example
guix import @var{importer} @var{options}@dots{}
guix import [@var{global-options}@dots{}] @var{importer} @var{package} [@var{options}@dots{}]
@end example

@var{importer} specifies the source from which to import package
metadata, and @var{options} specifies a package identifier and other
options specific to @var{importer}.
options specific to @var{importer}. @command{guix import} itself has the
following @var{global-options}:

@table @code
@item --insert=@var{file}
@itemx -i @var{file}
Insert the package definition(s) that the @var{importer} generated into the
specified @var{file}, either in alphabetical order among existing package
definitions, or at the end of the file otherwise.
@end table

Some of the importers rely on the ability to run the @command{gpgv} command.
For these, GnuPG must be installed and in @code{$PATH}; run @code{guix install

M guix/scripts/import.scm => guix/scripts/import.scm +53 -29
@@ 67,10 67,39 @@ Run IMPORTER with ARGS.\n"))
  (display (G_ "
  -h, --help             display this help and exit"))
  (display (G_ "
  -i, --insert           insert packages into file alphabetically"))
  (display (G_ "
  -V, --version          display version information and exit"))
  (newline)
  (show-bug-report-information))

(define (import-as-definitions importer args proc)
  "Wrap package expressions from IMPORTER with 'define-public and invoke
PROC callback."
  (if (member importer importers)
      (match (apply (resolve-importer importer) args)
        ((and expr (or ('package _ ...)
                       ('let _ ...)))
         (proc (package->definition expr)))
        ((and expr ('define-public _ ...))
         (proc expr))
        ((expressions ...)
         (for-each (lambda (expr)
                     (match expr
                       ((and expr (or ('package _ ...)
                                      ('let _ ...)))
                        (proc (package->definition expr)))
                       ((and expr ('define-public _ ...))
                        (proc expr))))
                   expressions))
        (x
         (leave (G_ "'~a' import failed~%") importer)))
      (let ((hint (string-closest importer importers #:threshold 3)))
        (report-error (G_ "~a: invalid importer~%") importer)
        (when hint
          (display-hint (G_ "Did you mean @code{~a}?~%") hint))
        (exit 1))))

(define-command (guix-import . args)
  (category packaging)
  (synopsis "import a package definition from an external repository")


@@ 84,33 113,28 @@ Run IMPORTER with ARGS.\n"))
     (exit 0))
    ((or ("-V") ("--version"))
     (show-version-and-exit "guix import"))
    ((or ("-i" file importer args ...)
         ("--insert" file importer args ...))
     (let ((find-and-insert
             (lambda (expr)
               (match expr
                 (('define-public term _ ...)
                  (let ((source-properties
                          (find-definition-insertion-location
                            file term)))
                    (if source-properties
                      (insert-expression source-properties expr)
                      (let ((port (open-file file "a")))
                        (pretty-print-with-comments port expr)
                        (newline port)
                        (close-port port)))))))))
       (import-as-definitions importer args find-and-insert)))
    ((importer args ...)
     (if (member importer importers)
         (let ((print (lambda (expr)
                        (leave-on-EPIPE
                         (pretty-print-with-comments (current-output-port) expr)))))
           (match (apply (resolve-importer importer) args)
             ((and expr (or ('package _ ...)
                            ('let _ ...)))
              (print (package->definition expr)))
             ((and expr ('define-public _ ...))
              (print expr))
             ((? list? expressions)
              (for-each (lambda (expr)
                          (match expr
                            ((and expr (or ('package _ ...)
                                           ('let _ ...)))
                             (print (package->definition expr)))
                            ((and expr ('define-public _ ...))
                             (print expr)))
                          ;; Two newlines: one after the closing paren, and
                          ;; one to leave a blank line.
                          (newline) (newline))
                        expressions))
             (x
              (leave (G_ "'~a' import failed~%") importer))))
         (let ((hint (string-closest importer importers #:threshold 3)))
           (report-error (G_ "~a: invalid importer~%") importer)
           (when hint
             (display-hint (G_ "Did you mean @code{~a}?~%") hint))
           (exit 1))))))
     (let ((print (lambda (expr)
                    (leave-on-EPIPE
                      (pretty-print-with-comments
                        (current-output-port) expr)
                      ;; Two newlines: one after the closing paren, and
                      ;; one to leave a blank line.
                      (newline) (newline)))))
       (import-as-definitions importer args print)))))