diff --git a/Capnp.Net.sln b/Capnp.Net.sln
index 41f5968..8e20bf5 100644
--- a/Capnp.Net.sln
+++ b/Capnp.Net.sln
@@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime.Tests.Cor
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "capnpc-csharp.tests", "capnpc-csharp.tests\capnpc-csharp.tests.csproj", "{B77AC567-E232-4072-85C3-8689566BF3D4}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnpc.Csharp.MsBuild.Generation", "Capnpc.Csharp.MsBuild.Generation\Capnpc.Csharp.MsBuild.Generation.csproj", "{1EFC1F20-C7BB-4F44-8BF9-DBB123AACCF4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -39,6 +41,10 @@ Global
{B77AC567-E232-4072-85C3-8689566BF3D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B77AC567-E232-4072-85C3-8689566BF3D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B77AC567-E232-4072-85C3-8689566BF3D4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1EFC1F20-C7BB-4F44-8BF9-DBB123AACCF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1EFC1F20-C7BB-4F44-8BF9-DBB123AACCF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1EFC1F20-C7BB-4F44-8BF9-DBB123AACCF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1EFC1F20-C7BB-4F44-8BF9-DBB123AACCF4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Capnpc.Csharp.MsBuild.Generation/AssemblyAttributes.cs b/Capnpc.Csharp.MsBuild.Generation/AssemblyAttributes.cs
new file mode 100644
index 0000000..ff364dc
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/AssemblyAttributes.cs
@@ -0,0 +1,4 @@
+
+using System.Runtime.CompilerServices;
+using System.Security;
+
diff --git a/Capnpc.Csharp.MsBuild.Generation/Capnpc.Csharp.MsBuild.Generation.csproj b/Capnpc.Csharp.MsBuild.Generation/Capnpc.Csharp.MsBuild.Generation.csproj
new file mode 100644
index 0000000..bb09bb6
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/Capnpc.Csharp.MsBuild.Generation.csproj
@@ -0,0 +1,79 @@
+
+
+ netstandard2.0;netcoreapp2.1
+ false
+ $(MSBuildThisFileDirectory)Capnpc.Csharp.MsBuild.Generation.nuspec
+ true
+
+
+ true
+ true
+
+ true
+ true
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+
+
+
+
+
+
+
+
+
+
+
+
+
+ All
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Microsoft.Build
+
+
+ Microsoft.Build.Framework
+
+
+ Microsoft.Build.Utilities.Core
+
+
+
+
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+
+
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/Capnpc.Csharp.MsBuild.Generation.nuspec b/Capnpc.Csharp.MsBuild.Generation/Capnpc.Csharp.MsBuild.Generation.nuspec
new file mode 100644
index 0000000..35629ed
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/Capnpc.Csharp.MsBuild.Generation.nuspec
@@ -0,0 +1,30 @@
+
+
+
+ Capnpc.Csharp.Generation
+ 1.0.0
+ Capnpc.Csharp.MsBuild.Generation
+ Christian Köllner and contributors
+ Christian Köllner
+ Package to enable the .capnp -> .cs file generation during build time
+ Package to enable the .capnp -> .cs file generation during build time
+ en-US
+ https://github.com/c80k/capnproto-dotnetcore
+ false
+ MIT
+ capnproto csharp msbuild
+ Christian Köllner and contributors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/CodeBehindWriter.cs b/Capnpc.Csharp.MsBuild.Generation/CodeBehindWriter.cs
new file mode 100644
index 0000000..f147ee7
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/CodeBehindWriter.cs
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+using Microsoft.Build.Utilities;
+
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public class CodeBehindWriter
+ {
+ public CodeBehindWriter(TaskLoggingHelper log)
+ {
+ Log = log;
+ }
+
+ public TaskLoggingHelper Log { get; }
+
+ public string WriteCodeBehindFile(string outputPath, string featureFile, TestFileGeneratorResult testFileGeneratorResult) //todo needs unit tests
+ {
+ //if (string.IsNullOrEmpty(testFileGeneratorResult.Filename))
+ //{
+ // Log?.LogWithNameTag(Log.LogError, $"{featureFile} has no generated filename");
+ // return null;
+ //}
+
+ //string directoryPath = Path.GetDirectoryName(outputPath) ?? throw new InvalidOperationException();
+ //Log?.LogWithNameTag(Log.LogMessage, directoryPath);
+
+ //Log?.LogWithNameTag(Log.LogMessage, $"Writing data to {outputPath}; path = {directoryPath}; generatedFilename = {testFileGeneratorResult.Filename}");
+
+ //if (File.Exists(outputPath))
+ //{
+ // if (!FileSystemHelper.FileCompareContent(outputPath, testFileGeneratorResult.GeneratedTestCode))
+ // {
+ // File.WriteAllText(outputPath, testFileGeneratorResult.GeneratedTestCode);
+ // }
+ //}
+ //else
+ //{
+ // if (!Directory.Exists(directoryPath))
+ // {
+ // Directory.CreateDirectory(directoryPath);
+ // }
+
+ // File.WriteAllText(outputPath, testFileGeneratorResult.GeneratedTestCode);
+ //}
+
+ return outputPath;
+ }
+ }
+}
diff --git a/Capnpc.Csharp.MsBuild.Generation/FeatureCodeBehindGenerator.cs b/Capnpc.Csharp.MsBuild.Generation/FeatureCodeBehindGenerator.cs
new file mode 100644
index 0000000..1f6d631
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/FeatureCodeBehindGenerator.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public class FeatureCodeBehindGenerator : IDisposable
+ {
+ //private SpecFlowProject _specFlowProject;
+ //private ITestGenerator _testGenerator;
+
+ public void InitializeProject(string projectPath, string rootNamespace, IEnumerable generatorPlugins)
+ {
+ //_specFlowProject = MsBuildProjectReader.LoadSpecFlowProjectFromMsBuild(Path.GetFullPath(projectPath), rootNamespace);
+
+ //var projectSettings = _specFlowProject.ProjectSettings;
+
+ //var testGeneratorFactory = new TestGeneratorFactory();
+
+ //_testGenerator = testGeneratorFactory.CreateGenerator(projectSettings, generatorPlugins);
+ }
+
+
+ public TestFileGeneratorResult GenerateCodeBehindFile(string featureFile)
+ {
+ //var featureFileInput = new FeatureFileInput(featureFile);
+ //var generatedFeatureFileName = Path.GetFileName(_testGenerator.GetTestFullPath(featureFileInput));
+
+ //var testGeneratorResult = _testGenerator.GenerateTestFile(featureFileInput, new GenerationSettings());
+
+ return new TestFileGeneratorResult(null, null);
+ }
+
+ public void Dispose()
+ {
+ //_testGenerator?.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/FeatureFileCodeBehindGenerator.cs b/Capnpc.Csharp.MsBuild.Generation/FeatureFileCodeBehindGenerator.cs
new file mode 100644
index 0000000..eeb369f
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/FeatureFileCodeBehindGenerator.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Build.Utilities;
+
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public class FeatureFileCodeBehindGenerator : ICapnpCsharpGenerator
+ {
+ private readonly FilePathGenerator _filePathGenerator;
+
+ public FeatureFileCodeBehindGenerator(TaskLoggingHelper log)
+ {
+ Log = log ?? throw new ArgumentNullException(nameof(log));
+ _filePathGenerator = new FilePathGenerator();
+ }
+
+ public TaskLoggingHelper Log { get; }
+
+ public IEnumerable GenerateFilesForProject(
+ string projectPath,
+ string rootNamespace,
+ List CapnpFiles,
+ List generatorPlugins,
+ string projectFolder,
+ string outputPath)
+ {
+ using (var featureCodeBehindGenerator = new FeatureCodeBehindGenerator())
+ {
+ featureCodeBehindGenerator.InitializeProject(projectPath, rootNamespace, generatorPlugins);
+
+ var codeBehindWriter = new CodeBehindWriter(null);
+
+ if (CapnpFiles == null)
+ {
+ yield break;
+ }
+
+ foreach (var featureFile in CapnpFiles)
+ {
+ var featureFileItemSpec = featureFile;
+ var generatorResult = featureCodeBehindGenerator.GenerateCodeBehindFile(featureFileItemSpec);
+
+ if (!generatorResult.Success)
+ {
+ foreach (var error in generatorResult.Errors)
+ {
+ //Log.LogError(
+ // null,
+ // null,
+ // null,
+ // featureFile,
+ // error.Line,
+ // error.LinePosition,
+ // 0,
+ // 0,
+ // error.Message);
+ }
+ continue;
+ }
+
+ var targetFilePath = _filePathGenerator.GenerateFilePath(
+ projectFolder,
+ outputPath,
+ featureFile,
+ generatorResult.Filename);
+
+ var resultedFile = codeBehindWriter.WriteCodeBehindFile(targetFilePath, featureFile, generatorResult);
+
+ yield return FileSystemHelper.GetRelativePath(resultedFile, projectFolder);
+ }
+ }
+
+ }
+ }
+}
diff --git a/Capnpc.Csharp.MsBuild.Generation/FilePathGenerator.cs b/Capnpc.Csharp.MsBuild.Generation/FilePathGenerator.cs
new file mode 100644
index 0000000..c1e71a1
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/FilePathGenerator.cs
@@ -0,0 +1,31 @@
+using System;
+using System.IO;
+
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public class FilePathGenerator
+ {
+ public string GenerateFilePath(string projectFolder, string relativeOutputPath, string featureFileName, string generatedCodeBehindFileName)
+ {
+ if (projectFolder is null)
+ {
+ throw new ArgumentNullException(nameof(projectFolder));
+ }
+
+ if (featureFileName is null)
+ {
+ throw new ArgumentNullException(nameof(featureFileName));
+ }
+
+ if (generatedCodeBehindFileName is null)
+ {
+ throw new ArgumentNullException(nameof(generatedCodeBehindFileName));
+ }
+
+ string featureFileFullPath = Path.GetFullPath(Path.Combine(projectFolder, relativeOutputPath ?? "", featureFileName));
+ string featureFileDirPath = Path.GetDirectoryName(featureFileFullPath);
+
+ return Path.Combine(featureFileDirPath, generatedCodeBehindFileName);
+ }
+ }
+}
diff --git a/Capnpc.Csharp.MsBuild.Generation/FileSystemHelper.cs b/Capnpc.Csharp.MsBuild.Generation/FileSystemHelper.cs
new file mode 100644
index 0000000..14cfd41
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/FileSystemHelper.cs
@@ -0,0 +1,204 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public static class FileSystemHelper
+ {
+ public static void CopyFileToFolder(string filePath, string folderName)
+ {
+ File.Copy(filePath, Path.Combine(folderName, Path.GetFileName(filePath)));
+ }
+
+ public static string GetRelativePath(string path, string basePath)
+ {
+ path = Path.GetFullPath(path);
+ basePath = Path.GetFullPath(basePath);
+ if (String.Equals(path, basePath, StringComparison.OrdinalIgnoreCase))
+ return "."; // the "this folder"
+
+ if (path.StartsWith(basePath + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
+ return path.Substring(basePath.Length + 1);
+
+ //handle different drives
+ string pathRoot = Path.GetPathRoot(path);
+ if (!String.Equals(pathRoot, Path.GetPathRoot(basePath), StringComparison.OrdinalIgnoreCase))
+ return path;
+
+ //handle ".." pathes
+ string[] pathParts = path.Substring(pathRoot.Length).Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+ string[] basePathParts = basePath.Substring(pathRoot.Length).Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+
+ int commonFolderCount = 0;
+ while (commonFolderCount < pathParts.Length && commonFolderCount < basePathParts.Length &&
+ String.Equals(pathParts[commonFolderCount], basePathParts[commonFolderCount], StringComparison.OrdinalIgnoreCase))
+ commonFolderCount++;
+
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < basePathParts.Length - commonFolderCount; i++)
+ {
+ result.Append("..");
+ result.Append(Path.DirectorySeparatorChar);
+ }
+
+ if (pathParts.Length - commonFolderCount == 0)
+ return result.ToString().TrimEnd(Path.DirectorySeparatorChar);
+
+ result.Append(String.Join(Path.DirectorySeparatorChar.ToString(), pathParts, commonFolderCount, pathParts.Length - commonFolderCount));
+ return result.ToString();
+ }
+
+ // This method accepts two strings the represent two files to
+ // compare. A return value of true indicates that the contents of the files
+ // are the same. A return value of any other value indicates that the
+ // files are not the same.
+ public static bool FileCompare(string filePath1, string filePath2)
+ {
+ int file1byte;
+ int file2byte;
+
+ // Determine if the same file was referenced two times.
+ if (String.Equals(filePath1, filePath2, StringComparison.CurrentCultureIgnoreCase))
+ {
+ // Return true to indicate that the files are the same.
+ return true;
+ }
+
+ // Open the two files.
+ using (FileStream fs1 = new FileStream(filePath1, FileMode.Open, FileAccess.Read))
+ using (FileStream fs2 = new FileStream(filePath2, FileMode.Open, FileAccess.Read))
+ {
+ // Check the file sizes. If they are not the same, the files
+ // are not the same.
+ if (fs1.Length != fs2.Length)
+ {
+ // Return false to indicate files are different
+ return false;
+ }
+
+ // Read and compare a byte from each file until either a
+ // non-matching set of bytes is found or until the end of
+ // file1 is reached.
+ do
+ {
+ // Read one byte from each file.
+ file1byte = fs1.ReadByte();
+ file2byte = fs2.ReadByte();
+ } while ((file1byte == file2byte) && (file1byte != -1));
+ }
+
+ // Return the success of the comparison. "file1byte" is
+ // equal to "file2byte" at this point only if the files are
+ // the same.
+ return ((file1byte - file2byte) == 0);
+ }
+
+ public static void CopyDirectory(string sourcePath, string destPath, bool cleanDestination = true)
+ {
+ if (cleanDestination)
+ EnsureEmptyFolder(destPath);
+ else
+ {
+ if (!Directory.Exists(destPath))
+ {
+ Directory.CreateDirectory(destPath);
+ }
+ }
+
+ foreach (string file in Directory.GetFiles(sourcePath))
+ {
+ var fileName = Path.GetFileName(file);
+ Debug.Assert(fileName != null);
+ string dest = Path.Combine(destPath, fileName);
+ File.Copy(file, dest, true);
+ File.SetAttributes(dest, File.GetAttributes(dest) & (~FileAttributes.ReadOnly));
+ }
+
+ foreach (string folder in Directory.GetDirectories(sourcePath))
+ {
+ var folderName = Path.GetFileName(folder);
+ Debug.Assert(folderName != null);
+ string dest = Path.Combine(destPath, folderName);
+ CopyDirectory(folder, dest);
+ }
+ }
+
+ public static void EnsureEmptyFolder(string folderName)
+ {
+ folderName = Path.GetFullPath(folderName);
+
+ if (!Directory.Exists(folderName))
+ {
+ Directory.CreateDirectory(folderName);
+ return;
+ }
+
+ DeleteFolderContent(folderName);
+ }
+
+ public static void EnsureFolderOfFile(string filePath)
+ {
+ string directory = Path.GetDirectoryName(filePath);
+ if (directory != null && !Directory.Exists(directory))
+ Directory.CreateDirectory(directory);
+ }
+
+
+ private static void Retry(int number, Action action)
+ {
+ try
+ {
+ action();
+ }
+ catch (UnauthorizedAccessException)
+ {
+ var i = number - 1;
+
+ if (i == 0)
+ throw;
+
+ Retry(i, action);
+ }
+ }
+
+ public static void DeleteFolderContent(string folderName)
+ {
+ foreach (string file in Directory.GetFiles(folderName))
+ {
+ try
+ {
+ Retry(5, () => File.Delete(file));
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Unable to delete file: " + file, ex);
+ }
+ }
+
+ foreach (string folder in Directory.GetDirectories(folderName))
+ {
+ try
+ {
+ Retry(5, () => Directory.Delete(folder, true));
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Unable to delete folder: " + folder, ex);
+ }
+ }
+ }
+
+ public static void DeleteFolder(string path)
+ {
+ if (!Directory.Exists(path))
+ return;
+
+ DeleteFolderContent(path);
+
+ Retry(5, () => Directory.Delete(path, true));
+ }
+ }
+}
diff --git a/Capnpc.Csharp.MsBuild.Generation/GenerateCapnpFileCodeBehindTask.cs b/Capnpc.Csharp.MsBuild.Generation/GenerateCapnpFileCodeBehindTask.cs
new file mode 100644
index 0000000..ee69aa8
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/GenerateCapnpFileCodeBehindTask.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Resources;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public class GenerateCapnpFileCodeBehindTask : Task
+ {
+ public GenerateCapnpFileCodeBehindTask()
+ {
+ CodeBehindGenerator = new FeatureFileCodeBehindGenerator(Log);
+ }
+
+ public ICapnpCsharpGenerator CodeBehindGenerator { get; set; }
+
+ [Required]
+ public string ProjectPath { get; set; }
+
+ public string RootNamespace { get; set; }
+
+ public string ProjectFolder => Path.GetDirectoryName(ProjectPath);
+ public string OutputPath { get; set; }
+
+ public ITaskItem[] CapnpFiles { get; set; }
+
+ public ITaskItem[] GeneratorPlugins { get; set; }
+
+ [Output]
+ public ITaskItem[] GeneratedFiles { get; private set; }
+
+ public override bool Execute()
+ {
+ try
+ {
+ try
+ {
+ var currentProcess = Process.GetCurrentProcess();
+
+ Log.LogWithNameTag(Log.LogMessage, $"process: {currentProcess.ProcessName}, pid: {currentProcess.Id}, CD: {Environment.CurrentDirectory}");
+
+ foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ Log.LogWithNameTag(Log.LogMessage, " " + assembly.FullName);
+ }
+ }
+ catch (Exception e)
+ {
+ Log.LogWithNameTag(Log.LogMessage, $"Error when dumping process info: {e}");
+ }
+
+ AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
+
+ var generator = CodeBehindGenerator ?? new FeatureFileCodeBehindGenerator(Log);
+
+ Log.LogWithNameTag(Log.LogMessage, "Starting GenerateFeatureFileCodeBehind");
+
+ var generatorPlugins = GeneratorPlugins?.Select(gp => gp.ItemSpec).ToList() ?? new List();
+
+ var capnpFiles = CapnpFiles?.Select(i => i.ItemSpec).ToList() ?? new List();
+
+ var generatedFiles = generator.GenerateFilesForProject(
+ ProjectPath,
+ RootNamespace,
+ capnpFiles,
+ generatorPlugins,
+ ProjectFolder,
+ OutputPath);
+
+ GeneratedFiles = generatedFiles.Select(file => new TaskItem { ItemSpec = file }).ToArray();
+
+ return !Log.HasLoggedErrors;
+ }
+ catch (Exception e)
+ {
+ if (e.InnerException != null)
+ {
+ if (e.InnerException is FileLoadException fle)
+ {
+ Log?.LogWithNameTag(Log.LogError, $"FileLoadException Filename: {fle.FileName}");
+ Log?.LogWithNameTag(Log.LogError, $"FileLoadException FusionLog: {fle.FusionLog}");
+ Log?.LogWithNameTag(Log.LogError, $"FileLoadException Message: {fle.Message}");
+ }
+
+ Log?.LogWithNameTag(Log.LogError, e.InnerException.ToString());
+ }
+
+ Log?.LogWithNameTag(Log.LogError, e.ToString());
+ return false;
+ }
+ finally
+ {
+ AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
+ }
+ }
+
+ private System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
+ {
+ Log.LogWithNameTag(Log.LogMessage, args.Name);
+
+
+ return null;
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/Helper/LogExtensions.cs b/Capnpc.Csharp.MsBuild.Generation/Helper/LogExtensions.cs
new file mode 100644
index 0000000..1343a80
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/Helper/LogExtensions.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Build.Utilities;
+
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public static class LogExtensions
+ {
+ public static void LogWithNameTag(
+ this TaskLoggingHelper loggingHelper,
+ Action loggingMethod,
+ string message,
+ params object[] messageArgs)
+ {
+ string fullMessage = $"[SpecFlow] {message}";
+ loggingMethod?.Invoke(fullMessage, messageArgs);
+ }
+ }
+}
diff --git a/Capnpc.Csharp.MsBuild.Generation/ICapnpCsharpGenerator.cs b/Capnpc.Csharp.MsBuild.Generation/ICapnpCsharpGenerator.cs
new file mode 100644
index 0000000..5368331
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/ICapnpCsharpGenerator.cs
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public interface ICapnpCsharpGenerator
+ {
+ IEnumerable GenerateFilesForProject(string projectPath, string rootNamespace, List CapnpFiles, List generatorPlugins, string projectFolder, string outputPath);
+ }
+}
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/TestFileGeneratorResult.cs b/Capnpc.Csharp.MsBuild.Generation/TestFileGeneratorResult.cs
new file mode 100644
index 0000000..5eb0160
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/TestFileGeneratorResult.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public class TestFileGeneratorResult
+ {
+ public TestFileGeneratorResult(TestGeneratorResult generatorResult, string fileName)
+ {
+ if (generatorResult == null)
+ {
+ throw new ArgumentNullException(nameof(generatorResult));
+ }
+
+ Filename = fileName ?? throw new ArgumentNullException(nameof(fileName));
+
+ Errors = generatorResult.Errors;
+ IsUpToDate = generatorResult.IsUpToDate;
+ GeneratedTestCode = generatorResult.GeneratedTestCode;
+ }
+
+ ///
+ /// The errors, if any.
+ ///
+ public IEnumerable Errors { get; }
+
+ ///
+ /// The generated file was up-to-date.
+ ///
+ public bool IsUpToDate { get; }
+
+ ///
+ /// The generated test code.
+ ///
+ public string GeneratedTestCode { get; }
+
+ public bool Success => Errors == null || !Errors.Any();
+
+ public string Filename { get; }
+ }
+}
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/TestGenerationError.cs b/Capnpc.Csharp.MsBuild.Generation/TestGenerationError.cs
new file mode 100644
index 0000000..1bf834c
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/TestGenerationError.cs
@@ -0,0 +1,6 @@
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public class TestGenerationError
+ {
+ }
+}
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/TestGeneratorResult.cs b/Capnpc.Csharp.MsBuild.Generation/TestGeneratorResult.cs
new file mode 100644
index 0000000..35b34e3
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/TestGeneratorResult.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace Capnpc.Csharp.MsBuild.Generation
+{
+ public class TestGeneratorResult
+ {
+ public IEnumerable Errors { get; internal set; }
+ public bool IsUpToDate { get; internal set; }
+ public string GeneratedTestCode { get; internal set; }
+ }
+}
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/build/CPS/Buildsystem/CpsExtension.DesignTime.targets b/Capnpc.Csharp.MsBuild.Generation/build/CPS/Buildsystem/CpsExtension.DesignTime.targets
new file mode 100644
index 0000000..b23690f
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/build/CPS/Buildsystem/CpsExtension.DesignTime.targets
@@ -0,0 +1,15 @@
+
+
+
+
+ $(MSBuildThisFileDirectory)Rules\
+
+
+
+
+
+
+ File;BrowseObject
+
+
+
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/build/CPS/Buildsystem/Rules/FeatureFileType.xaml b/Capnpc.Csharp.MsBuild.Generation/build/CPS/Buildsystem/Rules/FeatureFileType.xaml
new file mode 100644
index 0000000..0864f1e
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/build/CPS/Buildsystem/Rules/FeatureFileType.xaml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/build/CPS/Buildsystem/Rules/ProjectItemsSchema.xaml b/Capnpc.Csharp.MsBuild.Generation/build/CPS/Buildsystem/Rules/ProjectItemsSchema.xaml
new file mode 100644
index 0000000..47300db
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/build/CPS/Buildsystem/Rules/ProjectItemsSchema.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Capnpc.Csharp.MsBuild.Generation/build/Capnpc.Csharp.MsBuild.Generation.props b/Capnpc.Csharp.MsBuild.Generation/build/Capnpc.Csharp.MsBuild.Generation.props
new file mode 100644
index 0000000..e51a8aa
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/build/Capnpc.Csharp.MsBuild.Generation.props
@@ -0,0 +1,77 @@
+
+
+
+ $(MSBuildThisFileDirectory)CPS\Buildsystem\CpsExtension.DesignTime.targets
+
+
+
+
+
+
+ false
+ $(CapnpcCsharp_UseHostCompilerIfAvailable)
+
+
+
+
+ false
+ false
+
+ false
+ true
+ false
+
+ <_SpecFlowPropsImported Condition="'$(_SpecFlowPropsImported)'==''">true
+
+
+
+
+
+
+ false
+
+
+ true
+ $(CapnpcCsharp_EnableDefaultCompileItems)
+
+ $(DefaultItemExcludes);**/*.feature
+
+
+
+
+ %(RelativeDir)%(Filename).capnp(DefaultLanguageSourceExtension)
+ $(UsingMicrosoftNETSdk)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_CapnpcCsharp_TaskFolder Condition=" '$(MSBuildRuntimeType)' == 'Core' And '$(_CapnpcCsharp_TaskFolder)' == ''">netcoreapp2.0
+ <_CapnpcCsharp_TaskFolder Condition=" '$(MSBuildRuntimeType)' != 'Core' And '$(_CapnpcCsharp_TaskFolder)' == ''">net471
+ <_CapnpcCsharp_TaskAssembly Condition=" '$(_CapnpcCsharp_TaskAssembly)' == '' ">..\tasks\$(_CapnpcCsharp_TaskFolder)\Capnpc.Csharp.MsBuild.Generation.dll
+
+
+
+
+
diff --git a/Capnpc.Csharp.MsBuild.Generation/build/Capnpc.Csharp.MsBuild.Generation.targets b/Capnpc.Csharp.MsBuild.Generation/build/Capnpc.Csharp.MsBuild.Generation.targets
new file mode 100644
index 0000000..a61cde4
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/build/Capnpc.Csharp.MsBuild.Generation.targets
@@ -0,0 +1,145 @@
+
+
+
+
+
+ false
+ true
+
+
+ <_CapnpcCsharp_EnableDefaultCompileItems Condition="'$(CapnpcCsharp_EnableDefaultCompileItems)' == '' And '$(UsingMicrosoftNETSdk)' == 'true'">true
+ <_CapnpcCsharp_EnableDefaultCompileItems Condition="'$(CapnpcCsharp_EnableDefaultCompileItems)' == 'true' And '$(UsingMicrosoftNETSdk)' == 'true'">true
+
+
+
+
+ BeforeUpdateCapnpFilesInProject;
+ UpdateCapnpFilesInProject;
+ IncludeCodeBehindFilesInProject;
+ AfterUpdateCapnpFilesInProject;
+ $(BuildDependsOn)
+
+
+ CleanCapnpFilesInProject;
+ $(CleanDependsOn)
+
+
+ SwitchToForceGenerate;
+ $(RebuildDependsOn)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/build/Capnpc.Csharp.MsBuild.Generation.tasks b/Capnpc.Csharp.MsBuild.Generation/build/Capnpc.Csharp.MsBuild.Generation.tasks
new file mode 100644
index 0000000..9e4e977
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/build/Capnpc.Csharp.MsBuild.Generation.tasks
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/Capnpc.Csharp.MsBuild.Generation/buildMultiTargeting/Capnpc.Csharp.MsBuild.Generation.props b/Capnpc.Csharp.MsBuild.Generation/buildMultiTargeting/Capnpc.Csharp.MsBuild.Generation.props
new file mode 100644
index 0000000..f3c49ea
--- /dev/null
+++ b/Capnpc.Csharp.MsBuild.Generation/buildMultiTargeting/Capnpc.Csharp.MsBuild.Generation.props
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Licenses/SpecFlow-LICENSE-NewBSD.txt b/Licenses/SpecFlow-LICENSE-NewBSD.txt
new file mode 100644
index 0000000..665e1cd
--- /dev/null
+++ b/Licenses/SpecFlow-LICENSE-NewBSD.txt
@@ -0,0 +1,31 @@
+SpecFlow Licence (New BSD License)
+
+Copyright (c) 2009, TechTalk
+
+Disclaimer:
+ * The initial codebase of Specflow was written by TechTalk employees.
+ No 3rd party code was included.
+ * No code of customer projects was used to create this project.
+ * TechTalk had the full rights to publish the initial codebase.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the SpecFlow project nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL TECHTALK OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.