2025-03-02 20:33:27 +00:00
( import ( scheme base ) ( scheme write ) ( zilch statusbar ) ( zilch nix daemon ) ( zilch magic ) ( zilch lib getopt ) ( scheme process-context ) ( chicken process-context ) ( srfi 146 ) ( chicken port ) ( chicken foreign ) ( chicken condition ) )
( foreign-declare "#include <sched.h>" )
2025-03-02 21:25:32 +00:00
( foreign-declare "#include \"stock_overrides.h\"" )
( define stock-overrides ( foreign-value "stock_overrides" nonnull-c-string ) )
2025-03-02 20:33:27 +00:00
( define get-cpu-count
( foreign-lambda* int ( )
"cpu_set_t set; sched_getaffinity(0, sizeof(set), &set); C_return(CPU_COUNT(&set));" ) )
( define ( print-help msg )
( when msg
( write-string ( string-append msg "\n\n" ) ( current-error-port ) ) )
( write-string " Usage: zilch-cli-rust [ OPTION ] [ TARGET . . . ]
Process the given crate directory ( or the current directory, if unspecified )
and output derivations for each target given on the command line ( or all
executables in the crate, if unspecified )
-h, --help Print this help message .
-b, --build Build the store paths, rather than show their
derivations .
-j, --max-jobs COUNT The maximum amount of builds to run . Defaults
to the amount of cores .
-v, --verbose Increase the verbosity configured in the Nix
daemon .
-L, --print-build-logs Print derivation logs as they come in .
-m, --crate-dir DIR The directory to use as root crate .
2025-03-02 21:44:11 +00:00
-r, --replace DIR Replace the crate specified by the Cargo . toml
2025-03-02 20:33:27 +00:00
with this source directory, rather than using
2025-03-02 21:44:11 +00:00
the upstream crate . Can be specified more
2025-03-02 20:33:27 +00:00
than once .
-z, --overrides PATH Read build script overrides from this file .
2025-03-02 21:25:32 +00:00
By default, a stock set of overrides is read .
This can be disabled by passing ` -z \ "\" `
( a blank string ) .
2025-03-02 20:33:27 +00:00
--debug Crash on the first error, rather than
continuing with the next package .
" ( current-error-port ) )
( exit ( or ( not msg ) 1 ) ) )
( define-values ( options args )
( getopt
' ( ( help #f #\h )
( build #f #\b )
( max-jobs #t #\j )
( verbose #f #\v )
( print-build-logs #f #\L )
( crate-dir #t #\m )
( replace #t #\r )
( overrides #t #\z )
( debug #f ) )
( list->vector ( cdr ( command-line ) ) )
print-help ) )
( when ( assoc 'help options ) ( print-help #f ) )
; Set up the logger.
( define ( set-print-logs val ) #f )
( let ( ( prev-error-handler ( current-exception-handler ) ) ) ( current-exception-handler ( lambda data ( set-print-logs #t ) ( apply prev-error-handler data ) ) ) )
2025-03-02 22:11:59 +00:00
( when ( terminal-port? ( current-error-port ) )
2025-03-02 20:33:27 +00:00
( let-values ( ( ( new-out new-err statusbar-set-print-logs logger ) ( statusbar-logger ( current-output-port ) ( current-error-port ) ( assoc 'print-build-logs options ) ) ) )
( current-output-port new-out )
( current-error-port new-err )
( set! set-print-logs statusbar-set-print-logs )
( *logger* logger ) ) )
;; Flags passed to the nix daemon:
( define max-jobs ( if ( assoc 'max-jobs options ) ( string->number ( cdr ( assoc 'max-jobs options ) ) ) ( get-cpu-count ) ) )
( define verbosity 3 )
( for-each ( lambda ( val ) ( when ( eq? ( car val ) 'verbose ) ( set! verbosity ( + 1 verbosity ) ) ) ) options )
( write-string ( string-append "Connected to Nix daemon, version " ( daemon-link-daemon-version ( *daemon* ) ) "\n" ) ( current-error-port ) )
( daemon-wop-set-options ( *daemon* ) verbosity max-jobs #t )
( import ( scheme base ) ( scheme file ) ( scheme write ) ( zilch magic ) ( zilch zexpr ) ( zilch nix drv ) ( zilch file ) ( zilch lang rust registry ) ( zilch lang rust cargo ) ( zilch vfs ) ( zilch lang rust resolver ) json ( srfi 128 ) ( srfi 146 ) ( zilch nixpkgs ) )
( import ( chicken format ) )
( define ( read-file fname )
( call-with-input-file fname ( lambda ( p ) ( read-string 999999 p ) ) ) )
( define crate-dir ( let ( ( m ( assoc 'crate-dir options ) ) ) ( if m ( cdr m ) ( current-directory ) ) ) )
2025-03-02 22:12:30 +00:00
( define ( remove-target-dir vfs )
( vfs-dir-filter-all
( lambda ( dirname )
( not ( string=? dirname "target" ) ) )
vfs ) )
( define root-vfs ( remove-target-dir ( vfs-from-directory crate-dir ) ) )
2025-03-02 20:33:27 +00:00
( define-values ( cargo-toml cargo-workspace ) ( parse-cargo-toml root-vfs ( read-file ( string-append crate-dir "/Cargo.toml" ) ) #f ) )
( define projects ' ( ) )
( define ( add-crate-targets dirname vfs crate workspace )
; (printf "Adding crate target.. ~A\n" crate)
( set! projects ( cons ( cons crate vfs ) projects ) )
( define ( check-dep dep )
( define is-path ( cargo-dep-path? ( cargo-dependency-origin dep ) ) )
( define path ( and is-path ( cargo-dep-path-path ( cargo-dependency-origin dep ) ) ) )
( when is-path
( let*
( ( root ( if ( and ( pair? path ) ( eq? ( car path ) 'workspace ) ) crate-dir dirname ) )
( new-path ( string-append root "/" ( if ( pair? path ) ( cdr path ) path ) ) ) )
2025-03-02 22:12:30 +00:00
( append-dir new-path ( remove-target-dir ( vfs-from-directory new-path ) ) workspace ) ) ) )
2025-03-02 20:33:27 +00:00
( for-each check-dep ( cargo-crate-dependencies crate ) )
( for-each check-dep ( cargo-crate-build-dependencies crate ) ) )
( define seen-crate-names ' ( ) )
( define ( append-dir dirname vfs workspace )
( define-values ( parsed-cargo new-workspace ) ( parse-cargo-toml vfs ( call-with-input-file ( string-append dirname "/Cargo.toml" ) ( lambda ( p ) ( read-string 999999 p ) ) ) workspace ) )
( when ( and ( not workspace ) new-workspace )
( set-print-logs #t )
( fprintf ( current-error-port ) "Replaced directory ~S contains a Cargo workspace. This is unsupported.\n" dirname )
( exit 1 ) )
( unless ( member ( cargo-crate-name parsed-cargo ) seen-crate-names )
( set! seen-crate-names ( cons ( cargo-crate-name parsed-cargo ) seen-crate-names ) )
( add-crate-targets dirname vfs parsed-cargo workspace ) ) )
2025-03-03 15:13:27 +00:00
( when cargo-toml
( add-crate-targets crate-dir root-vfs cargo-toml #f ) )
2025-03-02 20:33:27 +00:00
( when cargo-workspace
( for-each
( lambda ( workspace-member )
( append-dir ( string-append crate-dir "/" workspace-member ) ( vfs-subdir root-vfs workspace-member ) cargo-workspace ) )
( cargo-workspace-members cargo-workspace ) ) )
( for-each
( lambda ( kv )
( when ( eq? ( car kv ) 'replace )
2025-03-02 22:12:30 +00:00
( append-dir ( cdr kv ) ( remove-target-dir ( vfs-from-directory ( cdr kv ) ) ) #f ) ) )
2025-03-02 20:33:27 +00:00
options )
( define lockfile ( parse-lockfile ( read-file ( string-append crate-dir "/Cargo.lock" ) ) ) )
( define output ( process-many-with-lockfile projects lockfile ) )
( define do-build ( assoc 'build options ) )
( define ( build-if-wanted path )
( store-path-materialize path )
( if do-build
( begin
( store-path-build path )
( store-path-realisation path ) )
( if ( string=? ( store-path-output path ) "out" )
( derivation-path ( store-path-drv path ) )
( string-append ( derivation-path ( store-path-drv path ) ) "!" ( store-path-output path ) ) ) ) )
( define build-script-overrides ( mapping ( make-default-comparator ) ) )
( define build-script-dependency-overrides ( mapping ( make-default-comparator ) ) )
( define rustc-overrides ( mapping ( make-default-comparator ) ) )
( define ( process-overrides data )
( for-each
( lambda ( pair )
( define crate-name ( car pair ) )
( define overrides ( vector->list ( cdr pair ) ) )
( define self ( if ( assoc "buildScript" overrides ) ( vector->list ( cdr ( assoc "buildScript" overrides ) ) ) ( list ) ) )
( define dependency ( if ( assoc "buildScriptDependency" overrides ) ( vector->list ( cdr ( assoc "buildScriptDependency" overrides ) ) ) ( list ) ) )
( define rustc ( if ( assoc "rustc" overrides ) ( vector->list ( cdr ( assoc "rustc" overrides ) ) ) ( list ) ) )
( define ( parse-inner vals )
( map ( lambda ( kv ) ( cons ( car kv ) ( nix-eval ( string-append "with (import <nixpkgs> {}); \"" ( cdr kv ) "\"" ) ) ) ) vals ) )
( set! build-script-overrides ( mapping-set! build-script-overrides crate-name ( parse-inner self ) ) )
( set! build-script-dependency-overrides ( mapping-set! build-script-dependency-overrides crate-name ( parse-inner dependency ) ) )
( set! rustc-overrides ( mapping-set! rustc-overrides crate-name ( parse-inner rustc ) ) ) )
( vector->list data ) ) )
2025-03-02 21:25:32 +00:00
; If we have no request to disable stock overrides, apply them.
( unless ( member ' ( overrides "" ) options )
( process-overrides ( call-with-port ( open-input-string stock-overrides ) json-read ) ) )
2025-03-02 20:33:27 +00:00
( for-each
( lambda ( kv )
2025-03-02 21:25:32 +00:00
( when ( eq? ( car kv ) 'overrides ) ( unless ( string=? ( cdr kv ) "" ) ( process-overrides ( call-with-input-file ( cdr kv ) json-read ) ) ) ) )
2025-03-02 20:33:27 +00:00
options )
( define ( build-script-env-overrides crate-name is-dependency )
( mapping-ref/default ( if is-dependency build-script-dependency-overrides build-script-overrides ) crate-name ' ( ) ) )
( define ( rustc-env-overrides crate-name )
( mapping-ref/default rustc-overrides crate-name ' ( ) ) )
( define ( should-skip pkg )
( define is-skippable #t )
( if ( null? args ) #f
( begin
( for-each
( lambda ( match )
( when
( or
( string=? ( cargo-target-name ( resolved-package-cargo-target pkg ) ) match )
( string=? ( cargo-crate-name ( resolved-package-crate pkg ) ) match ) )
( set! is-skippable #f ) ) )
args )
is-skippable ) ) )
( for-each
( lambda ( pkg )
( if ( equal? 'bin ( cargo-target-crate-type ( resolved-package-cargo-target pkg ) ) )
( if ( should-skip pkg )
( printf "~A\t~A\t~A\tskipped\n" ( cargo-crate-name ( resolved-package-crate pkg ) ) ( cargo-target-name ( resolved-package-cargo-target pkg ) ) ( cargo-target-crate-type ( resolved-package-cargo-target pkg ) ) )
( let ( ( built ( build-package pkg build-script-env-overrides rustc-env-overrides ) ) ) ( printf "~A\t~A\tbin\t~A\n" ( cargo-crate-name ( resolved-package-crate pkg ) ) ( cargo-target-name ( resolved-package-cargo-target pkg ) ) ( build-if-wanted built ) ) ) )
( printf "~A\t~A\t~A\tnot a binary\n" ( cargo-crate-name ( resolved-package-crate pkg ) ) ( cargo-target-name ( resolved-package-cargo-target pkg ) ) ( cargo-target-crate-type ( resolved-package-cargo-target pkg ) ) ) ) )
output )