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.
14
3
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 ;
21
5
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 } ;
38
7
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} ;
80
9
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)
83
19
}
84
20
85
21
#[ cfg( test) ]
86
22
mod test {
87
- use super :: * ;
23
+ use std :: { io :: Write as _ , path :: PathBuf } ;
88
24
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 :: * ;
90
34
91
35
#[ test_log:: test]
92
36
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 ( ) ;
105
48
assert ! ( !args. build. spirv_builder. release) ;
106
49
assert ! ( args. install. auto_install_rust_toolchain) ;
107
50
}
108
51
109
52
#[ test_log:: test]
110
53
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) ;
113
57
file. write_all (
114
58
[
115
59
"[package.metadata.rust-gpu.build]" ,
@@ -122,14 +66,21 @@ mod test {
122
66
)
123
67
. unwrap ( ) ;
124
68
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 ( ) ;
126
77
assert ! ( !args. build. spirv_builder. release) ;
127
78
assert ! ( args. install. auto_install_rust_toolchain) ;
128
79
}
129
80
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) ;
133
84
file. write_all (
134
85
[
135
86
"[package.metadata.rust-gpu.build]" ,
@@ -145,35 +96,41 @@ mod test {
145
96
#[ test_log:: test]
146
97
fn string_from_cargo ( ) {
147
98
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 ( ) ;
150
107
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" ) ) ;
152
109
} 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" ) ) ;
154
111
}
155
112
}
156
113
157
114
#[ test_log:: test]
158
115
fn string_from_cargo_overwritten_by_cli ( ) {
159
116
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" ) ) ;
172
128
}
173
129
174
130
#[ test_log:: test]
175
131
fn arrays_from_cargo ( ) {
176
132
let shader_crate_path = crate :: test:: shader_crate_test_path ( ) ;
133
+
177
134
let mut file = crate :: test:: overwrite_shader_cargo_toml ( & shader_crate_path) ;
178
135
file. write_all (
179
136
[
@@ -185,30 +142,33 @@ mod test {
185
142
)
186
143
. unwrap ( ) ;
187
144
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 ( ) ;
189
153
assert_eq ! (
190
154
args. build. spirv_builder. capabilities,
191
- vec![
192
- spirv_builder:: Capability :: AtomicStorage ,
193
- spirv_builder:: Capability :: Matrix
194
- ]
155
+ [ Capability :: AtomicStorage , Capability :: Matrix ]
195
156
) ;
196
157
}
197
158
198
159
#[ test_log:: test]
199
160
fn rename_manifest_parse ( ) {
200
161
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 ( ) ;
212
172
assert_eq ! ( args. build. manifest_file, "mymanifest" . to_owned( ) ) ;
213
173
}
214
174
}
0 commit comments