mirror of
https://github.com/FabInfra/capnproto-dotnetcore_Runtime.git
synced 2025-03-12 23:01:44 +01:00
Merge branch 'msbuild-integration'
This commit is contained in:
commit
e11f08f274
4
.gitignore
vendored
4
.gitignore
vendored
@ -332,3 +332,7 @@ ASALocalRun/
|
||||
.mfractor/
|
||||
.vscode/tasks.json
|
||||
.vscode/launch.json
|
||||
|
||||
# Capnp code behind
|
||||
*.capnp.cs
|
||||
/globalPackages
|
||||
|
@ -4,6 +4,8 @@
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -31,6 +33,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
|
||||
|
@ -8,6 +8,8 @@
|
||||
<LangVersion>7.1</LangVersion>
|
||||
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
@ -15,6 +17,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
|
||||
|
@ -7,6 +7,7 @@
|
||||
<AssemblyName>Capnp.Net.Runtime</AssemblyName>
|
||||
<PackageId>Capnp.Net.Runtime</PackageId>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageOutputPath>..\bin\$(Configuration)</PackageOutputPath>
|
||||
<Authors>Christian Köllner and contributors</Authors>
|
||||
<Description>A Cap'n Proto implementation for .NET Standard & Core</Description>
|
||||
<Product>capnproto-dotnetcore</Product>
|
||||
@ -17,17 +18,14 @@
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<PackageTags>capnp "Cap'n Proto" RPC serialization cerealization</PackageTags>
|
||||
<Version>1.0.0</Version>
|
||||
<Version>1.0-local$([System.DateTime]::UtcNow.ToString(yyMMddHHmm))</Version>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<DocumentationFile></DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
@ -11,7 +11,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime.Tests.Std
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime.Tests.Core21", "Capnp.Net.Runtime.Tests.Core21\Capnp.Net.Runtime.Tests.Core21.csproj", "{58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "capnpc-csharp.tests", "capnpc-csharp.tests\capnpc-csharp.tests.csproj", "{B77AC567-E232-4072-85C3-8689566BF3D4}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CapnpC.CSharp.Generator.Tests", "CapnpC.CSharp.Generator.Tests\CapnpC.CSharp.Generator.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
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CapnpC.CSharp.Generator", "CapnpC.CSharp.Generator\CapnpC.CSharp.Generator.csproj", "{C3A3BB49-356E-4762-A190-76D877BE18F7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CapnpC.CSharp.MsBuild.Generation.Tests", "CapnpC.CSharp.MsBuild.Generation.Tests\CapnpC.CSharp.MsBuild.Generation.Tests.csproj", "{EF05AD68-DE31-448E-B88D-4144F928ED5D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -39,6 +45,18 @@ 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
|
||||
{C3A3BB49-356E-4762-A190-76D877BE18F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C3A3BB49-356E-4762-A190-76D877BE18F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C3A3BB49-356E-4762-A190-76D877BE18F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C3A3BB49-356E-4762-A190-76D877BE18F7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EF05AD68-DE31-448E-B88D-4144F928ED5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EF05AD68-DE31-448E-B88D-4144F928ED5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EF05AD68-DE31-448E-B88D-4144F928ED5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EF05AD68-DE31-448E-B88D-4144F928ED5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
<RootNamespace>capnpc_csharp.Tests</RootNamespace>
|
||||
<RootNamespace>CapnpC.CSharp.Generator.Tests</RootNamespace>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -16,17 +18,18 @@
|
||||
<PackageReference Include="SpecFlow.Tools.MsBuild.Generation" Version="3.0.225" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\capnpc-csharp\capnpc-csharp.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="*.cs" />
|
||||
<Compile Remove="Embedded Resources\test.cs" />
|
||||
<None Remove="Embedded Resources\Empty.capnp" />
|
||||
<None Remove="Embedded Resources\Empty1.capnp" />
|
||||
<None Remove="Embedded Resources\invalid.capnp" />
|
||||
<None Remove="Embedded Resources\null.bin" />
|
||||
<None Remove="Embedded Resources\test.capnp" />
|
||||
<None Remove="Embedded Resources\test.capnp.bin" />
|
||||
<Compile Include="UnitTests.cs" />
|
||||
<None Remove="Embedded Resources\UnitTest1.capnp" />
|
||||
<Compile Include="CapnpMessageUnitTests.cs" />
|
||||
<Compile Include="CodeGeneratorUnitTests.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -34,9 +37,13 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Embedded Resources\Empty.capnp" />
|
||||
<EmbeddedResource Include="Embedded Resources\Empty1.capnp" />
|
||||
<EmbeddedResource Include="Embedded Resources\invalid.capnp" />
|
||||
<EmbeddedResource Include="Embedded Resources\null.bin" />
|
||||
<EmbeddedResource Include="Embedded Resources\test.capnp.bin" />
|
||||
<EmbeddedResource Include="Embedded Resources\test.cs" />
|
||||
<EmbeddedResource Include="Embedded Resources\UnitTest1.capnp" />
|
||||
<EmbeddedResource Include="Embedded Resources\UnitTest1.capnp.bin" />
|
||||
<EmbeddedResource Include="Embedded Resources\UnitTest2.capnp.bin" />
|
||||
<EmbeddedResource Include="Embedded Resources\UnitTest3.capnp.bin" />
|
||||
@ -47,11 +54,16 @@
|
||||
<EmbeddedResource Include="Embedded Resources\schema-with-offsets.capnp.bin" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CapnpC.CSharp.Generator\CapnpC.CSharp.Generator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SpecFlowFeatureFiles Update="CodeGenerator.feature">
|
||||
<Generator>SpecFlowSingleFileGenerator</Generator>
|
||||
<LastGenOutput>CodeGenerator.feature.cs</LastGenOutput>
|
||||
<Generator Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"></Generator>
|
||||
<Generator Condition="'$(Configuration)|$(Platform)'=='ReleaseTest|AnyCPU'"></Generator>
|
||||
</SpecFlowFeatureFiles>
|
||||
</ItemGroup>
|
||||
|
107
CapnpC.CSharp.Generator.Tests/CapnpMessageUnitTests.cs
Normal file
107
CapnpC.CSharp.Generator.Tests/CapnpMessageUnitTests.cs
Normal file
@ -0,0 +1,107 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CapnpC.CSharp.Generator.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class CapnpMessageUnitTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void ParseError()
|
||||
{
|
||||
var msg = new CapnpMessage(@"f:\code\invalid.capnp:5:1: error: Parse error.");
|
||||
Assert.AreEqual(@"f:\code\invalid.capnp:5:1: error: Parse error.", msg.FullMessage);
|
||||
Assert.IsTrue(msg.IsParseSuccess);
|
||||
Assert.AreEqual(@"f:\code\invalid.capnp", msg.FileName);
|
||||
Assert.AreEqual(5, msg.Line);
|
||||
Assert.AreEqual(1, msg.Column);
|
||||
Assert.AreEqual(0, msg.EndColumn);
|
||||
Assert.AreEqual("error", msg.Category);
|
||||
Assert.AreEqual("Parse error.", msg.MessageText);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ColumnSpan()
|
||||
{
|
||||
var msg = new CapnpMessage(@"f:\code\invalid.capnp:10:7-8: error: Duplicate ordinal number.");
|
||||
Assert.IsTrue(msg.IsParseSuccess);
|
||||
Assert.AreEqual(@"f:\code\invalid.capnp", msg.FileName);
|
||||
Assert.AreEqual(10, msg.Line);
|
||||
Assert.AreEqual(7, msg.Column);
|
||||
Assert.AreEqual(8, msg.EndColumn);
|
||||
Assert.AreEqual("error", msg.Category);
|
||||
Assert.AreEqual("Duplicate ordinal number.", msg.MessageText);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void NoSuchFile()
|
||||
{
|
||||
var msg = new CapnpMessage(@"C:\ProgramData\chocolatey\lib\capnproto\tools\capnproto-tools-win32-0.7.0\capnp.exe compile: doesnotexist.capnp: no such file");
|
||||
Assert.IsFalse(msg.IsParseSuccess);
|
||||
Assert.AreEqual(@"C:\ProgramData\chocolatey\lib\capnproto\tools\capnproto-tools-win32-0.7.0\capnp.exe compile: doesnotexist.capnp: no such file", msg.FullMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void NoId()
|
||||
{
|
||||
var msg = new CapnpMessage(@"empty.capnp:1:1: error: File does not declare an ID. I've generated one for you. Add this line to your file: @0xc82955a0c779197d;");
|
||||
Assert.IsTrue(msg.IsParseSuccess);
|
||||
Assert.AreEqual("empty.capnp", msg.FileName);
|
||||
Assert.AreEqual(1, msg.Line);
|
||||
Assert.AreEqual(1, msg.Column);
|
||||
Assert.AreEqual("error", msg.Category);
|
||||
Assert.AreEqual("File does not declare an ID. I've generated one for you. Add this line to your file: @0xc82955a0c779197d;", msg.MessageText);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AnnoyingNTFSAlternateDataStream1()
|
||||
{
|
||||
var msg = new CapnpMessage(@"3:2:1:1: error: File does not declare an ID. I've generated one for you. Add this line to your file: @0xc82955a0c779197d;");
|
||||
Assert.IsTrue(msg.IsParseSuccess);
|
||||
Assert.AreEqual("3:2", msg.FileName);
|
||||
Assert.AreEqual(1, msg.Line);
|
||||
Assert.AreEqual(1, msg.Column);
|
||||
Assert.AreEqual("error", msg.Category);
|
||||
Assert.AreEqual("File does not declare an ID. I've generated one for you. Add this line to your file: @0xc82955a0c779197d;", msg.MessageText);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AnnoyingNTFSAlternateDataStream2()
|
||||
{
|
||||
var msg = new CapnpMessage(@"c:\3:2:1:1: error: File does not declare an ID. I've generated one for you. Add this line to your file: @0xc82955a0c779197d;");
|
||||
Assert.IsTrue(msg.IsParseSuccess);
|
||||
Assert.AreEqual(@"c:\3:2", msg.FileName);
|
||||
Assert.AreEqual(1, msg.Line);
|
||||
Assert.AreEqual(1, msg.Column);
|
||||
Assert.AreEqual("error", msg.Category);
|
||||
Assert.AreEqual("File does not declare an ID. I've generated one for you. Add this line to your file: @0xc82955a0c779197d;", msg.MessageText);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AnnoyingNTFSAlternateDataStream3()
|
||||
{
|
||||
var msg = new CapnpMessage(@"\\?\c:\3:2:1:1: error: File does not declare an ID. I've generated one for you. Add this line to your file: @0xc82955a0c779197d;");
|
||||
Assert.IsTrue(msg.IsParseSuccess);
|
||||
Assert.AreEqual(@"\\?\c:\3:2", msg.FileName);
|
||||
Assert.AreEqual(1, msg.Line);
|
||||
Assert.AreEqual(1, msg.Column);
|
||||
Assert.AreEqual("error", msg.Category);
|
||||
Assert.AreEqual("File does not declare an ID. I've generated one for you. Add this line to your file: @0xc82955a0c779197d;", msg.MessageText);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AnnoyingNTFSAlternateDataStream4()
|
||||
{
|
||||
var msg = new CapnpMessage(@"1:2-3:10:7-8: error: Duplicate ordinal number.");
|
||||
Assert.IsTrue(msg.IsParseSuccess);
|
||||
Assert.AreEqual(@"1:2-3", msg.FileName);
|
||||
Assert.AreEqual(10, msg.Line);
|
||||
Assert.AreEqual(7, msg.Column);
|
||||
Assert.AreEqual(8, msg.EndColumn);
|
||||
Assert.AreEqual("error", msg.Category);
|
||||
Assert.AreEqual("Duplicate ordinal number.", msg.MessageText);
|
||||
}
|
||||
}
|
||||
}
|
48
CapnpC.CSharp.Generator.Tests/CodeGenerator.feature
Normal file
48
CapnpC.CSharp.Generator.Tests/CodeGenerator.feature
Normal file
@ -0,0 +1,48 @@
|
||||
Feature: CodeGenerator
|
||||
In order to ensure that the generator backend produces valid output
|
||||
As a contributor
|
||||
I want to get notified when there is any deviation from reference output
|
||||
|
||||
Scenario: Comparing backend output with reference
|
||||
Given I have a binary code generator request "test.capnp.bin"
|
||||
And my reference output is "test.cs"
|
||||
When I invoke capnpc-csharp
|
||||
Then the generated output must match the reference
|
||||
|
||||
Scenario Outline: Invalid binary code generator requests
|
||||
Given I have a binary code generator request <bin>
|
||||
When I invoke capnpc-csharp
|
||||
Then the invocation must fail
|
||||
|
||||
Examples:
|
||||
| bin |
|
||||
| null.bin |
|
||||
| test.cs |
|
||||
|
||||
Scenario: Combining frontend and backend
|
||||
Given capnp.exe is installed on my system
|
||||
And I have a schema "UnitTest1.capnp"
|
||||
When I try to generate code from that schema
|
||||
Then code generation must succeed
|
||||
|
||||
Scenario: Missing frontend
|
||||
Given capnp.exe is not installed on my system
|
||||
And I have a schema "UnitTest1.capnp"
|
||||
When I try to generate code from that schema
|
||||
Then the invocation must fail
|
||||
|
||||
Scenario: Schema without ID
|
||||
Given capnp.exe is installed on my system
|
||||
And I have a schema "Empty1.capnp"
|
||||
When I try to generate code from that schema
|
||||
Then the invocation must fail
|
||||
And the reason must be bad input
|
||||
And the error output must contain "File does not declare an ID"
|
||||
|
||||
Scenario: Multiple errors
|
||||
Given capnp.exe is installed on my system
|
||||
And I have a schema "invalid.capnp"
|
||||
When I try to generate code from that schema
|
||||
Then the invocation must fail
|
||||
And the reason must be bad input
|
||||
And the error output must contain multiple messages
|
@ -10,7 +10,7 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
#region Designer generated code
|
||||
#pragma warning disable
|
||||
namespace capnpc_csharp.Tests
|
||||
namespace CapnpC.CSharp.Generator.Tests
|
||||
{
|
||||
using TechTalk.SpecFlow;
|
||||
|
||||
@ -63,7 +63,7 @@ namespace capnpc_csharp.Tests
|
||||
if (((testRunner.FeatureContext != null)
|
||||
&& (testRunner.FeatureContext.FeatureInfo.Title != "CodeGenerator")))
|
||||
{
|
||||
global::capnpc_csharp.Tests.CodeGeneratorFeature.FeatureSetup(null);
|
||||
global::CapnpC.CSharp.Generator.Tests.CodeGeneratorFeature.FeatureSetup(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,6 +149,98 @@ this.InvalidBinaryCodeGeneratorRequests("null.bin", ((string[])(null)));
|
||||
this.InvalidBinaryCodeGeneratorRequests("test.cs", ((string[])(null)));
|
||||
#line hidden
|
||||
}
|
||||
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Combining frontend and backend")]
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "CodeGenerator")]
|
||||
public virtual void CombiningFrontendAndBackend()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Combining frontend and backend", null, ((string[])(null)));
|
||||
#line 22
|
||||
this.ScenarioInitialize(scenarioInfo);
|
||||
this.ScenarioStart();
|
||||
#line 23
|
||||
testRunner.Given("capnp.exe is installed on my system", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 24
|
||||
testRunner.And("I have a schema \"UnitTest1.capnp\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 25
|
||||
testRunner.When("I try to generate code from that schema", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 26
|
||||
testRunner.Then("code generation must succeed", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Missing frontend")]
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "CodeGenerator")]
|
||||
public virtual void MissingFrontend()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Missing frontend", null, ((string[])(null)));
|
||||
#line 28
|
||||
this.ScenarioInitialize(scenarioInfo);
|
||||
this.ScenarioStart();
|
||||
#line 29
|
||||
testRunner.Given("capnp.exe is not installed on my system", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 30
|
||||
testRunner.And("I have a schema \"UnitTest1.capnp\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 31
|
||||
testRunner.When("I try to generate code from that schema", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 32
|
||||
testRunner.Then("the invocation must fail", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Schema without ID")]
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "CodeGenerator")]
|
||||
public virtual void SchemaWithoutID()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Schema without ID", null, ((string[])(null)));
|
||||
#line 34
|
||||
this.ScenarioInitialize(scenarioInfo);
|
||||
this.ScenarioStart();
|
||||
#line 35
|
||||
testRunner.Given("capnp.exe is installed on my system", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 36
|
||||
testRunner.And("I have a schema \"Empty1.capnp\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 37
|
||||
testRunner.When("I try to generate code from that schema", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 38
|
||||
testRunner.Then("the invocation must fail", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line 39
|
||||
testRunner.And("the reason must be bad input", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 40
|
||||
testRunner.And("the error output must contain \"File does not declare an ID\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Multiple errors")]
|
||||
[Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "CodeGenerator")]
|
||||
public virtual void MultipleErrors()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Multiple errors", null, ((string[])(null)));
|
||||
#line 42
|
||||
this.ScenarioInitialize(scenarioInfo);
|
||||
this.ScenarioStart();
|
||||
#line 43
|
||||
testRunner.Given("capnp.exe is installed on my system", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 44
|
||||
testRunner.And("I have a schema \"invalid.capnp\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 45
|
||||
testRunner.When("I try to generate code from that schema", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 46
|
||||
testRunner.Then("the invocation must fail", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line 47
|
||||
testRunner.And("the reason must be bad input", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 48
|
||||
testRunner.And("the error output must contain multiple messages", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
@ -1,13 +1,13 @@
|
||||
using Capnp;
|
||||
using Model = CapnpC.Model;
|
||||
using Generator = CapnpC.Generator;
|
||||
using CodeGeneratorRequest = CapnpC.Schema.CodeGeneratorRequest;
|
||||
using Model = CapnpC.CSharp.Generator.Model;
|
||||
using CodeGen = CapnpC.CSharp.Generator.CodeGen;
|
||||
using CodeGeneratorRequest = CapnpC.CSharp.Generator.Schema.CodeGeneratorRequest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace capnpc_csharp.Tests
|
||||
namespace CapnpC.CSharp.Generator.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class CodeGeneratorUnitTests
|
||||
@ -98,13 +98,13 @@ namespace capnpc_csharp.Tests
|
||||
struct Run
|
||||
{
|
||||
public Model.SchemaModel Model;
|
||||
public Generator.CodeGenerator CodeGen;
|
||||
public CodeGen.CodeGenerator CodeGen;
|
||||
public Model.GenFile FirstFile;
|
||||
public string Code;
|
||||
}
|
||||
|
||||
static Generator.CodeGenerator NewGeneratorFor(Model.SchemaModel model)
|
||||
=> new Generator.CodeGenerator(model, new Generator.GeneratorOptions());
|
||||
static CodeGen.CodeGenerator NewGeneratorFor(Model.SchemaModel model)
|
||||
=> new CodeGen.CodeGenerator(model, new CodeGen.GeneratorOptions());
|
||||
|
||||
Run LoadAndGenerate(string inputName, int? testNum = null)
|
||||
{
|
@ -0,0 +1 @@
|
||||
|
@ -0,0 +1 @@
|
||||
|
@ -0,0 +1,11 @@
|
||||
@0xa5ac546b7bf6fbbc
|
||||
|
||||
enum Enumerant {
|
||||
byte @0;
|
||||
bit @1;
|
||||
}
|
||||
|
||||
struct Foo {
|
||||
foo @0: UInt8;
|
||||
bar @0: UInt8;
|
||||
}
|
149
CapnpC.CSharp.Generator.Tests/FeatureSteps/CodeGeneratorSteps.cs
Normal file
149
CapnpC.CSharp.Generator.Tests/FeatureSteps/CodeGeneratorSteps.cs
Normal file
@ -0,0 +1,149 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using TechTalk.SpecFlow;
|
||||
|
||||
namespace CapnpC.CSharp.Generator.Tests
|
||||
{
|
||||
[Binding]
|
||||
public class CodeGeneratorSteps
|
||||
{
|
||||
Stream _inputStream;
|
||||
string _inputSchemaFileName;
|
||||
string _inputSchema;
|
||||
string _referenceOutputContent;
|
||||
|
||||
GenerationResult _result;
|
||||
|
||||
public static Stream LoadResource(string name)
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
string[] names = assembly.GetManifestResourceNames();
|
||||
string urn = Array.Find(names, n => n.EndsWith(name, StringComparison.OrdinalIgnoreCase));
|
||||
Assert.IsNotNull(urn, $"Test specification error: {name} does not exist");
|
||||
return assembly.GetManifestResourceStream(urn);
|
||||
}
|
||||
|
||||
internal static bool IsCapnpExeInstalled()
|
||||
{
|
||||
using (var process = Process.Start("where", "capnp.exe"))
|
||||
{
|
||||
if (process == null)
|
||||
Assert.Fail("Unable to start 'where'");
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
return process.ExitCode == 0;
|
||||
}
|
||||
}
|
||||
|
||||
[Given(@"I have a binary code generator request ""(.*)""")]
|
||||
[Given(@"I have a binary code generator request (.*)")]
|
||||
public void GivenIHaveABinaryCodeGeneratorRequest(string binaryRequestFileName)
|
||||
{
|
||||
_inputStream = LoadResource(binaryRequestFileName);
|
||||
}
|
||||
|
||||
[Given(@"my reference output is ""(.*)""")]
|
||||
public void GivenMyReferenceOutputIs(string expectedOutputFileName)
|
||||
{
|
||||
using (var stream = LoadResource(expectedOutputFileName))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
_referenceOutputContent = reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
[When(@"I invoke capnpc-csharp")]
|
||||
public void WhenIInvokeCapnpc_Csharp()
|
||||
{
|
||||
using (_inputStream)
|
||||
{
|
||||
_result = CapnpCompilation.GenerateFromStream(_inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
[Then(@"the generated output must match the reference")]
|
||||
public void ThenTheGeneratedOutputMustMatchTheReference()
|
||||
{
|
||||
Assert.IsTrue(_result.IsSuccess, $"Tool invocation failed: {_result.Exception?.Message}");
|
||||
Assert.AreEqual(_referenceOutputContent, _result.GeneratedFiles.Single().GeneratedContent);
|
||||
}
|
||||
|
||||
[Then(@"the invocation must fail")]
|
||||
public void ThenTheInvocationMustFail()
|
||||
{
|
||||
Assert.IsFalse(_result.IsSuccess, "Tool invocation was supposed to fail, but it didn't");
|
||||
Assert.IsNotNull(_result.Exception, "Expected an exception");
|
||||
}
|
||||
|
||||
[Given(@"capnp\.exe is installed on my system")]
|
||||
public void GivenCapnp_ExeIsInstalledOnMySystem()
|
||||
{
|
||||
if (!IsCapnpExeInstalled())
|
||||
{
|
||||
Assert.Inconclusive("capnp.exe not found. Precondition of this test is not met.");
|
||||
}
|
||||
}
|
||||
|
||||
[Given(@"I have a schema ""(.*)""")]
|
||||
public void GivenIHaveASchema(string capnpFileName)
|
||||
{
|
||||
_inputSchemaFileName = capnpFileName;
|
||||
|
||||
using (var stream = LoadResource(capnpFileName))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
_inputSchema = reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
[When(@"I try to generate code from that schema")]
|
||||
public void WhenIWantToGenerateCodeFromThatSchema()
|
||||
{
|
||||
string path = Path.Combine(Path.GetTempPath(), _inputSchemaFileName);
|
||||
File.WriteAllText(path, _inputSchema);
|
||||
_result = CapnpCompilation.InvokeCapnpAndGenerate(new string[] { path });
|
||||
}
|
||||
|
||||
[Then(@"code generation must succeed")]
|
||||
public void ThenCodeGenerationMustSucceed()
|
||||
{
|
||||
Assert.IsNotNull(_result, "expected generation result");
|
||||
Assert.IsTrue(_result.IsSuccess, $"Tool invocation failed: {_result.Exception?.Message}");
|
||||
Assert.IsTrue(_result.GeneratedFiles.Count == 1, "Expected exactly one file");
|
||||
Assert.IsTrue(_result.GeneratedFiles[0].IsSuccess, $"Code generation failed: {_result.GeneratedFiles[0].Exception?.Message}");
|
||||
Assert.IsFalse(string.IsNullOrEmpty(_result.GeneratedFiles[0].GeneratedContent), "Expected non-empty generated content");
|
||||
}
|
||||
|
||||
[Given(@"capnp\.exe is not installed on my system")]
|
||||
public void GivenCapnp_ExeIsNotInstalledOnMySystem()
|
||||
{
|
||||
if (IsCapnpExeInstalled())
|
||||
{
|
||||
Assert.Inconclusive("capnp.exe found. Precondition of this test is not met.");
|
||||
}
|
||||
}
|
||||
|
||||
[Then(@"the reason must be bad input")]
|
||||
public void ThenTheReasonMustBeBadInput()
|
||||
{
|
||||
Assert.IsTrue(_result.ErrorCategory == CapnpProcessFailure.BadInput);
|
||||
}
|
||||
|
||||
[Then(@"the error output must contain ""(.*)""")]
|
||||
public void ThenTheErrorOutputMustContain(string p0)
|
||||
{
|
||||
Assert.IsTrue(_result.Messages.Any(m => m.FullMessage.Contains(p0)));
|
||||
}
|
||||
|
||||
[Then(@"the error output must contain multiple messages")]
|
||||
public void ThenTheErrorOutputMustContainMultipleMessages()
|
||||
{
|
||||
Assert.IsTrue(_result.Messages.Count >= 2);
|
||||
}
|
||||
}
|
||||
}
|
16
CapnpC.CSharp.Generator/CapnpC.CSharp.Generator.csproj
Normal file
16
CapnpC.CSharp.Generator/CapnpC.CSharp.Generator.csproj
Normal file
@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netcoreapp2.1</TargetFrameworks>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Capnp.Net.Runtime\Capnp.Net.Runtime.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
111
CapnpC.CSharp.Generator/CapnpCompilation.cs
Normal file
111
CapnpC.CSharp.Generator/CapnpCompilation.cs
Normal file
@ -0,0 +1,111 @@
|
||||
using Capnp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
[assembly: InternalsVisibleTo("CapnpC.CSharp.Generator.Tests")]
|
||||
|
||||
namespace CapnpC.CSharp.Generator
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods for controlling both the C# code generator backend and the frontend "capnpc"
|
||||
/// </summary>
|
||||
public static class CapnpCompilation
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates C# code from given input stream
|
||||
/// </summary>
|
||||
/// <param name="input">input stream containing the binary code generation request, which the frontend capnpc emits</param>
|
||||
/// <returns>generation result</returns>
|
||||
/// <exception cref="ArgumentNullException">if <paramref name="input"/> is null</exception>
|
||||
public static GenerationResult GenerateFromStream(Stream input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
|
||||
try
|
||||
{
|
||||
var segments = Framing.ReadSegments(input);
|
||||
var dec = DeserializerState.CreateRoot(segments);
|
||||
var reader = Schema.CodeGeneratorRequest.Reader.Create(dec);
|
||||
var model = Model.SchemaModel.Create(reader);
|
||||
var codeGen = new CodeGen.CodeGenerator(model, new CodeGen.GeneratorOptions());
|
||||
return new GenerationResult(codeGen.Generate());
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
return new GenerationResult(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes "capnp.exe -o-" with given additional arguments and redirects the output to the C# generator backend.
|
||||
/// </summary>
|
||||
/// <param name="arguments">additional command line arguments</param>
|
||||
/// <param name="workingDirectory">optional working directory</param>
|
||||
/// <returns>generation result</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="arguments"/>is null</exception>
|
||||
public static GenerationResult InvokeCapnpAndGenerate(IEnumerable<string> arguments, string workingDirectory = null)
|
||||
{
|
||||
if (arguments == null)
|
||||
throw new ArgumentNullException(nameof(arguments));
|
||||
|
||||
using (var compiler = new Process())
|
||||
{
|
||||
var argList = new List<string>();
|
||||
argList.Add("compile");
|
||||
argList.Add($"-o-");
|
||||
argList.AddRange(arguments);
|
||||
|
||||
compiler.StartInfo.FileName = "capnp.exe";
|
||||
compiler.StartInfo.Arguments = string.Join(" ", argList);
|
||||
compiler.StartInfo.UseShellExecute = false;
|
||||
compiler.StartInfo.RedirectStandardOutput = true;
|
||||
compiler.StartInfo.RedirectStandardError = true;
|
||||
if (!string.IsNullOrWhiteSpace(workingDirectory))
|
||||
{
|
||||
compiler.StartInfo.WorkingDirectory = workingDirectory;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
compiler.Start();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
return new GenerationResult(exception)
|
||||
{
|
||||
ErrorCategory = CapnpProcessFailure.NotFound
|
||||
};
|
||||
}
|
||||
|
||||
var result = GenerateFromStream(compiler.StandardOutput.BaseStream);
|
||||
|
||||
var messageList = new List<CapnpMessage>();
|
||||
|
||||
while (!compiler.StandardError.EndOfStream)
|
||||
{
|
||||
messageList.Add(new CapnpMessage(compiler.StandardError.ReadLine()));
|
||||
}
|
||||
|
||||
result.Messages = messageList;
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
compiler.WaitForExit();
|
||||
int exitCode = compiler.ExitCode;
|
||||
|
||||
if (exitCode == 0)
|
||||
result.ErrorCategory = CapnpProcessFailure.BadOutput;
|
||||
else
|
||||
result.ErrorCategory = CapnpProcessFailure.BadInput;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
116
CapnpC.CSharp.Generator/CapnpMessage.cs
Normal file
116
CapnpC.CSharp.Generator/CapnpMessage.cs
Normal file
@ -0,0 +1,116 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
[assembly: InternalsVisibleTo("CapnpC.CSharp.Generator.Tests")]
|
||||
|
||||
namespace CapnpC.CSharp.Generator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a capnp.exe output message
|
||||
/// </summary>
|
||||
public class CapnpMessage
|
||||
{
|
||||
// capnp outputs look like this:
|
||||
// empty.capnp:1:1: error: File does not declare an ID. I've generated one for you. Add this line to your file: @0xc82955a0c779197d;
|
||||
// f:\code\invalid.capnp:9:7-8: error: Ordinal @0 originally used here.
|
||||
// Parsing them is harder than it seems because the colon may be part of the file name (as in the example above).
|
||||
// And it becomes even worse! NTFS has a rarely used feature called "alternate data streams", identified by a colon:
|
||||
// f:\code\somefile:stream.capnp:9:7-8: error: Ordinal @0 originally used here.
|
||||
// What about a name which looks like a line number? (Hint: the 10 denotes the alternate data stream)
|
||||
// f:\code\somefile:10:9:7-8: error: Ordinal @0 originally used here.
|
||||
// Watching for the *last* colon as message separator does not work either, either. See first example.
|
||||
// Strategy: Watch out for the *last* occurence of pattern :[line]:[column]
|
||||
|
||||
static readonly Regex LineColumnRegex = new Regex(@":(?<Line>\d+):(?<Column>\d+)(-(?<EndColumn>\d+))?:", RegexOptions.Compiled | RegexOptions.RightToLeft);
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an instance from given message
|
||||
/// </summary>
|
||||
/// <param name="fullMessage">output message (one line)</param>
|
||||
public CapnpMessage(string fullMessage)
|
||||
{
|
||||
FullMessage = fullMessage;
|
||||
|
||||
var match = LineColumnRegex.Match(fullMessage);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
IsParseSuccess = true;
|
||||
FileName = fullMessage.Substring(0, match.Index);
|
||||
var lineMatch = match.Groups["Line"];
|
||||
if (lineMatch.Success)
|
||||
{
|
||||
int.TryParse(lineMatch.Value, out int value);
|
||||
Line = value;
|
||||
}
|
||||
var columnMatch = match.Groups["Column"];
|
||||
if (columnMatch.Success)
|
||||
{
|
||||
int.TryParse(columnMatch.Value, out int value);
|
||||
Column = value;
|
||||
}
|
||||
var endColumnMatch = match.Groups["EndColumn"];
|
||||
if (endColumnMatch.Success)
|
||||
{
|
||||
int.TryParse(endColumnMatch.Value, out int value);
|
||||
EndColumn = value;
|
||||
}
|
||||
|
||||
int restIndex = match.Index + match.Length;
|
||||
int bodyIndex = fullMessage.IndexOf(':', restIndex);
|
||||
|
||||
if (bodyIndex >= 0)
|
||||
{
|
||||
Category = fullMessage.Substring(restIndex, bodyIndex - restIndex).Trim();
|
||||
MessageText = fullMessage.Substring(bodyIndex + 1).Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Never observed "in the wild", just in case...
|
||||
Category = string.Empty;
|
||||
MessageText = fullMessage.Substring(restIndex).Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The original message
|
||||
/// </summary>
|
||||
public string FullMessage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the message could be decompsed into [filename]:[line]:[column]: [category]: [text]
|
||||
/// </summary>
|
||||
public bool IsParseSuccess { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parsed file name (null iff not IsParseSuccess)
|
||||
/// </summary>
|
||||
public string FileName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parsed line (0 if not IsParseSuccess)
|
||||
/// </summary>
|
||||
public int Line { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parsed column (0 if not IsParseSuccess)
|
||||
/// </summary>
|
||||
public int Column { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parsed end column (0 if there is none)
|
||||
/// </summary>
|
||||
public int EndColumn { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parsed category (e.g. "error", null iff not IsParseSuccess)
|
||||
/// </summary>
|
||||
public string Category { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parsed message body text (0 if not IsParseSuccess)
|
||||
/// </summary>
|
||||
public string MessageText { get; }
|
||||
}
|
||||
}
|
23
CapnpC.CSharp.Generator/CapnpProcessFailure.cs
Normal file
23
CapnpC.CSharp.Generator/CapnpProcessFailure.cs
Normal file
@ -0,0 +1,23 @@
|
||||
namespace CapnpC.CSharp.Generator
|
||||
{
|
||||
/// <summary>
|
||||
/// Why did invocation of capnpc.exe fail?
|
||||
/// </summary>
|
||||
public enum CapnpProcessFailure
|
||||
{
|
||||
/// <summary>
|
||||
/// Because capnpc.exe was not found. It is probably not installed.
|
||||
/// </summary>
|
||||
NotFound,
|
||||
|
||||
/// <summary>
|
||||
/// Because it exited with an error. Probably invalid .capnp file input.
|
||||
/// </summary>
|
||||
BadInput,
|
||||
|
||||
/// <summary>
|
||||
/// Because it produced an apparently bad code generation request.
|
||||
/// </summary>
|
||||
BadOutput
|
||||
}
|
||||
}
|
@ -1,18 +1,17 @@
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using CapnpC.Model;
|
||||
using CapnpC.CSharp.Generator.Model;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
||||
using static SyntaxHelpers;
|
||||
|
||||
class CodeGenerator
|
||||
internal class CodeGenerator
|
||||
{
|
||||
readonly SchemaModel _model;
|
||||
readonly GenNames _names;
|
||||
@ -169,14 +168,23 @@
|
||||
return cu.NormalizeWhitespace().ToFullString();
|
||||
}
|
||||
|
||||
public void Generate()
|
||||
public IReadOnlyList<FileGenerationResult> Generate()
|
||||
{
|
||||
var result = new List<FileGenerationResult>();
|
||||
|
||||
foreach (var file in _model.FilesToGenerate)
|
||||
{
|
||||
string content = Transform(file);
|
||||
string path = Path.ChangeExtension(file.Name, ".cs");
|
||||
File.WriteAllText(path, content);
|
||||
try
|
||||
{
|
||||
result.Add(new FileGenerationResult(file.Name, Transform(file)));
|
||||
}
|
||||
catch (System.Exception exception)
|
||||
{
|
||||
result.Add(new FileGenerationResult(file.Name, exception));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using CapnpC.Model;
|
||||
using CapnpC.CSharp.Generator.Model;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
||||
using static CapnpC.Generator.SyntaxHelpers;
|
||||
using static CapnpC.CSharp.Generator.CodeGen.SyntaxHelpers;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
class CommonSnippetGen
|
||||
{
|
@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using CapnpC.Model;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using CapnpC.CSharp.Generator.Model;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
||||
using static CapnpC.Generator.SyntaxHelpers;
|
||||
using static CapnpC.CSharp.Generator.CodeGen.SyntaxHelpers;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
class DomainClassSnippetGen
|
||||
{
|
@ -1,13 +1,12 @@
|
||||
using CapnpC.Model;
|
||||
using CapnpC.CSharp.Generator.Model;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
enum NameUsage
|
||||
{
|
@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
class GeneratorOptions
|
||||
{
|
@ -1,16 +1,15 @@
|
||||
using CapnpC.Model;
|
||||
using CapnpC.CSharp.Generator.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
||||
using static CapnpC.Generator.SyntaxHelpers;
|
||||
using static CapnpC.CSharp.Generator.CodeGen.SyntaxHelpers;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
class InterfaceSnippetGen
|
||||
{
|
@ -2,10 +2,8 @@
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
class Name
|
||||
{
|
@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using CapnpC.Model;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using CapnpC.CSharp.Generator.Model;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
||||
using static CapnpC.Generator.SyntaxHelpers;
|
||||
using static CapnpC.CSharp.Generator.CodeGen.SyntaxHelpers;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
class ReaderSnippetGen
|
||||
{
|
@ -1,8 +1,6 @@
|
||||
using Capnp;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
class SerializerStateWorder: SerializerState
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
class SkeletonWorder : Capnp.Rpc.Skeleton<object>
|
||||
{
|
@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
static class SyntaxHelpers
|
||||
{
|
@ -1,15 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using CapnpC.Model;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using CapnpC.CSharp.Generator.Model;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
||||
using static CapnpC.Generator.SyntaxHelpers;
|
||||
using static CapnpC.CSharp.Generator.CodeGen.SyntaxHelpers;
|
||||
|
||||
namespace CapnpC.Generator
|
||||
namespace CapnpC.CSharp.Generator.CodeGen
|
||||
{
|
||||
class WriterSnippetGen
|
||||
{
|
52
CapnpC.CSharp.Generator/FileGenerationResult.cs
Normal file
52
CapnpC.CSharp.Generator/FileGenerationResult.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System;
|
||||
|
||||
namespace CapnpC.CSharp.Generator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the generation result of a single .capnp file
|
||||
/// </summary>
|
||||
public class FileGenerationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs an instance in case of successful generation
|
||||
/// </summary>
|
||||
/// <param name="capnpFilePath">path to .capnp file</param>
|
||||
/// <param name="generatedContent">generated C# code</param>
|
||||
public FileGenerationResult(string capnpFilePath, string generatedContent)
|
||||
{
|
||||
CapnpFilePath = capnpFilePath;
|
||||
GeneratedContent = generatedContent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an instance in case of unsuccessful generation
|
||||
/// </summary>
|
||||
/// <param name="capnpFilePath">path to .capnp file</param>
|
||||
/// <param name="exception">Exception giving details on the error which prevented generation</param>
|
||||
public FileGenerationResult(string capnpFilePath, Exception exception)
|
||||
{
|
||||
CapnpFilePath = capnpFilePath;
|
||||
Exception = exception;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to .capnp file
|
||||
/// </summary>
|
||||
public string CapnpFilePath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Generated C# or null if generation failed
|
||||
/// </summary>
|
||||
public string GeneratedContent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Exception giving details on the error which prevented generation
|
||||
/// </summary>
|
||||
public Exception Exception { get; }
|
||||
|
||||
/// <summary>
|
||||
/// true iff generation was successful
|
||||
/// </summary>
|
||||
public bool IsSuccess => !string.IsNullOrEmpty(GeneratedContent);
|
||||
}
|
||||
}
|
54
CapnpC.CSharp.Generator/GenerationResult.cs
Normal file
54
CapnpC.CSharp.Generator/GenerationResult.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CapnpC.CSharp.Generator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a .capnp -> code generator result
|
||||
/// </summary>
|
||||
public class GenerationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs an instance in case of at least partially successful generation.
|
||||
/// </summary>
|
||||
/// <param name="generatedFiles">Generation result per file to generate</param>
|
||||
public GenerationResult(IReadOnlyList<FileGenerationResult> generatedFiles)
|
||||
{
|
||||
GeneratedFiles = generatedFiles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an instance in case of total failure.
|
||||
/// </summary>
|
||||
/// <param name="exception">Exception with details on error</param>
|
||||
public GenerationResult(Exception exception)
|
||||
{
|
||||
Exception = exception;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generation result per file to generate or null in case of total failure
|
||||
/// </summary>
|
||||
public IReadOnlyList<FileGenerationResult> GeneratedFiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Exception with details on error or null in case of success
|
||||
/// </summary>
|
||||
public Exception Exception { get; }
|
||||
|
||||
/// <summary>
|
||||
/// true iff generation was successful
|
||||
/// </summary>
|
||||
public bool IsSuccess => GeneratedFiles != null;
|
||||
|
||||
/// <summary>
|
||||
/// Messages read from standard error. Valid for both failure and success (capnp might spit out some warnings).
|
||||
/// </summary>
|
||||
public IReadOnlyList<CapnpMessage> Messages { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Error classification (if any error)
|
||||
/// </summary>
|
||||
public CapnpProcessFailure ErrorCategory { get; internal set; }
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
abstract class AbstractType
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class Annotation : IDefinition
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class Constant : IDefinition
|
||||
{
|
@ -2,7 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class DefinitionManager
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class Enumerant
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class Field
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class GenFile: IDefinition, IHasNestedDefinitions
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class GenericParameter
|
||||
{
|
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
namespace CapnpC.Model
|
||||
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
static class HasGenericParameters
|
||||
{
|
@ -1,5 +1,5 @@
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
interface IDefinition
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
interface IHasGenericParameters
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
interface IHasNestedDefinitions
|
||||
{
|
@ -3,7 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
public class IdentifierRenamer
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class InvalidSchemaException : Exception
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class Method: IHasGenericParameters
|
||||
{
|
@ -4,7 +4,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class SchemaModel
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
enum SpecialName
|
||||
{
|
@ -5,7 +5,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class Type: AbstractType
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
enum TypeCategory
|
||||
{
|
@ -1,7 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
namespace CapnpC.Model
|
||||
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class TypeDefinition : AbstractType, IDefinition, IHasNestedDefinitions, IHasGenericParameters
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
enum TypeTag
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
static class Types
|
||||
{
|
@ -3,7 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CapnpC.Model
|
||||
namespace CapnpC.CSharp.Generator.Model
|
||||
{
|
||||
class Value
|
||||
{
|
@ -1,9 +1,7 @@
|
||||
using Capnp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CapnpC.Schema
|
||||
namespace CapnpC.CSharp.Generator.Schema
|
||||
{
|
||||
namespace Superclass
|
||||
{
|
42
CapnpC.CSharp.MsBuild.Generation.Tests/BuildEngineMock.cs
Normal file
42
CapnpC.CSharp.MsBuild.Generation.Tests/BuildEngineMock.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
namespace CapnpC.CSharp.MsBuild.Generation.Tests
|
||||
{
|
||||
class BuildEngineMock : IBuildEngine
|
||||
{
|
||||
public bool ContinueOnError => true;
|
||||
|
||||
public int LineNumberOfTaskNode => 0;
|
||||
|
||||
public int ColumnNumberOfTaskNode => 0;
|
||||
|
||||
public string ProjectFileOfTaskNode => null;
|
||||
|
||||
public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void LogCustomEvent(CustomBuildEventArgs e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
|
||||
public void LogErrorEvent(BuildErrorEventArgs e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
|
||||
public void LogMessageEvent(BuildMessageEventArgs e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
|
||||
public void LogWarningEvent(BuildWarningEventArgs e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.8.166" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CapnpC.CSharp.Generator.Tests\CapnpC.CSharp.Generator.Tests.csproj" />
|
||||
<ProjectReference Include="..\CapnpC.CSharp.MsBuild.Generation\CapnpC.CSharp.MsBuild.Generation.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,51 @@
|
||||
using CapnpC.CSharp.Generator.Tests;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.IO;
|
||||
|
||||
namespace CapnpC.CSharp.MsBuild.Generation.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class GenerateCapnpFileCodeBehindTaskTest
|
||||
{
|
||||
string LoadResourceContent(string name)
|
||||
{
|
||||
using (var stream = CodeGeneratorSteps.LoadResource("UnitTest1.capnp"))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ExecutionWithoutParameters()
|
||||
{
|
||||
var task = new GenerateCapnpFileCodeBehindTask();
|
||||
task.BuildEngine = new BuildEngineMock();
|
||||
task.Execute();
|
||||
// Should not crash. Should Execute() return true or false if there is no input?
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SimpleGeneration()
|
||||
{
|
||||
string capnpFile = "UnitTask1.capnp";
|
||||
string content = LoadResourceContent(capnpFile);
|
||||
string tmpPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(tmpPath);
|
||||
string capnpPath = Path.Combine(tmpPath, capnpFile);
|
||||
File.WriteAllText(capnpPath, content);
|
||||
|
||||
var task = new GenerateCapnpFileCodeBehindTask();
|
||||
task.BuildEngine = new BuildEngineMock();
|
||||
task.ProjectPath = Path.Combine(tmpPath, "doesnotneedtoexist.csproj");
|
||||
task.CapnpFiles = new ITaskItem[1] { new TaskItemMock() { ItemSpec = capnpPath } };
|
||||
Assert.IsTrue(task.Execute());
|
||||
Assert.IsNotNull(task.GeneratedFiles);
|
||||
Assert.AreEqual(1, task.GeneratedFiles.Length);
|
||||
string csPath = Path.Combine(tmpPath, task.GeneratedFiles[0].ItemSpec);
|
||||
Assert.AreEqual(capnpPath + ".cs", csPath);
|
||||
Assert.IsTrue(File.Exists(csPath));
|
||||
}
|
||||
}
|
||||
}
|
42
CapnpC.CSharp.MsBuild.Generation.Tests/TaskItemMock.cs
Normal file
42
CapnpC.CSharp.MsBuild.Generation.Tests/TaskItemMock.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System.Collections;
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
namespace CapnpC.CSharp.MsBuild.Generation.Tests
|
||||
{
|
||||
|
||||
class TaskItemMock : ITaskItem
|
||||
{
|
||||
public string ItemSpec { get; set; }
|
||||
|
||||
public ICollection MetadataNames => null;
|
||||
|
||||
public int MetadataCount => 0;
|
||||
|
||||
public IDictionary CloneCustomMetadata()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void CopyMetadataTo(ITaskItem destinationItem)
|
||||
{
|
||||
}
|
||||
|
||||
public string GetMetadata(string metadataName)
|
||||
{
|
||||
if (metadataName == "FullPath")
|
||||
{
|
||||
return ItemSpec;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public void RemoveMetadata(string metadataName)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetMetadata(string metadataName, string metadataValue)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
4
CapnpC.CSharp.MsBuild.Generation/AssemblyAttributes.cs
Normal file
4
CapnpC.CSharp.MsBuild.Generation/AssemblyAttributes.cs
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security;
|
||||
|
@ -0,0 +1,113 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net471;netcoreapp2.1</TargetFrameworks>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<Version>1.0-local$([System.DateTime]::UtcNow.ToString(yyMMddHHmm))</Version>
|
||||
|
||||
<NuspecFile>$(MSBuildThisFileDirectory)CapnpC.CSharp.MsBuild.Generation.nuspec</NuspecFile>
|
||||
<NuspecProperties>version=$(Version);configuration=$(Configuration)</NuspecProperties>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageOutputPath>..\bin\$(Configuration)</PackageOutputPath>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Composition" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem.SDK" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem.SDK.Tools" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading" />
|
||||
<PackageReference Include="System.Collections.Immutable" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<PackageReference>
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build.Framework" Version="15.8.166" />
|
||||
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.8.166" />
|
||||
<PackageReference Update="@(PackageReference)" PrivateAssets="All" />
|
||||
<PackageReference Update="Microsoft.VisualStudio.Composition" Version="15.8.98" />
|
||||
<PackageReference Update="Microsoft.VisualStudio.ProjectSystem" Version="15.8.243" />
|
||||
<PackageReference Update="Microsoft.VisualStudio.ProjectSystem.SDK" Version="15.8.243" />
|
||||
<PackageReference Update="Microsoft.VisualStudio.ProjectSystem.SDK.Tools" Version="15.8.243" />
|
||||
<PackageReference Update="Microsoft.VisualStudio.Threading" Version="16.3.52" />
|
||||
<PackageReference Update="Microsoft.Xaml" Version="4.0.0.1" />
|
||||
<PackageReference Update="System.Collections.Immutable" Version="1.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="FrameworkDependent\**\*.cs" />
|
||||
<Compile Include="FrameworkDependent\*.cs" />
|
||||
<None Include="FrameworkDependent\**\*.cs" />
|
||||
<Compile Include="FrameworkDependent\FullFramework\**\*.cs" Condition="'$(TargetFramework)' == '$(CapnpcCsharp_FullFramework_Tools_TFM)'" />
|
||||
<Compile Include="FrameworkDependent\DotNetCore\**\*.cs" Condition="'$(TargetFramework)' == '$(CapnpcCsharp_Core_Tools_TFM)'" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="FrameworkDependent\DotNetCore\" />
|
||||
<Folder Include="FrameworkDependent\FullFramework\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CapnpC.CSharp.Generator\CapnpC.CSharp.Generator.csproj">
|
||||
<Private>true</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Build">
|
||||
<HintPath>Microsoft.Build</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Build.Framework">
|
||||
<HintPath>Microsoft.Build.Framework</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Build.Utilities.Core">
|
||||
<HintPath>Microsoft.Build.Utilities.Core</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="buildMultiTargeting\CapnpC.CSharp.MsBuild.Generation.props">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="build\CapnpC.CSharp.MsBuild.Generation.props">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="build\CapnpC.CSharp.MsBuild.Generation.targets">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="build\CapnpC.CSharp.MsBuild.Generation.tasks">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="build\CPS\Buildsystem\CpsExtension.DesignTime.targets">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="build\CPS\Buildsystem\Rules\CapnpFileType.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="build\CPS\Buildsystem\Rules\ProjectItemsSchema.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="rmdir /s /q $(SolutionDir)MsBuildGenerationTest\obj" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>CapnpC.CSharp.MsBuild.Generation</id>
|
||||
<version>$version$</version>
|
||||
<title>CapnpC.CSharp.MsBuild.Generation</title>
|
||||
<authors>Christian Köllner and contributors</authors>
|
||||
<owners>Christian Köllner</owners>
|
||||
<description>Package to enable the .capnp -> .cs file generation during build time</description>
|
||||
<summary>Package to enable the .capnp -> .cs file generation during build time</summary>
|
||||
<language>en-US</language>
|
||||
<projectUrl>https://github.com/c80k/capnproto-dotnetcore</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<tags>capnproto csharp msbuild</tags>
|
||||
<copyright>Christian Köllner and contributors</copyright>
|
||||
<dependencies>
|
||||
<dependency id="Capnp.Net.Runtime" version="1.0" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="build\**\*" target="build" />
|
||||
<file src="buildMultiTargeting\**\*" target="buildMultiTargeting" />
|
||||
<file src="bin\$configuration$\net471\*.dll" target="tasks\net471" />
|
||||
<file src="bin\$configuration$\netcoreapp2.1\*.dll" target="tasks\netcoreapp2.1" />
|
||||
<file src="bin\$configuration$\netcoreapp2.1\*.deps.json" target="tasks\netcoreapp2.1" />
|
||||
|
||||
<file src="..\Licenses\**\*" target="licenses" />
|
||||
<file src="..\LICENSE" target="LICENSE" />
|
||||
</files>
|
||||
</package>
|
99
CapnpC.CSharp.MsBuild.Generation/CapnpCodeBehindGenerator.cs
Normal file
99
CapnpC.CSharp.MsBuild.Generation/CapnpCodeBehindGenerator.cs
Normal file
@ -0,0 +1,99 @@
|
||||
using CapnpC.CSharp.Generator;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace CapnpC.CSharp.MsBuild.Generation
|
||||
{
|
||||
public class CapnpCodeBehindGenerator : IDisposable
|
||||
{
|
||||
|
||||
public void InitializeProject(string projectPath)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public CsFileGeneratorResult GenerateCodeBehindFile(CapnpGenJob job)
|
||||
{
|
||||
string capnpFile = job.CapnpPath;
|
||||
|
||||
// Works around a weird capnp.exe behavior: When the input file is empty, it will spit out an exception dump
|
||||
// instead of a parse error. But the parse error is nice because it contains a generated ID. We want the parse error!
|
||||
// Workaround: Generate a temporary file that contains a single line break (such that it is not empty...)
|
||||
try
|
||||
{
|
||||
if (File.Exists(capnpFile) && new FileInfo(capnpFile).Length == 0)
|
||||
{
|
||||
string tempFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".capnp");
|
||||
|
||||
File.WriteAllText(tempFile, Environment.NewLine);
|
||||
try
|
||||
{
|
||||
var jobCopy = new CapnpGenJob()
|
||||
{
|
||||
CapnpPath = tempFile,
|
||||
WorkingDirectory = job.WorkingDirectory
|
||||
};
|
||||
|
||||
jobCopy.AdditionalArguments.AddRange(job.AdditionalArguments);
|
||||
|
||||
return GenerateCodeBehindFile(jobCopy);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(tempFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
var args = new List<string>();
|
||||
args.AddRange(job.AdditionalArguments);
|
||||
args.Add(capnpFile);
|
||||
|
||||
var result = CapnpCompilation.InvokeCapnpAndGenerate(args, job.WorkingDirectory);
|
||||
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
if (result.GeneratedFiles.Count == 1)
|
||||
{
|
||||
return new CsFileGeneratorResult(
|
||||
result.GeneratedFiles[0],
|
||||
capnpFile + ".cs",
|
||||
result.Messages);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new CsFileGeneratorResult(
|
||||
"Code generation produced more than one file. This is not supported.",
|
||||
result.Messages);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (result.ErrorCategory)
|
||||
{
|
||||
case CapnpProcessFailure.NotFound:
|
||||
return new CsFileGeneratorResult("Unable to find capnp.exe - please install capnproto on your system first.");
|
||||
|
||||
case CapnpProcessFailure.BadInput:
|
||||
return new CsFileGeneratorResult("Invalid schema", result.Messages);
|
||||
|
||||
case CapnpProcessFailure.BadOutput:
|
||||
return new CsFileGeneratorResult(
|
||||
"Internal error: capnp.exe produced a binary code generation request which was not understood by the backend",
|
||||
result.Messages);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException("Invalid error category");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace CapnpC.CSharp.MsBuild.Generation
|
||||
{
|
||||
public class CapnpFileCodeBehindGenerator : ICapnpcCsharpGenerator
|
||||
{
|
||||
public CapnpFileCodeBehindGenerator(TaskLoggingHelper log)
|
||||
{
|
||||
Log = log ?? throw new ArgumentNullException(nameof(log));
|
||||
}
|
||||
|
||||
public TaskLoggingHelper Log { get; }
|
||||
|
||||
public IEnumerable<string> GenerateFilesForProject(
|
||||
string projectPath,
|
||||
List<CapnpGenJob> capnpFiles,
|
||||
string projectFolder)
|
||||
{
|
||||
using (var capnpCodeBehindGenerator = new CapnpCodeBehindGenerator())
|
||||
{
|
||||
capnpCodeBehindGenerator.InitializeProject(projectPath);
|
||||
|
||||
var codeBehindWriter = new CodeBehindWriter(null);
|
||||
|
||||
if (capnpFiles == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var genJob in capnpFiles)
|
||||
{
|
||||
Log.LogMessage(MessageImportance.Normal, "Generate {0}, working dir = {1}, options = {2}",
|
||||
genJob.CapnpPath,
|
||||
genJob.WorkingDirectory,
|
||||
string.Join(" ", genJob.AdditionalArguments));
|
||||
|
||||
var generatorResult = capnpCodeBehindGenerator.GenerateCodeBehindFile(genJob);
|
||||
|
||||
if (!generatorResult.Success)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(generatorResult.Error))
|
||||
{
|
||||
Log.LogError("{0}", generatorResult.Error);
|
||||
}
|
||||
|
||||
if (generatorResult.Messages != null)
|
||||
{
|
||||
foreach (var message in generatorResult.Messages)
|
||||
{
|
||||
if (message.IsParseSuccess)
|
||||
{
|
||||
Log.LogError(
|
||||
subcategory: null,
|
||||
errorCode: null,
|
||||
helpKeyword: null,
|
||||
file: genJob.CapnpPath,
|
||||
lineNumber: message.Line,
|
||||
columnNumber: message.Column,
|
||||
endLineNumber: message.Line,
|
||||
endColumnNumber: message.EndColumn == 0 ? message.Column : message.EndColumn,
|
||||
"{0}",
|
||||
message.MessageText);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.LogError("{0}", message.FullMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var resultedFile = codeBehindWriter.WriteCodeBehindFile(generatorResult.Filename, generatorResult);
|
||||
|
||||
yield return FileSystemHelper.GetRelativePath(resultedFile, projectFolder);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
11
CapnpC.CSharp.MsBuild.Generation/CapnpGenJob.cs
Normal file
11
CapnpC.CSharp.MsBuild.Generation/CapnpGenJob.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CapnpC.CSharp.MsBuild.Generation
|
||||
{
|
||||
public class CapnpGenJob
|
||||
{
|
||||
public string CapnpPath { get; set; }
|
||||
public string WorkingDirectory { get; set; }
|
||||
public List<string> AdditionalArguments { get; } = new List<string>();
|
||||
}
|
||||
}
|
38
CapnpC.CSharp.MsBuild.Generation/CodeBehindWriter.cs
Normal file
38
CapnpC.CSharp.MsBuild.Generation/CodeBehindWriter.cs
Normal file
@ -0,0 +1,38 @@
|
||||
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, CsFileGeneratorResult testFileGeneratorResult)
|
||||
{
|
||||
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.GeneratedCode))
|
||||
{
|
||||
File.WriteAllText(outputPath, testFileGeneratorResult.GeneratedCode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
File.WriteAllText(outputPath, testFileGeneratorResult.GeneratedCode);
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
}
|
||||
}
|
51
CapnpC.CSharp.MsBuild.Generation/CsFileGeneratorResult.cs
Normal file
51
CapnpC.CSharp.MsBuild.Generation/CsFileGeneratorResult.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using CapnpC.CSharp.Generator;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CapnpC.CSharp.MsBuild.Generation
|
||||
{
|
||||
public class CsFileGeneratorResult
|
||||
{
|
||||
public CsFileGeneratorResult(FileGenerationResult generatorResult, string fileName, IReadOnlyList<CapnpMessage> messages)
|
||||
{
|
||||
if (generatorResult == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(generatorResult));
|
||||
}
|
||||
|
||||
Filename = fileName ?? throw new ArgumentNullException(nameof(fileName));
|
||||
|
||||
Error = generatorResult.Exception?.Message;
|
||||
GeneratedCode = generatorResult.GeneratedContent;
|
||||
Messages = messages;
|
||||
}
|
||||
|
||||
public CsFileGeneratorResult(string error)
|
||||
{
|
||||
Error = error;
|
||||
}
|
||||
|
||||
public CsFileGeneratorResult(string error, IReadOnlyList<CapnpMessage> messages)
|
||||
{
|
||||
Error = error;
|
||||
Messages = messages;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The error, if any.
|
||||
/// </summary>
|
||||
public string Error { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The generated code.
|
||||
/// </summary>
|
||||
public string GeneratedCode { get; }
|
||||
|
||||
public IReadOnlyList<CapnpMessage> Messages { get; }
|
||||
|
||||
public bool Success => Error == null;
|
||||
|
||||
public string Filename { get; }
|
||||
}
|
||||
}
|
112
CapnpC.CSharp.MsBuild.Generation/FileSystemHelper.cs
Normal file
112
CapnpC.CSharp.MsBuild.Generation/FileSystemHelper.cs
Normal file
@ -0,0 +1,112 @@
|
||||
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);
|
||||
}
|
||||
|
||||
// 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 FileCompareContent(string filePath1, string fileContent)
|
||||
{
|
||||
var currentFileContent = File.ReadAllText(filePath1);
|
||||
|
||||
return string.CompareOrdinal(currentFileContent, fileContent) == 0;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
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 CapnpFileCodeBehindGenerator(Log);
|
||||
}
|
||||
|
||||
public ICapnpcCsharpGenerator CodeBehindGenerator { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ProjectPath { get; set; }
|
||||
|
||||
public string ProjectFolder => Path.GetDirectoryName(ProjectPath);
|
||||
|
||||
public ITaskItem[] CapnpFiles { get; set; }
|
||||
|
||||
[Output]
|
||||
public ITaskItem[] GeneratedFiles { get; private set; }
|
||||
|
||||
static CapnpGenJob ToGenJob(ITaskItem item)
|
||||
{
|
||||
var job = new CapnpGenJob()
|
||||
{
|
||||
CapnpPath = item.GetMetadata("FullPath"),
|
||||
WorkingDirectory = item.GetMetadata("WorkingDirectory")
|
||||
};
|
||||
|
||||
string importPaths = item.GetMetadata("ImportPaths");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(importPaths))
|
||||
{
|
||||
job.AdditionalArguments.AddRange(importPaths.Split(new char[] { ';' },
|
||||
StringSplitOptions.RemoveEmptyEntries).Select(p => $"-I\"{p.TrimEnd('\\')}\""));
|
||||
}
|
||||
|
||||
string sourcePrefix = item.GetMetadata("SourcePrefix");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(sourcePrefix))
|
||||
{
|
||||
job.AdditionalArguments.Add(sourcePrefix);
|
||||
}
|
||||
|
||||
|
||||
string verbose = item.GetMetadata("Verbose");
|
||||
|
||||
if ("true".Equals(verbose, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
job.AdditionalArguments.Add("--verbose");
|
||||
}
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
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 CapnpFileCodeBehindGenerator(Log);
|
||||
|
||||
Log.LogWithNameTag(Log.LogMessage, "Starting GenerateCapnpFileCodeBehind");
|
||||
|
||||
var capnpFiles = CapnpFiles?.Select(ToGenJob).ToList() ?? new List<CapnpGenJob>();
|
||||
|
||||
var generatedFiles = generator.GenerateFilesForProject(
|
||||
ProjectPath,
|
||||
capnpFiles,
|
||||
ProjectFolder);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
22
CapnpC.CSharp.MsBuild.Generation/Helper/LogExtensions.cs
Normal file
22
CapnpC.CSharp.MsBuild.Generation/Helper/LogExtensions.cs
Normal file
@ -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<string, object[]> loggingMethod,
|
||||
string message,
|
||||
params object[] messageArgs)
|
||||
{
|
||||
string fullMessage = $"[Cap'n Proto] {message}";
|
||||
loggingMethod?.Invoke(fullMessage, messageArgs);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CapnpC.CSharp.MsBuild.Generation
|
||||
{
|
||||
public interface ICapnpcCsharpGenerator
|
||||
{
|
||||
IEnumerable<string> GenerateFilesForProject(string projectPath, List<CapnpGenJob> jobs, string projectFolder);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
|
||||
<PropertyGroup>
|
||||
<CpsExtensionSchemaDirectory Condition="'$(CpsExtensionSchemaDirectory)' == ''">$(MSBuildThisFileDirectory)Rules\</CpsExtensionSchemaDirectory>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PropertyPageSchema Include="$(CpsExtensionSchemaDirectory)\ProjectItemsSchema.xaml;"/>
|
||||
|
||||
<PropertyPageSchema Include="$(CpsExtensionSchemaDirectory)\CapnpFileType.xaml;">
|
||||
<Context>File;BrowseObject</Context>
|
||||
</PropertyPageSchema>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--Copyright, Microsoft Corporation, All rights reserved.-->
|
||||
|
||||
<Rule
|
||||
Name="Capnp"
|
||||
DisplayName="Cap'n Proto"
|
||||
PageTemplate="tool"
|
||||
Description="Cap'n Proto schema file"
|
||||
xmlns="http://schemas.microsoft.com/build/2009/properties">
|
||||
|
||||
<Rule.DataSource>
|
||||
<DataSource Persistence="ProjectFile" HasConfigurationCondition="True" ItemType="CapnpFiles" />
|
||||
</Rule.DataSource>
|
||||
|
||||
|
||||
<StringProperty Name="Identity" DisplayName="File Name" ReadOnly="true" Category="Misc">
|
||||
<StringProperty.DataSource>
|
||||
<DataSource Persistence="Intrinsic" ItemType="CapnpFiles" PersistedName="Identity" />
|
||||
</StringProperty.DataSource>
|
||||
</StringProperty>
|
||||
|
||||
<StringProperty Name="FullPath" DisplayName="Full Path" ReadOnly="true" Category="Misc">
|
||||
<StringProperty.DataSource>
|
||||
<DataSource Persistence="Intrinsic" ItemType="CapnpFiles" PersistedName="FullPath" />
|
||||
</StringProperty.DataSource>
|
||||
</StringProperty>
|
||||
|
||||
<StringProperty Name="DependentUpon" Visible="false" />
|
||||
<StringProperty Name="Link" Visible="false" />
|
||||
<!--<StringProperty Name="Generator" Visible="true" DisplayName="Custom Tool"/>-->
|
||||
|
||||
<!--<BoolProperty Name="Exclude" DisplayName="Exclude from build" Category="Misc" Visible="True"
|
||||
Description="Whether to skip code generation for this item"/>-->
|
||||
|
||||
<StringProperty Name="WorkingDirectory" DisplayName="Working Directory" ReadOnly="false" Category="Misc" Visible="True"
|
||||
Subtype="Folder" Description="Working directory for capnp"/>
|
||||
|
||||
<StringListProperty Name="ImportPaths" DisplayName="Import Paths" Category="Misc" Visible="True" Subtype="Folder"
|
||||
Description="List of directories searched for non-relative imports (ones that start with a '/')"/>
|
||||
|
||||
<StringProperty Name="SourcePrefix" DisplayName="Source Prefix" Switch="src-prefix" SwitchPrefix="--" Category="Misc" Visible="True"
|
||||
Description="If a file specified for compilation starts with the specified prefix, remove the prefix for the purpose of deciding the names of output files."/>
|
||||
|
||||
<BoolProperty Name="Verbose" DisplayName="Verbose" Switch="verbose" SwitchPrefix="--" Category="Misc" Visible="True"
|
||||
Description="Log informational messages to stderr; useful for debugging."/>
|
||||
</Rule>
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--Copyright, Microsoft Corporation, All rights reserved.-->
|
||||
<ProjectSchemaDefinitions
|
||||
xmlns="http://schemas.microsoft.com/build/2009/properties">
|
||||
|
||||
<ContentType
|
||||
Name="CapnpFile"
|
||||
DisplayName="CapnpFileType source file"
|
||||
ItemType="CapnpFiles">
|
||||
<NameValuePair Name="DependentExtensions" Value=".capnp.cs" />
|
||||
</ContentType>
|
||||
|
||||
<ItemType Name="CapnpFiles" DisplayName="Cap'n Proto schema file"/>
|
||||
|
||||
<FileExtension Name=".capnp" ContentType="CapnpFile" />
|
||||
|
||||
</ProjectSchemaDefinitions>
|
||||
|
@ -0,0 +1,78 @@
|
||||
<Project TreatAsLocalProperty="TaskFolder;TaskAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<CapnpcCsharp_CpsExtensionDesignTimeTargetsPath Condition="'$(CapnpcCsharp_CpsExtensionDesignTimeTargetsPath)' == ''">$(MSBuildThisFileDirectory)CPS\Buildsystem\CpsExtension.DesignTime.targets</CapnpcCsharp_CpsExtensionDesignTimeTargetsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(CapnpcCsharp_CpsExtensionDesignTimeTargetsPath)" Condition="'$(DesignTimeBuild)' == 'true' " />
|
||||
|
||||
|
||||
<PropertyGroup>
|
||||
<CapnpcCsharp_UseHostCompilerIfAvailable Condition="'$(CapnpcCsharp_UseHostCompilerIfAvailable)'==''">false</CapnpcCsharp_UseHostCompilerIfAvailable>
|
||||
<UseHostCompilerIfAvailable>$(CapnpcCsharp_UseHostCompilerIfAvailable)</UseHostCompilerIfAvailable>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<PropertyGroup>
|
||||
<OverwriteReadOnlyFiles Condition="'$(OverwriteReadOnlyFiles)'==''">false</OverwriteReadOnlyFiles>
|
||||
<ForceGeneration Condition="'$(ForceGeneration)'==''">false</ForceGeneration>
|
||||
|
||||
<ShowTrace Condition="'$(ShowTrace)'==''">false</ShowTrace>
|
||||
<VerboseOutput Condition="'$(VerboseOutput)'==''">true</VerboseOutput>
|
||||
<CapnpcCsharp_DebugMSBuildTask Condition="'$(CapnpcCsharp_DebugMSBuildTask)' == ''">false</CapnpcCsharp_DebugMSBuildTask>
|
||||
|
||||
<_CapnpcCsharpPropsImported Condition="'$(_CapnpcCsharpPropsImported)'==''">true</_CapnpcCsharpPropsImported>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
property group for feature flags
|
||||
-->
|
||||
<PropertyGroup>
|
||||
|
||||
<!--
|
||||
feature flag to enable experimental support for cleaning up generated code-behind files during rebuild and clean scenarios
|
||||
-->
|
||||
<CapnpcCsharp_DeleteCodeBehindFilesOnCleanRebuild Condition="'$(CapnpcCsharp_DeleteCodeBehindFilesOnCleanRebuild)'==''">false</CapnpcCsharp_DeleteCodeBehindFilesOnCleanRebuild>
|
||||
|
||||
<!--
|
||||
net.sdk support: feature flag to enable experimental support for net.sdk project system
|
||||
-->
|
||||
<CapnpcCsharp_EnableDefaultCompileItems Condition="'$(CapnpcCsharp_EnableDefaultCompileItems)'==''">true</CapnpcCsharp_EnableDefaultCompileItems>
|
||||
<CapnpcCsharp_EnableWarnForFeatureCodeBehindFilesWithoutCorrespondingCapnpFile Condition="'$(CapnpcCsharp_EnableWarnForFeatureCodeBehindFilesWithoutCorrespondingCapnpFile)'==''">$(CapnpcCsharp_EnableDefaultCompileItems)</CapnpcCsharp_EnableWarnForFeatureCodeBehindFilesWithoutCorrespondingCapnpFile>
|
||||
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);**/*.capnp</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<CapnpFiles Include="**\*.capnp" >
|
||||
<CodeBehindFile>%(RelativeDir)%(Filename).capnp.cs</CodeBehindFile>
|
||||
<Visible>$(UsingMicrosoftNETSdk)</Visible>
|
||||
<WorkingDirectory>$(ProjectDir)</WorkingDirectory>
|
||||
</CapnpFiles>
|
||||
|
||||
<!-- obsolete codebehind files, scenarios:
|
||||
- after rename operation
|
||||
- after deletion of a feature file
|
||||
- after pulling latest changes from version control with above changes
|
||||
-->
|
||||
<CapnpCsharpObsoleteCodeBehindFiles Include="**\*.capnp.cs" Exclude="@(CapnpFiles->'%(CodeBehindFile)')" />
|
||||
|
||||
<!-- Support for Visual Studio Incremental Build
|
||||
https://github.com/techtalk/SpecFlow/issues/1319
|
||||
-->
|
||||
<UpToDateCheckInput Include="@(CapnpFiles)" />
|
||||
<UpToDateCheckBuild Include="@(CapnpFiles->'%(CodeBehindFile)')" Original="@(CapnpFiles)" />
|
||||
<CustomAdditionalCompileInputs Include="@(CapnpFiles->'%(CodeBehindFile)')" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<PropertyGroup>
|
||||
<_CapnpcCsharp_TaskFolder Condition=" '$(MSBuildRuntimeType)' == 'Core' And '$(_CapnpcCsharp_TaskFolder)' == ''">netcoreapp2.1</_CapnpcCsharp_TaskFolder>
|
||||
<_CapnpcCsharp_TaskFolder Condition=" '$(MSBuildRuntimeType)' != 'Core' And '$(_CapnpcCsharp_TaskFolder)' == ''">net471</_CapnpcCsharp_TaskFolder>
|
||||
<_CapnpcCsharp_TaskAssembly Condition=" '$(_CapnpcCsharp_TaskAssembly)' == '' ">..\tasks\$(_CapnpcCsharp_TaskFolder)\CapnpC.CSharp.MsBuild.Generation.dll</_CapnpcCsharp_TaskAssembly>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="CapnpC.CSharp.MsBuild.Generation.tasks"/>
|
||||
|
||||
</Project>
|
@ -0,0 +1,133 @@
|
||||
<Project>
|
||||
|
||||
<Import Project="CapnpC.CSharp.MsBuild.Generation.props" Condition="'$(_CapnpcCsharpPropsImported)'==''"/>
|
||||
|
||||
<PropertyGroup Condition="'$(BuildServerMode)' == ''">
|
||||
<BuildServerMode Condition="'$(BuildingInsideVisualStudio)'=='true'">false</BuildServerMode>
|
||||
<BuildServerMode Condition="'$(BuildingInsideVisualStudio)'!='true'">true</BuildServerMode>
|
||||
|
||||
<!--
|
||||
net.sdk experimental support:
|
||||
- currently we only want to support either classic project system or netsdk project system.
|
||||
- currently we don't want to support globbing with classic project system => ensure globbing only get enabled with 'UsingMicrosoftNETSdk'
|
||||
- currently we are supporting $(EnableDefaultCompileItems) for disabling globbing support for codebehind files
|
||||
-->
|
||||
<_CapnpcCsharp_EnableDefaultCompileItems Condition="'$(CapnpcCsharp_EnableDefaultCompileItems)' == '' And '$(UsingMicrosoftNETSdk)' == 'true'">true</_CapnpcCsharp_EnableDefaultCompileItems>
|
||||
<_CapnpcCsharp_EnableDefaultCompileItems Condition="'$(CapnpcCsharp_EnableDefaultCompileItems)' == 'true' And '$(UsingMicrosoftNETSdk)' == 'true'">true</_CapnpcCsharp_EnableDefaultCompileItems>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<BuildDependsOn>
|
||||
BeforeUpdateCapnpFilesInProject;
|
||||
UpdateCapnpFilesInProject;
|
||||
IncludeCodeBehindFilesInProject;
|
||||
AfterUpdateCapnpFilesInProject;
|
||||
$(BuildDependsOn)
|
||||
</BuildDependsOn>
|
||||
<CleanDependsOn>
|
||||
CleanCapnpFilesInProject;
|
||||
$(CleanDependsOn)
|
||||
</CleanDependsOn>
|
||||
<RebuildDependsOn>
|
||||
SwitchToForceGenerate;
|
||||
$(RebuildDependsOn)
|
||||
</RebuildDependsOn>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
net.sdk support: update default compile items to show generated files as nested items
|
||||
-->
|
||||
<ItemGroup Condition="'$(_CapnpcCsharp_EnableDefaultCompileItems)' == 'true' and '$(EnableDefaultItems)' == 'true' ">
|
||||
<Compile Update="@(CapnpFiles->'%(CodeBehindFile)')"
|
||||
DependentUpon="%(Filename)"
|
||||
AutoGen="true"
|
||||
DesignTime="true"
|
||||
Visible="true"
|
||||
Condition="'$(EnableDefaultCompileItems)' == 'true'" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<Target Name="WarnForCapnpCsharpCodeBehindFilesWithoutCorrespondingCapnpFile" AfterTargets="CoreCompile"
|
||||
Condition="'$(CapnpcCsharp_EnableWarnForFeatureCodeBehindFilesWithoutCorrespondingCapnpFile)' == 'true'">
|
||||
<Warning Text="For codebehind file '@(CapnpCsharpObsoleteCodeBehindFiles)', no capnp file was found." File="@(CapnpCsharpObsoleteCodeBehindFiles)" Condition="'@(CapnpCsharpObsoleteCodeBehindFiles)' != ''" />
|
||||
</Target>
|
||||
|
||||
|
||||
<Target Name="SwitchToForceGenerate">
|
||||
<PropertyGroup>
|
||||
<ForceGeneration>true</ForceGeneration>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
|
||||
<Target Name="UpdateCapnpFilesInProject"
|
||||
DependsOnTargets="BeforeUpdateCapnpFilesInProject">
|
||||
|
||||
<Message Text="CapnpFiles: @(CapnpFiles)" Importance="high" Condition="'$(VerboseOutput)' == 'true'" />
|
||||
|
||||
<GenerateCapnpFileCodeBehindTask
|
||||
ProjectPath="$(MSBuildProjectFullPath)"
|
||||
CapnpFiles="@(CapnpFiles)" >
|
||||
|
||||
<Output TaskParameter="GeneratedFiles" ItemName="CapnpcCsharpGeneratedFiles" />
|
||||
</GenerateCapnpFileCodeBehindTask>
|
||||
|
||||
<Message Text="CapnpcCsharpGeneratedFiles: %(CapnpcCsharpGeneratedFiles.Identity)" Importance="high" Condition="'$(VerboseOutput)' == 'true'" />
|
||||
|
||||
|
||||
<!--
|
||||
net.sdk support: globbing does not support including files which are dynamically generated inside targets, we have to manually update compile items
|
||||
-->
|
||||
<ItemGroup Condition="'$(_CapnpcCsharp_EnableDefaultCompileItems)' == 'true' and '$(EnableDefaultItems)' == 'true' and '$(EnableDefaultCompileItems)' == 'true'">
|
||||
|
||||
<!-- if this is the first time generation of codebehind files, we have to manually add them as compile items -->
|
||||
<Compile Include="@(CapnpFiles->'%(CodeBehindFile)')"
|
||||
Exclude="@(Compile)"/>
|
||||
|
||||
<!--
|
||||
eather if codebehind files are added manually to compile item group or are added by net.sdk globbing support,
|
||||
ensure they are nested under feature files like in previous specflow versions
|
||||
currently, we cannot use itemgroup update attribute inside a target because of some bugs in MSBuild (all items will be updated)
|
||||
- https://github.com/Microsoft/msbuild/issues/1618
|
||||
- https://github.com/Microsoft/msbuild/issues/2835
|
||||
- https://github.com/Microsoft/msbuild/issues/1124
|
||||
-->
|
||||
<Compile DependentUpon="@(CapnpFiles)"
|
||||
AutoGen="true"
|
||||
DesignTime="true"
|
||||
Visible="true"
|
||||
Condition="'%(Compile.Identity)' == '@(CapnpFiles->'%(CodeBehindFile)')'" />
|
||||
|
||||
<!-- remove files which got obsolete, typically after rename operation, or getting changes from source control -->
|
||||
<Compile Remove="@(CapnpCsharpObsoleteCodeBehindFiles)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Target>
|
||||
|
||||
<Target Name="BeforeUpdateCapnpFilesInProject">
|
||||
|
||||
</Target>
|
||||
|
||||
<Target Name="IncludeCodeBehindFilesInProject" DependsOnTargets="UpdateCapnpFilesInProject">
|
||||
<ItemGroup Condition="'$(UsingMicrosoftNETSdk)' != 'true'">
|
||||
<Compile Include="@(CapnpcCsharpGeneratedFiles)" Exclude="@(Compile)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="AfterUpdateCapnpFilesInProject" DependsOnTargets="IncludeCodeBehindFilesInProject">
|
||||
<!-- include any generated SpecFlow files in the compilation of the project if not included yet -->
|
||||
</Target>
|
||||
|
||||
<Target Name="CleanCapnpFilesInProject" Condition="'$(CapnpcCsharp_DeleteCodeBehindFilesOnCleanRebuild)' == 'true'">
|
||||
<!-- remove known codebehind files for existing capnp files -->
|
||||
<Delete Files="%(CapnpFiles.CodeBehindFile)" ContinueOnError="true" />
|
||||
|
||||
<!-- remove obsolete codebehind files, scenarios:
|
||||
- after rename operation
|
||||
- after deletion of a capnp file
|
||||
- after pulling latest changes from version control with above changes
|
||||
-->
|
||||
<Delete Files="@(CapnpCsharpObsoleteCodeBehindFiles)" ContinueOnError="true" />
|
||||
</Target>
|
||||
</Project>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user