Skip to content

Commit

Permalink
Merge pull request #614 from Particular/dotnet-tool-backport
Browse files Browse the repository at this point in the history
dotnet tool for script generation
  • Loading branch information
HEskandari authored Feb 16, 2021
2 parents eb8e966 + cfcef81 commit f28bc7b
Show file tree
Hide file tree
Showing 22 changed files with 577 additions and 242 deletions.
11 changes: 1 addition & 10 deletions src/AcceptanceTestHelper/RuntimeSagaDefinitionReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,11 @@ public static IEnumerable<SagaDefinition> GetSagaDefinitions(EndpointConfigurati
return Enumerable.Empty<SagaDefinition>();
}
var sagaAssembly = sagaTypes.First().Assembly;
var exceptions = new List<Exception>();
//Validate the saga definitions using script builder compile-time validation
using (var moduleDefinition = ModuleDefinition.ReadModule(sagaAssembly.Location, new ReaderParameters(ReadingMode.Deferred)))
{
var compileTimeReader = new AllSagaDefinitionReader(moduleDefinition);

compileTimeReader.GetSagas((e, d) =>
{
exceptions.Add(e);
});
}
if (exceptions.Any())
{
throw new AggregateException(exceptions);
compileTimeReader.GetSagas();
}
return sagaTypes.Select(sagaType => GetSagaDefinition(sagaType, sqlDialect));
}
Expand Down
4 changes: 4 additions & 0 deletions src/CommandLine/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[*.cs]

# Justification: Application synchronization contexts don't require ConfigureAwait(false)
dotnet_diagnostic.CA2007.severity = none
34 changes: 34 additions & 0 deletions src/CommandLine/DialectTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace NServiceBus.Persistence.Sql.CommandLine
{
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ScriptBuilder;

public enum DialectTypes
{
SqlServer,
MySql,
Oracle,
PostgreSql,
}

public static class DialectTypesExtensions
{
static readonly Dictionary<DialectTypes, BuildSqlDialect> DialectMap = new Dictionary<DialectTypes, BuildSqlDialect>
{
[DialectTypes.Oracle] = BuildSqlDialect.Oracle,
[DialectTypes.MySql] = BuildSqlDialect.MySql,
[DialectTypes.MySql] = BuildSqlDialect.MySql,
[DialectTypes.PostgreSql] = BuildSqlDialect.PostgreSql,
[DialectTypes.SqlServer] = BuildSqlDialect.MsSqlServer,
};

public static BuildSqlDialect ToBuildSqlDialect(this DialectTypes dialect) => DialectMap[dialect];

public static IReadOnlyList<BuildSqlDialect> ToBuildSqlDialects(this IReadOnlyList<DialectTypes> dialects)
{
return dialects?.Select(d => d.ToBuildSqlDialect()).ToList().AsReadOnly();
}
}
}
45 changes: 45 additions & 0 deletions src/CommandLine/ExceptionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Text;

static class ExceptionExtensions
{
public static string ToFriendlyString(this Exception exception)
{

var stringBuilder = new StringBuilder();
stringBuilder.Append("Exception:");
stringBuilder.Append(Environment.NewLine);
while (exception != null)
{
stringBuilder.Append(exception.Message);
stringBuilder.Append(Environment.NewLine);

foreach (var i in exception.Data)
{
stringBuilder.Append("Data :");
stringBuilder.Append(i);
stringBuilder.Append(Environment.NewLine);
}

if (exception.StackTrace != null)
{
stringBuilder.Append("StackTrace:");
stringBuilder.Append(Environment.NewLine);
stringBuilder.Append(exception.StackTrace);
stringBuilder.Append(Environment.NewLine);
}

if (exception.Source != null)
{
stringBuilder.Append("Source:");
stringBuilder.Append(Environment.NewLine);
stringBuilder.Append(exception.Source);
stringBuilder.Append(Environment.NewLine);
}

exception = exception.InnerException;
}

return stringBuilder.ToString();
}
}
29 changes: 29 additions & 0 deletions src/CommandLine/Generator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace NServiceBus.Persistence.Sql.CommandLine
{
using System;
using System.IO;
using System.Threading.Tasks;
using McMaster.Extensions.CommandLineUtils;

static class Generator
{
public static Task Run(
CommandArgument assemblyPath,
CommandOption outputPath,
CommandOption<bool> overwriteOption,
CommandOption<bool> cleanOption,
CommandOption<DialectTypes> dialectOption)
{
var output = outputPath.HasValue() ? outputPath.Value() : Directory.GetCurrentDirectory();

var writer = new ScriptGenerator(assemblyPath.Value, output,
cleanOption.ParsedValue, overwriteOption.ParsedValue,
dialectOption.ParsedValues.ToBuildSqlDialects());

writer.Generate();

Console.WriteLine($"Script for {assemblyPath.Value} was generated at {output}.");
return Task.CompletedTask;
}
}
}
20 changes: 20 additions & 0 deletions src/CommandLine/NServiceBus.Persistence.Sql.CommandLine.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<OutputType>Exe</OutputType>
<ToolCommandName>sql-persistence</ToolCommandName>
<PackAsTool>True</PackAsTool>
<Description>.NET Core global tool to generate scripts for NServiceBus Sql persistence</Description>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="3.1.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ScriptBuilder\ScriptBuilder.csproj" />
</ItemGroup>

</Project>
61 changes: 61 additions & 0 deletions src/CommandLine/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
namespace NServiceBus.Persistence.Sql.CommandLine
{
using System;
using System.Collections.Generic;
using McMaster.Extensions.CommandLineUtils;
using ScriptBuilder;

class Program
{
internal const string AppName = "sql-persistence";

static int Main(string[] args)
{
var app = new CommandLineApplication
{
Name = AppName
};

var verboseOption = app.Option<bool>("-v | --verbose", "Verbose logging", CommandOptionType.NoValue, inherited: true);

app.HelpOption(inherited: true);

app.Command("script", cmd =>
{
var assemblyPath = cmd.Argument("assembly", "File path to the endpoint assembly.").IsRequired();
var outputOption = cmd.Option("-o | --output-dir", "Path to the output directory.", CommandOptionType.SingleOrNoValue);
var cleanOption = cmd.Option<bool>("--clean", "Removes existing files in the output directory.", CommandOptionType.SingleOrNoValue);
var overwriteOption = cmd.Option<bool>("--overwrite", "Overwrites existing files in the output if they match the files to be generated.", CommandOptionType.SingleOrNoValue);
var dialectOption = cmd.Option<DialectTypes>("--dialect", "Specifies a dialect to generate", CommandOptionType.SingleOrNoValue);

cmd.OnExecuteAsync(async ct =>
{
await Generator.Run(assemblyPath, outputOption, overwriteOption, cleanOption, dialectOption);
});
});

app.OnExecute(() =>
{
Console.WriteLine("Specify a subcommand");
app.ShowHelp();
return 1;
});

try
{
return app.Execute(args);
}
catch (Exception exception)
{
var error = exception.ToFriendlyString();
Console.Error.WriteLine($"{AppName} failed: {exception.Message}");

if (verboseOption.HasValue())
{
Console.Error.WriteLine(error);
}
return 1;
}
}
}
}
6 changes: 6 additions & 0 deletions src/NServiceBus.Persistence.Sql.sln
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MsSqlMicrosoftDataClientSql
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MsSqlMicrosoftDataClientAcceptanceTests", "MsSqlMicrosoftDataClientAcceptanceTests\MsSqlMicrosoftDataClientAcceptanceTests.csproj", "{7C16BE00-7198-4B6C-A094-C0B62A539F77}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NServiceBus.Persistence.Sql.CommandLine", "CommandLine\NServiceBus.Persistence.Sql.CommandLine.csproj", "{DC682A5A-3ECD-4FB1-826E-A2BD988F40E3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -122,6 +124,10 @@ Global
{7C16BE00-7198-4B6C-A094-C0B62A539F77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C16BE00-7198-4B6C-A094-C0B62A539F77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C16BE00-7198-4B6C-A094-C0B62A539F77}.Release|Any CPU.Build.0 = Release|Any CPU
{DC682A5A-3ECD-4FB1-826E-A2BD988F40E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC682A5A-3ECD-4FB1-826E-A2BD988F40E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC682A5A-3ECD-4FB1-826E-A2BD988F40E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC682A5A-3ECD-4FB1-826E-A2BD988F40E3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ namespace NServiceBus.Persistence.Sql.ScriptBuilder
public static void BuildDropScript(NServiceBus.Persistence.Sql.ScriptBuilder.SagaDefinition saga, NServiceBus.Persistence.Sql.ScriptBuilder.BuildSqlDialect sqlDialect, System.IO.TextWriter writer) { }
public static string BuildDropScript(NServiceBus.Persistence.Sql.ScriptBuilder.SagaDefinition saga, NServiceBus.Persistence.Sql.ScriptBuilder.BuildSqlDialect sqlDialect) { }
}
public class static ScriptWriter
{
public static void Write(string assemblyPath, string targetDirectory, System.Action<string, string> logError, System.Func<string, string> promotionPathFinder) { }
}
public class static SubscriptionScriptBuilder
{
public static void BuildCreateScript(System.IO.TextWriter writer, NServiceBus.Persistence.Sql.ScriptBuilder.BuildSqlDialect sqlDialect) { }
Expand All @@ -88,4 +84,19 @@ namespace NServiceBus.Persistence.Sql.ScriptBuilder
public static void BuildDropScript(System.IO.TextWriter writer, NServiceBus.Persistence.Sql.ScriptBuilder.BuildSqlDialect sqlDialect) { }
public static string BuildDropScript(NServiceBus.Persistence.Sql.ScriptBuilder.BuildSqlDialect sqlDialect) { }
}
}
public class ScriptGenerator
{
public ScriptGenerator(string assemblyPath, string destinationDirectory, bool clean = True, bool overwrite = True, System.Collections.Generic.IReadOnlyList<NServiceBus.Persistence.Sql.ScriptBuilder.BuildSqlDialect> dialectOptions = null, System.Func<string, string> promotionFinder = null, System.Action<string, string> logError = null) { }
public static void Generate(string assemblyPath, string targetDirectory, System.Action<string, string> logError, System.Func<string, string> promotionPathFinder) { }
public void Generate() { }
}
public abstract class ScriptWriter
{
protected ScriptWriter(bool clean, bool overwrite, string scriptPath) { }
protected bool Clean { get; }
protected bool Overwrite { get; }
protected string ScriptPath { get; }
protected void WriteScript(string fileName, System.Action<System.IO.StreamWriter> action) { }
public abstract void WriteScripts(NServiceBus.Persistence.Sql.ScriptBuilder.BuildSqlDialect dialect);
}
18 changes: 12 additions & 6 deletions src/ScriptBuilder/Saga/AllSagaDefinitionReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@

class AllSagaDefinitionReader
{
ModuleDefinition module;
readonly ModuleDefinition module;

public AllSagaDefinitionReader(ModuleDefinition module)
{
this.module = module;
}

public IEnumerable<SagaDefinition> GetSagas(Action<ErrorsException, TypeDefinition> logError)
public IList<SagaDefinition> GetSagas(Action<string, string> logger = null)
{
var sagas = new List<SagaDefinition>();
var errors = new List<Exception>();

foreach (var type in module.AllClasses())
{
try
Expand All @@ -27,12 +29,16 @@ public IEnumerable<SagaDefinition> GetSagas(Action<ErrorsException, TypeDefiniti
}
catch (ErrorsException exception)
{
logError(exception, type);
logger?.Invoke(exception.Message, type.FullName);
errors.Add(new Exception($"Error in '{type.FullName}' (Filename='{type.GetFileName()}'). Error: {exception.Message}", exception));
}
}
return sagas;
}


if (errors.Count > 0 && logger == null)
{
throw new AggregateException(errors);
}

return sagas;
}
}
Loading

0 comments on commit f28bc7b

Please sign in to comment.