-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from mark-s/updatetonet6
- Loading branch information
Showing
22 changed files
with
656 additions
and
699 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }); | ||
} | ||
|
||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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), | ||
}; | ||
} |
Oops, something went wrong.