#!/usr/bin/env cargo
#![warn(missing_docs)]
use decrust_core::{DependencyAnalyzer, RecommendationType, SecurityImpact};
use std::fs;
use std::io;
use std::path::Path;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("đ **Decrust Dependency Optimizer**");
println!("====================================");
println!("Scanning your project for dependency optimization opportunities...\n");
let source_files = find_rust_source_files(".")?;
println!("đ Found {} Rust source files", source_files.len());
let mut all_code = String::new();
for file_path in &source_files {
if let Ok(content) = fs::read_to_string(file_path) {
all_code.push_str(&content);
all_code.push('\n');
}
}
let mut analyzer = DependencyAnalyzer::new();
let results = analyzer.analyze_code_dependencies(&all_code);
if results.is_empty() {
println!("⨠No external dependencies found in your project.");
return Ok(());
}
println!("\nđ **Dependency Analysis Results**");
println!("==================================\n");
let mut optimization_opportunities = Vec::new();
let mut total_potential_savings = 0;
let mut total_time_savings = 0.0;
for result in &results {
println!("đĻ **{}** v{}", result.crate_name, result.current_version);
println!(
" đ§ Current features: {}",
result.enabled_features.join(", ")
);
println!(" đ¯ Actually used: {}", result.used_features.join(", "));
if !result.unused_features.is_empty() {
println!(
" â ī¸ **UNUSED**: {} (wasting space!)",
result.unused_features.join(", ")
);
}
if !result.missing_features.is_empty() {
println!(
" â **MISSING**: {} (potential issues!)",
result.missing_features.join(", ")
);
}
let usage = &result.usage_analysis;
if !usage.functions_used.is_empty()
|| !usage.types_used.is_empty()
|| !usage.derive_macros_used.is_empty()
{
println!(" đ Usage details:");
if !usage.functions_used.is_empty() {
println!(" âĸ Functions: {}", usage.functions_used.join(", "));
}
if !usage.types_used.is_empty() {
println!(" âĸ Types: {}", usage.types_used.join(", "));
}
if !usage.derive_macros_used.is_empty() {
println!(
" âĸ Derive macros: {}",
usage.derive_macros_used.join(", ")
);
}
if !usage.attribute_macros_used.is_empty() {
println!(
" âĸ Attribute macros: {}",
usage.attribute_macros_used.join(", ")
);
}
}
for rec in &result.interactive_recommendations {
if rec.confidence > 0.8 {
optimization_opportunities.push((result.crate_name.clone(), rec.clone()));
if let Some(savings) = rec.estimated_impact.binary_size_reduction {
total_potential_savings += savings;
}
if let Some(time) = rec.estimated_impact.compile_time_improvement {
total_time_savings += time;
}
}
}
println!();
}
if !optimization_opportunities.is_empty() {
println!("đĄ **Optimization Opportunities Found**");
println!("=======================================\n");
for (i, (crate_name, rec)) in optimization_opportunities.iter().enumerate() {
println!(
"{}. **{}** - {:?}",
i + 1,
crate_name,
rec.recommendation_type
);
println!(" đ {}", rec.explanation);
println!(" đ§ Current: {}", rec.current_config);
println!(" ⨠Optimal: {}", rec.recommended_config);
if let Some(savings) = rec.estimated_impact.binary_size_reduction {
println!(" đž Savings: ~{} KB", savings / 1000);
}
if let Some(time) = rec.estimated_impact.compile_time_improvement {
println!(" ⥠Faster builds: ~{:.1}s", time);
}
match rec.estimated_impact.security_improvement {
SecurityImpact::High => println!(" đ Security: HIGH improvement"),
SecurityImpact::Medium => println!(" đ Security: MEDIUM improvement"),
SecurityImpact::Low => println!(" đ Security: LOW improvement"),
SecurityImpact::None => {}
}
if rec.auto_applicable {
println!(" â
**SAFE TO AUTO-APPLY**");
} else {
println!(" â ī¸ **REQUIRES MANUAL REVIEW**");
}
println!();
}
println!("đ **Total Potential Impact**");
println!("============================");
if total_potential_savings > 0 {
println!(
"đž Binary size reduction: ~{} KB",
total_potential_savings / 1000
);
}
if total_time_savings > 0.0 {
println!("⥠Compile time improvement: ~{:.1}s", total_time_savings);
}
println!("đ Security improvement: Reduced attack surface");
println!();
println!("đ¯ **Interactive Optimization**");
println!("===============================");
println!("Would you like to automatically optimize your Cargo.toml? (y/N): ");
let mut input = String::new();
io::stdin().read_line(&mut input)?;
if input.trim().to_lowercase() == "y" || input.trim().to_lowercase() == "yes" {
apply_optimizations(&optimization_opportunities)?;
} else {
println!("đĄ Run this tool again anytime to optimize your dependencies!");
}
} else {
println!("⨠**Excellent!** Your dependency configuration is already well-optimized!");
println!(" No high-confidence optimization opportunities found.");
}
Ok(())
}
fn find_rust_source_files(dir: &str) -> Result<Vec<String>, Box<dyn std::error::Error>> {
let mut rust_files = Vec::new();
find_rust_files_recursive(Path::new(dir), &mut rust_files)?;
Ok(rust_files)
}
fn find_rust_files_recursive(
dir: &Path,
rust_files: &mut Vec<String>,
) -> Result<(), Box<dyn std::error::Error>> {
if dir.is_dir() {
if let Some(dir_name) = dir.file_name() {
if dir_name == "target" || dir_name.to_string_lossy().starts_with('.') {
return Ok(());
}
}
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
find_rust_files_recursive(&path, rust_files)?;
} else if let Some(extension) = path.extension() {
if extension == "rs" {
rust_files.push(path.to_string_lossy().to_string());
}
}
}
}
Ok(())
}
fn apply_optimizations(
opportunities: &[(String, decrust_core::InteractiveRecommendation)],
) -> Result<(), Box<dyn std::error::Error>> {
println!("\nđ§ **Applying Optimizations**");
println!("============================\n");
let cargo_content = fs::read_to_string("Cargo.toml")?;
let mut new_content = cargo_content.clone();
let mut changes_made = 0;
for (crate_name, rec) in opportunities {
if rec.auto_applicable && rec.confidence > 0.85 {
println!(
"â
Optimizing {} ({:?})...",
crate_name, rec.recommendation_type
);
match rec.recommendation_type {
RecommendationType::RemoveUnusedFeatures => {
if let Some(updated) =
update_crate_features(&new_content, crate_name, &rec.recommended_config)
{
new_content = updated;
changes_made += 1;
println!(" ⨠Updated features for {}", crate_name);
}
}
RecommendationType::SplitFeatures => {
if let Some(updated) =
update_crate_features(&new_content, crate_name, &rec.recommended_config)
{
new_content = updated;
changes_made += 1;
println!(" ⨠Split features for {}", crate_name);
}
}
_ => {
println!(
" â ī¸ Skipping {:?} (requires manual review)",
rec.recommendation_type
);
}
}
} else {
println!(
"â ī¸ Skipping {} (confidence: {:.0}%, auto-applicable: {})",
crate_name,
rec.confidence * 100.0,
rec.auto_applicable
);
}
}
if changes_made > 0 {
fs::write("Cargo.toml.backup", &cargo_content)?;
println!("\nđž Created backup: Cargo.toml.backup");
fs::write("Cargo.toml", new_content)?;
println!(
"â
Updated Cargo.toml with {} optimization(s)",
changes_made
);
println!("\nđ¯ **Next Steps:**");
println!("1. Run `cargo check` to verify everything still works");
println!("2. Run `cargo build --release` to see the improvements");
println!("3. If there are issues, restore with: `mv Cargo.toml.backup Cargo.toml`");
} else {
println!("âšī¸ No auto-applicable optimizations found.");
}
Ok(())
}
fn update_crate_features(content: &str, crate_name: &str, new_config: &str) -> Option<String> {
if let Some(start) = new_config.find('[') {
if let Some(end) = new_config.find(']') {
let features_str = &new_config[start..=end];
let lines: Vec<&str> = content.lines().collect();
let mut new_lines = Vec::new();
for line in lines {
if line.contains(crate_name) && line.contains("features") {
if let Some(eq_pos) = line.find('=') {
let before_eq = &line[..eq_pos];
new_lines.push(format!(
"{} = {{ version = \"*\", features = {} }}",
before_eq.trim(),
features_str
));
} else {
new_lines.push(line.to_string());
}
} else {
new_lines.push(line.to_string());
}
}
return Some(new_lines.join("\n"));
}
}
None
}