Skip to content

Commit 021073e

Browse files
tmvkrpxl0Firestar99
authored andcommitted
replace cargo tree with cargo metadata
1 parent f5660df commit 021073e

File tree

6 files changed

+110
-145
lines changed

6 files changed

+110
-145
lines changed

Cargo.lock

Lines changed: 42 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ serde_json = "1.0.132"
2828
toml = "0.8.19"
2929
tempdir = "0.3.7"
3030
test-log = "0.2.16"
31+
cargo_metadata = "0.19.2"
3132

3233
[workspace.lints.rust]
3334
missing_docs = "warn"

crates/cargo-gpu/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ default-run = "cargo-gpu"
1111
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1212

1313
[dependencies]
14+
cargo_metadata.workspace = true
1415
anyhow.workspace = true
1516
spirv-builder = { workspace = true, features = ["clap"] }
1617
clap.workspace = true

crates/cargo-gpu/src/install.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,12 @@ impl Install {
104104
{
105105
let version_spec = match &spirv_cli.source {
106106
SpirvSource::CratesIO(version) => {
107-
format!("version = \"{}\"", version.replace('v', ""))
107+
format!("version = \"{}\"", version)
108108
}
109109
SpirvSource::Git { url, rev } => format!("git = \"{url}\"\nrev = \"{rev}\""),
110-
SpirvSource::Path((path, version)) => format!(
111-
"path = \"{path}\"\nversion = \"{}\"",
112-
version.replace('v', "")
113-
),
110+
SpirvSource::Path((path, version)) => {
111+
format!("path = \"{path}\"\nversion = \"{}\"", version)
112+
}
114113
};
115114
let cargo_toml = format!(
116115
r#"

crates/cargo-gpu/src/spirv_cli.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
44
use std::io::Write as _;
55

6-
use anyhow::Context as _;
7-
86
use crate::spirv_source::SpirvSource;
7+
use anyhow::Context as _;
8+
use cargo_metadata::semver::Version;
99

1010
/// `Cargo.lock` manifest version 4 became the default in Rust 1.83.0. Conflicting manifest
1111
/// versions between the workspace and the shader crate, can cause problems.
@@ -86,7 +86,7 @@ impl SpirvCli {
8686

8787
let mut maybe_spirv_source: Option<SpirvSource> = None;
8888
if let Some(rust_gpu_version) = maybe_rust_gpu_version {
89-
let mut source = SpirvSource::CratesIO(rust_gpu_version.clone());
89+
let mut source = SpirvSource::CratesIO(Version::parse(&rust_gpu_version)?);
9090
if let Some(rust_gpu_source) = maybe_rust_gpu_source {
9191
source = SpirvSource::Git {
9292
url: rust_gpu_source,
@@ -501,7 +501,7 @@ mod test {
501501
.map(std::string::ToString::to_string)
502502
.unwrap();
503503
assert_eq!(
504-
"https___github_com_Rust-GPU_rust-gpu+82a0f69+nightly-2024-04-24",
504+
"https___github_com_Rust-GPU_rust-gpu+82a0f69008414f51d59184763146caa6850ac588+nightly-2024-04-24",
505505
&name
506506
);
507507
}

crates/cargo-gpu/src/spirv_source.rs

Lines changed: 58 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
//! version. Then with that we `git checkout` the `rust-gpu` repo that corresponds to that version.
55
//! From there we can look at the source code to get the required Rust toolchain.
66
7-
use anyhow::Context as _;
7+
use anyhow::{anyhow, Context as _};
8+
use cargo_metadata::semver::Version;
9+
use cargo_metadata::{MetadataCommand, Package};
810
use std::path::{Path, PathBuf};
911

1012
/// The canonical `rust-gpu` URI
@@ -17,9 +19,7 @@ const RUST_GPU_REPO: &str = "https://github.com/Rust-GPU/rust-gpu";
1719
pub enum SpirvSource {
1820
/// If the shader specifies a simple version like `spirv-std = "0.9.0"` then the source of
1921
/// `rust-gpu` is the conventional crates.io version.
20-
///
21-
/// `String` is the simple version like, "0.9.0"
22-
CratesIO(String),
22+
CratesIO(Version),
2323
/// If the shader specifies a version like:
2424
/// `spirv-std = { git = "https://github.com..." ... }`
2525
/// then the source of `rust-gpu` is `Git`.
@@ -32,7 +32,7 @@ pub enum SpirvSource {
3232
/// If the shader specifies a version like:
3333
/// `spirv-std = { path = "/path/to/rust-gpu" ... }`
3434
/// then the source of `rust-gpu` is `Path`.
35-
Path((String, String)),
35+
Path((String, Version)),
3636
}
3737

3838
impl core::fmt::Display for SpirvSource {
@@ -42,7 +42,7 @@ impl core::fmt::Display for SpirvSource {
4242
)]
4343
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
4444
match self {
45-
Self::CratesIO(version) => f.write_str(version),
45+
Self::CratesIO(version) => version.fmt(f),
4646
Self::Git { url, rev } => f.write_str(&format!("{url}+{rev}")),
4747
Self::Path((a, b)) => f.write_str(&format!("{a}+{b}")),
4848
}
@@ -198,123 +198,72 @@ impl SpirvSource {
198198
let canonical_shader_path = Self::shader_crate_path_canonical(shader_crate_path)?;
199199

200200
log::debug!(
201-
"Running `cargo tree` on {}",
201+
"Running `cargo metadata` on {}",
202202
canonical_shader_path.display()
203203
);
204-
let output_cargo_tree = std::process::Command::new("cargo")
205-
.current_dir(canonical_shader_path.clone())
206-
.args(["tree", "--workspace", "--prefix", "none"])
207-
.output()?;
208-
anyhow::ensure!(
209-
output_cargo_tree.status.success(),
210-
format!(
211-
"could not query shader's `Cargo.toml` for `spirv-std` dependency: {}",
212-
String::from_utf8(output_cargo_tree.stderr)?
213-
)
214-
);
215-
let cargo_tree_string = String::from_utf8_lossy(&output_cargo_tree.stdout);
216-
217-
let maybe_spirv_std_def = cargo_tree_string
218-
.lines()
219-
.find(|line| line.contains("spirv-std"));
220-
log::trace!(" found {maybe_spirv_std_def:?}");
221-
222-
let Some(spirv_std_def) = maybe_spirv_std_def else {
223-
anyhow::bail!("`spirv-std` not found in shader's `Cargo.toml` at {canonical_shader_path:?}:\n{cargo_tree_string}");
204+
let metadata = MetadataCommand::new()
205+
.current_dir(&canonical_shader_path)
206+
.exec()?;
207+
208+
let Some(spirv_std_package) = metadata
209+
.packages
210+
.iter()
211+
.find(|package| package.name.eq("spirv-std"))
212+
else {
213+
anyhow::bail!(
214+
"`spirv-std` not found in shader's `Cargo.toml` at {canonical_shader_path:?}"
215+
);
224216
};
217+
log::trace!(" found {spirv_std_package:?}");
225218

226-
Self::parse_spirv_std_source_and_version(spirv_std_def)
219+
Ok(Self::parse_spirv_std_source_and_version(spirv_std_package)?)
227220
}
228221

229222
/// Parse a string like:
230223
/// `spirv-std v0.9.0 (https://github.com/Rust-GPU/rust-gpu?rev=54f6978c#54f6978c) (*)`
231224
/// Which would return:
232225
/// `SpirvSource::Git("https://github.com/Rust-GPU/rust-gpu", "54f6978c")`
233-
fn parse_spirv_std_source_and_version(spirv_std_def: &str) -> anyhow::Result<Self> {
234-
log::trace!("parsing spirv-std source and version from def: '{spirv_std_def}'");
235-
let parts: Vec<String> = spirv_std_def.split_whitespace().map(String::from).collect();
236-
let version = parts
237-
.get(1)
238-
.context("Couldn't find `spirv_std` version in shader crate")?
239-
.to_owned();
240-
let mut source = Self::CratesIO(version.clone());
241-
242-
if parts.len() > 2 {
243-
let mut source_string = parts
244-
.get(2)
245-
.context("Couldn't get Uri from dependency string")?
246-
.to_owned();
247-
source_string = source_string.replace(['(', ')'], "");
248-
249-
// Unfortunately Uri ignores the fragment/hash portion of the Uri.
250-
//
251-
// There's been a ticket open for years:
252-
// <https://github.com/hyperium/http/issues/127>
253-
//
254-
// So here we'll parse the fragment out of the source string by hand
255-
let uri = source_string.parse::<http::Uri>()?;
256-
let maybe_hash = if source_string.contains('#') {
257-
let mut splits = source_string.split('#');
258-
splits.next_back().map(std::borrow::ToOwned::to_owned)
259-
} else {
260-
None
261-
};
262-
if uri.scheme().is_some() {
263-
source = Self::parse_git_source(version, &uri, maybe_hash)?;
264-
} else {
265-
source = Self::Path((source_string, version));
266-
}
267-
}
268-
269-
log::debug!("Parsed `rust-gpu` source and version: {source:?}");
270-
271-
Ok(source)
272-
}
273-
274-
/// Parse a Git source like: `https://github.com/Rust-GPU/rust-gpu?rev=54f6978c#54f6978c`
275-
fn parse_git_source(
276-
version: String,
277-
uri: &http::Uri,
278-
fragment: Option<String>,
279-
) -> anyhow::Result<Self> {
226+
fn parse_spirv_std_source_and_version(spirv_std_package: &Package) -> anyhow::Result<Self> {
280227
log::trace!(
281-
"parsing git source from version: '{version}' and uri: '{uri}' and fragment: {}",
282-
fragment.as_deref().unwrap_or("?")
228+
"parsing spirv-std source and version from package: '{:?}'",
229+
spirv_std_package
283230
);
284-
let repo = format!(
285-
"{}://{}{}",
286-
uri.scheme().context("Couldn't parse scheme from Uri")?,
287-
uri.host().context("Couldn't parse host from Uri")?,
288-
uri.path()
289-
);
290-
291-
let rev = Self::parse_git_revision(uri.query(), fragment, version);
292231

293-
Ok(Self::Git { url: repo, rev })
294-
}
295-
296-
/// Decide the Git revision to use.
297-
fn parse_git_revision(
298-
maybe_query: Option<&str>,
299-
maybe_fragment: Option<String>,
300-
version: String,
301-
) -> String {
302-
let marker = "rev=";
303-
let maybe_sane_query = maybe_query.and_then(|query| {
304-
// TODO: This might seem a little crude, but it saves adding a whole query parsing dependency.
305-
let sanity_check = query.contains(marker) && query.split('=').count() == 2;
306-
sanity_check.then_some(query)
307-
});
308-
309-
if let Some(query) = maybe_sane_query {
310-
return query.replace(marker, "");
311-
}
232+
let result = match &spirv_std_package.source {
233+
Some(source) => {
234+
let is_git = source.repr.starts_with("git+");
235+
let is_crates_io = source.is_crates_io();
236+
237+
match (is_git, is_crates_io) {
238+
(true, true) => unreachable!(),
239+
(true, false) => {
240+
let link = &source.repr[4..];
241+
let sharp_index = link.find('#').ok_or(anyhow!(
242+
"Git url of spirv-std package does not contain revision!"
243+
))?;
244+
let question_mark_index = link.find('?').ok_or(anyhow!(
245+
"Git url of spirv-std package does not contain revision!"
246+
))?;
247+
let url = link[..question_mark_index].to_string();
248+
let rev = link[sharp_index + 1..].to_string();
249+
Self::Git { url, rev }
250+
}
251+
(false, true) => Self::CratesIO(spirv_std_package.version.clone()),
252+
(false, false) => {
253+
anyhow::bail!("Metadata of spirv-std package uses unknown url format!")
254+
}
255+
}
256+
}
257+
None => {
258+
let path = &spirv_std_package.manifest_path;
259+
let version = &spirv_std_package.version;
260+
Self::Path((path.to_string(), version.clone()))
261+
}
262+
};
312263

313-
if let Some(fragment) = maybe_fragment {
314-
return fragment;
315-
}
264+
log::debug!("Parsed `rust-gpu` source and version: {result:?}");
316265

317-
version
266+
Ok(result)
318267
}
319268

320269
/// `git clone` the `rust-gpu` repo. We use it to get the required Rust toolchain to compile
@@ -370,34 +319,7 @@ mod test {
370319
source,
371320
SpirvSource::Git {
372321
url: "https://github.com/Rust-GPU/rust-gpu".to_owned(),
373-
rev: "82a0f69".to_owned()
374-
}
375-
);
376-
}
377-
378-
#[test_log::test]
379-
fn parsing_spirv_std_dep_for_git_source() {
380-
let definition =
381-
"spirv-std v9.9.9 (https://github.com/Rust-GPU/rust-gpu?rev=82a0f69#82a0f69) (*)";
382-
let source = SpirvSource::parse_spirv_std_source_and_version(definition).unwrap();
383-
assert_eq!(
384-
source,
385-
SpirvSource::Git {
386-
url: "https://github.com/Rust-GPU/rust-gpu".to_owned(),
387-
rev: "82a0f69".to_owned()
388-
}
389-
);
390-
}
391-
392-
#[test_log::test]
393-
fn parsing_spirv_std_dep_for_git_source_hash() {
394-
let definition = "spirv-std v9.9.9 (https://github.com/Rust-GPU/rust-gpu#82a0f69) (*)";
395-
let source = SpirvSource::parse_spirv_std_source_and_version(definition).unwrap();
396-
assert_eq!(
397-
source,
398-
SpirvSource::Git {
399-
url: "https://github.com/Rust-GPU/rust-gpu".to_owned(),
400-
rev: "82a0f69".to_owned()
322+
rev: "82a0f69008414f51d59184763146caa6850ac588".to_owned()
401323
}
402324
);
403325
}

0 commit comments

Comments
 (0)