On Wed, Dec 13, 2023 at 10:34:11AM +0200, Efraim Flashner wrote:
> * Compiled rust packages currently have a 'package' phase, which runs
> the command used to crate a 'crate tarball', and is installed in
> %output/share/cargo/registry, with unpacked sources in
> %output/share/cargo/src.  In theory it should be possible to use these
> for local rust development.  The benefits include everything that comes
> with being a guix package, including pre-patched shebangs.  Currently no
> index file is created in $GUIX_ENVIRONMENT/share/cargo/registry/index,
> which is likely necessary to actually make use of this.  Additionally, I
> am unsure how to use '$GUIX_ENVIRONMENT' in ~/.cargo/config so that it
> is expanded and not taken as a literal string.

In the Guix London meetup someone mentioned that they were interested in
playing around with using Guix for rust development.  I've adjusted the
cargo-build-system to produce the registry index files and I added a
profile hook to generate the config.json to locate the packaged crates.

toml files can't process environment variables (which is probably a good
thing ...) but that means its a little harder to test out.

with the two patches applied create an environment with the crates you
want and get the location of GUIX_ENVIRONMENT:
`env | grep GUIX_ENVIRONMENT | cut -f2 -d=`

in ~/.cargo/config:
[source.crates-io]
local-registry = '<location of GUIX_ENVIRONMENT>/share/cargo/registry'

'cargo build' should pull from the local crates in the GUIX_ENVIRONMENT.
I'm not sure what happens if it doesn't have those crates available and
would need to get them from crates.io.


-- 
Efraim Flashner   <efr...@flashner.co.il>   רנשלפ םירפא
GPG key = A28B F40C 3E55 1372 662D  14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted
From 84d2f06e9facec9a1646afd53adcbf2b95da4da0 Mon Sep 17 00:00:00 2001
Message-ID: 
<84d2f06e9facec9a1646afd53adcbf2b95da4da0.1702565894.git.efr...@flashner.co.il>
In-Reply-To: <cover.1702565894.git.efr...@flashner.co.il>
References: <cover.1702565894.git.efr...@flashner.co.il>
From: Efraim Flashner <efr...@flashner.co.il>
Date: Thu, 14 Dec 2023 16:49:58 +0200
Subject: [PATCH 1/2] build: cargo-build-system: Produce registry index files.

* guix/build/cargo-build-system.scm (rewrite-deps): New procedure.
(package): Obtain output from 'cargo manifest' of the current package
when the package will be installed.
(install): Don't install cargo crates and source.
(install-source): New phase.  Install cargo crates.  Generate cargo
registry index files and install them in a known location.
(%standard-phases): Add 'install-source phase after 'install.

Change-Id: I6ce6c5b33fe3eb7667f86964daef798320724a25
---
 guix/build/cargo-build-system.scm | 102 +++++++++++++++++++++++++-----
 1 file changed, 87 insertions(+), 15 deletions(-)

diff --git a/guix/build/cargo-build-system.scm 
b/guix/build/cargo-build-system.scm
index ffb2ec898e..f1e35a5c65 100644
--- a/guix/build/cargo-build-system.scm
+++ b/guix/build/cargo-build-system.scm
@@ -73,6 +73,21 @@ (define (crate-src? path)
                                             " | cut -d/ -f2"
                                             " | grep -q '^Cargo.toml$'")))))
 
+(define (rewrite-deps cargo-deps)
+  (map (lambda (dependency)
+         `(@ ("name" . ,(assoc-ref dependency "name"))
+             ("req" . ,(assoc-ref dependency "req"))
+             ("features" . ,(assoc-ref dependency "features"))
+             ("optional" . ,(assoc-ref dependency "optional"))
+             ("default_features" . ,(assoc-ref dependency
+                                               "uses_default_features"))
+             ("target" . ,(assoc-ref dependency "target"))
+             ("kind" . ,(match (assoc-ref dependency "kind")
+                               (null? "normal")
+                               (kind kind)))
+             ("registry" . ,(assoc-ref dependency "registry"))))
+       cargo-deps))
+
 (define* (unpack-rust-crates #:key inputs vendor-dir #:allow-other-keys)
   (define (inputs->rust-inputs inputs)
     "Filter using the label part from INPUTS."
@@ -271,7 +286,8 @@ (define* (package #:key
                   install-source?
                   (cargo-package-flags '("--no-metadata" "--no-verify"))
                   #:allow-other-keys)
-  "Run 'cargo-package' for a given Cargo package."
+  "Run 'cargo-package' for a given Cargo package.  Also generate metadata so 
we can
+create a package index for the crates."
   (if install-source?
     (if skip-build?
       (begin
@@ -322,19 +338,24 @@ (define* (package #:key
                 (delete-file-recursively dir)))
             (find-files "." "\\.crate$")))))
     (format #t "Not installing cargo sources, skipping `cargo package`.~%"))
-  #t)
+
+  (when install-source?
+    ;; First generate the metadata so we can create the index file.
+    ;; https://doc.rust-lang.org/cargo/commands/cargo-metadata.html#json-format
+    (with-output-to-file "cargo-metadata.json"
+      (lambda _
+        (invoke "cargo" "metadata"
+                "--manifest-path" "Cargo.toml"
+                "--format-version" "1"
+                "--no-deps")))))
 
 (define* (install #:key
-                  inputs
                   outputs
                   skip-build?
-                  install-source?
                   features
                   #:allow-other-keys)
   "Install a given Cargo package."
-  (let* ((out      (assoc-ref outputs "out"))
-         (registry (string-append out "/share/cargo/registry"))
-         (sources  (string-append out "/share/cargo/src")))
+  (let ((out (assoc-ref outputs "out")))
     (mkdir-p out)
 
     ;; Make cargo reuse all the artifacts we just built instead
@@ -346,21 +367,71 @@ (define* (install #:key
     (or skip-build?
         (not (has-executable-target?))
         (invoke "cargo" "install" "--no-track" "--path" "." "--root" out
-                "--features" (string-join features)))
+                "--features" (string-join features)))))
+
+(define* (install-sources #:key
+                          name
+                          outputs
+                          install-source?
+                          #:allow-other-keys)
+  "Install a given Cargo package."
+  (let* ((out      (assoc-ref outputs "out"))
+         (registry (string-append out "/share/cargo/registry/"))
+         (name+ver (if (string-prefix? "rust-" name)
+                       (string-drop name 5)
+                       name))
+         ;; Strip the version if it exists.
+         (pkgname  (if (char-set-every
+                         (lambda (item)
+                           (char-set-contains?
+                             (list->char-set (list #\- #\.) char-set:digit) 
item))
+                         (string->char-set
+                           (string-drop name+ver (string-index-right name+ver 
#\-))))
+                     (string-take name+ver (string-index-right name+ver #\-))
+                     name+ver)))
 
     (when install-source?
       ;; Install crate tarballs and unpacked sources for later use.
-      ;; TODO: Is there a better format/directory for these files?
-      (mkdir-p sources)
       (for-each (lambda (crate)
                   (install-file crate registry))
                 (find-files "target/package" "\\.crate$"))
 
-      (for-each (lambda (crate)
-                  (invoke "tar" "xzf" crate "-C" sources))
-                (find-files registry "\\.crate$")))
+      (let ((path (match (string-length pkgname)
+                         (1 "1")
+                         (2 "2")
+                         (3 (string-append "3/" (string-take pkgname 1)))
+                         (else (string-append (substring pkgname 0 2) "/"
+                                              (substring pkgname 2 4)))))
+            (cargo-metadata (match (call-with-input-file
+                                     "cargo-metadata.json" read-json)
+                                   (('@ . alist) alist)))
+            (sha256sum (read-delimited
+                         " "
+                         (open-pipe* OPEN_READ
+                                     "sha256sum" "--"
+                                     (first (find-files registry pkgname))))))
 
-    #t))
+        ;; Now it's time to generate the actual index file:
+        ;; 
https://doc.rust-lang.org/cargo/reference/registry-index.html#json-schema
+        (call-with-output-file pkgname
+          (lambda (out)
+            (write-json
+              `(@ ("name" . ,(assoc-ref
+                               (first (assoc-ref cargo-metadata "packages"))
+                               "name"))
+                  ("vers" . ,(assoc-ref
+                               (first (assoc-ref cargo-metadata "packages"))
+                               "version"))
+                  ("deps" . ,(rewrite-deps (assoc-ref
+                               (first (assoc-ref cargo-metadata "packages"))
+                               "dependencies")))
+                  ("cksum" . ,sha256sum)
+                  ("features" . ,(assoc-ref
+                                   (first (assoc-ref cargo-metadata 
"packages"))
+                                   "features"))
+                  ("yanked" . #f))
+              out)))
+        (install-file pkgname (string-append registry "/index/" path))))))
 
 (define %standard-phases
   (modify-phases gnu:%standard-phases
@@ -372,7 +443,8 @@ (define %standard-phases
     (add-after 'build 'package package)
     (add-after 'unpack 'check-for-pregenerated-files 
check-for-pregenerated-files)
     (add-after 'check-for-pregenerated-files 'unpack-rust-crates 
unpack-rust-crates)
-    (add-after 'patch-generated-file-shebangs 'patch-cargo-checksums 
patch-cargo-checksums)))
+    (add-after 'patch-generated-file-shebangs 'patch-cargo-checksums 
patch-cargo-checksums)
+    (add-after 'install 'install-sources install-sources)))
 
 (define* (cargo-build #:key inputs (phases %standard-phases)
                       #:allow-other-keys #:rest args)
-- 
Efraim Flashner   <efr...@flashner.co.il>   רנשלפ םירפא
GPG key = A28B F40C 3E55 1372 662D  14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted

From 1dca2772f81df7d9a66f7a97668c3f9acca141a8 Mon Sep 17 00:00:00 2001
Message-ID: 
<1dca2772f81df7d9a66f7a97668c3f9acca141a8.1702565894.git.efr...@flashner.co.il>
In-Reply-To: <cover.1702565894.git.efr...@flashner.co.il>
References: <cover.1702565894.git.efr...@flashner.co.il>
From: Efraim Flashner <efr...@flashner.co.il>
Date: Thu, 14 Dec 2023 16:54:11 +0200
Subject: [PATCH 2/2] guix: profiles: Add cargo-registry profile hook.

* guix/profiles.scm (cargo-registry): New profile-hook.
(%default-profile-hooks): Add cargo-registry.

Change-Id: I8642e116e7ff7df2ae2dde77c98d5cfeed85f99d
---
 guix/profiles.scm | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/guix/profiles.scm b/guix/profiles.scm
index ce2f8337bf..129448b2b1 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -13,6 +13,7 @@
 ;;; Copyright © 2020 Danny Milosavljevic <dan...@scratchpost.org>
 ;;; Copyright © 2014 David Thompson <da...@gnu.org>
 ;;; Copyright © 2022 Arun Isaac <arunis...@systemreboot.net>
+;;; Copyright © 2023 Efraim Flashner <efr...@flashner.co.il>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -1193,6 +1194,29 @@ (define* (ca-certificate-bundle manifest #:optional 
system)
                     `((type . profile-hook)
                       (hook . ca-certificate-bundle))))
 
+(define* (cargo-registry manifest #:optional system)
+  (define build
+    (with-imported-modules '((guix build utils))
+      #~(begin
+          (use-modules (guix build utils))
+          (let ((registry (string-append #$output "/share/cargo/registry")))
+            (mkdir-p registry)
+            ;; 
https://doc.rust-lang.org/cargo/reference/registry-index.html#index-configuration
+            (with-output-to-file (string-append registry "/config.json")
+              (lambda _
+                (format #t "{~@
+                        \"dl\": \"~a/{crate}-{version}.crate\",~@
+                        }~%"
+                        registry)))))))
+
+  (gexp->derivation "cargo-registry" build
+                    #:system system
+                    #:local-build? #t
+                    #:substitutable? #f
+                    #:properties
+                    `((type . profile-hook)
+                      (hook . cargo-registry))))
+
 (define* (emacs-subdirs manifest #:optional system)
   (define build
     (with-imported-modules (source-module-closure
@@ -1932,6 +1956,7 @@ (define %default-profile-hooks
         fonts-dir-file
         ghc-package-cache-file
         ca-certificate-bundle
+        cargo-registry
         emacs-subdirs
         gdk-pixbuf-loaders-cache-file
         glib-schemas
-- 
Efraim Flashner   <efr...@flashner.co.il>   רנשלפ םירפא
GPG key = A28B F40C 3E55 1372 662D  14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted

Attachment: signature.asc
Description: PGP signature

Reply via email to