Skip to content

Commit

Permalink
Merge pull request #29 from mark-s/updatetonet6
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-s committed May 5, 2024
2 parents 927b110 + bca4759 commit b0d1d98
Show file tree
Hide file tree
Showing 22 changed files with 656 additions and 699 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CIBuildTest-Linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
dotnet-version: 6.x

- name: Build
working-directory: src
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/CodeQuality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
dotnet-version: 6.x

- name: Restore
working-directory: src
Expand Down
7 changes: 2 additions & 5 deletions src/QnapBackupDecryptor.Console/DecryptResult.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
using System.IO;
namespace QnapBackupDecryptor.Console;

namespace QnapBackupDecryptor.Console
{
public record DecryptResult(FileSystemInfo Source, FileSystemInfo Dest, bool Success, string ErrorMessage);
}
public record DecryptResult(FileSystemInfo Source, FileSystemInfo Dest, bool Success, string ErrorMessage);
60 changes: 28 additions & 32 deletions src/QnapBackupDecryptor.Console/Options.cs
Original file line number Diff line number Diff line change
@@ -1,48 +1,44 @@
using CommandLine;
using CommandLine.Text;
using System.Collections.Generic;

namespace QnapBackupDecryptor.Console
{
namespace QnapBackupDecryptor.Console;

public class Options
{
[Option('p', "password", Required = false, HelpText = "Password")]
public string Password { get; set; }
public class Options
{
[Option('p', "password", Required = false, HelpText = "Password")]
public string? Password { get; set; }

[Option('e', "encrypted", Required = true, HelpText = "Encrypted file or folder")]
public string EncryptedSource { get; set; }
[Option('e', "encrypted", Required = true, HelpText = "Encrypted file or folder")]
public string EncryptedSource { get; set; } = null!;

[Option('d', "decrypted", Required = true, HelpText = "Where to place the decrypted file(s)")]
public string OutputDestination { get; set; }
[Option('d', "decrypted", Required = true, HelpText = "Where to place the decrypted file(s)")]
public string OutputDestination { get; set; } = null!;

[Option('s', "subfolders", Required = false, HelpText = "Include Subfolders (default: false)")]
public bool IncludeSubfolders { get; set; }
[Option('s', "subfolders", Required = false, HelpText = "Include Subfolders (default: false)")]
public bool IncludeSubfolders { get; set; }

[Option('v', "verbose", Required = false, HelpText = "Set output to verbose")]
public bool Verbose { get; set; }
[Option('v', "verbose", Required = false, HelpText = "Set output to verbose")]
public bool Verbose { get; set; }

[Option('o', "overwrite", Required = false, HelpText = "Overwrite file(s) in output (default: false)")]
public bool Overwrite { get; set; }
[Option('o', "overwrite", Required = false, HelpText = "Overwrite file(s) in output (default: false)")]
public bool Overwrite { get; set; }

[Option('r', "removeencrypted", Required = false, HelpText = "Delete encrypted files when decrypted (default: false)")]
public bool RemoveEncrypted { get; set; }
[Option('r', "removeencrypted", Required = false, HelpText = "Delete encrypted files when decrypted (default: false)")]
public bool RemoveEncrypted { get; set; }


[Usage(ApplicationAlias = "QnapBackupDecryptor")]
// ReSharper disable once UnusedMember.Global
public static IEnumerable<Example> Examples
[Usage(ApplicationAlias = "QnapBackupDecryptor")]
// ReSharper disable once UnusedMember.Global
public static IEnumerable<Example> Examples
{
get
{
get
{
yield return new Example("Decrypt a single file", new Options { EncryptedSource = "file.bin", OutputDestination = "out.bin", Password = "Pa$$word" });
yield return new Example("Decrypt a folder", new Options { EncryptedSource = "./encryptedfolder", OutputDestination = "./decryptedfolder", Password = "Pa$$word" });
yield return new Example("Decrypt a folder, and delete the source encrypted files", new Options { EncryptedSource = "./encryptedfolder", OutputDestination = "./decryptedfolder", RemoveEncrypted = true });
yield return new Example("Decrypt a folder, overwriting files in the destination", new Options { EncryptedSource = "./encryptedfolder", OutputDestination = "./decryptedfolder", Password = "Pa$$word", Overwrite = true });
yield return new Example("Decrypt a folder and all subfolders, and prompt for password", new Options { EncryptedSource = "./encryptedfolder", OutputDestination = "./decryptedfolder", IncludeSubfolders = true });
}
yield return new Example("Decrypt a single file", new Options { EncryptedSource = "file.bin", OutputDestination = "out.bin", Password = "Pa$$word" });
yield return new Example("Decrypt a folder", new Options { EncryptedSource = "./encryptedfolder", OutputDestination = "./decryptedfolder", Password = "Pa$$word" });
yield return new Example("Decrypt a folder, and delete the source encrypted files", new Options { EncryptedSource = "./encryptedfolder", OutputDestination = "./decryptedfolder", RemoveEncrypted = true });
yield return new Example("Decrypt a folder, overwriting files in the destination", new Options { EncryptedSource = "./encryptedfolder", OutputDestination = "./decryptedfolder", Password = "Pa$$word", Overwrite = true });
yield return new Example("Decrypt a folder and all subfolders, and prompt for password", new Options { EncryptedSource = "./encryptedfolder", OutputDestination = "./decryptedfolder", IncludeSubfolders = true });
}

}

}
}
220 changes: 108 additions & 112 deletions src/QnapBackupDecryptor.Console/Output.cs
Original file line number Diff line number Diff line change
@@ -1,145 +1,141 @@
using QnapBackupDecryptor.Core;
using Spectre.Console;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace QnapBackupDecryptor.Console
namespace QnapBackupDecryptor.Console;

internal class Output
{
internal class Output
public static void ShowResults(ConcurrentBag<DecryptResult> decryptResults, ConcurrentBag<DeleteResult> deleteResults, bool verbose, TimeSpan swElapsed)
{
public static void ShowResults(ConcurrentBag<DecryptResult> decryptResults, ConcurrentBag<DeleteResult> deleteResults, bool verbose, TimeSpan swElapsed)
if (verbose && decryptResults.Count > 1)
{
if (verbose && decryptResults.Count > 1)
{
ShowFileListResults(decryptResults, deleteResults);
ShowSimpleResults(decryptResults, deleteResults);
}
else
{
ShowSimpleResults(decryptResults, deleteResults);
AnsiConsole.MarkupLine("Add --verbose to see details.");
}

ShowTiming(swElapsed);

if (decryptResults.Any(r => r.Success == false) || deleteResults.Any(r => r.DeletedOk == false))
Environment.ExitCode = 1;
ShowFileListResults(decryptResults, deleteResults);
ShowSimpleResults(decryptResults, deleteResults);
}

private static void ShowSimpleResults(ConcurrentBag<DecryptResult> decryptResults, ConcurrentBag<DeleteResult> deleteResults)
else
{
var table = new Table();
table
.AddColumn(new TableColumn("Total encrypted files").RightAligned())
.AddColumn(new TableColumn("Decrypt Ok").RightAligned())
.AddColumn(new TableColumn("Decrypt Failed").RightAligned())
.AddColumn(new TableColumn("Delete Ok").RightAligned())
.AddColumn(new TableColumn("Delete Failed").RightAligned());

table.AddRow(
$"{decryptResults.Count}",
$"[green]{decryptResults.Count(r => r.Success)}[/]",
$"[red]{decryptResults.Count(r => !r.Success)}[/]",
$"[green]{deleteResults.Count(r => r.DeletedOk)}[/]",
$"[red]{deleteResults.Count(r => !r.DeletedOk)}[/]"
);

AnsiConsole.Render(table);
ShowSimpleResults(decryptResults, deleteResults);
AnsiConsole.MarkupLine("Add --verbose to see details.");
}

private static void ShowFileListResults(ConcurrentBag<DecryptResult> decryptResults, ConcurrentBag<DeleteResult> deleteResults)
{
var table = new Table();
table
.AddColumn(new TableColumn("Decrypt Status").Centered())
.AddColumn("Encrypted")
.AddColumn("Decrypted");
ShowTiming(swElapsed);

if (decryptResults.Any(r => r.Success == false))
table.AddColumn("Error");
if (decryptResults.Any(r => r.Success == false) || deleteResults.Any(r => r.DeletedOk == false))
Environment.ExitCode = 1;
}

if (deleteResults.Any())
{
table.AddColumn(new TableColumn("Delete Status").Centered());
if (deleteResults.Any(r => r.DeletedOk == false))
table.AddColumn("Error");
}
private static void ShowSimpleResults(ConcurrentBag<DecryptResult> decryptResults, ConcurrentBag<DeleteResult> deleteResults)
{
var table = new Table();
table
.AddColumn(new TableColumn("Total encrypted files").RightAligned())
.AddColumn(new TableColumn("Decrypt Ok").RightAligned())
.AddColumn(new TableColumn("Decrypt Failed").RightAligned())
.AddColumn(new TableColumn("Delete Ok").RightAligned())
.AddColumn(new TableColumn("Delete Failed").RightAligned());

table.AddRow(
$"{decryptResults.Count}",
$"[green]{decryptResults.Count(r => r.Success)}[/]",
$"[red]{decryptResults.Count(r => !r.Success)}[/]",
$"[green]{deleteResults.Count(r => r.DeletedOk)}[/]",
$"[red]{deleteResults.Count(r => !r.DeletedOk)}[/]"
);

AnsiConsole.Write(table);
}

var deleteResultsLookup = deleteResults.ToDictionary(r => r.ToDelete, r => r);
private static void ShowFileListResults(ConcurrentBag<DecryptResult> decryptResults, ConcurrentBag<DeleteResult> deleteResults)
{
var table = new Table();
table
.AddColumn(new TableColumn("Decrypt Status").Centered())
.AddColumn("Encrypted")
.AddColumn("Decrypted");

foreach (var result in decryptResults)
{
var resultRow = DecryptResultToRow(result);
if (decryptResults.Any(r => r.Success == false))
table.AddColumn("Error");

if (deleteResultsLookup.TryGetValue(result.Source, out var deleteResult))
resultRow.AddRange(DeleteResultToRow(deleteResult));
if (deleteResults.Any())
{
table.AddColumn(new TableColumn("Delete Status").Centered());
if (deleteResults.Any(r => r.DeletedOk == false))
table.AddColumn("Error");
}

table.AddRow(resultRow.ToArray());
}
var deleteResultsLookup = deleteResults.ToDictionary(r => r.ToDelete, r => r);

AnsiConsole.Render(table);
foreach (var result in decryptResults)
{
var resultRow = DecryptResultToRow(result);

}
if (deleteResultsLookup.TryGetValue(result.Source, out var deleteResult))
resultRow.AddRange(DeleteResultToRow(deleteResult));

private static List<string> DecryptResultToRow(DecryptResult decryptResult)
{
var colour = decryptResult.Success ? "green" : "red";
var status = decryptResult.Success ? "OK" : "Fail";
table.AddRow(resultRow.ToArray());
}

var row = new List<string>
{
$"[{colour}]{status}[/]",
$"[{colour}]{decryptResult.Source.FullName}[/]",
$"[{colour}]{decryptResult.Dest.FullName}[/]"
};
AnsiConsole.Write(table);

if (decryptResult.Success == false)
row.Add($"[{colour}]{decryptResult.ErrorMessage}[/]");
}

return row;
}
private static List<string> DecryptResultToRow(DecryptResult decryptResult)
{
var colour = decryptResult.Success ? "green" : "red";
var status = decryptResult.Success ? "OK" : "Fail";

private static List<string> DeleteResultToRow(DeleteResult deleteResult)
var row = new List<string>
{
if (deleteResult == null)
return new List<string>(0);
$"[{colour}]{status}[/]",
$"[{colour}]{decryptResult.Source.FullName}[/]",
$"[{colour}]{decryptResult.Dest.FullName}[/]"
};

var colour = deleteResult.DeletedOk ? "green" : "red";
var status = deleteResult.DeletedOk ? "Deleted" : "Failed";
if (decryptResult.Success == false)
row.Add($"[{colour}]{decryptResult.ErrorMessage}[/]");

var row = new List<string>
{
$"[{colour}]{status}[/]"
};
return row;
}

if (deleteResult.DeletedOk == false)
row.Add($"[{colour}]{deleteResult.ErrorMessage}[/]");
private static List<string> DeleteResultToRow(DeleteResult deleteResult)
{
if (deleteResult == null)
return new List<string>(0);

return row;
}
var colour = deleteResult.DeletedOk ? "green" : "red";
var status = deleteResult.DeletedOk ? "Deleted" : "Failed";

private static void ShowTiming(TimeSpan swElapsed)
var row = new List<string>
{
switch (swElapsed.TotalMinutes)
{
case < 1:
AnsiConsole.MarkupLine($"[bold]Took {swElapsed.TotalSeconds:0.000} seconds[/]");
break;
default:
AnsiConsole.MarkupLine($"[bold]Took {swElapsed.TotalMinutes} minutes[/]");
break;
}
}
$"[{colour}]{status}[/]"
};

if (deleteResult.DeletedOk == false)
row.Add($"[{colour}]{deleteResult.ErrorMessage}[/]");

public static ProgressColumn[] GetProgressColumns()
=> new ProgressColumn[]
{
new TaskDescriptionColumn(),
new ProgressBarColumn(),
new PercentageColumn(),
new SpinnerColumn(Spinner.Known.SimpleDots),
};
return row;
}
}

private static void ShowTiming(TimeSpan swElapsed)
{
switch (swElapsed.TotalMinutes)
{
case < 1:
AnsiConsole.MarkupLine($"[bold]Took {swElapsed.TotalSeconds:0.000} seconds[/]");
break;
default:
AnsiConsole.MarkupLine($"[bold]Took {swElapsed.TotalMinutes} minutes[/]");
break;
}
}

public static ProgressColumn[] GetProgressColumns()
=> new ProgressColumn[]
{
new TaskDescriptionColumn(),
new ProgressBarColumn(),
new PercentageColumn(),
new SpinnerColumn(Spinner.Known.SimpleDots),
};
}
Loading

0 comments on commit b0d1d98

Please sign in to comment.