Skip to content

Commit 119d378

Browse files
committed
Eliminate reliance on cargo-sort
1 parent 9199636 commit 119d378

5 files changed

Lines changed: 144 additions & 8 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ jobs:
9696

9797
- uses: taiki-e/install-action@v2
9898
with:
99-
tool: cargo-sort, cargo-udeps
99+
tool: cargo-udeps
100100

101101
# smoelius: I expect this list to grow.
102102
- name: Install tools

Cargo.lock

Lines changed: 69 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
@@ -55,6 +55,7 @@ subprocess = "0.2"
5555
syn = { version = "2.0", features = ["full", "parsing", "visit", "visit-mut"] }
5656
tempfile = "3.23"
5757
termsize = "0.1"
58+
toml_edit = "0.23"
5859
walkdir = "2.5"
5960
xshell = "0.2"
6061

test-fuzz/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ semver = { workspace = true }
2929
serde_json = { workspace = true }
3030
similar-asserts = { workspace = true }
3131
tempfile = { workspace = true }
32+
toml_edit = { workspace = true }
3233
walkdir = { workspace = true }
3334

3435
testing = { workspace = true }

test-fuzz/tests/integration/ci.rs

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
ffi::OsStr,
77
fs::{read_dir, read_to_string, write},
88
io::Write,
9+
ops::Range,
910
path::Path,
1011
process::{Command, ExitStatus},
1112
str::FromStr,
@@ -181,19 +182,83 @@ fn shellcheck() {
181182
}
182183

183184
#[test]
184-
fn sort() {
185+
fn dependencies_are_sorted() {
185186
for entry in WalkDir::new("..")
186187
.into_iter()
187188
.filter_map(Result::ok)
188189
.filter(|e| e.file_name() == OsStr::new("Cargo.toml"))
189190
{
190-
let dir = entry.path().parent().unwrap();
191-
Command::new("cargo")
192-
.args(["sort", "--check", "--grouped", "--no-format"])
193-
.current_dir(dir)
194-
.logged_assert()
195-
.success();
191+
let path = entry.path();
192+
let contents = read_to_string(path).unwrap();
193+
let document = contents.parse::<toml_edit::Document<_>>().unwrap();
194+
for table_name in ["dependencies", "dev-dependencies", "build-dependencies"] {
195+
let Some(span) = key_value_pair_span(&document, table_name) else {
196+
continue;
197+
};
198+
assert!(
199+
key_value_pairs_are_sorted(&document, span),
200+
"`{table_name}` in `{}` are not sorted",
201+
path.display()
202+
);
203+
}
204+
}
205+
}
206+
207+
fn key_value_pair_span<S>(
208+
document: &toml_edit::Document<S>,
209+
table_name: &str,
210+
) -> Option<Range<usize>> {
211+
// smoelius: The table might not exist.
212+
let item = document.get(table_name)?;
213+
let table = item.as_table().unwrap();
214+
// smoelius: The table might exist but be empty.
215+
let (_, last_item) = table.iter().last()?;
216+
let header_span = table.span().unwrap();
217+
let last_item_span = last_item.span().unwrap();
218+
Some(header_span.end..last_item_span.end)
219+
}
220+
221+
fn key_value_pairs_are_sorted<S: AsRef<str>>(
222+
document: &toml_edit::Document<S>,
223+
span: Range<usize>,
224+
) -> bool {
225+
for group in groups(document, span) {
226+
let pairs = &document.raw()[group]
227+
.parse::<toml_edit::Document<_>>()
228+
.unwrap();
229+
if !pairs.iter().map(|(k, _)| k).is_sorted() {
230+
return false;
231+
}
196232
}
233+
true
234+
}
235+
236+
fn groups<S: AsRef<str>>(
237+
document: &toml_edit::Document<S>,
238+
span: Range<usize>,
239+
) -> Vec<Range<usize>> {
240+
let group_starts = group_starts(document, &span);
241+
let mut groups = Vec::with_capacity(group_starts.len() + 1);
242+
let mut start = span.start;
243+
for partition in group_starts {
244+
groups.push(start..partition);
245+
start = partition;
246+
}
247+
groups.push(start..span.end);
248+
groups
249+
}
250+
251+
/// Find the offsets in `span` that are not newlines, but that are preceded by two (or more)
252+
/// newlines.
253+
fn group_starts<S: AsRef<str>>(
254+
document: &toml_edit::Document<S>,
255+
span: &Range<usize>,
256+
) -> Vec<usize> {
257+
let raw = &document.raw()[span.clone()].as_bytes();
258+
(2..raw.len())
259+
.filter(|&i| raw[i - 2] == b'\n' && raw[i - 1] == b'\n' && raw[i] != b'\n')
260+
.map(|i| span.start + i)
261+
.collect()
197262
}
198263

199264
// smoelius: No other test uses supply_chain.json.

0 commit comments

Comments
 (0)