Skip to content

Commit 77185b6

Browse files
committed
Trying to refactor config & metadata modules of cargo-gpu
1 parent f8850ce commit 77185b6

File tree

8 files changed

+368
-318
lines changed

8 files changed

+368
-318
lines changed

crates/cargo-gpu/src/build.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use cargo_gpu_build::{
99
spirv_builder::{CompileResult, ModuleResult, SpirvBuilder},
1010
};
1111

12-
use crate::{install::Install, linkage::Linkage, user_consent::ask_for_user_consent};
12+
use crate::{install::InstallArgs, linkage::Linkage, user_consent::ask_for_user_consent};
1313

1414
/// Args for just a build.
1515
#[derive(Debug, Clone, clap::Parser, serde::Deserialize, serde::Serialize)]
@@ -47,12 +47,12 @@ impl Default for BuildArgs {
4747
}
4848

4949
/// `cargo build` subcommands.
50-
#[derive(Clone, Debug, clap::Parser, serde::Deserialize, serde::Serialize)]
50+
#[derive(Clone, Debug, Default, clap::Parser, serde::Deserialize, serde::Serialize)]
5151
#[non_exhaustive]
5252
pub struct Build {
5353
/// CLI args for install the `rust-gpu` compiler and components.
5454
#[clap(flatten)]
55-
pub install: Install,
55+
pub install: InstallArgs,
5656

5757
/// CLI args for configuring the build of the shader.
5858
#[clap(flatten)]
@@ -195,22 +195,25 @@ impl Build {
195195
mod test {
196196
use clap::Parser as _;
197197

198-
use crate::{Cli, Command};
198+
use crate::{
199+
test::{shader_crate_template_path, tests_teardown},
200+
Cli, Command,
201+
};
199202

200203
#[test_log::test]
201204
fn builder_from_params() {
202-
crate::test::tests_teardown();
205+
tests_teardown();
203206

204-
let shader_crate_path = crate::test::shader_crate_template_path();
207+
let shader_crate_path = shader_crate_template_path();
205208
let output_dir = shader_crate_path.join("shaders");
206209

207210
let args = [
208-
"target/debug/cargo-gpu",
209-
"build",
210-
"--shader-crate",
211-
&format!("{}", shader_crate_path.display()),
212-
"--output-dir",
213-
&format!("{}", output_dir.display()),
211+
"target/debug/cargo-gpu".as_ref(),
212+
"build".as_ref(),
213+
"--shader-crate".as_ref(),
214+
shader_crate_path.as_os_str(),
215+
"--output-dir".as_ref(),
216+
output_dir.as_os_str(),
214217
];
215218
if let Cli {
216219
command: Command::Build(build),

crates/cargo-gpu/src/config.rs

Lines changed: 90 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,59 @@
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:\ndefaults: {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)]
8622
mod 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

Comments
 (0)