Skip to content

Commit 6273f60

Browse files
committed
Switch to tomling crate for reduced dependencies
`tomling` crate was specifically created to provide a simple TOML parser with fewer dependencies and focus on Cargo.toml parsing. Fixes #37.
1 parent e2c5dbe commit 6273f60

File tree

2 files changed

+73
-45
lines changed

2 files changed

+73
-45
lines changed

Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ readme = "./README.md"
1515
rust-version = "1.67.0"
1616

1717
[dependencies]
18-
toml_edit = { version = "0.22.20", default-features = false, features = [
19-
"parse",
20-
] }
18+
tomling = { git = "https://github.com/zeenix/tomling.git", rev = "89d780ba" }
2119

2220
[dev-dependencies]
2321
quote = "1.0.37"

src/lib.rs

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ at your option.
8686
*/
8787

8888
use std::{
89+
cmp::Ordering,
8990
collections::btree_map::{self, BTreeMap},
9091
env, fmt, fs, io,
9192
path::{Path, PathBuf},
@@ -94,7 +95,10 @@ use std::{
9495
time::SystemTime,
9596
};
9697

97-
use toml_edit::{DocumentMut, Item, Table, TomlError};
98+
use tomling::{
99+
cargo::{Dependencies, Dependency, Manifest},
100+
from_str, Error as TomlError,
101+
};
98102

99103
/// Error type used by this crate.
100104
pub enum Error {
@@ -125,10 +129,12 @@ impl fmt::Debug for Error {
125129
impl fmt::Display for Error {
126130
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127131
match self {
128-
Error::NotFound(path) =>
129-
write!(f, "Could not find `Cargo.toml` in manifest dir: `{}`.", path.display()),
130-
Error::CargoManifestDirNotSet =>
131-
f.write_str("`CARGO_MANIFEST_DIR` env variable not set."),
132+
Error::NotFound(path) => {
133+
write!(f, "Could not find `Cargo.toml` in manifest dir: `{}`.", path.display())
134+
},
135+
Error::CargoManifestDirNotSet => {
136+
f.write_str("`CARGO_MANIFEST_DIR` env variable not set.")
137+
},
132138
Error::CouldNotRead { path, .. } => write!(f, "Could not read `{}`.", path.display()),
133139
Error::InvalidToml { .. } => f.write_str("Invalid toml file."),
134140
Error::CrateNotFound { crate_name, path } => write!(
@@ -139,6 +145,7 @@ impl fmt::Display for Error {
139145
),
140146
Error::FailedGettingWorkspaceManifestPath =>
141147
f.write_str("Failed to get the path of the workspace manifest path."),
148+
Error::CargoEnvVariableNotSet => f.write_str("`CARGO` env variable not set."),
142149
}
143150
}
144151
}
@@ -197,8 +204,8 @@ pub fn crate_name(orig_name: &str) -> Result<FoundCrate, Error> {
197204
let workspace_manifest_ts = cargo_toml_timestamp(&workspace_manifest_path)?;
198205

199206
// Timestamp changed, rebuild this cache entry.
200-
if manifest_ts != cache_entry.manifest_ts ||
201-
workspace_manifest_ts != cache_entry.workspace_manifest_ts
207+
if manifest_ts != cache_entry.manifest_ts
208+
|| workspace_manifest_ts != cache_entry.workspace_manifest_ts
202209
{
203210
*cache_entry = read_cargo_toml(
204211
&manifest_path,
@@ -280,10 +287,12 @@ fn read_cargo_toml(
280287
manifest_ts: SystemTime,
281288
workspace_manifest_ts: SystemTime,
282289
) -> Result<CacheEntry, Error> {
283-
let manifest = open_cargo_toml(manifest_path)?;
290+
let content = open_cargo_toml(manifest_path)?;
291+
let manifest = parse_cargo_toml(&content)?;
284292

285293
let workspace_dependencies = if manifest_path != workspace_manifest_path {
286-
let workspace_manifest = open_cargo_toml(workspace_manifest_path)?;
294+
let content = open_cargo_toml(workspace_manifest_path)?;
295+
let workspace_manifest = parse_cargo_toml(&content)?;
287296
extract_workspace_dependencies(&workspace_manifest)?
288297
} else {
289298
extract_workspace_dependencies(&manifest)?
@@ -304,42 +313,41 @@ fn read_cargo_toml(
304313
/// Returns a hash map that maps from dep name to the package name. Dep name
305314
/// and package name can be the same if there doesn't exist any rename.
306315
fn extract_workspace_dependencies(
307-
workspace_toml: &DocumentMut,
316+
workspace_toml: &Manifest,
308317
) -> Result<BTreeMap<String, String>, Error> {
309-
Ok(workspace_dep_tables(&workspace_toml)
318+
Ok(workspace_toml
319+
.workspace()
320+
.and_then(|w| w.dependencies())
321+
.map(|d| d.iter())
310322
.into_iter()
311323
.flatten()
312-
.map(move |(dep_name, dep_value)| {
313-
let pkg_name = dep_value.get("package").and_then(|i| i.as_str()).unwrap_or(dep_name);
324+
.map(move |(dep_name, dep)| {
325+
let pkg_name = dep.package().unwrap_or(dep_name);
314326

315327
(dep_name.to_owned(), pkg_name.to_owned())
316328
})
317329
.collect())
318330
}
319331

320-
/// Return an iterator over all `[workspace.dependencies]`
321-
fn workspace_dep_tables(cargo_toml: &DocumentMut) -> Option<&Table> {
322-
cargo_toml
323-
.get("workspace")
324-
.and_then(|w| w.as_table()?.get("dependencies")?.as_table())
325-
}
326-
327332
/// Make sure that the given crate name is a valid rust identifier.
328333
fn sanitize_crate_name<S: AsRef<str>>(name: S) -> String {
329334
name.as_ref().replace('-', "_")
330335
}
331336

337+
/// Open the given `Cargo.toml` file and read it's content as a string.
338+
fn open_cargo_toml(path: &Path) -> Result<String, Error> {
339+
fs::read_to_string(path).map_err(|e| Error::CouldNotRead { source: e, path: path.into() })
340+
}
341+
332342
/// Open the given `Cargo.toml` and parse it into a hashmap.
333-
fn open_cargo_toml(path: &Path) -> Result<DocumentMut, Error> {
334-
let content = fs::read_to_string(path)
335-
.map_err(|e| Error::CouldNotRead { source: e, path: path.into() })?;
336-
content.parse::<DocumentMut>().map_err(|e| Error::InvalidToml { source: e })
343+
fn parse_cargo_toml(content: &str) -> Result<Manifest<'_>, Error> {
344+
from_str(content).map_err(|e| Error::InvalidToml { source: e })
337345
}
338346

339347
/// Extract all crate names from the given `Cargo.toml` by checking the `dependencies` and
340348
/// `dev-dependencies`.
341349
fn extract_crate_names(
342-
cargo_toml: &DocumentMut,
350+
cargo_toml: &Manifest,
343351
workspace_dependencies: BTreeMap<String, String>,
344352
) -> Result<CrateNames, Error> {
345353
let package_name = extract_package_name(cargo_toml);
@@ -355,16 +363,16 @@ fn extract_crate_names(
355363
});
356364

357365
let dep_tables = dep_tables(cargo_toml).chain(target_dep_tables(cargo_toml));
358-
let dep_pkgs = dep_tables.flatten().filter_map(move |(dep_name, dep_value)| {
359-
let pkg_name = dep_value.get("package").and_then(|i| i.as_str()).unwrap_or(dep_name);
366+
let dep_pkgs = dep_tables.filter_map(move |(dep_name, dep)| {
367+
let pkg_name = dep.package().unwrap_or(dep_name);
360368

361369
// We already handle this via `root_pkg` above.
362370
if package_name.as_ref().map_or(false, |n| *n == pkg_name) {
363-
return None
371+
return None;
364372
}
365373

366374
// Check if this is a workspace dependency.
367-
let workspace = dep_value.get("workspace").and_then(|w| w.as_bool()).unwrap_or_default();
375+
let workspace = dep.workspace().unwrap_or_default();
368376

369377
let pkg_name = workspace
370378
.then(|| workspace_dependencies.get(pkg_name).map(|p| p.as_ref()))
@@ -379,22 +387,42 @@ fn extract_crate_names(
379387
Ok(root_pkg.into_iter().chain(dep_pkgs).collect())
380388
}
381389

382-
fn extract_package_name(cargo_toml: &DocumentMut) -> Option<&str> {
383-
cargo_toml.get("package")?.get("name")?.as_str()
390+
fn extract_package_name<'c>(cargo_toml: &'c Manifest) -> Option<&'c str> {
391+
cargo_toml.package().map(|p| p.name())
384392
}
385393

386-
fn target_dep_tables(cargo_toml: &DocumentMut) -> impl Iterator<Item = &Table> {
387-
cargo_toml.get("target").into_iter().filter_map(Item::as_table).flat_map(|t| {
388-
t.iter().map(|(_, value)| value).filter_map(Item::as_table).flat_map(dep_tables)
394+
fn target_dep_tables<'c>(
395+
cargo_toml: &'c Manifest,
396+
) -> impl Iterator<Item = (&'c str, &'c Dependency<'c>)> {
397+
cargo_toml.targets().into_iter().flat_map(|t| {
398+
t.iter()
399+
.map(|(_, t)| t)
400+
.flat_map(|t| combined_dep_tables(t.dependencies(), t.dev_dependencies()))
389401
})
390402
}
391403

392-
fn dep_tables(table: &Table) -> impl Iterator<Item = &Table> {
393-
table
394-
.get("dependencies")
404+
fn dep_tables<'c>(cargo_toml: &'c Manifest) -> impl Iterator<Item = (&'c str, &'c Dependency<'c>)> {
405+
combined_dep_tables(cargo_toml.dependencies(), cargo_toml.dev_dependencies())
406+
}
407+
408+
fn combined_dep_tables<'c>(
409+
deps: Option<&'c Dependencies<'c>>,
410+
dev_deps: Option<&'c Dependencies<'c>>,
411+
) -> impl Iterator<Item = (&'c str, &'c Dependency<'c>)> {
412+
let mut deps = deps
395413
.into_iter()
396-
.chain(table.get("dev-dependencies"))
397-
.filter_map(Item::as_table)
414+
.flat_map(|deps| deps.iter())
415+
.chain(dev_deps.into_iter().flat_map(|deps| deps.iter()))
416+
.collect::<Vec<_>>();
417+
// Ensure renames (i-e deps with `package` key) are listed the last.
418+
deps.sort_by(|(_, a), (_, b)| match (a.package(), b.package()) {
419+
(Some(a), Some(b)) => a.cmp(b),
420+
(Some(_), None) => Ordering::Greater,
421+
(None, Some(_)) => Ordering::Less,
422+
(None, None) => Ordering::Equal,
423+
});
424+
425+
deps.into_iter()
398426
}
399427

400428
#[cfg(test)]
@@ -410,16 +438,18 @@ mod tests {
410438
) => {
411439
#[test]
412440
fn $name() {
413-
let cargo_toml = $cargo_toml.parse::<DocumentMut>()
441+
let cargo_toml = from_str($cargo_toml)
414442
.expect("Parses `Cargo.toml`");
415-
let workspace_cargo_toml = $workspace_toml.parse::<DocumentMut>()
443+
let workspace_cargo_toml = from_str($workspace_toml)
416444
.expect("Parses workspace `Cargo.toml`");
417445

418446
let workspace_deps = extract_workspace_dependencies(&workspace_cargo_toml)
419447
.expect("Extracts workspace dependencies");
420448

421449
match extract_crate_names(&cargo_toml, workspace_deps)
422-
.map(|mut map| map.remove("my_crate"))
450+
.map(|mut map| {
451+
map.remove("my_crate")
452+
})
423453
{
424454
$( $result )* => (),
425455
o => panic!("Invalid result: {:?}", o),

0 commit comments

Comments
 (0)