Commit 2f9526d9 authored by Mark van Renswoude's avatar Mark van Renswoude

Refactored console output to ILog interface

Moved strings to resource file
parent 2ec03549
*.user
*.suo
/.nuget/
......@@ -3,6 +3,7 @@ using System.Linq;
using System.Text;
using NUnit.Framework;
using RabbitMetaQueue.Domain;
using RabbitMetaQueue.Infrastructure;
using RabbitMetaQueue.Model;
using RabbitMetaQueue.Tests.Mock;
......@@ -120,7 +121,7 @@ namespace RabbitMetaQueue.Tests.Infrastructure
private void TestCompare(List<string> expectedActions)
{
var writer = new MockTopologyWriter();
var comparator = new TopologyComparator(writer)
var comparator = new TopologyComparator(new NullLog(), writer)
{
AllowDelete = true,
AllowRecreate = true,
......
......@@ -7,6 +7,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RabbitMetaQueue", "RabbitMe
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RabbitMetaQueue.Tests", "RabbitMetaQueue.Tests\RabbitMetaQueue.Tests.csproj", "{233DB210-B52D-47B9-87B9-7156CD16045D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{FFAE3CE7-1035-4A81-96D1-C722C2533FBD}"
ProjectSection(SolutionItems) = preProject
.nuget\NuGet.Config = .nuget\NuGet.Config
.nuget\NuGet.exe = .nuget\NuGet.exe
.nuget\NuGet.targets = .nuget\NuGet.targets
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
......
using System;
namespace RabbitMetaQueue.Infrastructure
{
public enum LogLevel
{
Debug,
Info,
Warn,
Error,
Fatal
}
public abstract class BaseLog : ILog
{
public bool IsDebugEnabled { get; set; }
public bool IsInfoEnabled { get; set; }
public bool IsWarnEnabled { get; set; }
public bool IsErrorEnabled { get; set; }
public bool IsFatalEnabled { get; set; }
protected BaseLog()
{
IsDebugEnabled = false;
IsInfoEnabled = true;
IsWarnEnabled = true;
IsErrorEnabled = true;
IsFatalEnabled = true;
}
protected abstract void Log(LogLevel level, string message, Exception exception);
protected void LogFormat(LogLevel level, string format, params object[] args)
{
Log(level, String.Format(format, args), null);
}
protected void LogFormat(LogLevel level, IFormatProvider provider, string format, params object[] args)
{
Log(level, String.Format(provider, format, args), null);
}
public void Debug(string message)
{
if (IsDebugEnabled)
Log(LogLevel.Debug, message, null);
}
public void Info(string message)
{
if (IsInfoEnabled)
Log(LogLevel.Info, message, null);
}
public void Warn(string message)
{
if (IsWarnEnabled)
Log(LogLevel.Warn, message, null);
}
public void Error(string message)
{
if (IsErrorEnabled)
Log(LogLevel.Error, message, null);
}
public void Fatal(string message)
{
if (IsFatalEnabled)
Log(LogLevel.Fatal, message, null);
}
public void Debug(string message, Exception exception)
{
if (IsDebugEnabled)
Log(LogLevel.Debug, message, exception);
}
public void Info(string message, Exception exception)
{
if (IsInfoEnabled)
Log(LogLevel.Info, message, exception);
}
public void Warn(string message, Exception exception)
{
if (IsWarnEnabled)
Log(LogLevel.Warn, message, exception);
}
public void Error(string message, Exception exception)
{
if (IsErrorEnabled)
Log(LogLevel.Error, message, exception);
}
public void Fatal(string message, Exception exception)
{
if (IsFatalEnabled)
Log(LogLevel.Fatal, message, exception);
}
public void DebugFormat(string format, params object[] args)
{
if (IsDebugEnabled)
LogFormat(LogLevel.Debug, format, args);
}
public void InfoFormat(string format, params object[] args)
{
if (IsInfoEnabled)
LogFormat(LogLevel.Info, format, args);
}
public void WarnFormat(string format, params object[] args)
{
if (IsWarnEnabled)
LogFormat(LogLevel.Warn, format, args);
}
public void ErrorFormat(string format, params object[] args)
{
if (IsErrorEnabled)
LogFormat(LogLevel.Error, format, args);
}
public void FatalFormat(string format, params object[] args)
{
if (IsFatalEnabled)
LogFormat(LogLevel.Fatal, format, args);
}
public void DebugFormat(IFormatProvider provider, string format, params object[] args)
{
if (IsDebugEnabled)
LogFormat(LogLevel.Debug, provider, format, args);
}
public void InfoFormat(IFormatProvider provider, string format, params object[] args)
{
if (IsInfoEnabled)
LogFormat(LogLevel.Info, provider, format, args);
}
public void WarnFormat(IFormatProvider provider, string format, params object[] args)
{
if (IsWarnEnabled)
LogFormat(LogLevel.Warn, provider, format, args);
}
public void ErrorFormat(IFormatProvider provider, string format, params object[] args)
{
if (IsErrorEnabled)
LogFormat(LogLevel.Error, provider, format, args);
}
public void FatalFormat(IFormatProvider provider, string format, params object[] args)
{
if (IsFatalEnabled)
LogFormat(LogLevel.Fatal, provider, format, args);
}
}
}
using System;
using RabbitMetaQueue.Resources;
namespace RabbitMetaQueue.Infrastructure
{
public class ConsoleLog : BaseLog
{
protected override void Log(LogLevel level, string message, Exception exception)
{
Console.Write(Strings.LogPrefix);
switch(level)
{
case LogLevel.Warn: Console.Write(Strings.LogWarning); break;
case LogLevel.Error: Console.Write(Strings.LogError); break;
case LogLevel.Fatal: Console.Write(Strings.LogFatal); break;
}
Console.WriteLine(message);
if (exception != null)
Console.WriteLine(exception.Message);
}
}
}
using System;
using RabbitMetaQueue.Domain;
using RabbitMetaQueue.Model;
namespace RabbitMetaQueue.Infrastructure
{
// ToDo arguments
public class ConsoleTopologyWriter : ITopologyWriter
{
public void CreateExchange(Exchange exchange)
{
Console.WriteLine("> Adding exchange: " + exchange.Name);
Console.WriteLine(" Type: " + exchange.ExchangeType);
Console.WriteLine(" Durable: " + exchange.Durable);
}
public void DeleteExchange(Exchange exchange)
{
Console.WriteLine("> Deleting exchange: " + exchange.Name);
}
public void CreateQueue(Queue queue)
{
Console.WriteLine("> Adding queue: " + queue.Name);
Console.WriteLine(" Durable: " + queue.Durable);
}
public void DeleteQueue(Queue queue)
{
Console.WriteLine("> Deleting queue: " + queue.Name);
}
public void CreateBinding(Queue queue, Binding binding)
{
Console.WriteLine("> Binding queue: " + queue.Name);
Console.WriteLine(" Exchange: " + binding.Exchange);
Console.WriteLine(" Routing key: " + binding.RoutingKey);
}
public void DeleteBinding(Queue queue, Binding binding)
{
Console.WriteLine("> Unbinding queue: " + queue.Name);
Console.WriteLine(" Exchange: " + binding.Exchange);
Console.WriteLine(" Routing key: " + binding.RoutingKey);
}
}
}
using System;
namespace RabbitMetaQueue.Infrastructure
{
public interface ILog
{
bool IsDebugEnabled { get; }
bool IsInfoEnabled { get; }
bool IsWarnEnabled { get; }
bool IsErrorEnabled { get; }
bool IsFatalEnabled { get; }
void Debug(string message);
void Info(string message);
void Warn(string message);
void Error(string message);
void Fatal(string message);
void Debug(string message, Exception exception);
void Info(string message, Exception exception);
void Warn(string message, Exception exception);
void Error(string message, Exception exception);
void Fatal(string message, Exception exception);
void DebugFormat(string format, params object[] args);
void InfoFormat(string format, params object[] args);
void WarnFormat(string format, params object[] args);
void ErrorFormat(string format, params object[] args);
void FatalFormat(string format, params object[] args);
void DebugFormat(IFormatProvider provider, string format, params object[] args);
void InfoFormat(IFormatProvider provider, string format, params object[] args);
void WarnFormat(IFormatProvider provider, string format, params object[] args);
void ErrorFormat(IFormatProvider provider, string format, params object[] args);
void FatalFormat(IFormatProvider provider, string format, params object[] args);
}
}
using System;
namespace RabbitMetaQueue.Infrastructure
{
/* Derived from BaseLog instead of ILog so String.Format does get applied in the unit tests */
public class NullLog : BaseLog
{
protected override void Log(LogLevel level, string message, Exception exception)
{
}
}
}
using System.Collections.Generic;
using RabbitMetaQueue.Domain;
using RabbitMetaQueue.Domain;
using RabbitMetaQueue.Model;
namespace RabbitMetaQueue.Infrastructure
{
public class MulticastTopologyWriter : ITopologyWriter
public class NullTopologyWriter : ITopologyWriter
{
private readonly List<ITopologyWriter> topologyWriters = new List<ITopologyWriter>();
public void Add(ITopologyWriter topologyWriter)
{
topologyWriters.Add(topologyWriter);
}
public void CreateExchange(Exchange exchange)
{
topologyWriters.ForEach(to => to.CreateExchange(exchange));
}
public void DeleteExchange(Exchange exchange)
{
topologyWriters.ForEach(to => to.DeleteExchange(exchange));
}
public void CreateQueue(Queue queue)
{
topologyWriters.ForEach(to => to.CreateQueue(queue));
}
public void DeleteQueue(Queue queue)
{
topologyWriters.ForEach(to => to.DeleteQueue(queue));
}
public void CreateBinding(Queue queue, Binding binding)
{
topologyWriters.ForEach(to => to.CreateBinding(queue, binding));
}
public void DeleteBinding(Queue queue, Binding binding)
{
topologyWriters.ForEach(to => to.DeleteBinding(queue, binding));
}
}
}
......@@ -49,14 +49,17 @@ namespace RabbitMetaQueue.Infrastructure
foreach (var binding in client.GetBindingsForQueue(queue))
{
var modelBinding = new Model.Binding
if (!IsSystemBinding(binding))
{
Exchange = binding.Source,
RoutingKey = binding.RoutingKey
};
var modelBinding = new Model.Binding
{
Exchange = binding.Source,
RoutingKey = binding.RoutingKey
};
MapArguments(binding.Arguments, modelBinding.Arguments);
modelQueue.Bindings.Add(modelBinding);
MapArguments(binding.Arguments, modelBinding.Arguments);
modelQueue.Bindings.Add(modelBinding);
}
}
topology.Queues.Add(modelQueue);
......@@ -78,5 +81,11 @@ namespace RabbitMetaQueue.Infrastructure
return (String.IsNullOrEmpty(name) ||
name.StartsWith("amq.", StringComparison.InvariantCulture));
}
private static bool IsSystemBinding(EasyNetQ.Management.Client.Model.Binding binding)
{
return (String.IsNullOrEmpty(binding.Source));
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RabbitMetaQueue.Infrastructure
{
public class TextTable
{
private readonly List<KeyValuePair<string, string>> entries = new List<KeyValuePair<string, string>>();
public void Add(string key, string value)
{
entries.Add(new KeyValuePair<string, string>(key, value));
}
public override string ToString()
{
return ToString(2);
}
public string ToString(int indent)
{
var keyLength = entries.Max(p => p.Key.Length) + 1;
var prefix = new string(' ', indent);
var result = new StringBuilder();
foreach (var pair in entries)
{
result.Append(prefix)
.Append(pair.Key.PadRight(keyLength))
.AppendLine(pair.Value);
}
return result.ToString();
}
}
}
......@@ -7,6 +7,7 @@ using NDesk.Options;
using RabbitMetaQueue.Domain;
using RabbitMetaQueue.Infrastructure;
using RabbitMetaQueue.Model;
using RabbitMetaQueue.Resources;
namespace RabbitMetaQueue
{
......@@ -16,6 +17,9 @@ namespace RabbitMetaQueue
{
public string TopologyFilename { get; set; }
public bool DryRun { get; set; }
public bool Mirror { get; set; }
public bool Verbose { get; set; }
public ConnectionParams ConnectionParams { get; private set; }
public Options()
......@@ -33,46 +37,56 @@ namespace RabbitMetaQueue
if (!ParseOptions(args, options))
return 1;
var log = new ConsoleLog
{
IsDebugEnabled = options.Verbose
};
var optionTable = new TextTable();
optionTable.Add(Strings.OptionDryRun, options.DryRun ? Strings.OptionDryRunYes
: Strings.OptionDryRunNo);
optionTable.Add(Strings.OptionMirror, options.Mirror ? Strings.OptionYes
: Strings.OptionNo);
optionTable.Add(Strings.OptionVerbose, options.Verbose ? Strings.OptionYes
: Strings.OptionNo);
Console.WriteLine(Strings.Options);
Console.Write(optionTable.ToString());
Console.WriteLine();
try
{
Console.WriteLine("Parsing topology definition");
Console.WriteLine(Strings.StatusParsingDefinition);
var definedTopology = new XmlTopologyReader().Parse(options.TopologyFilename);
Console.WriteLine("Connecting to RabbitMQ server [{0}{1}]", options.ConnectionParams.Host, options.ConnectionParams.VirtualHost);
Console.WriteLine(String.Format(Strings.StatusConnectingRabbitMQ, options.ConnectionParams.Host, options.ConnectionParams.VirtualHost));
var client = Connect(options.ConnectionParams);
var virtualHost = client.GetVhost(options.ConnectionParams.VirtualHost);
Console.WriteLine("Reading existing topology");
Console.WriteLine(Strings.StatusReadingTopology);
var existingTopology = new RabbitMQTopologyReader().Parse(client, virtualHost);
var writer = new MulticastTopologyWriter();
writer.Add(new ConsoleTopologyWriter());
if (!options.DryRun)
{
Console.WriteLine("Changes WILL be applied");
writer.Add(new RabbitMQTopologyWriter(client, virtualHost));
}
else
Console.WriteLine("Dry run - changes will not be applied");
var writer = (options.DryRun ? (ITopologyWriter)new NullTopologyWriter()
: new RabbitMQTopologyWriter(client, virtualHost));
var comparator = new TopologyComparator(writer)
var comparator = new TopologyComparator(log, writer)
{
AllowDelete = true,
AllowRecreate = true,
AllowUnbind = true
AllowDelete = options.Mirror,
AllowRecreate = options.Mirror,
AllowUnbind = options.Mirror
};
Console.WriteLine("Comparing topology");
Console.WriteLine(Strings.StatusComparing);
comparator.Compare(existingTopology, definedTopology);
Console.WriteLine("Done!");
Console.WriteLine();
Console.WriteLine(Strings.StatusDone);
return 0;
}
catch(Exception e)
{
Console.Write("Error: ");
Console.WriteLine(e.Message);
Console.WriteLine();
Console.WriteLine(String.Format(Strings.StatusError, e.Message));
return 1;
}
}
......@@ -81,7 +95,7 @@ namespace RabbitMetaQueue
if (Debugger.IsAttached)
{
Console.WriteLine();
Console.WriteLine("Press any Enter key to continue...");
Console.WriteLine(Strings.StatusWaitForKey);
Console.ReadLine();
}
}
......@@ -103,28 +117,36 @@ namespace RabbitMetaQueue
var optionSet = new OptionSet
{
{
"i|input=", "The {file name} of the topology definition. Required.",
Strings.OptionKeyInput, Strings.OptionDescriptionInput,
v => filename = v
},
{
"h|host=", "The host {name} of the RabbitMQ server. Defaults to localhost.",
Strings.OptionKeyHost, Strings.OptionDescriptionHost,
v => options.ConnectionParams.Host = v
},
{
"v|virtualhost=", "The virtual host {name} as configured in RabbitMQ. Defaults to /.",
Strings.OptionKeyVirtualHost, Strings.OptionDescriptionVirtualHost,
v => options.ConnectionParams.VirtualHost = v
},
{
"u|username=", "The {username} used in the connection. Defaults to guest.",
Strings.OptionKeyUsername, Strings.OptionDescriptionUsername,
v => options.ConnectionParams.Username = v
},
{
"p|password=", "The {password} used in the connection. Defaults to guest.",
Strings.OptionKeyPassword, Strings.OptionDescriptionPassword,
v => options.ConnectionParams.Password = v
},
{
"d|dryrun", "When specified, changes are not applied to the RabbitMQ server.",
Strings.OptionKeyDryRun, Strings.OptionDescriptionDryRun,
v => options.DryRun = (v != null)
},
{
Strings.OptionKeyMirror, Strings.OptionDescriptionMirror,
v => options.Mirror = (v != null)
},
{
Strings.OptionKeyVerbose, Strings.OptionDescriptionVerbose,
v => options.Verbose = (v != null)
}
};
......@@ -133,20 +155,20 @@ namespace RabbitMetaQueue
optionSet.Parse(args);
if (String.IsNullOrEmpty(filename))
throw new OptionException("Topology file name is required", "i");
throw new OptionException(Strings.OptionInputRequired, Strings.OptionKeyInput);
if (!File.Exists(filename))
throw new OptionException("Topology file not found", "i");
throw new OptionException(Strings.OptionInputNotFound, Strings.OptionKeyInput);
options.TopologyFilename = filename;
return true;
}
catch(OptionException e)
{
Console.Write("Invalid arguments: ");
Console.Write(Strings.OptionInvalidArguments);
Console.WriteLine(e.Message);
Console.WriteLine("Usage:");
Console.WriteLine(Strings.OptionUsage);
optionSet.WriteOptionDescriptions(Console.Out);
return false;
......
......@@ -53,12 +53,16 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Infrastructure\ConsoleTopologyWriter.cs" />
<Compile Include="Infrastructure\BaseLog.cs" />
<Compile Include="Infrastructure\ConsoleLog.cs" />
<Compile Include="Domain\ITopologyWriter.cs" />
<Compile Include="Infrastructure\MulticastTopologyWriter.cs" />
<Compile Include="Infrastructure\ILog.cs" />
<Compile Include="Infrastructure\NullLog.cs" />
<Compile Include="Infrastructure\NullTopologyWriter.cs" />
<Compile Include="Infrastructure\RabbitMQTopologyWriter.cs" />
<Compile Include="Infrastructure\RabbitMQTopologyReader.cs" />
<Compile Include="Domain\TopologyComparator.cs" />
<Compile Include="Infrastructure\TextTable.cs" />
<Compile Include="Infrastructure\XmlTopologyReader.cs" />
<Compile Include="Model\Arguments.cs" />
<Compile Include="Model\Binding.cs" />
......@@ -68,14 +72,31 @@
<Compile Include="Model\Topology.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources\Strings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Strings.resx</DependentUpon>
</Compile>
<Compile Include="Schema\Topology.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<EmbeddedResource Include="Resources\Strings.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment