Skip to content

Commit 56b33fb

Browse files
authored
Merge pull request #183 from rust-secure-code/add-resolverver
Add `resolverver` crate
2 parents 77bc08b + 9702f03 commit 56b33fb

File tree

9 files changed

+449
-6
lines changed

9 files changed

+449
-6
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ members = [
55
"auditable-extract",
66
"auditable-serde",
77
"cargo-auditable",
8-
"auditable-cyclonedx", "auditable2cdx",
8+
"auditable-cyclonedx",
9+
"auditable2cdx",
10+
"resolverver",
911
]
1012

1113
# Config for 'cargo dist'

resolverver/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "resolverver"
3+
version = "0.1.0"
4+
edition = "2021"
5+
description = "Determines the Cargo resolver version for a workspace"
6+
license = "MIT OR Apache-2.0"
7+
authors = ["Sergey \"Shnatsel\" Davidoff <[email protected]>"]
8+
repository = "https://github.com/rust-secure-code/cargo-auditable"
9+
10+
[dependencies]
11+
serde = { version = "1.0.217", features = ["derive"] }
12+
toml = { version = "0.8.19", default-features = false, features = ["parse"] }
13+
14+
[dev-dependencies]
15+
cargo_metadata = "0.18.1"
16+

resolverver/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# resolverver: Get the Cargo resolver version
2+
3+
Knowing the [Cargo resolver version](https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions)
4+
used in a given workspace is important to some tooling that interfaces with Cargo.
5+
You'll know it when you need it.
6+
7+
### Usage
8+
9+
Since resolver version is a global property for the entire workspace,
10+
it is important that you read the **workspace** Cargo.toml rather than
11+
the Cargo.toml of an individual package.
12+
13+
Here's how to locate it using the [`cargo_metadata`](https://crates.io/crates/cargo_metadata) crate:
14+
15+
```rust
16+
use cargo_metadata;
17+
use resolverver;
18+
19+
// Locate and load the Cargo.toml for the workspace
20+
let metadata = cargo_metadata::MetadataCommand::new().no_deps().exec().unwrap();
21+
let toml = std::fs::read_to_string(metadata.workspace_root.join("Cargo.toml")).unwrap();
22+
23+
// Deduce the resolver version in use
24+
let resolver_version = resolverver::from_toml(&toml).unwrap();
25+
println!("Resolver version in this workspace is: {resolver_version:?}");
26+
```
27+
28+
### Caveats
29+
30+
Cargo has a config option [`resolver.incompatible-rust-versions`](https://doc.rust-lang.org/cargo/reference/config.html#resolverincompatible-rust-versions)
31+
that may enable V3 resolver even when everything else would indicate that V2 resolver should be used.
32+
33+
The only difference between V2 and V3 resolvers is the selected versions of some dependencies.
34+
As long as you're letting Cargo generate the Cargo.lock file and aren't doing version resolution yourself,
35+
this distinction doesn't matter.
36+
37+
If this does matter for your use case, you can use [`cargo-config2`](https://crates.io/crates/cargo-config2)
38+
to read and resolve Cargo configuration.

resolverver/src/error.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use std::fmt;
2+
3+
#[derive(Debug, Clone, PartialEq, Eq)]
4+
pub enum UnrecognizedValue {
5+
UnknownResolver(String),
6+
UnknownEdition(String),
7+
}
8+
9+
impl std::fmt::Display for UnrecognizedValue {
10+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11+
match self {
12+
UnrecognizedValue::UnknownResolver(resolver) => {
13+
write!(f, "Unrecognized resolver version: {}", resolver)
14+
}
15+
UnrecognizedValue::UnknownEdition(edition) => {
16+
write!(f, "Unrecognized Rust edition: {}", edition)
17+
}
18+
}
19+
}
20+
}
21+
22+
impl std::error::Error for UnrecognizedValue {}
23+
24+
#[derive(Debug, Clone, PartialEq, Eq)]
25+
pub enum Error {
26+
UnrecognizedValue(UnrecognizedValue),
27+
TomlParseError(toml::de::Error), // Adjust for the specific Serde library in use (e.g., `serde_json` or `serde_yaml`)
28+
}
29+
30+
impl fmt::Display for Error {
31+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32+
match self {
33+
Error::UnrecognizedValue(msg) => write!(f, "{}", msg),
34+
Error::TomlParseError(err) => write!(f, "Failed to parse Cargo.toml: {}", err),
35+
}
36+
}
37+
}
38+
39+
impl std::error::Error for Error {
40+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
41+
match self {
42+
Error::UnrecognizedValue(err) => Some(err),
43+
Error::TomlParseError(err) => Some(err),
44+
}
45+
}
46+
}
47+
48+
impl From<UnrecognizedValue> for Error {
49+
fn from(value: UnrecognizedValue) -> Self {
50+
Error::UnrecognizedValue(value)
51+
}
52+
}
53+
54+
impl From<toml::de::Error> for Error {
55+
fn from(err: toml::de::Error) -> Self {
56+
Error::TomlParseError(err)
57+
}
58+
}

resolverver/src/fields.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use crate::{error::UnrecognizedValue, Resolver};
2+
3+
#[derive(Debug, Clone, PartialEq, Eq)]
4+
pub(crate) struct TomlFields {
5+
pub resolver: Option<String>,
6+
pub edition: Option<String>,
7+
}
8+
9+
impl TomlFields {
10+
pub fn resolver(self) -> Result<Resolver, UnrecognizedValue> {
11+
if let Some(ver) = self.resolver {
12+
match ver.as_str() {
13+
"1" => Ok(Resolver::V1),
14+
"2" => Ok(Resolver::V2),
15+
"3" => Ok(Resolver::V3),
16+
_ => Err(UnrecognizedValue::UnknownResolver(ver)),
17+
}
18+
} else if let Some(ed) = self.edition {
19+
match ed.as_str() {
20+
"2015" => Ok(Resolver::V1),
21+
"2018" | "2021" => Ok(Resolver::V2),
22+
"2024" => Ok(Resolver::V3),
23+
_ => Err(UnrecognizedValue::UnknownEdition(ed)),
24+
}
25+
} else {
26+
Ok(Resolver::V1)
27+
}
28+
}
29+
}

resolverver/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![doc = include_str!("../README.md")]
2+
3+
mod error;
4+
mod fields;
5+
mod raw_fields;
6+
mod resolver;
7+
8+
pub use error::Error;
9+
use raw_fields::RawTomlFields;
10+
pub use resolver::Resolver;
11+
12+
pub fn from_toml(workspace_root_cargo_toml: &str) -> Result<Resolver, crate::Error> {
13+
let parsed: RawTomlFields = toml::from_str(workspace_root_cargo_toml)?;
14+
Ok(parsed.resolve().resolver()?)
15+
}

0 commit comments

Comments
 (0)