fix: Race Condition bei paralleler Umbenennung, Clippy/Deprecation-Warnings und Formatierung
- Parallele Berechnung (par_iter) entfernt, da sie die tiefenbasierte Sortierung zerstörte und Parent-Verzeichnisse vor ihren Kindern umbenannt werden konnten - Duplizierten Code zwischen parallelem und sequentiellem Pfad entfernt - Clippy-Warning behoben: collapsible str::replace in sanitizer.rs - Deprecation-Warning behoben: #[allow(deprecated)] für cargo_bin Import - cargo fmt angewendet Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0c26e5244c
commit
ad44139e21
3 changed files with 105 additions and 119 deletions
153
src/main.rs
153
src/main.rs
|
|
@ -11,7 +11,6 @@ use config::Config;
|
|||
use glob::Pattern;
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use log::{debug, error, info};
|
||||
use rayon::prelude::*;
|
||||
use sanitizer::{clean_filename, is_excluded, is_safe_rename, Sequence};
|
||||
use std::fs;
|
||||
use std::io::IsTerminal;
|
||||
|
|
@ -32,9 +31,6 @@ const DEFAULT_EXCLUDES: &[&str] = &[
|
|||
"__pycache__/**",
|
||||
];
|
||||
|
||||
// Schwellwert für parallele Verarbeitung (bei weniger Dateien lohnt sich Overhead nicht)
|
||||
const PARALLEL_THRESHOLD: usize = 100;
|
||||
|
||||
/// Repräsentiert eine geplante Umbenennungsoperation
|
||||
#[derive(Debug)]
|
||||
struct RenameOperation {
|
||||
|
|
@ -84,8 +80,12 @@ fn main() -> Result<()> {
|
|||
|
||||
// Config-Datei laden: entweder --conf oder Standard-Hierarchie
|
||||
let config = if let Some(config_path) = &args.config_file {
|
||||
Config::from_file(config_path, args.verbose)
|
||||
.with_context(|| format!("Fehler beim Laden der Konfiguration: {}", config_path.display()))?
|
||||
Config::from_file(config_path, args.verbose).with_context(|| {
|
||||
format!(
|
||||
"Fehler beim Laden der Konfiguration: {}",
|
||||
config_path.display()
|
||||
)
|
||||
})?
|
||||
} else {
|
||||
Config::from_default_locations(args.verbose)?
|
||||
};
|
||||
|
|
@ -139,7 +139,10 @@ fn main() -> Result<()> {
|
|||
if let Ok(entry) = entry_result {
|
||||
entries.push(entry);
|
||||
} else if let Err(e) = entry_result {
|
||||
error!("{}", format!("Fehler beim Durchlaufen von {}: {}", path.display(), e).red());
|
||||
error!(
|
||||
"{}",
|
||||
format!("Fehler beim Durchlaufen von {}: {}", path.display(), e).red()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -158,69 +161,39 @@ fn main() -> Result<()> {
|
|||
None
|
||||
};
|
||||
|
||||
// Berechne Umbenennungen (parallel bei vielen Dateien)
|
||||
let rename_ops: Vec<RenameOperation> = if entries.len() >= PARALLEL_THRESHOLD {
|
||||
// Parallel mit rayon
|
||||
entries
|
||||
.par_iter()
|
||||
.filter_map(|entry| {
|
||||
let old_path = entry.path();
|
||||
// Berechne Umbenennungen
|
||||
// Hinweis: Die Reihenfolge (tiefste zuerst) muss erhalten bleiben,
|
||||
// damit Parent-Verzeichnisse nicht vor ihren Kindern umbenannt werden.
|
||||
let rename_ops: Vec<RenameOperation> = entries
|
||||
.iter()
|
||||
.filter_map(|entry| {
|
||||
let old_path = entry.path();
|
||||
|
||||
// Ebenentiefe 0 -> überspringen
|
||||
if entry.depth() == 0 && entry.file_type().is_dir() && !args.modify_root {
|
||||
return None;
|
||||
// Ebenentiefe 0 -> überspringen
|
||||
if entry.depth() == 0 && entry.file_type().is_dir() && !args.modify_root {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Special Files (Symlinks, Sockets, etc.) nur mit --special
|
||||
let file_type = entry.file_type();
|
||||
if !args.special && (!file_type.is_file() && !file_type.is_dir()) {
|
||||
if args.verbose && file_type.is_symlink() {
|
||||
debug!("Überspringe Symlink: {} (nutze --special um Symlink-Namen zu bereinigen)", old_path.display());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// Special Files (Symlinks, Sockets, etc.) nur mit --special
|
||||
let file_type = entry.file_type();
|
||||
if !args.special && (!file_type.is_file() && !file_type.is_dir()) {
|
||||
if args.verbose && file_type.is_symlink() {
|
||||
debug!("Überspringe Symlink: {} (nutze --special um Symlink-Namen zu bereinigen)", old_path.display());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
// Dateiname ermitteln und bereinigen
|
||||
let filename = old_path.file_name()?;
|
||||
let new_name = clean_filename(filename, &config, &sequence, false)?;
|
||||
let new_path = old_path.with_file_name(&new_name);
|
||||
|
||||
// Dateiname ermitteln und bereinigen
|
||||
let filename = old_path.file_name()?;
|
||||
let new_name = clean_filename(filename, &config, &sequence, false)?;
|
||||
let new_path = old_path.with_file_name(&new_name);
|
||||
|
||||
Some(RenameOperation {
|
||||
old_path: old_path.to_path_buf(),
|
||||
new_path,
|
||||
})
|
||||
Some(RenameOperation {
|
||||
old_path: old_path.to_path_buf(),
|
||||
new_path,
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
// Sequenziell bei wenigen Dateien
|
||||
entries
|
||||
.iter()
|
||||
.filter_map(|entry| {
|
||||
let old_path = entry.path();
|
||||
|
||||
if entry.depth() == 0 && entry.file_type().is_dir() && !args.modify_root {
|
||||
return None;
|
||||
}
|
||||
|
||||
let file_type = entry.file_type();
|
||||
if !args.special && (!file_type.is_file() && !file_type.is_dir()) {
|
||||
if args.verbose && file_type.is_symlink() {
|
||||
debug!("Überspringe Symlink: {} (nutze --special um Symlink-Namen zu bereinigen)", old_path.display());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
let filename = old_path.file_name()?;
|
||||
let new_name = clean_filename(filename, &config, &sequence, false)?;
|
||||
let new_path = old_path.with_file_name(&new_name);
|
||||
|
||||
Some(RenameOperation {
|
||||
old_path: old_path.to_path_buf(),
|
||||
new_path,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Statistiken
|
||||
let total_processed = entries.len();
|
||||
|
|
@ -236,13 +209,15 @@ fn main() -> Result<()> {
|
|||
|
||||
if !args.quiet {
|
||||
if args.dry_run {
|
||||
info!("{} {} {}",
|
||||
info!(
|
||||
"{} {} {}",
|
||||
op.old_path.display().to_string().dimmed(),
|
||||
"->".yellow(),
|
||||
op.new_path.display().to_string().yellow()
|
||||
);
|
||||
} else {
|
||||
info!("{} {} {}",
|
||||
info!(
|
||||
"{} {} {}",
|
||||
op.old_path.display().to_string().dimmed(),
|
||||
"->".green(),
|
||||
op.new_path.display().to_string().green()
|
||||
|
|
@ -259,13 +234,15 @@ fn main() -> Result<()> {
|
|||
match fs::rename(&op.old_path, &op.new_path) {
|
||||
Ok(_) => renamed_count += 1,
|
||||
Err(e) => {
|
||||
error!("{}",
|
||||
error!(
|
||||
"{}",
|
||||
format!(
|
||||
"Fehler beim Umbenennen: {} -> {}: {}",
|
||||
op.old_path.display(),
|
||||
op.new_path.display(),
|
||||
e
|
||||
).red()
|
||||
)
|
||||
.red()
|
||||
);
|
||||
skipped_count += 1;
|
||||
}
|
||||
|
|
@ -283,15 +260,35 @@ fn main() -> Result<()> {
|
|||
// Zusammenfassung ausgeben (außer im quiet mode)
|
||||
if !args.quiet {
|
||||
info!("");
|
||||
info!("{}", format!("=== Zusammenfassung für {} ===", path.display()).cyan().bold());
|
||||
info!("Verarbeitete Dateien/Verzeichnisse: {}", total_processed.to_string().cyan());
|
||||
info!("Umbenennungen geplant: {}", total_planned.to_string().cyan());
|
||||
info!(
|
||||
"{}",
|
||||
format!("=== Zusammenfassung für {} ===", path.display())
|
||||
.cyan()
|
||||
.bold()
|
||||
);
|
||||
info!(
|
||||
"Verarbeitete Dateien/Verzeichnisse: {}",
|
||||
total_processed.to_string().cyan()
|
||||
);
|
||||
info!(
|
||||
"Umbenennungen geplant: {}",
|
||||
total_planned.to_string().cyan()
|
||||
);
|
||||
if args.dry_run {
|
||||
info!("Modus: {}", "Dry-run (keine Änderungen)".yellow());
|
||||
info!(
|
||||
"Modus: {}",
|
||||
"Dry-run (keine Änderungen)".yellow()
|
||||
);
|
||||
} else {
|
||||
info!("Erfolgreich umbenannt: {}", renamed_count.to_string().green().bold());
|
||||
info!(
|
||||
"Erfolgreich umbenannt: {}",
|
||||
renamed_count.to_string().green().bold()
|
||||
);
|
||||
if skipped_count > 0 {
|
||||
info!("Übersprungen/Fehler: {}", skipped_count.to_string().red());
|
||||
info!(
|
||||
"Übersprungen/Fehler: {}",
|
||||
skipped_count.to_string().red()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -317,11 +314,7 @@ fn list_sequences(args: &Cli) {
|
|||
println!(" Case transform: {:?}", seq.apply_case);
|
||||
println!(
|
||||
" Emoji handling: {}",
|
||||
if seq.apply_emojis {
|
||||
"replace"
|
||||
} else {
|
||||
"keep"
|
||||
}
|
||||
if seq.apply_emojis { "replace" } else { "keep" }
|
||||
);
|
||||
println!(
|
||||
" Mode: {}",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue