Compare commits
4 Commits
b66e7dd4ad
...
45796d9bb2
| Author | SHA1 | Date | |
|---|---|---|---|
| 45796d9bb2 | |||
| 1bb7d461e0 | |||
| 63c1c88393 | |||
| 5800f2229f |
@ -10,6 +10,8 @@ namespace RedundancyFinder
|
|||||||
|
|
||||||
string[] extensions;
|
string[] extensions;
|
||||||
|
|
||||||
|
List<string> ignorePaths = new List<string>();
|
||||||
|
|
||||||
public event EventHandler<DirectoryErrorEventArgs>? DirectoryError;
|
public event EventHandler<DirectoryErrorEventArgs>? DirectoryError;
|
||||||
public event EventHandler<FileErrorEventArgs>? FileError;
|
public event EventHandler<FileErrorEventArgs>? FileError;
|
||||||
public event EventHandler<FileFoundEventArgs>? FileFound;
|
public event EventHandler<FileFoundEventArgs>? FileFound;
|
||||||
@ -17,6 +19,7 @@ namespace RedundancyFinder
|
|||||||
public event EventHandler<ProcessingFileEventArgs>? ProcessingFile;
|
public event EventHandler<ProcessingFileEventArgs>? ProcessingFile;
|
||||||
public void FindRedundancies(string[] paths, string[] extensions)
|
public void FindRedundancies(string[] paths, string[] extensions)
|
||||||
{
|
{
|
||||||
|
redundancies?.Values.SelectMany(x => x.Paths).ToList().ForEach(x => ignorePaths.Add(x));
|
||||||
this.extensions = extensions;
|
this.extensions = extensions;
|
||||||
foreach (var path in paths)
|
foreach (var path in paths)
|
||||||
{
|
{
|
||||||
@ -35,8 +38,6 @@ namespace RedundancyFinder
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// Process files in the current directory
|
// Process files in the current directory
|
||||||
foreach (var file in Directory.GetFiles(directoryPath))
|
foreach (var file in Directory.GetFiles(directoryPath))
|
||||||
{
|
{
|
||||||
@ -72,47 +73,45 @@ namespace RedundancyFinder
|
|||||||
|
|
||||||
private void ProcessFile(string filePath)
|
private void ProcessFile(string filePath)
|
||||||
{
|
{
|
||||||
|
if(ignorePaths.Contains(filePath))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!extensions.Contains(Path.GetExtension(filePath)))
|
if (!extensions.Contains(Path.GetExtension(filePath)))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TaskStarted?.Invoke(this, filePath);
|
TaskStarted?.Invoke(this, filePath);
|
||||||
ProcessingFile?.Invoke(this, new ProcessingFileEventArgs() { Path = filePath });
|
ProcessingFile?.Invoke(this, new ProcessingFileEventArgs() { Path = filePath });
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
var fileHash = ComputeFileHash(filePath);
|
var fileHash = ComputeFileHash(filePath);
|
||||||
if (fileHash == null)
|
if (fileHash == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long fileSize = new FileInfo(filePath).Length;
|
long fileSize = new FileInfo(filePath).Length;
|
||||||
lock (redundancies)
|
lock (redundancies)
|
||||||
{
|
{
|
||||||
if (redundancies.ContainsKey(fileHash))
|
if (!redundancies.ContainsKey(fileHash))
|
||||||
{
|
{
|
||||||
return;
|
var redundancy = new Redundancy() { Hash = fileHash, FileSize = fileSize };
|
||||||
}
|
redundancies.Add(fileHash, redundancy);
|
||||||
|
}
|
||||||
|
redundancies[fileHash].Paths.Add(filePath);
|
||||||
|
}
|
||||||
|
FileFound?.Invoke(this, new FileFoundEventArgs(filePath, fileHash, fileSize));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
FileError?.Invoke(this, new FileErrorEventArgs() { Exception = ex, Path = filePath });
|
||||||
|
}
|
||||||
|
|
||||||
if (!redundancies.ContainsKey(fileHash))
|
}
|
||||||
{
|
|
||||||
var redundancy = new Redundancy() { Hash = fileHash, FileSize = fileSize };
|
|
||||||
redundancies.Add(fileHash, redundancy);
|
|
||||||
}
|
|
||||||
redundancies[fileHash].Paths.Add(filePath);
|
|
||||||
}
|
|
||||||
FileFound?.Invoke(this, new FileFoundEventArgs(filePath, fileHash, fileSize));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
FileError?.Invoke(this, new FileErrorEventArgs() { Exception = ex, Path = filePath });
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ComputeFileHash(string filePath)
|
private static string ComputeFileHash(string filePath)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -38,19 +38,42 @@ namespace RedundancyFinderCLI
|
|||||||
}
|
}
|
||||||
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
|
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
var extensions = settings.Extensions.Split(",", StringSplitOptions.RemoveEmptyEntries);
|
var extensions = settings.Extensions.Split(",", StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
Finder finder = new Finder();
|
Finder finder = new Finder();
|
||||||
int hashingTasks = 0;
|
int hashingTasks = 0;
|
||||||
int hashingTasksFinished = 0;
|
int hashingTasksFinished = 0;
|
||||||
|
|
||||||
|
// Register the ProcessExit event to save redundancies on exit
|
||||||
|
AppDomain.CurrentDomain.ProcessExit += (sender, e) =>
|
||||||
|
{
|
||||||
|
SaveRedundancies(finder, settings.OutputPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load existing redundancies if the output file exists
|
||||||
|
if (File.Exists(settings.OutputPath))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var existingData = File.ReadAllText(settings.OutputPath);
|
||||||
|
var existingRedundancies = JsonConvert.DeserializeObject<Dictionary<string, Redundancy>>(existingData);
|
||||||
|
|
||||||
|
if (existingRedundancies != null)
|
||||||
|
{
|
||||||
|
foreach (var entry in existingRedundancies)
|
||||||
|
{
|
||||||
|
finder.Redundancies[entry.Key] = entry.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteLine($"[yellow]Resumed from existing output file: [/]'{settings.OutputPath}'");
|
||||||
|
WriteLine($"[yellow]Loaded {finder.Redundancies.Count} redundancies from the file.[/]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteLine($"[red]Failed to load existing output file: {ex.Message}[/]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
finder.FileError += (sender, e) =>
|
finder.FileError += (sender, e) =>
|
||||||
{
|
{
|
||||||
@ -58,14 +81,14 @@ namespace RedundancyFinderCLI
|
|||||||
{
|
{
|
||||||
if (settings.Verbose)
|
if (settings.Verbose)
|
||||||
{
|
{
|
||||||
AnsiConsole.MarkupLine($"[red]Access denied to file: [/]{e.Path}. Skipping. Error: [red]{e.Exception.Message}[/]");
|
WriteLine($"[red]Access denied to file: [/]{e.Path}. Skipping. Error: [red]{e.Exception.Message}[/]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (settings.Verbose)
|
if (settings.Verbose)
|
||||||
{
|
{
|
||||||
AnsiConsole.MarkupLine($"[red] Error processing file:\n[/]Path:{e.Path}\n[red]{e.Exception.Message}[/]");
|
WriteLine($"[red] Error processing file:\n[/]Path:{e.Path}\n[red]{e.Exception.Message}[/]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -76,14 +99,14 @@ namespace RedundancyFinderCLI
|
|||||||
{
|
{
|
||||||
if (settings.Verbose)
|
if (settings.Verbose)
|
||||||
{
|
{
|
||||||
AnsiConsole.MarkupLine($"[red]Access denied to directory: [/]{e.Path}. Skipping. Error: [red]{e.Exception.Message}[/]");
|
WriteLine($"[red]Access denied to directory: [/]{e.Path}. Skipping. Error: [red]{e.Exception.Message}[/]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (settings.Verbose)
|
if (settings.Verbose)
|
||||||
{
|
{
|
||||||
AnsiConsole.MarkupLine($"[red] Error processing directory:\n[/]Path:{e.Path}\n[red]{e.Exception.Message}[/]");
|
WriteLine($"[red] Error processing directory:\n[/]Path:{e.Path}\n[red]{e.Exception.Message}[/]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -92,68 +115,41 @@ namespace RedundancyFinderCLI
|
|||||||
{
|
{
|
||||||
if (settings.Verbose)
|
if (settings.Verbose)
|
||||||
{
|
{
|
||||||
AnsiConsole.MarkupLine($"[green]Processing file: [/]{e.Path}");
|
WriteLine($"[green]Processing file: [/]{e.Path}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var p = AnsiConsole.Progress();
|
var p = AnsiConsole.Progress();
|
||||||
p
|
p.Start(ctx =>
|
||||||
.Start(ctx =>
|
|
||||||
{
|
{
|
||||||
// Define tasks
|
|
||||||
//var hashing = ctx.AddTask("[green]Hashing Files[/]",autoStart:false,);
|
|
||||||
|
|
||||||
finder.TaskStarted += (sender, e) =>
|
finder.TaskStarted += (sender, e) =>
|
||||||
{
|
{
|
||||||
hashingTasks++;
|
hashingTasks++;
|
||||||
if (settings.Verbose)
|
if (settings.Verbose)
|
||||||
{
|
{
|
||||||
AnsiConsole.MarkupLine($"[green]Task started: [/]{e}");
|
WriteLine($"[green]Task started: [/]{e}");
|
||||||
}
|
}
|
||||||
//hashing.MaxValue = hashingTasks;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
finder.FileFound += (sender, e) =>
|
finder.FileFound += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (settings.Verbose)
|
if (settings.Verbose)
|
||||||
{
|
{
|
||||||
AnsiConsole.MarkupLine($"[green]File found: [/]{e.FilePath} {GetSizeFormat((ulong)e.Size)} ");
|
WriteLine($"[green]File found: [/]{e.FilePath} {GetSizeFormat((ulong)e.Size)} ");
|
||||||
}
|
}
|
||||||
hashingTasksFinished++;
|
hashingTasksFinished++;
|
||||||
//hashing.Value = hashingTasksFinished;
|
|
||||||
};
|
};
|
||||||
//hashing.Value = hashing.MaxValue;
|
|
||||||
finder.FindRedundancies(settings.SearchPaths, extensions);
|
finder.FindRedundancies(settings.SearchPaths, extensions);
|
||||||
//hashing.StopTask();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var json = JsonConvert.SerializeObject(finder.Redundancies, Formatting.Indented);
|
SaveRedundancies(finder, settings.OutputPath);
|
||||||
|
|
||||||
var outputPath = settings.OutputPath;
|
|
||||||
//check if path is relative or absolute
|
|
||||||
if (!Path.IsPathRooted(settings.OutputPath))
|
|
||||||
{
|
|
||||||
outputPath = Path.Combine(Directory.GetCurrentDirectory(), outputPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
File.WriteAllText(outputPath, json);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[yellow]Wrote [/]{finder.Redundancies.Count}[yellow] redundancies to [/]'{outputPath}'");
|
|
||||||
|
|
||||||
|
|
||||||
ulong totalSize = finder.Redundancies.Select(x => (ulong)x.Value.FileSize).Aggregate((a, b) => a + b);
|
ulong totalSize = finder.Redundancies.Select(x => (ulong)x.Value.FileSize).Aggregate((a, b) => a + b);
|
||||||
string sizeFormat = GetSizeFormat(totalSize);
|
string sizeFormat = GetSizeFormat(totalSize);
|
||||||
AnsiConsole.MarkupLine($"Total Size: [green]{sizeFormat}[/]");
|
WriteLine($"Total Size: [green]{sizeFormat}[/]");
|
||||||
|
|
||||||
if (settings.Verbose)
|
if (settings.Verbose)
|
||||||
{
|
{
|
||||||
@ -167,17 +163,43 @@ namespace RedundancyFinderCLI
|
|||||||
}
|
}
|
||||||
AnsiConsole.WriteLine();
|
AnsiConsole.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
AnsiConsole.MarkupLine($"[red] Error:\n[/]{e.Message}");
|
WriteLine($"[red] Error:\n[/]{e.Message}");
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SaveRedundancies(Finder finder, string outputPath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = JsonConvert.SerializeObject(finder.Redundancies, Formatting.Indented);
|
||||||
|
|
||||||
|
// Check if path is relative or absolute
|
||||||
|
if (!Path.IsPathRooted(outputPath))
|
||||||
|
{
|
||||||
|
outputPath = Path.Combine(Directory.GetCurrentDirectory(), outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllText(outputPath, json);
|
||||||
|
WriteLine($"[yellow]Wrote [/]{finder.Redundancies.Count}[yellow] redundancies to [/]'{outputPath}'");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteLine($"[red]Failed to save redundancies: {ex.Message}[/]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void WriteLine(string v)
|
||||||
|
{
|
||||||
|
string now = Markup.Escape($"[{DateTime.Now.ToString("HH:mm:ss")}]");
|
||||||
|
AnsiConsole.MarkupLine($"[gray]{now}[/] {v}");
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetSizeFormat(ulong totalSize)
|
private static string GetSizeFormat(ulong totalSize)
|
||||||
{
|
{
|
||||||
string sizeUnit = "B";
|
string sizeUnit = "B";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user