Subject: [bug#77093] [PATCH rust-team 17/18] import: crate: Add ‘--lockfile’ option.

From: Efraim Flashner <[email-masked]>
Date: Tue, 18 Mar 2025 13:49:46 +0200

On Tue, Mar 18, 2025 at 03:24:30PM +0800, Hilton Chain wrote:
> * guix/scripts/import/crate.scm (%options): Add ‘--lockfile’ option.
> * guix/scripts/import/crate.scm (show-help): Add it.
> (guix-import-crate): Use it.
> * doc/guix.texi (Invoking guix import): Document it.
> * tests/crate.scm (temp-file): New variable.
> ("crate-lockfile-import"): New test.
> 
> Change-Id: I291478e04adf9f2df0bf216425a5e8aeba0bedd9
> ---
>  doc/guix.texi                 | 15 ++++++
>  guix/scripts/import/crate.scm | 58 +++++++++++++++++++----
>  tests/crate.scm               | 88 +++++++++++++++++++++++++++++++++++
>  3 files changed, 151 insertions(+), 10 deletions(-)
> 
> diff --git a/doc/guix.texi b/doc/guix.texi
> index c20e1d7f9c..029c8cf59c 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -14703,6 +14703,21 @@ Invoking guix import
>  If a crate dependency is not (yet) packaged, make the corresponding
>  input in @code{#:cargo-inputs} or @code{#:cargo-development-inputs} into
>  a comment.
> +@item --lockfile=@var{file}
> +@itemx -f @var{file}
> +When @option{--lockfile} is specified, importer will ignore other
> +options and won't output package definitions, instead generating source
> +definition for all dependencies in @var{file}, a @file{Cargo.lock} file.

When @option{--lockfile} is specified, the importer will ignore other
options and won't output package definitions, instead generating source
definitions for all dependencies in @var{file}, a @file{Cargo.lock} file.

> +For example:
> +
> +@example
> +guix import crate --lockfile=/path/to/Cargo.lock my-package
> +@end example
> +
> +generates sources from @file{/path/to/Cargo.lock}, and a list
> +@code{my-package-cargo-inputs} referencing these sources.  The generated
> +list is intended for package's base @code{inputs}, replacing
> +@code{#:cargo-inputs} and @code{#:cargo-development-inputs}.

generates sources from @file{/path/to/Cargo.lock} and a list
@code{my-package-cargo-inputs} referencing these sources.  The generated
list is intended for the package's @code{inputs}, replacing
@code{#:cargo-inputs} and @code{#:cargo-development-inputs}.

>  @end table
>  
>  @item elm
> diff --git a/guix/scripts/import/crate.scm b/guix/scripts/import/crate.scm
> index 723cbb3665..3b536e135a 100644
> --- a/guix/scripts/import/crate.scm
> +++ b/guix/scripts/import/crate.scm
> @@ -25,11 +25,13 @@
>  (define-module (guix scripts import crate)
>    #:use-module (guix ui)
>    #:use-module (guix utils)
> +  #:use-module (guix read-print)
>    #:use-module (guix scripts)
>    #:use-module (guix import crate)
>    #:use-module (guix scripts import)
>    #:use-module (srfi srfi-1)
>    #:use-module (srfi srfi-11)
> +  #:use-module (srfi srfi-26)
>    #:use-module (srfi srfi-37)
>    #:use-module (ice-9 match)
>    #:use-module (ice-9 format)
> @@ -60,6 +62,9 @@ (define (show-help)
>                           sufficient package exists for it"))
>    (newline)
>    (display (G_ "
> +  -f, --lockfile=FILE    import dependencies from FILE, a 'Cargo.lock' file"))
> +  (newline)
> +  (display (G_ "
>    -h, --help             display this help and exit"))
>    (display (G_ "
>    -V, --version          display version information and exit"))
> @@ -87,6 +92,9 @@ (define %options
>           (option '("mark-missing") #f #f
>                   (lambda (opt name arg result)
>                     (alist-cons 'mark-missing #t result)))
> +         (option '(#\f "lockfile") #f #t
> +                 (lambda (opt name arg result)
> +                   (alist-cons 'lockfile arg result)))
>           %standard-import-options))
>  
>  
> @@ -101,6 +109,8 @@ (define (guix-import-crate . args)
>                          #:build-options? #f))
>  
>    (let* ((opts (parse-options))
> +         (lockfile (assoc-ref opts 'lockfile))
> +         (file-to-insert (assoc-ref opts 'file-to-insert))
>           (args (filter-map (match-lambda
>                               (('argument . value)
>                                value)
> @@ -111,16 +121,44 @@ (define (guix-import-crate . args)
>         (define-values (name version)
>           (package-name->name+version spec))
>  
> -       (match (if (assoc-ref opts 'recursive)
> -                  (crate-recursive-import
> -                   name #:version version
> -                   #:recursive-dev-dependencies?
> -                   (assoc-ref opts 'recursive-dev-dependencies)
> -                   #:allow-yanked? (assoc-ref opts 'allow-yanked))
> -                  (crate->guix-package
> -                   name #:version version #:include-dev-deps? #t
> -                   #:allow-yanked? (assoc-ref opts 'allow-yanked)
> -                   #:mark-missing? (assoc-ref opts 'mark-missing)))
> +       (match (cond
> +               ((and=> lockfile
> +                       (lambda (file)
> +                         (or (file-exists? file)
> +                             (leave (G_ "file '~a' does not exist~%") file))))
> +                (let-values (((crate-definitions input-list)
> +                              (cargo-lock->definitions lockfile name)))
> +                  (if file-to-insert
> +                      ;; Adjusted from ‘--insert’ option of guix-import.
> +                      (let ((term (second input-list)))
> +                        (begin
> +                          ;; Remove existing input list definition.
> +                          (and=> (find-definition-location file-to-insert term)
> +                                 delete-expression)
> +                          ;; Insert input list alphabetically.
> +                          (or (and=> (find-definition-insertion-location
> +                                      file-to-insert term)
> +                                     (cut insert-expression <> input-list))
> +                              (let ((port (open-file file-to-insert "a")))
> +                                (newline port)
> +                                (pretty-print-with-comments port input-list)
> +                                (newline port)
> +                                (newline port)
> +                                (close-port port))))
> +                        crate-definitions)
> +                      `(,@crate-definitions
> +                        ,input-list))))
> +               ((assoc-ref opts 'recursive)
> +                (crate-recursive-import
> +                 name #:version version
> +                 #:recursive-dev-dependencies?
> +                 (assoc-ref opts 'recursive-dev-dependencies)
> +                 #:allow-yanked? (assoc-ref opts 'allow-yanked)))
> +               (else
> +                (crate->guix-package
> +                 name #:version version #:include-dev-deps? #t
> +                 #:allow-yanked? (assoc-ref opts 'allow-yanked)
> +                 #:mark-missing? (assoc-ref opts 'mark-missing))))
>           ((or #f '())
>            (leave (G_ "failed to download meta-data for package '~a'~%")
>                   (if version
> diff --git a/tests/crate.scm b/tests/crate.scm
> index d0dc779cd2..d46f753f9c 100644
> --- a/tests/crate.scm
> +++ b/tests/crate.scm
> @@ -34,6 +34,7 @@ (define-module (test-crate)
>    #:use-module (gnu packages)
>    #:use-module (ice-9 iconv)
>    #:use-module (ice-9 match)
> +  #:use-module (srfi srfi-11)
>    #:use-module (srfi srfi-64))
>  
>  
> @@ -476,6 +477,9 @@ (define rust-leaf-bob-3.0.2-yanked
>      (description #f)
>      (license #f)))
>  
> +(define temp-file
> +  (string-append "t-utils-" (number->string (getpid))))
> +
>  
>  (test-begin "crate")
>  
> @@ -1178,4 +1182,88 @@ (define rust-leaf-bob-3.0.2-yanked
>            (x
>             (pk 'fail (pretty-print-with-comments (current-output-port) x) #f)))))
>  
> +
> +(test-assert "crate-lockfile-import"
> +  (begin
> +    (call-with-output-file temp-file
> +      (lambda (port)
> +        (display "\
> +# This file is automatically @generated by Cargo.
> +# It is not intended for manual editing.
> +version = 3
> +
> +[[package]]
> +name = \"adler2\"
> +version = \"2.0.0\"
> +source = \"registry+https://github.com/rust-lang/crates.io-index\"
> +checksum = \"512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627\"
> +
> +[[package]]
> +name = \"aho-corasick\"
> +version = \"1.1.3\"
> +source = \"registry+https://github.com/rust-lang/crates.io-index\"
> +checksum = \"8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916\"
> +dependencies = [
> + \"memchr\",
> +]
> +
> +[[package]]
> +name = \"smithay\"
> +version = \"0.4.0\"
> +source = \"git+https://github.com/Smithay/smithay.git?rev=\
> +0cd3345c59f7cb139521f267956a1a4e33248393#\
> +0cd3345c59f7cb139521f267956a1a4e33248393\"
> +dependencies = [
> + \"appendlist\",
> +]
> +
> +[[package]]
> +name = \"test\"
> +version = \"25.2.0\"\n" port)))
> +    (mock
> +     ((guix scripts download) guix-download
> +      (lambda _
> +        (format #t "~a~%~a~%"
> +                "/gnu/store/in056fyrz6nvy3jpxrxglgj30g0lwniv-smithay-0cd3345"
> +                "191h87bpzg0l1ihfb4hmx00b86pfb5mwwc6s8i49al0vigc14l37")))
> +     (let-values
> +         (((crates-definitions input-list)
> +           (cargo-lock->definitions temp-file "test")))
> +       (and
> +        (match crates-definitions
> +          (((define 'rust-adler2-2.0.0
> +              (crate-source
> +               "adler2" "2.0.0"
> +               "09r6drylvgy8vv8k20lnbvwq8gp09h7smfn6h1rxsy15pgh629si"))
> +            (define 'rust-aho-corasick-1.1.3
> +              (crate-source
> +               "aho-corasick" "1.1.3"
> +               "05mrpkvdgp5d20y2p989f187ry9diliijgwrs254fs9s1m1x6q4f"))
> +            (define 'rust-smithay-0.4.0.0cd3345
> +              ($ <comment>
> +                 ";; TODO: Define standalone package if this is a workspace.\n"
> +                 #f)
> +              (origin
> +                (method git-fetch)
> +                (uri (git-reference
> +                      (url "https://github.com/Smithay/smithay.git")
> +                      (commit "0cd3345c59f7cb139521f267956a1a4e33248393")))
> +                (file-name (git-file-name "rust-smithay" "0.4.0.0cd3345"))
> +                (sha256
> +                 (base32
> +                  "191h87bpzg0l1ihfb4hmx00b86pfb5mwwc6s8i49al0vigc14l37")))))
> +           #t)
> +          (x
> +           (pk 'fail (pretty-print-with-comments (current-output-port) x) #f)))
> +        (match input-list
> +          ((define-public 'test-cargo-inputs
> +             (list rust-adler2-2.0.0
> +                   rust-aho-corasick-1.1.3
> +                   rust-smithay-0.4.0.0cd3345))
> +           #t)
> +          (x
> +           (pk 'fail x #f))))))))
> +
>  (test-end "crate")
> +
> +(false-if-exception (delete-file temp-file))
> -- 
> 2.48.1
> 
> 
> 

-- 
Efraim Flashner   <[email-masked]>   אפרים פלשנר
GPG key = A28B F40C 3E55 1372 662D  14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted