Skip to content

Commit 19b48c4

Browse files
committed
cargo-rail: major dx, perf, and reliability updated.
1 parent 7ff3906 commit 19b48c4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1293
-939
lines changed

Cargo.lock

Lines changed: 10 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
@@ -29,6 +29,7 @@ exclude = [
2929

3030
[dependencies]
3131
clap = { version = "4.5.53", features = ["derive", "cargo"] }
32+
clap_complete = "4.5"
3233
cargo_metadata = "0.23.1"
3334
petgraph = { version = "0.8.3", default-features = false }
3435
toml_edit = { version = "0.23.9", features = ["serde"] }

src/backup/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,20 @@ pub use metadata::{BackupMetadata, BackupRecord};
4040
/// Backup identifier (timestamp-based)
4141
pub type BackupId = String;
4242

43-
/// Creates a backup ID from current timestamp
43+
/// Creates a backup ID from current timestamp.
44+
#[doc(hidden)]
4445
pub fn create_backup_id() -> BackupId {
4546
chrono::Local::now().format("%Y-%m-%d-%H%M%S-%3f").to_string()
4647
}
4748

48-
/// Get the backup root directory for a workspace
49-
///
49+
/// Get the backup root directory for a workspace.
50+
#[doc(hidden)]
5051
pub fn get_backup_root(workspace_root: &Path) -> PathBuf {
5152
workspace_root.join("target").join("cargo-rail").join("backups")
5253
}
5354

54-
/// Get the path to a specific backup directory
55+
/// Get the path to a specific backup directory.
56+
#[doc(hidden)]
5557
pub fn get_backup_dir(workspace_root: &Path, backup_id: &str) -> PathBuf {
5658
get_backup_root(workspace_root).join(backup_id)
5759
}

src/cargo/manifest_analyzer.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,6 @@ impl DepKey {
3636
}
3737
}
3838

39-
/// Get the canonical key (package name only, ignoring rename)
40-
///
41-
/// Used when `include_renamed = true` to group renamed and non-renamed deps together
42-
pub fn canonical(&self) -> Self {
43-
Self {
44-
name: Arc::clone(&self.name),
45-
renamed_from: None,
46-
}
47-
}
48-
4939
/// Check if this is a renamed dependency
5040
pub fn is_renamed(&self) -> bool {
5141
self.renamed_from.is_some()

src/cargo/manifest_ops/entry_builder.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,7 @@ mod tests {
165165
use crate::cargo::unify_types::UnifiedDep;
166166
use std::path::PathBuf;
167167

168-
use super::super::fields::{extract_features, extract_path, has_default_features, has_path};
169-
use super::super::transform::{extract_version, is_inline_table_dep, is_optional, is_simple_string_dep};
168+
use super::super::fields::extract_features;
170169
use super::super::workspace_ref::is_workspace_dep;
171170

172171
fn create_test_dep(name: &str, version: &str) -> UnifiedDep {
@@ -185,9 +184,9 @@ mod tests {
185184
fn test_build_dep_entry_simple() {
186185
let dep = create_test_dep("serde", "1.0");
187186
let entry = build_dep_entry(&dep);
188-
assert!(is_simple_string_dep(&entry));
189-
// Version requirement parsing adds the caret operator
190-
assert_eq!(extract_version(&entry).unwrap(), "^1.0");
187+
// Simple case returns a string value
188+
assert!(entry.as_str().is_some());
189+
assert_eq!(entry.as_str().unwrap(), "^1.0");
191190
}
192191

193192
#[test]
@@ -196,7 +195,7 @@ mod tests {
196195
dep.features = vec!["derive".to_string()];
197196

198197
let entry = build_dep_entry(&dep);
199-
assert!(is_inline_table_dep(&entry));
198+
assert!(entry.as_inline_table().is_some());
200199
let features = extract_features(&entry).unwrap();
201200
assert_eq!(features, vec!["derive"]);
202201
}
@@ -207,9 +206,9 @@ mod tests {
207206
dep.path = Some(PathBuf::from("../local-crate"));
208207

209208
let entry = build_dep_entry(&dep);
210-
assert!(is_inline_table_dep(&entry));
211-
assert!(has_path(&entry));
212-
assert_eq!(extract_path(&entry).unwrap(), "../local-crate");
209+
let table = entry.as_inline_table().unwrap();
210+
assert!(table.contains_key("path"));
211+
assert_eq!(table.get("path").unwrap().as_str().unwrap(), "../local-crate");
213212
}
214213

215214
#[test]
@@ -218,15 +217,15 @@ mod tests {
218217
dep.default_features = false;
219218

220219
let entry = build_dep_entry(&dep);
221-
assert!(is_inline_table_dep(&entry));
222-
assert!(!has_default_features(&entry));
220+
let table = entry.as_inline_table().unwrap();
221+
assert!(!table.get("default-features").unwrap().as_bool().unwrap());
223222
}
224223

225224
#[test]
226225
fn test_build_workspace_dep_entry_simple() {
227226
let entry = build_workspace_dep_entry(None, false);
228227
assert!(is_workspace_dep(&entry));
229-
assert!(is_inline_table_dep(&entry));
228+
assert!(entry.as_inline_table().is_some());
230229
}
231230

232231
#[test]
@@ -241,7 +240,8 @@ mod tests {
241240
fn test_build_workspace_dep_entry_optional() {
242241
let entry = build_workspace_dep_entry(None, true);
243242
assert!(is_workspace_dep(&entry));
244-
assert!(is_optional(&entry));
243+
let table = entry.as_inline_table().unwrap();
244+
assert!(table.get("optional").unwrap().as_bool().unwrap());
245245
}
246246

247247
#[test]

src/cargo/manifest_ops/fields.rs

Lines changed: 2 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@ use toml_edit::{Array, InlineTable, Item, Table, Value};
88
// ============================================================================
99

1010
/// Build feature array from strings
11-
///
12-
/// # Arguments
13-
///
14-
/// * `features` - List of feature names
15-
///
16-
/// # Returns
17-
///
18-
/// `Value::Array` containing the features
1911
pub fn build_feature_array(features: &[String]) -> Value {
2012
let mut array = Array::new();
2113
for feature in features {
@@ -25,10 +17,6 @@ pub fn build_feature_array(features: &[String]) -> Value {
2517
}
2618

2719
/// Extract features from dependency entry
28-
///
29-
/// # Returns
30-
///
31-
/// `Some(features)` if present, `None` otherwise
3220
pub fn extract_features(item: &Item) -> Option<Vec<String>> {
3321
if let Some(table) = item.as_inline_table() {
3422
extract_features_from_inline_table(table)
@@ -67,56 +55,11 @@ pub fn set_features(item: &mut Item, features: Vec<String>) -> RailResult<()> {
6755
}
6856
}
6957

70-
/// Remove features field from dependency entry
71-
///
72-
/// # Returns
73-
///
74-
/// `true` if features were present and removed, `false` otherwise
75-
pub fn remove_features(item: &mut Item) -> bool {
76-
if let Some(table) = item.as_inline_table_mut() {
77-
table.remove("features").is_some()
78-
} else if let Some(table) = item.as_table_mut() {
79-
table.remove("features").is_some()
80-
} else {
81-
false
82-
}
83-
}
84-
8558
// ============================================================================
8659
// Path Dependency Operations
8760
// ============================================================================
8861

89-
/// Check if dependency has path field
90-
pub fn has_path(item: &Item) -> bool {
91-
if let Some(table) = item.as_inline_table() {
92-
table.contains_key("path")
93-
} else if let Some(table) = item.as_table() {
94-
table.contains_key("path")
95-
} else {
96-
false
97-
}
98-
}
99-
100-
/// Extract path value from dependency
101-
pub fn extract_path(item: &Item) -> Option<String> {
102-
if let Some(table) = item.as_inline_table() {
103-
table.get("path").and_then(|v| v.as_str()).map(String::from)
104-
} else if let Some(table) = item.as_table() {
105-
table
106-
.get("path")
107-
.and_then(|item| item.as_value())
108-
.and_then(|v| v.as_str())
109-
.map(String::from)
110-
} else {
111-
None
112-
}
113-
}
114-
11562
/// Remove path field from dependency
116-
///
117-
/// # Returns
118-
///
119-
/// `true` if path was present and removed, `false` otherwise
12063
pub fn remove_path(item: &mut Item) -> bool {
12164
if let Some(table) = item.as_inline_table_mut() {
12265
table.remove("path").is_some()
@@ -127,64 +70,6 @@ pub fn remove_path(item: &mut Item) -> bool {
12770
}
12871
}
12972

130-
/// Set path field on dependency
131-
pub fn set_path(item: &mut Item, path: &str) -> RailResult<()> {
132-
if let Some(table) = item.as_inline_table_mut() {
133-
table.insert("path", Value::from(path));
134-
Ok(())
135-
} else if let Some(table) = item.as_table_mut() {
136-
table.insert("path", Item::Value(Value::from(path)));
137-
Ok(())
138-
} else {
139-
Err(RailError::message("cannot set path: item is not a table"))
140-
}
141-
}
142-
143-
// ============================================================================
144-
// Default Features Operations
145-
// ============================================================================
146-
147-
/// Check default-features setting
148-
///
149-
/// Returns `true` if not specified (default) or explicitly set to true
150-
pub fn has_default_features(item: &Item) -> bool {
151-
if let Some(table) = item.as_inline_table() {
152-
table.get("default-features").and_then(|v| v.as_bool()).unwrap_or(true)
153-
} else if let Some(table) = item.as_table() {
154-
table
155-
.get("default-features")
156-
.and_then(|item| item.as_value())
157-
.and_then(|v| v.as_bool())
158-
.unwrap_or(true)
159-
} else {
160-
true
161-
}
162-
}
163-
164-
/// Set default-features flag
165-
pub fn set_default_features(item: &mut Item, enabled: bool) -> RailResult<()> {
166-
if let Some(table) = item.as_inline_table_mut() {
167-
table.insert("default-features", Value::from(enabled));
168-
Ok(())
169-
} else if let Some(table) = item.as_table_mut() {
170-
table.insert("default-features", Item::Value(Value::from(enabled)));
171-
Ok(())
172-
} else {
173-
Err(RailError::message("cannot set default-features: item is not a table"))
174-
}
175-
}
176-
177-
/// Remove default-features field
178-
pub fn remove_default_features(item: &mut Item) -> bool {
179-
if let Some(table) = item.as_inline_table_mut() {
180-
table.remove("default-features").is_some()
181-
} else if let Some(table) = item.as_table_mut() {
182-
table.remove("default-features").is_some()
183-
} else {
184-
false
185-
}
186-
}
187-
18873
#[cfg(test)]
18974
mod tests {
19075
use super::*;
@@ -223,93 +108,14 @@ mod tests {
223108
assert_eq!(features, vec!["new"]);
224109
}
225110

226-
#[test]
227-
fn test_remove_features() {
228-
let mut table = InlineTable::new();
229-
table.insert("version", Value::from("1.0"));
230-
table.insert("features", build_feature_array(&["old".to_string()]));
231-
let mut item = Item::Value(Value::InlineTable(table));
232-
233-
assert!(extract_features(&item).is_some());
234-
let removed = remove_features(&mut item);
235-
assert!(removed);
236-
assert!(extract_features(&item).is_none());
237-
}
238-
239-
#[test]
240-
fn test_has_path() {
241-
let mut table = InlineTable::new();
242-
table.insert("path", Value::from("../other"));
243-
let item = Item::Value(Value::InlineTable(table));
244-
245-
assert!(has_path(&item));
246-
}
247-
248-
#[test]
249-
fn test_extract_path() {
250-
let mut table = InlineTable::new();
251-
table.insert("path", Value::from("../local"));
252-
let item = Item::Value(Value::InlineTable(table));
253-
254-
assert_eq!(extract_path(&item).unwrap(), "../local");
255-
}
256-
257111
#[test]
258112
fn test_remove_path() {
259113
let mut table = InlineTable::new();
260114
table.insert("path", Value::from("../other"));
261115
let mut item = Item::Value(Value::InlineTable(table));
262116

263117
assert!(remove_path(&mut item));
264-
assert!(!has_path(&item));
265-
}
266-
267-
#[test]
268-
fn test_set_path() {
269-
let mut table = InlineTable::new();
270-
table.insert("version", Value::from("1.0"));
271-
let mut item = Item::Value(Value::InlineTable(table));
272-
273-
set_path(&mut item, "../new-path").unwrap();
274-
assert_eq!(extract_path(&item).unwrap(), "../new-path");
275-
}
276-
277-
#[test]
278-
fn test_has_default_features_default_true() {
279-
let item = Item::Value(Value::from("1.0"));
280-
assert!(has_default_features(&item));
281-
}
282-
283-
#[test]
284-
fn test_has_default_features_explicit_false() {
285-
let mut table = InlineTable::new();
286-
table.insert("version", Value::from("1.0"));
287-
table.insert("default-features", Value::from(false));
288-
let item = Item::Value(Value::InlineTable(table));
289-
290-
assert!(!has_default_features(&item));
291-
}
292-
293-
#[test]
294-
fn test_set_default_features() {
295-
let mut table = InlineTable::new();
296-
table.insert("version", Value::from("1.0"));
297-
let mut item = Item::Value(Value::InlineTable(table));
298-
299-
set_default_features(&mut item, false).unwrap();
300-
assert!(!has_default_features(&item));
301-
}
302-
303-
#[test]
304-
fn test_remove_default_features() {
305-
let mut table = InlineTable::new();
306-
table.insert("version", Value::from("1.0"));
307-
table.insert("default-features", Value::from(false));
308-
let mut item = Item::Value(Value::InlineTable(table));
309-
310-
let removed = remove_default_features(&mut item);
311-
assert!(removed);
312-
// Should now be true (default)
313-
assert!(has_default_features(&item));
118+
// Path should be gone
119+
assert!(item.as_inline_table().unwrap().get("path").is_none());
314120
}
315121
}

0 commit comments

Comments
 (0)