Skip to content

Commit b5d4f89

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 b5d4f89

File tree

2 files changed

+67
-41
lines changed

2 files changed

+67
-41
lines changed

Cargo.toml

+1-3
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 = "0e859855" }
2119

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

src/lib.rs

+66-38
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,8 +129,9 @@ 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()),
132+
Error::NotFound(path) => {
133+
write!(f, "Could not find `Cargo.toml` in manifest dir: `{}`.", path.display())
134+
},
130135
Error::CargoManifestDirNotSet =>
131136
f.write_str("`CARGO_MANIFEST_DIR` env variable not set."),
132137
Error::CouldNotRead { path, .. } => write!(f, "Could not read `{}`.", path.display()),
@@ -280,10 +285,12 @@ fn read_cargo_toml(
280285
manifest_ts: SystemTime,
281286
workspace_manifest_ts: SystemTime,
282287
) -> Result<CacheEntry, Error> {
283-
let manifest = open_cargo_toml(manifest_path)?;
288+
let content = open_cargo_toml(manifest_path)?;
289+
let manifest = parse_cargo_toml(&content)?;
284290

285291
let workspace_dependencies = if manifest_path != workspace_manifest_path {
286-
let workspace_manifest = open_cargo_toml(workspace_manifest_path)?;
292+
let content = open_cargo_toml(workspace_manifest_path)?;
293+
let workspace_manifest = parse_cargo_toml(&content)?;
287294
extract_workspace_dependencies(&workspace_manifest)?
288295
} else {
289296
extract_workspace_dependencies(&manifest)?
@@ -304,42 +311,41 @@ fn read_cargo_toml(
304311
/// Returns a hash map that maps from dep name to the package name. Dep name
305312
/// and package name can be the same if there doesn't exist any rename.
306313
fn extract_workspace_dependencies(
307-
workspace_toml: &DocumentMut,
314+
workspace_toml: &Manifest,
308315
) -> Result<BTreeMap<String, String>, Error> {
309-
Ok(workspace_dep_tables(&workspace_toml)
316+
Ok(workspace_toml
317+
.workspace()
318+
.and_then(|w| w.dependencies())
319+
.map(|d| d.iter())
310320
.into_iter()
311321
.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);
322+
.map(move |(dep_name, dep)| {
323+
let pkg_name = dep.package().unwrap_or(dep_name);
314324

315325
(dep_name.to_owned(), pkg_name.to_owned())
316326
})
317327
.collect())
318328
}
319329

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-
327330
/// Make sure that the given crate name is a valid rust identifier.
328331
fn sanitize_crate_name<S: AsRef<str>>(name: S) -> String {
329332
name.as_ref().replace('-', "_")
330333
}
331334

335+
/// Open the given `Cargo.toml` file and read it's content as a string.
336+
fn open_cargo_toml(path: &Path) -> Result<String, Error> {
337+
fs::read_to_string(path).map_err(|e| Error::CouldNotRead { source: e, path: path.into() })
338+
}
339+
332340
/// 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 })
341+
fn parse_cargo_toml(content: &str) -> Result<Manifest<'_>, Error> {
342+
from_str(content).map_err(|e| Error::InvalidToml { source: e })
337343
}
338344

339345
/// Extract all crate names from the given `Cargo.toml` by checking the `dependencies` and
340346
/// `dev-dependencies`.
341347
fn extract_crate_names(
342-
cargo_toml: &DocumentMut,
348+
cargo_toml: &Manifest,
343349
workspace_dependencies: BTreeMap<String, String>,
344350
) -> Result<CrateNames, Error> {
345351
let package_name = extract_package_name(cargo_toml);
@@ -355,16 +361,16 @@ fn extract_crate_names(
355361
});
356362

357363
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);
364+
let dep_pkgs = dep_tables.filter_map(move |(dep_name, dep)| {
365+
let pkg_name = dep.package().unwrap_or(dep_name);
360366

361367
// We already handle this via `root_pkg` above.
362368
if package_name.as_ref().map_or(false, |n| *n == pkg_name) {
363-
return None
369+
return None;
364370
}
365371

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

369375
let pkg_name = workspace
370376
.then(|| workspace_dependencies.get(pkg_name).map(|p| p.as_ref()))
@@ -379,22 +385,42 @@ fn extract_crate_names(
379385
Ok(root_pkg.into_iter().chain(dep_pkgs).collect())
380386
}
381387

382-
fn extract_package_name(cargo_toml: &DocumentMut) -> Option<&str> {
383-
cargo_toml.get("package")?.get("name")?.as_str()
388+
fn extract_package_name<'c>(cargo_toml: &'c Manifest) -> Option<&'c str> {
389+
cargo_toml.package().map(|p| p.name())
384390
}
385391

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)
392+
fn target_dep_tables<'c>(
393+
cargo_toml: &'c Manifest,
394+
) -> impl Iterator<Item = (&'c str, &'c Dependency<'c>)> {
395+
cargo_toml.targets().into_iter().flat_map(|t| {
396+
t.iter()
397+
.map(|(_, t)| t)
398+
.flat_map(|t| combined_dep_tables(t.dependencies(), t.dev_dependencies()))
389399
})
390400
}
391401

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

400426
#[cfg(test)]
@@ -410,16 +436,18 @@ mod tests {
410436
) => {
411437
#[test]
412438
fn $name() {
413-
let cargo_toml = $cargo_toml.parse::<DocumentMut>()
439+
let cargo_toml = from_str($cargo_toml)
414440
.expect("Parses `Cargo.toml`");
415-
let workspace_cargo_toml = $workspace_toml.parse::<DocumentMut>()
441+
let workspace_cargo_toml = from_str($workspace_toml)
416442
.expect("Parses workspace `Cargo.toml`");
417443

418444
let workspace_deps = extract_workspace_dependencies(&workspace_cargo_toml)
419445
.expect("Extracts workspace dependencies");
420446

421447
match extract_crate_names(&cargo_toml, workspace_deps)
422-
.map(|mut map| map.remove("my_crate"))
448+
.map(|mut map| {
449+
map.remove("my_crate")
450+
})
423451
{
424452
$( $result )* => (),
425453
o => panic!("Invalid result: {:?}", o),

0 commit comments

Comments
 (0)