Compare commits

..

3 Commits

Author SHA1 Message Date
3834c2fba0 release 0.5 2025-05-11 00:20:45 +02:00
f8d8c4461f Delete command imlpemented
Cancellation
Formatting
2025-05-11 00:19:58 +02:00
30738eef24 Implemented DeleteCommand 2025-05-10 22:21:11 +02:00
8 changed files with 320 additions and 134 deletions

BIN
0.5.zip Normal file

Binary file not shown.

View File

@ -4,6 +4,8 @@ namespace RedundancyFinder
{ {
public class Finder public class Finder
{ {
public CancellationToken cancellation;
Dictionary<string, Redundancy> redundancies = new Dictionary<string, Redundancy>(); Dictionary<string, Redundancy> redundancies = new Dictionary<string, Redundancy>();
public Dictionary<string, Redundancy> Redundancies { get => redundancies; } public Dictionary<string, Redundancy> Redundancies { get => redundancies; }
@ -19,10 +21,14 @@ 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)); 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)
{ {
if (cancellation.IsCancellationRequested)
{
return;
}
if (Directory.Exists(path)) if (Directory.Exists(path))
{ {
ProcessDirectory(path); ProcessDirectory(path);
@ -36,17 +42,29 @@ namespace RedundancyFinder
private void ProcessDirectory(string directoryPath) private void ProcessDirectory(string directoryPath)
{ {
if (cancellation.IsCancellationRequested)
{
return;
}
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))
{ {
if (cancellation.IsCancellationRequested)
{
return;
}
ProcessFile(file); ProcessFile(file);
} }
// Recursively process subdirectories // Recursively process subdirectories
foreach (var subDirectory in Directory.GetDirectories(directoryPath)) foreach (var subDirectory in Directory.GetDirectories(directoryPath))
{ {
if (cancellation.IsCancellationRequested)
{
return;
}
// Check if the directory is hidden and skip it if true // Check if the directory is hidden and skip it if true
var attributes = File.GetAttributes(subDirectory); var attributes = File.GetAttributes(subDirectory);
if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden) if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
@ -73,7 +91,11 @@ namespace RedundancyFinder
private void ProcessFile(string filePath) private void ProcessFile(string filePath)
{ {
if(ignorePaths.Contains(filePath)) if (cancellation.IsCancellationRequested)
{
return;
}
if (ignorePaths.Contains(filePath))
{ {
return; return;
} }
@ -83,8 +105,8 @@ namespace RedundancyFinder
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
{ {
@ -95,14 +117,14 @@ namespace RedundancyFinder
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))
{ {
var redundancy = new Redundancy() { Hash = fileHash, FileSize = fileSize }; var redundancy = new Redundancy() { Hash = fileHash, FileSize = fileSize };
redundancies.Add(fileHash, redundancy); Redundancies.Add(fileHash, redundancy);
} }
redundancies[fileHash].Paths.Add(filePath); Redundancies[fileHash].Paths.Add(filePath);
} }
FileFound?.Invoke(this, new FileFoundEventArgs(filePath, fileHash, fileSize)); FileFound?.Invoke(this, new FileFoundEventArgs(filePath, fileHash, fileSize));
} }

View File

@ -24,7 +24,7 @@ namespace RedundancyFinderCLI
[Description("File extensions to search for. Comma separated.")] [Description("File extensions to search for. Comma separated.")]
[CommandOption("-e|--extensions")] [CommandOption("-e|--extensions")]
[DefaultValue(".jpg,.webp,.raw,.pdf,.xsl,.xslx,.doc,.docx,.txt,.jpeg,.mov,.mp4,.mp3,.wav,.bmp,.gif,.png,.cu,.mid,.msb ,.mov,.avi,.wmv,.flv,.m4v,.bak ,.cpr ,.xml,.psd")] [DefaultValue(".jpg,.webp,.raw,.pdf,.xsl,.xslx,.doc,.docx,.txt,.jpeg,.mov,.mp4,.mp3,.wav,.bmp,.gif,.png,.cu,.mid,.msb,.mov,.avi,.wmv,.flv,.m4v,.bak ,.cpr,.xml,.psd")]
public string? Extensions { get; init; } public string? Extensions { get; init; }
[Description("Show all information.")] [Description("Show all information.")]
@ -35,42 +35,62 @@ namespace RedundancyFinderCLI
} }
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
{ {
WriteLine($"[yellow]Analyzing {settings.Path}[/]");
var redundancies = JsonConvert.DeserializeObject<Dictionary<string, Redundancy>>(File.ReadAllText(settings.Path)); Dictionary<string, Redundancy> redundancies = null;
AnsiConsole.Status()
.Start($"[yellow]Analyzing [/]'{settings.Path}'", ctx =>
{
ctx.Spinner(Spinner.Known.Clock);
ctx.SpinnerStyle = Style.Parse("yellow bold");
Thread.Sleep(1000);
redundancies = JsonConvert.DeserializeObject<Dictionary<string, Redundancy>>(File.ReadAllText(settings.Path));
});
if (redundancies == null)
{
}
var groups = redundancies var groups = redundancies
.GroupBy(x => Path.GetExtension(x.Value.Paths[0]), x => x.Value) .GroupBy(x => Path.GetExtension(x.Value.Paths[0]), x => x.Value)
.ToDictionary(x => x.Key, x => new .ToDictionary(x => x.Key, x => new
{ {
FileSize = x.Sum(y => y.FileSize), FileSize = x.Sum(y => y.FileSize),
RedundancySize = x.Sum(y => y.FileSize) * (x.Sum(y => y.Paths.Count) - 1), RedundancySize = x.Sum(y => y.FileSize * (y.Paths.Count - 1)),
RedundancyCount = x.Sum(y => y.Paths.Count)-1, RedundancyCount = x.Sum(y => y.Paths.Count) - 1,
RedundantFiles = x.Count(y => y.Paths.Count > 1)
}); });
// x => new { FileSize = x, RedundancySize = x.Sum()*(x.Count()-1)} // x => new { FileSize = x, RedundancySize = x.Sum()*(x.Count()-1)}
var extensions = settings.Extensions.Split(",", StringSplitOptions.RemoveEmptyEntries); var extensions = settings.Extensions.Split(",", StringSplitOptions.RemoveEmptyEntries);
var table = new Table(); var table = new Table();
table.AddColumn("Type"); table.AddColumn("Extension");
table.AddColumn(new TableColumn("Files").RightAligned());
table.AddColumn(new TableColumn("Size").RightAligned()); table.AddColumn(new TableColumn("Size").RightAligned());
table.AddColumn(new TableColumn("Redundancy size").RightAligned()); table.AddColumn(new TableColumn("Redundancies").RightAligned());
table.AddColumn(new TableColumn("Redundancy count").RightAligned()); table.AddColumn(new TableColumn("Redundancies size").RightAligned());
foreach (var extension in extensions)
foreach (var extension in extensions.OrderBy(x => x))
{ {
if (groups.ContainsKey(extension)) if (groups.ContainsKey(extension))
{ {
var size = groups[extension].FileSize; var size = groups[extension].FileSize;
var sizeFormat = GetSizeFormat((ulong)size); var sizeFormat = Global.GetSizeFormat((ulong)size);
var redundancySize = groups[extension].RedundancySize; var redundancySize = groups[extension].RedundancySize;
var redundancySizeFormat = GetSizeFormat((ulong)redundancySize); var redundancySizeFormat = Global.GetSizeFormat((ulong)redundancySize);
table.AddRow( table.AddRow(
new Text(extension), new Text(extension),
new Markup($"[darkgreen]{groups[extension].RedundantFiles}[/]"),
new Markup($"[green]{sizeFormat}[/]"), new Markup($"[green]{sizeFormat}[/]"),
new Markup($"[yellow]{redundancySizeFormat}[/]"), new Markup($"[cyan]{groups[extension].RedundancyCount}[/]"),
new Markup($"{groups[extension].RedundancyCount}")); new Markup($"[yellow]{redundancySizeFormat}[/]"));
} }
} }
AnsiConsole.Write(table); AnsiConsole.Write(table);
@ -78,31 +98,5 @@ namespace RedundancyFinderCLI
} }
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)
{
string sizeUnit = "B";
double size = totalSize;
while (size > 1024)
{
size /= 1024d;
sizeUnit = sizeUnit switch
{
"B" => "KB",
"KB" => "MB",
"MB" => "GB",
"GB" => "TB",
_ => sizeUnit
};
}
string sizeFormat = $"{size:.00} {sizeUnit}";
return sizeFormat;
}
} }
} }

View File

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Newtonsoft.Json;
using RedundancyFinder;
using Spectre.Console;
using Spectre.Console.Cli;
namespace RedundancyFinderCLI
{
internal sealed class DeleteCommand : Command<DeleteCommand.Settings>
{
public sealed class Settings : CommandSettings
{
[Description("Paths to Keep.")]
[DefaultValue(new string[] { "H:\\" })]
[CommandArgument(1, "[path]")]
public string[]? FoldersToKeep { get; init; }
[Description("Path to analyze.")]
[DefaultValue("redundancies.json")]
[CommandArgument(0, "[path]")]
public string? Path { get; init; }
[Description("File extensions to search for. Comma separated.")]
[CommandOption("-e|--extensions")]
[DefaultValue(".jpg,.webp,.raw,.pdf,.xsl,.xslx,.doc,.docx,.txt,.jpeg,.mov,.mp4,.mp3,.wav,.bmp,.gif,.png,.cu,.mid,.msb,.mov,.avi,.wmv,.flv,.m4v,.bak,.cpr,.xml,.psd")]
public string? Extensions { get; init; }
[Description("Show all information.")]
[CommandOption("-v|--verbose")]
[DefaultValue(false)]
public bool Verbose { get; init; }
}
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
{
Global.WriteLine($"[yellow]Analyzing {settings.Path}[/]");
var redundancies = JsonConvert.DeserializeObject<Dictionary<string, Redundancy>>(File.ReadAllText(settings.Path));
var pathsToDelete = new List<string>();
foreach (var redundancy in redundancies.Values)
{
var pathToKeep = redundancy.Paths.FirstOrDefault(x => settings.FoldersToKeep.Any(y => x.StartsWith(y)));
if (pathToKeep != default)
{
foreach (var path in redundancy.Paths)
{
if (path != pathToKeep)
{
pathsToDelete.Add(path);
}
}
}
else if(settings.Verbose)
{
if (redundancy.Paths.Count > 0)
{
Global.WriteLine($"[blue]Skipping [/]'{redundancy.Paths.FirstOrDefault()}'[blue]. No paths to keep![/]");
}
else
{
Global.WriteLine($"[yellow]Skipping [/]'{redundancy.Hash}'[/].[blue] No paths![/]");
}
}
}
foreach (var path in pathsToDelete)
{
AnsiConsole.WriteLine(path);
}
if (pathsToDelete.Count == 0)
{
Global.WriteLine("[yellow]Nothing to delete![/]");
return 0;
}
var confirmation = AnsiConsole.Prompt(
new TextPrompt<bool>("Delete all of the above?")
.AddChoice(true)
.AddChoice(false)
.DefaultValue(true)
.WithConverter(choice => choice ? "y" : "n"));
if (confirmation)
{
foreach (var path in pathsToDelete)
{
try
{
File.Delete(path);
}
catch (Exception e)
{
Global.WriteLine($"[red]Error deleting file: [/]'{path}'\nMessage:\n{e.Message}");
}
Global.WriteLine($"[yellow]Deleted file: [/]'{path}'");
}
}
return 0;
}
}
}

View File

@ -34,29 +34,39 @@ namespace RedundancyFinderCLI
[Description("Output path.")] [Description("Output path.")]
[CommandOption("-o|--output")] [CommandOption("-o|--output")]
[DefaultValue("redundancies.json")] [DefaultValue("redundancies.json")]
public string? OutputPath {get; init;} public string? OutputPath { get; init; }
} }
CancellationTokenSource cancellation = new CancellationTokenSource();
Task task = null;
Finder finder = new Finder();
Settings settings = null;
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
{ {
finder.cancellation = cancellation.Token;
this.settings = settings;
var extensions = settings.Extensions.Split(",", StringSplitOptions.RemoveEmptyEntries); var extensions = settings.Extensions.Split(",", StringSplitOptions.RemoveEmptyEntries);
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 // Register the ProcessExit event to save redundancies on exit
AppDomain.CurrentDomain.ProcessExit += (sender, e) => AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{ {
SaveRedundancies(finder, settings.OutputPath); End();
}; };
// Register the CancelKeyPress event to handle Ctrl+C // Register the CancelKeyPress event to handle Ctrl+C
Console.CancelKeyPress += (sender, e) => Console.CancelKeyPress += (sender, e) =>
{ {
cancellation.Cancel(); // Cancel the ongoing tasks
e.Cancel = true; // Prevent the process from terminating immediately e.Cancel = true; // Prevent the process from terminating immediately
WriteLine("[yellow]Ctrl+C detected. Saving redundancies before exiting...[/]");
SaveRedundancies(finder, settings.OutputPath ?? "redundancies.json"); Global.WriteLine("[yellow]Ctrl+C detected. Saving redundancies before exiting...[/]");
Environment.Exit(0); // Exit the application gracefully
End();
}; };
// Load existing redundancies if the output file exists // Load existing redundancies if the output file exists
@ -74,13 +84,13 @@ namespace RedundancyFinderCLI
finder.Redundancies[entry.Key] = entry.Value; finder.Redundancies[entry.Key] = entry.Value;
} }
WriteLine($"[yellow]Resumed from existing output file: [/]'{settings.OutputPath}'"); Global.WriteLine($"[yellow]Resumed from existing output file: [/]'{settings.OutputPath}'");
WriteLine($"[yellow]Loaded {finder.Redundancies.Count} redundancies from the file.[/]"); Global.WriteLine($"[yellow]Loaded {finder.Redundancies.Count} redundancies from the file.[/]");
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
WriteLine($"[red]Failed to load existing output file: {ex.Message}[/]"); Global.WriteLine($"[red]Failed to load existing output file: {Markup.Escape(ex.Message)}[/]");
} }
} }
@ -90,14 +100,14 @@ namespace RedundancyFinderCLI
{ {
if (settings.Verbose) if (settings.Verbose)
{ {
WriteLine($"[red]Access denied to file: [/]{e.Path}. Skipping. Error: [red]{e.Exception.Message}[/]"); Global.WriteLine($"[red]Access denied to file: [/]{e.Path}. Skipping. Error: [red]{Markup.Escape(e.Exception.Message)}[/]");
} }
} }
else else
{ {
if (settings.Verbose) if (settings.Verbose)
{ {
WriteLine($"[red] Error processing file:\n[/]Path:{e.Path}\n[red]{e.Exception.Message}[/]"); Global.WriteLine($"[red] Error processing file:\n[/]Path:{e.Path}\n[red]{Markup.Escape(e.Exception.Message)}[/]");
} }
} }
}; };
@ -108,14 +118,14 @@ namespace RedundancyFinderCLI
{ {
if (settings.Verbose) if (settings.Verbose)
{ {
WriteLine($"[red]Access denied to directory: [/]{e.Path}. Skipping. Error: [red]{e.Exception.Message}[/]"); Global.WriteLine($"[red]Access denied to directory: [/]{e.Path}. Skipping. Error: [red]{Markup.Escape(e.Exception.Message)}[/]");
} }
} }
else else
{ {
if (settings.Verbose) if (settings.Verbose)
{ {
WriteLine($"[red] Error processing directory:\n[/]Path:{e.Path}\n[red]{e.Exception.Message}[/]"); Global.WriteLine($"[red] Error processing directory:\n[/]Path:{e.Path}\n[red]{Markup.Escape(e.Exception.Message)}[/]");
} }
} }
}; };
@ -124,109 +134,102 @@ namespace RedundancyFinderCLI
{ {
if (settings.Verbose) if (settings.Verbose)
{ {
WriteLine($"[green]Processing file: [/]{e.Path}"); Global.WriteLine($"[green]Processing file: [/]{e.Path}");
} }
}; };
try try
{ {
var p = AnsiConsole.Progress();
p.Start(ctx => finder.TaskStarted += (sender, e) =>
{ {
finder.TaskStarted += (sender, e) => hashingTasks++;
if (settings.Verbose)
{ {
hashingTasks++; Global.WriteLine($"[green]Task started: [/]{e}");
if (settings.Verbose)
{
WriteLine($"[green]Task started: [/]{e}");
}
};
finder.FileFound += (sender, e) =>
{
if (settings.Verbose)
{
WriteLine($"[green]File found: [/]{e.FilePath} {GetSizeFormat((ulong)e.Size)} ");
}
hashingTasksFinished++;
};
finder.FindRedundancies(settings.SearchPaths, extensions);
});
SaveRedundancies(finder, settings.OutputPath);
ulong totalSize = finder.Redundancies.Select(x => (ulong)x.Value.FileSize).Aggregate((a, b) => a + b);
string sizeFormat = GetSizeFormat(totalSize);
WriteLine($"Total Size: [green]{sizeFormat}[/]");
if (settings.Verbose)
{
foreach (var redundancy in finder.Redundancies.Values)
{
AnsiConsole.WriteLine($"Hash: {redundancy.Hash}");
AnsiConsole.WriteLine("Paths:");
foreach (var path in redundancy.Paths)
{
AnsiConsole.WriteLine(path);
}
AnsiConsole.WriteLine();
} }
};
finder.FileFound += (sender, e) =>
{
if (settings.Verbose)
{
Global.WriteLine($"[green]File found: [/]{e.FilePath} [darkgreen]{Global.GetSizeFormat((ulong)e.Size)}[/]");
}
hashingTasksFinished++;
};
task = Task.Run(() =>
{
finder.FindRedundancies(settings.SearchPaths, extensions);
}, cancellation.Token);
try
{
task.Wait(cancellation.Token);
}
catch (Exception)
{
}
finally
{
End();
} }
} }
catch (Exception e) catch (Exception e)
{ {
WriteLine($"[red] Error:\n[/]{e.Message}"); Global.WriteLine($"[red] Error:\n[/]{e.Message}");
} }
return 0; return 0;
} }
private void End()
{
SaveRedundancies(finder, settings.OutputPath);
ulong totalSize = finder.Redundancies.Select(x => (ulong)x.Value.FileSize).Aggregate((a, b) => a + b);
string sizeFormat = Global.GetSizeFormat(totalSize);
Global.WriteLine($"Total Size: [green]{sizeFormat}[/]");
Environment.Exit(0); // Exit the application gracefully
}
private void SaveRedundancies(Finder finder, string outputPath) private void SaveRedundancies(Finder finder, string outputPath)
{ {
try try
{ {
var json = JsonConvert.SerializeObject(finder.Redundancies, Formatting.Indented);
// Check if path is relative or absolute // Check if path is relative or absolute
if (!Path.IsPathRooted(outputPath)) if (!Path.IsPathRooted(outputPath))
{ {
outputPath = Path.Combine(Directory.GetCurrentDirectory(), outputPath); outputPath = Path.Combine(Directory.GetCurrentDirectory(), outputPath);
} }
string json = null;
// AnsiConsole.Status()
//.Start(Global.Format($"[yellow]Writing to [/]'{outputPath}' [yellow] This may take a long time.[/]"), ctx =>
//{
// ctx.Spinner(Spinner.Known.Clock);
// ctx.SpinnerStyle = Style.Parse("yellow bold");
// Thread.Sleep(1000);
// lock (finder.Redundancies)
// {
// }
//});
json = JsonConvert.SerializeObject(finder.Redundancies, Formatting.Indented);
File.WriteAllText(outputPath, json); File.WriteAllText(outputPath, json);
WriteLine($"[yellow]Wrote [/]{finder.Redundancies.Count}[yellow] redundancies to [/]'{outputPath}'");
Global.WriteLine($"[yellow]Wrote [/]{finder.Redundancies.Count}[yellow] redundancies to [/]'{outputPath}'");
} }
catch (Exception ex) catch (Exception ex)
{ {
WriteLine($"[red]Failed to save redundancies: {ex.Message}[/]"); Global.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)
{
string sizeUnit = "B";
while (totalSize > 1024)
{
totalSize /= 1024;
sizeUnit = sizeUnit switch
{
"B" => "KB",
"KB" => "MB",
"MB" => "GB",
"GB" => "TB",
_ => sizeUnit
};
}
string sizeFormat = $"{totalSize:.##} {sizeUnit}";
return sizeFormat;
}
} }
} }

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Spectre.Console;
namespace RedundancyFinderCLI
{
public static class Global
{
public static void WriteLine(string v)
{
AnsiConsole.MarkupLine(Format(v));
}
public static string Format(string v)
{
string now = Markup.Escape($"[{DateTime.Now.ToString("HH:mm:ss")}]");
return $"[gray]{now}[/] {v}";
}
public static string GetSizeFormat(ulong totalSize)
{
string sizeUnit = "B";
double size = totalSize;
while (size > 1024)
{
size /= 1024d;
sizeUnit = sizeUnit switch
{
"B" => "KB",
"KB" => "MB",
"MB" => "GB",
"GB" => "TB",
_ => sizeUnit
};
}
string sizeFormat = $"{size:.00} {sizeUnit}";
return sizeFormat;
}
}
}

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Text;
using System.Text.Json; using System.Text.Json;
using RedundancyFinder; using RedundancyFinder;
using RedundancyFinderCLI; using RedundancyFinderCLI;
@ -9,10 +10,12 @@ internal class Program
{ {
private static void Main(string[] args) private static void Main(string[] args)
{ {
Console.OutputEncoding = Encoding.UTF8;
var app = new CommandApp<FinderCommand>(); var app = new CommandApp<FinderCommand>();
app.Configure(config => app.Configure(config =>
{ {
config.AddCommand<AnalyzeCommand>("analyze"); config.AddCommand<AnalyzeCommand>("analyze");
config.AddCommand<DeleteCommand>("delete");
#if DEBUG #if DEBUG
config.PropagateExceptions(); config.PropagateExceptions();

View File

@ -7,6 +7,10 @@
"Analyze": { "Analyze": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "analyze" "commandLineArgs": "analyze"
},
"Delete": {
"commandName": "Project",
"commandLineArgs": "delete redundancies.json C:\\Users\\daskn\\Pictures\\B\\ -v"
} }
} }
} }