wip
- funktionierende Version
This commit is contained in:
parent
f13829f14d
commit
1210da7601
16
.gitignore
vendored
16
.gitignore
vendored
@ -1,7 +1,7 @@
|
|||||||
# Generated by Cargo
|
# Generated by Cargo
|
||||||
# will have compiled files and executables
|
# will have compiled files and executables
|
||||||
debug/
|
debug/**
|
||||||
target/
|
target/**
|
||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
@ -9,12 +9,8 @@ target/
|
|||||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
*.pdb
|
*.pdb
|
||||||
|
|
||||||
# RustRover
|
|
||||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
||||||
#.idea/
|
|
||||||
|
|
||||||
# Build - Test:
|
# Build - Test:
|
||||||
*.txt
|
*.txt
|
||||||
|
|
||||||
|
# Releases (realAscot)
|
||||||
|
releases/**
|
||||||
|
32
.vscode/tasks.json
vendored
Normal file
32
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "cargo",
|
||||||
|
"command": "check",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$rustc"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"label": "rust: cargo check"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "cargo",
|
||||||
|
"command": "clean",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$rustc"
|
||||||
|
],
|
||||||
|
"group": "clean",
|
||||||
|
"label": "rust: cargo clean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "cargo",
|
||||||
|
"command": "build",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$rustc"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"label": "rust: cargo build"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -10,6 +10,14 @@ use std::path::PathBuf;
|
|||||||
about = "Generiert eine ASCII-Baumstruktur eines Verzeichnisses."
|
about = "Generiert eine ASCII-Baumstruktur eines Verzeichnisses."
|
||||||
)]
|
)]
|
||||||
pub struct CliArgs {
|
pub struct CliArgs {
|
||||||
|
/// Aktiviere den Debug-Modus
|
||||||
|
#[clap(short = 'D', long = "debug", global = true, action)]
|
||||||
|
pub debug: bool,
|
||||||
|
|
||||||
|
/// Aktiviere den Silent-Mode für Verwendung in Batch und Skripten
|
||||||
|
#[clap(short = 'q', long, global = true, action)]
|
||||||
|
pub quiet: bool,
|
||||||
|
|
||||||
/// Stammverzeichnis (default: aktuelles Verzeichnis)
|
/// Stammverzeichnis (default: aktuelles Verzeichnis)
|
||||||
#[arg(default_value = ".")]
|
#[arg(default_value = ".")]
|
||||||
pub root_path: PathBuf,
|
pub root_path: PathBuf,
|
||||||
|
3
src/lib.rs
Normal file
3
src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod config;
|
||||||
|
pub mod app;
|
||||||
|
pub mod utils;
|
35
src/main.rs
35
src/main.rs
@ -6,11 +6,16 @@ use config::args::CliArgs;
|
|||||||
use config::loader::load_config_from_home;
|
use config::loader::load_config_from_home;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use treescanner::utils::ascii_spinner::start_spinner;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = CliArgs::parse();
|
let args = CliArgs::parse();
|
||||||
let file_config = load_config_from_home().unwrap_or_default();
|
let file_config = load_config_from_home().unwrap_or_default();
|
||||||
|
|
||||||
|
let start_time = Instant::now();
|
||||||
|
|
||||||
if !args.root_path.is_dir() {
|
if !args.root_path.is_dir() {
|
||||||
eprintln!("Fehler: '{}' ist kein gültiges Verzeichnis.", args.root_path.display());
|
eprintln!("Fehler: '{}' ist kein gültiges Verzeichnis.", args.root_path.display());
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
@ -41,8 +46,21 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut builder = TreeBuilder::new(config);
|
let mut builder = TreeBuilder::new(config);
|
||||||
|
|
||||||
|
// Spinner starten, wenn nicht quiet
|
||||||
|
let spinner = if !args.quiet {
|
||||||
|
Some(start_spinner(2))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let output = builder.build_tree();
|
let output = builder.build_tree();
|
||||||
|
|
||||||
|
if let Some(stop) = spinner {
|
||||||
|
let _ = stop.send(());
|
||||||
|
}
|
||||||
|
println!(); // saubere Zeile nach Spinner
|
||||||
|
|
||||||
let viewonly = args.viewonly || file_config.viewonly.unwrap_or(false);
|
let viewonly = args.viewonly || file_config.viewonly.unwrap_or(false);
|
||||||
let output_path = args.output.clone().or_else(|| file_config.output.map(Into::into)).unwrap_or_else(|| "tree.txt".into());
|
let output_path = args.output.clone().or_else(|| file_config.output.map(Into::into)).unwrap_or_else(|| "tree.txt".into());
|
||||||
|
|
||||||
@ -51,13 +69,16 @@ fn main() {
|
|||||||
eprintln!("Fehler beim Schreiben der Datei: {e}");
|
eprintln!("Fehler beim Schreiben der Datei: {e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
let (folders, files) = builder.stats();
|
if !args.quiet {
|
||||||
println!(
|
let (folders, files) = builder.stats();
|
||||||
"Erfasst wurden {} Ordner und {} Dateien. Ergebnis in {} gespeichert.",
|
println!(
|
||||||
folders,
|
"Erfasst wurden {} Ordner und {} Dateien. Ergebnis in {} gespeichert.",
|
||||||
files,
|
folders,
|
||||||
output_path.display()
|
files,
|
||||||
);
|
output_path.display()
|
||||||
|
);
|
||||||
|
println!("⏱️ Gesamtlaufzeit: {:.2?}", start_time.elapsed());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("{}", output);
|
println!("{}", output);
|
||||||
}
|
}
|
||||||
|
35
src/utils/ascii_spinner.rs
Normal file
35
src/utils/ascii_spinner.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use std::sync::mpsc::{self, Sender};
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
/// Startet einen minimalistischen ASCII-Spinner in einem Hintergrundthread.
|
||||||
|
///
|
||||||
|
/// Gibt alle X Millisekunden einen neuen Frame auf stdout aus (mit `\r`).
|
||||||
|
/// Die Frequenz wird über `ticks_per_second` gesteuert.
|
||||||
|
///
|
||||||
|
/// # Beispiel
|
||||||
|
/// ```
|
||||||
|
/// let stop = ascii_spinner::start_spinner(8); // 8 Ticks pro Sekunde
|
||||||
|
/// // ... lange Operation ...
|
||||||
|
/// let _ = stop.send(());
|
||||||
|
/// ```
|
||||||
|
pub fn start_spinner(ticks_per_second: u64) -> Sender<()> {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
let frames = vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
||||||
|
let clamped = ticks_per_second.clamp(1, 20);
|
||||||
|
let interval = Duration::from_millis(1000 / clamped);
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut idx = 0;
|
||||||
|
while rx.try_recv().is_err() {
|
||||||
|
print!("\r[{}] läuft ...", frames[idx % frames.len()]);
|
||||||
|
let _ = std::io::Write::flush(&mut std::io::stdout());
|
||||||
|
idx += 1;
|
||||||
|
thread::sleep(interval);
|
||||||
|
}
|
||||||
|
print!("\r \r"); // Spinner löschen
|
||||||
|
let _ = std::io::Write::flush(&mut std::io::stdout());
|
||||||
|
});
|
||||||
|
|
||||||
|
tx
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
pub mod logger;
|
pub mod logger;
|
||||||
|
pub mod ascii_spinner;
|
||||||
|
29
tests/config_tests.rs
Normal file
29
tests/config_tests.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use treescanner::config::loader::{load_config_from_home, ConfigFile};
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn write_temp_config(content: &str) -> PathBuf {
|
||||||
|
let path = dirs::home_dir().unwrap().join(".treescanner.conf");
|
||||||
|
fs::write(&path, content).expect("Konnte Testdatei nicht schreiben");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_config_wird_korrekt_geladen() {
|
||||||
|
let config_text = r#"
|
||||||
|
max_depth = 2
|
||||||
|
max_files_per_dir = 5
|
||||||
|
ignore = [".git", "target"]
|
||||||
|
viewonly = true
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let conf_path = write_temp_config(config_text);
|
||||||
|
let loaded: ConfigFile = load_config_from_home().expect("Konfig konnte nicht geladen werden");
|
||||||
|
|
||||||
|
assert_eq!(loaded.max_depth, Some(2));
|
||||||
|
assert_eq!(loaded.max_files_per_dir, Some(5));
|
||||||
|
assert!(loaded.ignore.as_ref().unwrap().contains(".git"));
|
||||||
|
assert_eq!(loaded.viewonly, Some(true));
|
||||||
|
|
||||||
|
fs::remove_file(conf_path).ok();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user