1- //! Manage and merge the various sources of config: shader crate's `Cargo.toml`(s) and CLI args.
2- use anyhow:: Context as _;
3- use clap:: Parser as _;
4-
5- /// Config
6- pub struct Config ;
7-
8- impl Config {
9- /// Get all the config defaults as JSON.
10- pub fn defaults_as_json ( ) -> anyhow:: Result < serde_json:: Value > {
11- let defaults_json = Self :: cli_args_to_json ( vec ! [ String :: new( ) ] ) ?;
12- Ok ( defaults_json)
13- }
1+ //! Manage and merge the various sources of config:
2+ //! shader crate's `Cargo.toml`(s) and provided args.
143
15- /// Convert CLI args to their serde JSON representation.
16- fn cli_args_to_json ( env_args : Vec < String > ) -> anyhow:: Result < serde_json:: Value > {
17- Ok ( serde_json:: to_value ( crate :: build:: Build :: parse_from (
18- env_args,
19- ) ) ?)
20- }
4+ use std:: path:: Path ;
215
22- /// Config for the `cargo gpu build` and `cargo gpu install` can be set in the shader crate's
23- /// `Cargo.toml`, so here we load that config first as the base config, and the CLI arguments can
24- /// then later override it.
25- pub fn clap_command_with_cargo_config (
26- shader_crate_path : & std:: path:: PathBuf ,
27- mut env_args : Vec < String > ,
28- ) -> anyhow:: Result < crate :: build:: Build > {
29- let mut config = crate :: metadata:: Metadata :: as_json ( shader_crate_path) ?;
30-
31- env_args. retain ( |arg| !( arg == "build" || arg == "install" ) ) ;
32- let cli_args_json = Self :: cli_args_to_json ( env_args) ?;
33- Self :: json_merge ( & mut config, cli_args_json, None ) ?;
34-
35- let args = serde_json:: from_value :: < crate :: build:: Build > ( config) ?;
36- Ok ( args)
37- }
6+ use serde:: { de:: DeserializeOwned , Serialize } ;
387
39- /// Merge 2 JSON objects. But only if the incoming patch value isn't the default value.
40- /// Inspired by: <https://stackoverflow.com/a/47142105/575773>
41- pub fn json_merge (
42- left_in : & mut serde_json:: Value ,
43- right_in : serde_json:: Value ,
44- maybe_pointer : Option < & String > ,
45- ) -> anyhow:: Result < ( ) > {
46- let defaults = Self :: defaults_as_json ( ) ?;
47-
48- match ( left_in, right_in) {
49- ( left @ & mut serde_json:: Value :: Object ( _) , serde_json:: Value :: Object ( right) ) => {
50- let left_as_object = left
51- . as_object_mut ( )
52- . context ( "Unreachable, we've already proved it's an object" ) ?;
53- for ( key, value) in right {
54- let new_pointer = maybe_pointer. as_ref ( ) . map_or_else (
55- || format ! ( "/{}" , key. clone( ) ) ,
56- |pointer| format ! ( "{}/{}" , pointer, key. clone( ) ) ,
57- ) ;
58- Self :: json_merge (
59- left_as_object
60- . entry ( key. clone ( ) )
61- . or_insert ( serde_json:: Value :: Null ) ,
62- value,
63- Some ( & new_pointer) ,
64- ) ?;
65- }
66- }
67- ( left, right) => {
68- if let Some ( pointer) = maybe_pointer {
69- let default = defaults. pointer ( pointer) . context ( format ! (
70- "Configuration option with path `{pointer}` was not found in the default configuration, \
71- which is:\n defaults: {defaults:#?}"
72- ) ) ?;
73- if & right != default {
74- // Only overwrite if the new value differs from the defaults.
75- * left = right;
76- }
77- }
78- }
79- }
8+ use crate :: { merge:: merge, metadata:: from_cargo_metadata} ;
809
81- Ok ( ( ) )
82- }
10+ /// Overrides the config options from `Cargo.toml` of the shader crate
11+ /// with options from the provided config.
12+ pub fn from_cargo_metadata_with_config < C > ( shader_crate : & Path , config : & C ) -> anyhow:: Result < C >
13+ where
14+ C : Default + Serialize + DeserializeOwned ,
15+ {
16+ let from_cargo = from_cargo_metadata ( shader_crate) ?;
17+ let merged = merge ( & from_cargo, config) ?;
18+ Ok ( merged)
8319}
8420
8521#[ cfg( test) ]
8622mod test {
87- use super :: * ;
23+ use std :: { io :: Write as _ , path :: PathBuf } ;
8824
89- use std:: io:: Write as _;
25+ use clap:: Parser as _;
26+ use spirv_builder:: Capability ;
27+
28+ use crate :: {
29+ build:: Build ,
30+ test:: { overwrite_shader_cargo_toml, shader_crate_test_path} ,
31+ } ;
32+
33+ use super :: * ;
9034
9135 #[ test_log:: test]
9236 fn booleans_from_cli ( ) {
93- let shader_crate_path = crate :: test:: shader_crate_test_path ( ) ;
94-
95- let args = Config :: clap_command_with_cargo_config (
96- & shader_crate_path,
97- vec ! [
98- "gpu" . to_owned( ) ,
99- "build" . to_owned( ) ,
100- "--debug" . to_owned( ) ,
101- "--auto-install-rust-toolchain" . to_owned( ) ,
102- ] ,
103- )
104- . unwrap ( ) ;
37+ let shader_crate_path = shader_crate_test_path ( ) ;
38+ let config = Build :: parse_from ( [
39+ "gpu" . as_ref ( ) ,
40+ // "build".as_ref(),
41+ "--shader-crate" . as_ref ( ) ,
42+ shader_crate_path. as_os_str ( ) ,
43+ "--debug" . as_ref ( ) ,
44+ "--auto-install-rust-toolchain" . as_ref ( ) ,
45+ ] ) ;
46+
47+ let args = from_cargo_metadata_with_config ( & shader_crate_path, & config) . unwrap ( ) ;
10548 assert ! ( !args. build. spirv_builder. release) ;
10649 assert ! ( args. install. auto_install_rust_toolchain) ;
10750 }
10851
10952 #[ test_log:: test]
11053 fn booleans_from_cargo ( ) {
111- let shader_crate_path = crate :: test:: shader_crate_test_path ( ) ;
112- let mut file = crate :: test:: overwrite_shader_cargo_toml ( & shader_crate_path) ;
54+ let shader_crate_path = shader_crate_test_path ( ) ;
55+
56+ let mut file = overwrite_shader_cargo_toml ( & shader_crate_path) ;
11357 file. write_all (
11458 [
11559 "[package.metadata.rust-gpu.build]" ,
@@ -122,14 +66,21 @@ mod test {
12266 )
12367 . unwrap ( ) ;
12468
125- let args = Config :: clap_command_with_cargo_config ( & shader_crate_path, vec ! [ ] ) . unwrap ( ) ;
69+ let config = Build :: parse_from ( [
70+ "gpu" . as_ref ( ) ,
71+ // "build".as_ref(),
72+ "--shader-crate" . as_ref ( ) ,
73+ shader_crate_path. as_os_str ( ) ,
74+ ] ) ;
75+
76+ let args = from_cargo_metadata_with_config ( & shader_crate_path, & config) . unwrap ( ) ;
12677 assert ! ( !args. build. spirv_builder. release) ;
12778 assert ! ( args. install. auto_install_rust_toolchain) ;
12879 }
12980
130- fn update_cargo_output_dir ( ) -> std :: path :: PathBuf {
131- let shader_crate_path = crate :: test :: shader_crate_test_path ( ) ;
132- let mut file = crate :: test :: overwrite_shader_cargo_toml ( & shader_crate_path) ;
81+ fn update_cargo_output_dir ( ) -> PathBuf {
82+ let shader_crate_path = shader_crate_test_path ( ) ;
83+ let mut file = overwrite_shader_cargo_toml ( & shader_crate_path) ;
13384 file. write_all (
13485 [
13586 "[package.metadata.rust-gpu.build]" ,
@@ -145,35 +96,41 @@ mod test {
14596 #[ test_log:: test]
14697 fn string_from_cargo ( ) {
14798 let shader_crate_path = update_cargo_output_dir ( ) ;
148-
149- let args = Config :: clap_command_with_cargo_config ( & shader_crate_path, vec ! [ ] ) . unwrap ( ) ;
99+ let config = Build :: parse_from ( [
100+ "gpu" . as_ref ( ) ,
101+ // "build".as_ref(),
102+ "--shader-crate" . as_ref ( ) ,
103+ shader_crate_path. as_os_str ( ) ,
104+ ] ) ;
105+
106+ let args = from_cargo_metadata_with_config ( & shader_crate_path, & config) . unwrap ( ) ;
150107 if cfg ! ( target_os = "windows" ) {
151- assert_eq ! ( args. build. output_dir, std :: path :: Path :: new( "C:/the/moon" ) ) ;
108+ assert_eq ! ( args. build. output_dir, Path :: new( "C:/the/moon" ) ) ;
152109 } else {
153- assert_eq ! ( args. build. output_dir, std :: path :: Path :: new( "/the/moon" ) ) ;
110+ assert_eq ! ( args. build. output_dir, Path :: new( "/the/moon" ) ) ;
154111 }
155112 }
156113
157114 #[ test_log:: test]
158115 fn string_from_cargo_overwritten_by_cli ( ) {
159116 let shader_crate_path = update_cargo_output_dir ( ) ;
160-
161- let args = Config :: clap_command_with_cargo_config (
162- & shader_crate_path,
163- vec ! [
164- "gpu" . to_owned( ) ,
165- "build" . to_owned( ) ,
166- "--output-dir" . to_owned( ) ,
167- "/the/river" . to_owned( ) ,
168- ] ,
169- )
170- . unwrap ( ) ;
171- assert_eq ! ( args. build. output_dir, std:: path:: Path :: new( "/the/river" ) ) ;
117+ let config = Build :: parse_from ( [
118+ "gpu" . as_ref ( ) ,
119+ // "build".as_ref(),
120+ "--shader-crate" . as_ref ( ) ,
121+ shader_crate_path. as_os_str ( ) ,
122+ "--output-dir" . as_ref ( ) ,
123+ "/the/river" . as_ref ( ) ,
124+ ] ) ;
125+
126+ let args = from_cargo_metadata_with_config ( & shader_crate_path, & config) . unwrap ( ) ;
127+ assert_eq ! ( args. build. output_dir, Path :: new( "/the/river" ) ) ;
172128 }
173129
174130 #[ test_log:: test]
175131 fn arrays_from_cargo ( ) {
176132 let shader_crate_path = crate :: test:: shader_crate_test_path ( ) ;
133+
177134 let mut file = crate :: test:: overwrite_shader_cargo_toml ( & shader_crate_path) ;
178135 file. write_all (
179136 [
@@ -185,30 +142,33 @@ mod test {
185142 )
186143 . unwrap ( ) ;
187144
188- let args = Config :: clap_command_with_cargo_config ( & shader_crate_path, vec ! [ ] ) . unwrap ( ) ;
145+ let config = Build :: parse_from ( [
146+ "gpu" . as_ref ( ) ,
147+ // "build".as_ref(),
148+ "--shader-crate" . as_ref ( ) ,
149+ shader_crate_path. as_os_str ( ) ,
150+ ] ) ;
151+
152+ let args = from_cargo_metadata_with_config ( & shader_crate_path, & config) . unwrap ( ) ;
189153 assert_eq ! (
190154 args. build. spirv_builder. capabilities,
191- vec![
192- spirv_builder:: Capability :: AtomicStorage ,
193- spirv_builder:: Capability :: Matrix
194- ]
155+ [ Capability :: AtomicStorage , Capability :: Matrix ]
195156 ) ;
196157 }
197158
198159 #[ test_log:: test]
199160 fn rename_manifest_parse ( ) {
200161 let shader_crate_path = crate :: test:: shader_crate_test_path ( ) ;
201-
202- let args = Config :: clap_command_with_cargo_config (
203- & shader_crate_path,
204- vec ! [
205- "gpu" . to_owned( ) ,
206- "build" . to_owned( ) ,
207- "--manifest-file" . to_owned( ) ,
208- "mymanifest" . to_owned( ) ,
209- ] ,
210- )
211- . unwrap ( ) ;
162+ let config = Build :: parse_from ( [
163+ "gpu" . as_ref ( ) ,
164+ // "build".as_ref(),
165+ "--shader-crate" . as_ref ( ) ,
166+ shader_crate_path. as_os_str ( ) ,
167+ "--manifest-file" . as_ref ( ) ,
168+ "mymanifest" . as_ref ( ) ,
169+ ] ) ;
170+
171+ let args = from_cargo_metadata_with_config ( & shader_crate_path, & config) . unwrap ( ) ;
212172 assert_eq ! ( args. build. manifest_file, "mymanifest" . to_owned( ) ) ;
213173 }
214174}
0 commit comments