#33 Tapeti.Cmd confirm overwrite existing files when exporting
Also fixed issue with input remaining in buffer which can cause accidental confirms
This commit is contained in:
parent
71df3e3f22
commit
0fb2c48083
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Console = System.Console;
|
||||
|
||||
namespace Tapeti.Cmd.ConsoleHelper
|
||||
{
|
||||
@ -138,39 +140,79 @@ namespace Tapeti.Cmd.ConsoleHelper
|
||||
|
||||
public abstract bool Enabled { get; }
|
||||
|
||||
public abstract void WriteCaptured(string value, Action processInput);
|
||||
public abstract void WriteLine(string value);
|
||||
|
||||
|
||||
public void Confirm(string message)
|
||||
{
|
||||
WriteLine(message);
|
||||
TryReadKey(false, out _);
|
||||
|
||||
// Clear any previous key entered before this confirmation
|
||||
while (!Owner.Cancelled && Console.KeyAvailable)
|
||||
Console.ReadKey(true);
|
||||
|
||||
while (!Owner.Cancelled && !Console.KeyAvailable)
|
||||
Thread.Sleep(50);
|
||||
|
||||
if (Owner.Cancelled)
|
||||
return;
|
||||
|
||||
Console.ReadKey(true);
|
||||
}
|
||||
|
||||
|
||||
public bool ConfirmYesNo(string message)
|
||||
{
|
||||
WriteLine($"{message} (Y/N) ");
|
||||
if (!TryReadKey(true, out var key))
|
||||
return false;
|
||||
var confirmed = false;
|
||||
|
||||
return key.KeyChar == 'y' || key.KeyChar == 'Y';
|
||||
}
|
||||
|
||||
|
||||
private bool TryReadKey(bool showKeyOutput, out ConsoleKeyInfo keyInfo)
|
||||
WriteCaptured($"{message} (Y/N) ", () =>
|
||||
{
|
||||
// Clear any previous key entered before this confirmation
|
||||
while (!Owner.Cancelled && Console.KeyAvailable)
|
||||
Console.ReadKey(true);
|
||||
|
||||
var input = new StringBuilder();
|
||||
|
||||
while (!Owner.Cancelled)
|
||||
{
|
||||
if (!Console.KeyAvailable)
|
||||
{
|
||||
while (!Owner.Cancelled && !Console.KeyAvailable)
|
||||
Thread.Sleep(50);
|
||||
|
||||
if (Owner.Cancelled)
|
||||
{
|
||||
keyInfo = default;
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
keyInfo = Console.ReadKey(!showKeyOutput);
|
||||
return true;
|
||||
var keyInfo = Console.ReadKey(false);
|
||||
|
||||
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault - by design
|
||||
switch (keyInfo.Key)
|
||||
{
|
||||
case ConsoleKey.Enter:
|
||||
Console.WriteLine();
|
||||
confirmed = input.ToString().Equals("Y", StringComparison.CurrentCultureIgnoreCase);
|
||||
return;
|
||||
|
||||
case ConsoleKey.Backspace:
|
||||
if (input.Length > 0)
|
||||
{
|
||||
input.Remove(input.Length - 1, 1);
|
||||
|
||||
// We need to handle erasing the character ourselves, as we want to use ReadKey so that we can monitor Cancelled
|
||||
Console.Write(" \b");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (keyInfo.KeyChar != -1)
|
||||
input.Append(keyInfo.KeyChar);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return confirmed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,6 +227,22 @@ namespace Tapeti.Cmd.ConsoleHelper
|
||||
public override bool Enabled => true;
|
||||
|
||||
|
||||
|
||||
public override void WriteCaptured(string value, Action waitForInput)
|
||||
{
|
||||
Owner.AcquirePermanent();
|
||||
try
|
||||
{
|
||||
Console.Write(value);
|
||||
waitForInput();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Owner.ReleasePermanent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void WriteLine(string value)
|
||||
{
|
||||
Owner.AcquirePermanent();
|
||||
@ -217,6 +275,13 @@ namespace Tapeti.Cmd.ConsoleHelper
|
||||
public override bool Enabled => !Console.IsOutputRedirected;
|
||||
|
||||
|
||||
public override void WriteCaptured(string value, Action waitForInput)
|
||||
{
|
||||
WriteLine(value);
|
||||
waitForInput();
|
||||
}
|
||||
|
||||
|
||||
public override void WriteLine(string value)
|
||||
{
|
||||
if (!Enabled)
|
||||
|
@ -31,6 +31,12 @@ namespace Tapeti.Cmd.Serialization
|
||||
}
|
||||
|
||||
|
||||
public static bool OutputExists(string path)
|
||||
{
|
||||
return Directory.Exists(path) && Directory.GetFiles(path, "*.message.txt").Length > 0;
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using CommandLine;
|
||||
using RabbitMQ.Client;
|
||||
using Tapeti.Cmd.ConsoleHelper;
|
||||
using Tapeti.Cmd.Serialization;
|
||||
|
||||
@ -18,6 +17,9 @@ namespace Tapeti.Cmd.Verbs
|
||||
[Option('o', "output", Required = true, HelpText = "Path or filename (depending on the chosen serialization method) where the messages will be output to.")]
|
||||
public string OutputPath { get; set; }
|
||||
|
||||
[Option('y', "overwrite", HelpText = "If the output exists, do not ask to overwrite.")]
|
||||
public bool Overwrite { get; set; }
|
||||
|
||||
[Option('r', "remove", HelpText = "If specified messages are acknowledged and removed from the queue. If not messages are kept.")]
|
||||
public bool RemoveMessages { get; set; }
|
||||
|
||||
@ -40,8 +42,12 @@ namespace Tapeti.Cmd.Verbs
|
||||
public void Execute(IConsole console)
|
||||
{
|
||||
var consoleWriter = console.GetPermanentWriter();
|
||||
|
||||
using var messageSerializer = GetMessageSerializer(options, consoleWriter);
|
||||
if (messageSerializer == null)
|
||||
return;
|
||||
|
||||
var factory = options.CreateConnectionFactory(console);
|
||||
using var messageSerializer = GetMessageSerializer(options);
|
||||
using var connection = factory.CreateConnection();
|
||||
using var channel = connection.CreateModel();
|
||||
|
||||
@ -86,16 +92,27 @@ namespace Tapeti.Cmd.Verbs
|
||||
}
|
||||
|
||||
|
||||
private static IMessageSerializer GetMessageSerializer(ExportOptions options)
|
||||
private static IMessageSerializer GetMessageSerializer(ExportOptions options, IConsoleWriter consoleWriter)
|
||||
{
|
||||
switch (options.SerializationMethod)
|
||||
{
|
||||
case SerializationMethod.SingleFileJSON:
|
||||
// ReSharper disable once InvertIf - causes two lines of "new SingleFileJSONMessageSerializer". DRY ReSharper.
|
||||
if (!options.Overwrite && File.Exists(options.OutputPath))
|
||||
{
|
||||
if (!consoleWriter.ConfirmYesNo($"The output file '{options.OutputPath}' already exists, do you want to overwrite it?"))
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SingleFileJSONMessageSerializer(new FileStream(options.OutputPath, FileMode.Create, FileAccess.Write, FileShare.Read), true, Encoding.UTF8);
|
||||
|
||||
case SerializationMethod.EasyNetQHosepipe:
|
||||
if (string.IsNullOrEmpty(options.OutputPath))
|
||||
throw new ArgumentException("An output path must be provided when using EasyNetQHosepipe serialization");
|
||||
// ReSharper disable once InvertIf - causes two lines of "new SingleFileJSONMessageSerializer". DRY ReSharper.
|
||||
if (!options.Overwrite && EasyNetQMessageSerializer.OutputExists(options.OutputPath))
|
||||
{
|
||||
if (!consoleWriter.ConfirmYesNo($"The output path '{options.OutputPath}' already contains a previous export, do you want to overwrite it?"))
|
||||
return null;
|
||||
}
|
||||
|
||||
return new EasyNetQMessageSerializer(options.OutputPath);
|
||||
|
||||
|
@ -45,6 +45,9 @@ Fetches messages from a queue and writes them to disk.
|
||||
-o <target>, --output <target>
|
||||
*Required*. Path or filename (depending on the chosen serialization method) where the messages will be output to.
|
||||
|
||||
-y, --overwrite
|
||||
If the output exists, do not ask to overwrite.
|
||||
|
||||
-r, --remove
|
||||
If specified messages are acknowledged and removed from the queue. If not messages are kept.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user