11//! Get config from the shader crate's `Cargo.toml` `[*.metadata.rust-gpu.*]`
22
3+ use cargo_metadata:: MetadataCommand ;
34use serde_json:: Value ;
45
56/// `Metadata` refers to the `[metadata.*]` section of `Cargo.toml` that `cargo` formally
@@ -15,37 +16,17 @@ impl Metadata {
1516 /// First we generate the CLI arg defaults as JSON. Then on top of those we merge any config
1617 /// from the workspace `Cargo.toml`, then on top of those we merge any config from the shader
1718 /// crate's `Cargo.toml`.
18- pub fn as_json ( path : & std:: path:: PathBuf ) -> anyhow:: Result < serde_json :: Value > {
19+ pub fn as_json ( path : & std:: path:: PathBuf ) -> anyhow:: Result < Value > {
1920 let cargo_json = Self :: get_cargo_toml_as_json ( path) ?;
2021 let config = Self :: merge_configs ( & cargo_json, path) ?;
2122 Ok ( config)
2223 }
2324
24- /// Convert JSON keys from kebab case to snake case. Eg: `a-b` to `a_b`.
25- ///
26- /// Detection of keys for serde deserialization must match the case in the Rust structs.
27- /// However clap defaults to detecting CLI args in kebab case. So here we do the conversion.
28- fn keys_to_snake_case ( json : & mut serde_json:: Value ) {
29- let serde_json:: Value :: Object ( object) = json else {
30- return ;
31- } ;
32-
33- * object = core:: mem:: take ( object)
34- . into_iter ( )
35- . map ( |( key, mut value) | {
36- if let serde_json:: Value :: Object ( _) = value {
37- Self :: keys_to_snake_case ( & mut value) ;
38- }
39- ( key. replace ( '-' , "_" ) , value)
40- } )
41- . collect ( ) ;
42- }
43-
4425 /// Merge the various source of config: defaults, workspace and shader crate.
4526 fn merge_configs (
46- cargo_json : & serde_json :: Value ,
27+ cargo_json : & cargo_metadata :: Metadata ,
4728 path : & std:: path:: Path ,
48- ) -> anyhow:: Result < serde_json :: Value > {
29+ ) -> anyhow:: Result < Value > {
4930 let mut metadata = crate :: config:: Config :: defaults_as_json ( ) ?;
5031 crate :: config:: Config :: json_merge (
5132 & mut metadata,
@@ -85,74 +66,62 @@ impl Metadata {
8566 /// Convert a `Cargo.toml` to JSON
8667 //
8768 // TODO: reuse for getting the default `rust-gpu` source and toolchain.
88- fn get_cargo_toml_as_json ( path : & std:: path:: PathBuf ) -> anyhow:: Result < serde_json:: Value > {
89- let cargo_toml_path = path. join ( "Cargo.toml" ) ;
90- if !cargo_toml_path. exists ( ) {
91- anyhow:: bail!( "{path:?} must be a shader crate directory" ) ;
92- }
93-
94- log:: debug!( "Querying Cargo metadata for {cargo_toml_path:?}" ) ;
95- let output_cargo = std:: process:: Command :: new ( "cargo" )
96- . args ( [
97- "metadata" ,
98- "--no-deps" ,
99- "--manifest-path" ,
100- cargo_toml_path. display ( ) . to_string ( ) . as_ref ( ) ,
101- ] )
102- . output ( ) ?;
103- anyhow:: ensure!(
104- output_cargo. status. success( ) ,
105- "could not run `cargo metadata` on {cargo_toml_path:?}"
106- ) ;
107-
108- Ok ( serde_json:: from_slice ( & output_cargo. stdout ) ?)
69+ fn get_cargo_toml_as_json (
70+ path : & std:: path:: PathBuf ,
71+ ) -> anyhow:: Result < cargo_metadata:: Metadata > {
72+ Ok ( MetadataCommand :: new ( ) . current_dir ( path) . exec ( ) ?)
10973 }
11074
11175 /// Get any `rust-gpu` metadata set in the root workspace `Cargo.toml`
112- fn get_workspace_metadata ( json : & serde_json:: Value ) -> serde_json:: Value {
113- let empty_json_object = serde_json:: json!( { } ) ;
114- let mut metadata = json
115- . pointer ( "/metadata/rust-gpu" )
116- . unwrap_or ( & empty_json_object)
117- . clone ( ) ;
118-
119- Self :: keys_to_snake_case ( & mut metadata) ;
120- metadata. clone ( )
76+ fn get_workspace_metadata ( metadata : & cargo_metadata:: Metadata ) -> Value {
77+ Self :: get_rust_gpu_from_metadata ( & metadata. workspace_metadata )
12178 }
12279
12380 /// Get any `rust-gpu` metadata set in the crate's `Cargo.toml`
12481 fn get_crate_metadata (
125- json : & serde_json:: Value ,
126- path : & std:: path:: Path ,
127- ) -> anyhow:: Result < serde_json:: Value > {
128- let empty_json_object = serde_json:: json!( { } ) ;
129- if let Some ( serde_json:: Value :: Array ( packages) ) = json. pointer ( "/packages" ) {
130- for package in packages {
131- if let Some ( serde_json:: Value :: String ( manifest_path_dirty) ) =
132- package. pointer ( "/manifest_path" )
133- {
134- let mut shader_crate_path = std:: fs:: canonicalize ( path) ?
135- . join ( "Cargo.toml" )
136- . display ( )
137- . to_string ( ) ;
138-
139- // Windows prefixs paths with `\\?\`
140- shader_crate_path = shader_crate_path. replace ( r"\\?\" , "" ) ;
141- let manifest_path = manifest_path_dirty. replace ( r"\\?\" , "" ) ;
142- log:: debug!( "Matching shader crate path with manifest path: {shader_crate_path} == {manifest_path}?" ) ;
143- if manifest_path == shader_crate_path {
144- log:: debug!( "...matches! Getting metadata" ) ;
145- let mut metadata = package
146- . pointer ( "/metadata/rust-gpu" )
147- . unwrap_or ( & empty_json_object)
148- . clone ( ) ;
149- Self :: keys_to_snake_case ( & mut metadata) ;
150- return Ok ( metadata) ;
151- }
152- }
82+ json : & cargo_metadata:: Metadata ,
83+ shader_crate_path : & std:: path:: Path ,
84+ ) -> anyhow:: Result < Value > {
85+ let shader_crate_path = std:: fs:: canonicalize ( shader_crate_path) ?. join ( "Cargo.toml" ) ;
86+
87+ for package in & json. packages {
88+ let manifest_path = std:: fs:: canonicalize ( package. manifest_path . as_std_path ( ) ) ?;
89+ log:: debug!(
90+ "Matching shader crate path with manifest path: '{}' == '{}'?" ,
91+ shader_crate_path. display( ) ,
92+ manifest_path. display( )
93+ ) ;
94+ if manifest_path == shader_crate_path {
95+ log:: debug!( "...matches! Getting metadata" ) ;
96+ return Ok ( Self :: get_rust_gpu_from_metadata ( & package. metadata ) ) ;
15397 }
15498 }
155- Ok ( empty_json_object)
99+ Ok ( serde_json:: json!( { } ) )
100+ }
101+
102+ fn get_rust_gpu_from_metadata ( metadata : & Value ) -> Value {
103+ Self :: keys_to_snake_case (
104+ metadata
105+ . pointer ( "/rust-gpu" )
106+ . cloned ( )
107+ . unwrap_or ( Value :: Null ) ,
108+ )
109+ }
110+
111+ /// Convert JSON keys from kebab case to snake case. Eg: `a-b` to `a_b`.
112+ ///
113+ /// Detection of keys for serde deserialization must match the case in the Rust structs.
114+ /// However clap defaults to detecting CLI args in kebab case. So here we do the conversion.
115+ fn keys_to_snake_case ( json : Value ) -> Value {
116+ match json {
117+ Value :: Object ( object) => Value :: Object (
118+ object
119+ . into_iter ( )
120+ . map ( |( key, value) | ( key. replace ( '-' , "_" ) , Self :: keys_to_snake_case ( value) ) )
121+ . collect ( ) ,
122+ ) ,
123+ e => e,
124+ }
156125 }
157126}
158127
@@ -163,59 +132,73 @@ impl Metadata {
163132#[ cfg( test) ]
164133mod test {
165134 use super :: * ;
135+ use std:: path:: Path ;
166136
167137 #[ test_log:: test]
168138 fn generates_defaults ( ) {
169- let json = serde_json:: json!( { } ) ;
170- let configs = Metadata :: merge_configs ( & json, std:: path:: Path :: new ( "./" ) ) . unwrap ( ) ;
171- assert_eq ! ( configs[ "build" ] [ "release" ] , serde_json:: Value :: Bool ( true ) ) ;
139+ let mut metadata = MetadataCommand :: new ( )
140+ . current_dir ( env ! ( "CARGO_MANIFEST_DIR" ) )
141+ . exec ( )
142+ . unwrap ( ) ;
143+ metadata. packages . first_mut ( ) . unwrap ( ) . metadata = serde_json:: json!( { } ) ;
144+ let configs = Metadata :: merge_configs ( & metadata, Path :: new ( "./" ) ) . unwrap ( ) ;
145+ assert_eq ! ( configs[ "build" ] [ "release" ] , Value :: Bool ( true ) ) ;
172146 assert_eq ! (
173147 configs[ "install" ] [ "auto_install_rust_toolchain" ] ,
174- serde_json :: Value :: Bool ( false )
148+ Value :: Bool ( false )
175149 ) ;
176150 }
177151
178152 #[ test_log:: test]
179153 fn can_override_config_from_workspace_toml ( ) {
180- let json = serde_json:: json!(
181- { "metadata" : { "rust-gpu" : {
154+ let mut metadata = MetadataCommand :: new ( )
155+ . current_dir ( env ! ( "CARGO_MANIFEST_DIR" ) )
156+ . exec ( )
157+ . unwrap ( ) ;
158+ metadata. workspace_metadata = serde_json:: json!( {
159+ "rust-gpu" : {
182160 "build" : {
183161 "release" : false
184162 } ,
185163 "install" : {
186164 "auto-install-rust-toolchain" : true
187165 }
188- } } }
189- ) ;
190- let configs = Metadata :: merge_configs ( & json , std :: path :: Path :: new ( "./" ) ) . unwrap ( ) ;
191- assert_eq ! ( configs[ "build" ] [ "release" ] , serde_json :: Value :: Bool ( false ) ) ;
166+ }
167+ } ) ;
168+ let configs = Metadata :: merge_configs ( & metadata , Path :: new ( "./" ) ) . unwrap ( ) ;
169+ assert_eq ! ( configs[ "build" ] [ "release" ] , Value :: Bool ( false ) ) ;
192170 assert_eq ! (
193171 configs[ "install" ] [ "auto_install_rust_toolchain" ] ,
194- serde_json :: Value :: Bool ( true )
172+ Value :: Bool ( true )
195173 ) ;
196174 }
197175
198176 #[ test_log:: test]
199177 fn can_override_config_from_crate_toml ( ) {
200- let marker = std:: path:: Path :: new ( "./Cargo.toml" ) ;
201- let json = serde_json:: json!(
202- { "packages" : [ {
203- "metadata" : { "rust-gpu" : {
204- "build" : {
205- "release" : false
206- } ,
207- "install" : {
208- "auto-install-rust-toolchain" : true
209- }
210- } } ,
211- "manifest_path" : std:: fs:: canonicalize( marker) . unwrap( )
212- } ] }
213- ) ;
214- let configs = Metadata :: merge_configs ( & json, marker. parent ( ) . unwrap ( ) ) . unwrap ( ) ;
215- assert_eq ! ( configs[ "build" ] [ "release" ] , serde_json:: Value :: Bool ( false ) ) ;
178+ let mut metadata = MetadataCommand :: new ( )
179+ . current_dir ( env ! ( "CARGO_MANIFEST_DIR" ) )
180+ . exec ( )
181+ . unwrap ( ) ;
182+ let cargo_gpu = metadata
183+ . packages
184+ . iter_mut ( )
185+ . find ( |p| p. name . contains ( "cargo-gpu" ) )
186+ . unwrap ( ) ;
187+ cargo_gpu. metadata = serde_json:: json!( {
188+ "rust-gpu" : {
189+ "build" : {
190+ "release" : false
191+ } ,
192+ "install" : {
193+ "auto-install-rust-toolchain" : true
194+ }
195+ }
196+ } ) ;
197+ let configs = Metadata :: merge_configs ( & metadata, Path :: new ( "." ) ) . unwrap ( ) ;
198+ assert_eq ! ( configs[ "build" ] [ "release" ] , Value :: Bool ( false ) ) ;
216199 assert_eq ! (
217200 configs[ "install" ] [ "auto_install_rust_toolchain" ] ,
218- serde_json :: Value :: Bool ( true )
201+ Value :: Bool ( true )
219202 ) ;
220203 }
221204}
0 commit comments