~ruther/guix-local

b1440e1f37e01a00218732cce4b656598db83267 — Hilton Chain 1 year, 2 months ago a51c34a
build-system: cargo: Add ‘cargo-inputs’.

* gnu/packages/rust-crates.scm: New file.
* gnu/packages/rust-sources.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Regisiter them.
* guix/build-system/cargo.scm (define-cargo-inputs): New macro.
(crate-source, cargo-inputs): New procedures.
* guix/import/crate.scm: Hide ‘crate-source’ from (guix build-system cargo).
* etc/teams/rust/audit-rust-crates: New file.
* etc/teams/rust/cleanup-crates.sh: New file.
* etc/teams/rust/rust-crates.tmpl: New file.
* etc/teams/rust/unpack-new-crates.sh: New file.

Change-Id: I2f2d705a3e376ed3c646f31b824052a2278d4fb3
A etc/teams/rust/audit-rust-crates => etc/teams/rust/audit-rust-crates +70 -0
@@ 0,0 1,70 @@
#!/usr/bin/env -S gawk -f
# GNU Guix --- Functional package management for GNU
# Copyright © 2025 Efraim Flashner <efraim@flashner.co.il>
#
# 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/>.

# To run:
# ./etc/teams/rust/audit-rust-crates ./path/to/file.scm
# Prints the output of cargo-audit to the shell.

# Make sure we have cargo-audit in our PATH
BEGIN {
    if (system("which cargo-audit 1> /dev/null"))
        exit 1;
    # Parse a record at a time.
    RS = "\n\n"
    cargoAudit = "cargo-audit audit --file -"
}

# Check the crate-source origin-only inputs
/crate-source/ {
    for(i=3; i <= NF-2; i++) {
        if($i == "(crate-source") {
            cargoLock = cargoLock "[[package]]\nname = " $(i+1) "\nversion = " $(i+2) "\n"
            next
        }
    }
}

# Check the crates packaged from crates.io tarballs
/crate-uri/ {
    for(i=3; i <= NF; i++) {
        if($i == "(version")
           crateVersion = $(i+1)
        if($i == "(crate-uri")
           crateName = $(i+1)
    }
    gsub(/)/, "", crateVersion)
    cargoLock = cargoLock "[[package]]\nname = " crateName "\nversion = " crateVersion "\n"
}

# The xxxx-cargo-input variables have a set style
# TODO: Replace the last dash between the name and the version with a space!
# This doesn't take into account swapping between "-" and "_" so we skip it.
#( $2 ~ /-cargo-inputs/ ) {
#    sub(/-cargo-inputs/, "", $2)
#    gsub(/)/, "", $0)
#    gsub(/rust-/, "", $0)
#    #gensub(/([[:alpha:]])-([[:digit:]]+)/, "\\1 \\2", "g", $i)
#    print "[[package]]\nname = \"" $2 "\"\nversion = \"1.0.0\"\ndependencies = ["
#    for (i = 4; i <= NF; i++) {
#        print "\"" $i "\","
#    }
#    print "]"
#}

END { print cargoLock | cargoAudit }

A etc/teams/rust/cleanup-crates.sh => etc/teams/rust/cleanup-crates.sh +37 -0
@@ 0,0 1,37 @@
#!/bin/sh
# GNU Guix --- Functional package management for GNU
# Copyright © 2025 Hilton Chain <hako@ultrarare.space>
#
# 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/>.

FILE=gnu/packages/rust-crates.scm
PATTERN='^(define rust-'

grep "$PATTERN" $FILE | cut -d' ' -f2 | while IFS= read -r crate
do
    if [ "$(grep -wc "$crate" $FILE)" -eq 1 ]; then
        echo "\
(begin
  (use-modules (guix utils))
  (let ((source-properties
         (find-definition-location \"$FILE\" '$crate #:define-prefix 'define)))
    (and=> source-properties delete-expression)))" |
            guix repl -t machine
    fi
done

# Delete extra newlines.
sed --in-place ':a;N;$!ba;s/\n\n\+/\n\n/g' $FILE

A etc/teams/rust/rust-crates.tmpl => etc/teams/rust/rust-crates.tmpl +46 -0
@@ 0,0 1,46 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2025 Hilton Chain <hako@ultrarare.space>
;;;
;;; 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 (gnu packages rust-crates)
  #:use-module (guix gexp)
  #:use-module (guix packages)
  #:use-module (guix download)
  #:use-module (guix git-download)
  #:use-module (guix build-system cargo)
  #:use-module (gnu packages rust-sources)
  #:export (lookup-cargo-inputs))

;;;
;;; This file is managed by ‘guix import’.  Do NOT add definitions manually.
;;;

;;;
;;; Rust libraries fetched from crates.io and non-workspace development
;;; snapshots.
;;;

(define qqqq-separator 'begin-of-crates)

(define ssss-separator 'end-of-crates)


;;;
;;; Cargo inputs.
;;;

(define-cargo-inputs lookup-cargo-inputs)

A etc/teams/rust/unpack-new-crates.sh => etc/teams/rust/unpack-new-crates.sh +45 -0
@@ 0,0 1,45 @@
#!/bin/sh
# GNU Guix --- Functional package management for GNU
# Copyright © 2025 Hilton Chain <hako@ultrarare.space>
#
# 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/>.

# Usage: ./etc/teams/rust/unpack-new-crates.sh <DIR>
# Then inspect DIR with your tool of choice.
#
# For example:
# ./etc/teams/rust/unpack-new-crates.sh tmp-rust-crates &&
#     emacs --eval '(find-dired "tmp-rust-crates" "")'
#
# Note this uses ‘git diff’, only unstaged one are unpacked.

UNPACK_DIR="$1"
CHANGES="$(git diff gnu/packages/rust-crates.scm | grep -E '^\+\(define rust-' | cut -f2 -d' ')"

rm -rf "$UNPACK_DIR"
mkdir -p "$UNPACK_DIR"

for crate in $CHANGES
do
    built="$(./pre-inst-env guix build -e "(@@ (gnu packages rust-crates) "$crate")" -v0 2>/dev/null)"
    if [[ -n $built ]]; then
        if [[ -d $built ]]; then
            cp -r "$built" "$UNPACK_DIR"
        else
            tar xf "$built" -C "$UNPACK_DIR"
        fi
    fi
done

M gnu/local.mk => gnu/local.mk +2 -0
@@ 629,6 629,8 @@ GNU_SYSTEM_MODULES =				\
  %D%/packages/rush.scm				\
  %D%/packages/rust.scm				\
  %D%/packages/rust-apps.scm			\
  %D%/packages/rust-crates.scm			\
  %D%/packages/rust-sources.scm			\
  %D%/packages/samba.scm			\
  %D%/packages/sagemath.scm			\
  %D%/packages/sawfish.scm			\

A gnu/packages/rust-crates.scm => gnu/packages/rust-crates.scm +44 -0
@@ 0,0 1,44 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2025 Hilton Chain <hako@ultrarare.space>
;;;
;;; 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 (gnu packages rust-crates)
  #:use-module (guix gexp)
  #:use-module (guix packages)
  #:use-module (guix download)
  #:use-module (guix git-download)
  #:use-module (guix build-system cargo)
  #:use-module (gnu packages rust-sources)
  #:export (lookup-cargo-inputs))

;;;
;;; This file is managed by ‘guix import’.  Do NOT add definitions manually.
;;;

;;;
;;; Rust libraries fetched from crates.io and non-workspace development
;;; snapshots.
;;;

(define qqqq-separator 'begin-of-crates)

(define ssss-separator 'end-of-crates)


;;;
;;; Cargo inputs.
;;;

A gnu/packages/rust-sources.scm => gnu/packages/rust-sources.scm +29 -0
@@ 0,0 1,29 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2025 Hilton Chain <hako@ultrarare.space>
;;;
;;; 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 (gnu packages rust-sources)
  #:use-module (guix gexp)
  #:use-module (guix packages)
  #:use-module (guix download)
  #:use-module (guix git-download)
  #:use-module (guix build-system cargo))

;;;
;;; Cargo workspaces and Rust libraries requiring external inputs to unbundle.
;;; These packages are hidden, as they are not interesting to users.
;;;

M guix/build-system/cargo.scm => guix/build-system/cargo.scm +45 -1
@@ 25,12 25,15 @@
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (guix build-system cargo)
  #:use-module (guix diagnostics)
  #:use-module (guix i18n)
  #:use-module (guix search-paths)
  #:use-module (guix store)
  #:use-module (guix utils)
  #:use-module (guix gexp)
  #:use-module (guix monads)
  #:use-module (guix packages)
  #:use-module (guix download)
  #:use-module (guix platform)
  #:use-module (guix build-system)
  #:use-module (guix build-system gnu)


@@ 45,7 48,10 @@
            crate-url
            crate-url?
            crate-uri
            crate-name->package-name))
            crate-name->package-name
            crate-source
            define-cargo-inputs
            cargo-inputs))

(define %crate-base-url
  (make-parameter "https://crates.io"))


@@ 62,6 68,44 @@ to NAME and VERSION."
(define (crate-name->package-name name)
  (downstream-package-name "rust-" name))

;; NOTE: Only use this procedure in (gnu packages rust-crates).
(define* (crate-source name version hash #:key (patches '()) (snippet #f))
  (origin
    (method url-fetch)
    (uri (crate-uri name version))
    (file-name
     (string-append (crate-name->package-name name) "-" version ".tar.gz"))
    (sha256 (base32 hash))
    (modules '((guix build utils)))
    (patches patches)
    (snippet snippet)))

(define-syntax define-cargo-inputs
  (syntax-rules (=>)
    ((_ lookup inputs ...)
     (define lookup
       (let ((table (make-hash-table)))
         (letrec-syntax ((record
                          (syntax-rules (=>)
                            ((_) #t)
                            ((_ (name => lst) rest (... ...))
                             (begin
                               (hashq-set! table 'name (filter identity lst))
                               (record rest (... ...)))))))
           (record inputs ...)
           (lambda (name)
             "Return the inputs for NAME."
             (hashq-ref table name))))))))

(define* (cargo-inputs name #:key (module '(gnu packages rust-crates)))
  "Lookup Cargo inputs for NAME defined in MODULE, return an empty list if
unavailable."
  (let ((lookup (module-ref (resolve-interface module) 'lookup-cargo-inputs)))
    (or (lookup name)
        (begin
          (warning (G_ "no Cargo inputs available for '~a'~%") name)
          '()))))

(define (default-rust target)
  "Return the default Rust package."
  ;; Lazily resolve the binding to avoid a circular dependency.

M guix/import/crate.scm => guix/import/crate.scm +1 -1
@@ 27,7 27,7 @@

(define-module (guix import crate)
  #:use-module (guix base32)
  #:use-module (guix build-system cargo)
  #:use-module ((guix build-system cargo) #:hide (crate-source))
  #:use-module (guix diagnostics)
  #:use-module (gcrypt hash)
  #:use-module (guix http-client)