Skip to content

Commit

Permalink
rework sdk integration (#98)
Browse files Browse the repository at this point in the history
* rework sdk integration

- remove unused props
- allow multiple proto
- generated .fs files, by default, are alongside the .proto files
- use `OutputPath` metadata of `ProtoFile` item to specify generated .fs file path
- compile files are included at beginning of the compile list (allow use in console app)
- not yet implemented the clean process

add integration tests:

- custom namespace
- no generation on build if proto is unchanged
- the .fs file is regenerated on build if proto file is changed
  • Loading branch information
enricosada authored and Dave Thomas committed Jan 2, 2019
1 parent 267e7c5 commit 9584bfe
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 104 deletions.
99 changes: 35 additions & 64 deletions Falanx.Sdk/build/Falanx.Sdk.targets
Original file line number Diff line number Diff line change
@@ -1,114 +1,85 @@
<Project TreatAsLocalProperty="
FalanxSdk_CodeGenDirectory;
FalanxSdk_CodeGeneratorEnabled;
FalanxSdk_DotNetHost;
FalanxSdk_MSBuildIsCore;
FalanxSdk_OutputFileName;
FalanxSdk_InputFileName;
FalanxSdk_TargetIsCore;
FalanxSdk_TaskAssembly;
FalanxSdk_CodeGeneratorTargetFramework;">
<Project>

<PropertyGroup>
<FalanxSdk_CodeGeneratorTargetFramework>netcoreapp2.0</FalanxSdk_CodeGeneratorTargetFramework>
<FalanxSdk_DotNetHost>dotnet</FalanxSdk_DotNetHost>

<!-- Specify the assembly containing the MSBuild tasks. -->
<FalanxSdk_MSBuildIsCore Condition="'$(MSBuildRuntimeType)' == 'Core' or '$(OS)' != 'Windows_NT'">true</FalanxSdk_MSBuildIsCore>
<FalanxSdk_TaskAssembly Condition="'$(FalanxSdkCodeGenTasksAssembly)' != ''">$(FalanxSdkCodeGenTasksAssembly)</FalanxSdk_TaskAssembly>
<FalanxSdk_TaskAssembly Condition="'$(FalanxSdk_TaskAssembly)' == '' and '$(FalanxSdk_MSBuildIsCore)' == 'true'">$(MSBuildThisFileDirectory)..\tasks\$(FalanxSdk_CodeGeneratorTargetFramework)\FalanxSdk.CodeGenerator.MSBuild.Tasks.dll</FalanxSdk_TaskAssembly>

<!-- When the MSBuild host is full-framework, we defer to PATH for dotnet -->
<FalanxSdk_DotNetHost Condition="'$(FalanxSdk_MSBuildIsCore)' != 'true'">dotnet</FalanxSdk_DotNetHost>
<FalanxSdk_DotNetHost Condition="'$(DotNetHost)' != ''">$(DotNetHost)</FalanxSdk_DotNetHost>
</PropertyGroup>

<PropertyGroup>
<FalanxSdkCodeGenLogLevel Condition="'$(FalanxSdkCodeGenLogLevel)' == ''">Warning</FalanxSdkCodeGenLogLevel>
<FalanxSdk_CodeGenDirectory Condition="'$([System.IO.Path]::IsPathRooted($(IntermediateOutputPath)))' == 'true'">$(IntermediateOutputPath)</FalanxSdk_CodeGenDirectory>
<FalanxSdk_CodeGenDirectory Condition="'$(FalanxSdk_CodeGenDirectory)' == ''">$(ProjectDir)$(IntermediateOutputPath)</FalanxSdk_CodeGenDirectory>
<FalanxSdk_OutputFileName>$(FalanxSdk_CodeGenDirectory)$(TargetName).FalanxSdk.g.fs</FalanxSdk_OutputFileName>
<FalanxSdk_CodeGeneratorEnabled Condition=" '$(DesignTimeBuild)' != 'true'">true</FalanxSdk_CodeGeneratorEnabled>
<FalanxSdkGenerateCodeDependsOn>$(FalanxSdkGenerateCodeDependsOn);ResolveReferences;FalanxSdkGenerateInputCache</FalanxSdkGenerateCodeDependsOn>
<FalanxSdk_InputFileName>@(ProtoFile -> '%(FullPath)')</FalanxSdk_InputFileName>
</PropertyGroup>

<!--
Input to the code generator should not include its output.
-->
<ItemGroup>
<FalanxSdk_CodeGenInputs Include="$(FalanxSdk_InputFileName);@(ReferencePath)" />
<FalanxSdk_CodeGenInputs Remove="$(FalanxSdk_OutputFileName)" />
</ItemGroup>

<!-- Properties used to support correct, incremental builds. -->
<PropertyGroup>
<Target Name="_FalanxSdkProtoFilesList"
BeforeTargets="FalanxSdkGenerateInputCache">
<ItemGroup>
<ProtoFileCodegen Include="%(ProtoFile.FullPath)">
<OutputPath Condition=" '%(ProtoFile.OutputPath)' != '' ">$([System.IO.Path]::GetFullPath('%(ProtoFile.OutputPath)')</OutputPath>
<OutputPath Condition=" '%(ProtoFile.OutputPath)' == '' ">%(ProtoFile.FullPath).fs</OutputPath>
</ProtoFileCodegen>
</ItemGroup>
<!--
Since the FalanxSdk code generator also affects the state of @(Compile) and hence the compile inputs file,
we maintain a separate cache with FalanxSdk' own files removed. Otherwise there would be a circular dependency
whereby the cache updates and triggers the code generator, which triggers a cache update.
-->
<FalanxSdk_CodeGenInputCache>$(IntermediateOutputPath)$(MSBuildProjectFile).FalanxSdkCodeGenInputs.cache</FalanxSdk_CodeGenInputCache>
</PropertyGroup>
<PropertyGroup>
<_FalanxSdkCodeGenInputCache>$(IntermediateOutputPath)$(MSBuildProjectFile).FalanxSdkCodeGenInputs.cache</_FalanxSdkCodeGenInputCache>
</PropertyGroup>
</Target>

<!--
Update the file which captures the total set of all inputs to the code generator.
This is based on the _GenerateCompileDependencyCache target from the .NET project system.
-->
<Target Name="FalanxSdkGenerateInputCache"
DependsOnTargets="ResolveAssemblyReferences"
DependsOnTargets="ResolveAssemblyReferences;_FalanxSdkProtoFilesList"
BeforeTargets="FalanxSdkGenerateCode">

<ItemGroup>
<FalanxSdk_CodeGenInputs Include="@(ProtoFileCodegen);@(ReferencePath)" />
</ItemGroup>

<Hash ItemsToHash="@(FalanxSdk_CodeGenInputs)">
<Output TaskParameter="HashResult" PropertyName="FalanxSdk_UpdatedInputCacheContents" />
</Hash>

<WriteLinesToFile
Overwrite="true"
File="$(FalanxSdk_CodeGenInputCache)"
File="$(_FalanxSdkCodeGenInputCache)"
Lines="$(FalanxSdk_UpdatedInputCacheContents)"
WriteOnlyWhenDifferent="True" />

<ItemGroup>
<FileWrites Include="$(FalanxSdk_CodeGenInputCache)" />
</ItemGroup>

</Target>

<PropertyGroup>
<FalanxSdkGenerateCodeDependsOn>$(FalanxSdkGenerateCodeDependsOn);ResolveReferences;FalanxSdkGenerateInputCache</FalanxSdkGenerateCodeDependsOn>
</PropertyGroup>

<Target Name="FalanxSdkGenerateCode"
DependsOnTargets="$(FalanxSdkGenerateCodeDependsOn)"
AfterTargets="FalanxSdkGenerateInputCache"
BeforeTargets="CoreCompile"
Condition="'$(FalanxSdk_CodeGeneratorEnabled)' == 'true'"
Inputs="@(FalanxSdk_CodeGenInputs);$(FalanxSdk_CodeGenInputCache)"
Outputs="$(FalanxSdk_OutputFileName)">
Condition=" '$(DesignTimeBuild)' != 'true' "
Inputs="@(ProtoFileCodegen);$(_FalanxSdkCodeGenInputCache)"
Outputs="%(ProtoFileCodegen.OutputPath)">

<PropertyGroup>
<_FalanxSdk_InputFileName>$(FalanxSdk_InputFileName)</_FalanxSdk_InputFileName>
<_FalanxSdk_InputFileName>%(ProtoFileCodegen.Identity)</_FalanxSdk_InputFileName>
<_FalanxSdk_OutputFileName>%(ProtoFileCodegen.OutputPath)</_FalanxSdk_OutputFileName>
</PropertyGroup>

<ItemGroup>
<FalanxSdk_CodeGenArgs Include='--inputfile "$(_FalanxSdk_InputFileName)"' />
<FalanxSdk_CodeGenArgs Include='--outputfile "$(FalanxSdk_OutputFileName)"' />
<FalanxSdk_CodeGenArgs Include='--outputfile "$(_FalanxSdk_OutputFileName)"' />
<FalanxSdk_CodeGenArgs Include='--defaultnamespace "$(RootNamespace)"' />
<FalanxSdk_CodeGenArgs Include='--serializer %(FalanxSdkSerializer.Identity)' />
</ItemGroup>

<!-- Use dotnet to execute the process. -->
<Exec Command="$(FalanxSdk_GeneratorExeHost)&quot;$(FalanxSdk_GeneratorExe)&quot; @(FalanxSdk_CodeGenArgs -> '%(Identity)', ' ')" Outputs="$(FalanxSdk_OutputFileName)" />
<Exec Command="$(FalanxSdk_GeneratorExeHost)&quot;$(FalanxSdk_GeneratorExe)&quot; @(FalanxSdk_CodeGenArgs -> '%(Identity)', ' ')" />

<ItemGroup>
<Compile Include="$(FalanxSdk_OutputFileName)" Condition="Exists('$(FalanxSdk_OutputFileName)')" />
<FileWrites Include="$(FalanxSdk_OutputFileName)" Condition="Exists('$(FalanxSdk_OutputFileName)')"/>
<CompileBefore Include="$(_FalanxSdk_OutputFileName)" Condition="Exists('$(_FalanxSdk_OutputFileName)')" />
</ItemGroup>
</Target>

<Target Name="FalanxSdkIncludeCodegenOutputDuringDesignTimeBuild"
BeforeTargets="CoreCompile"
Condition="'$(FalanxSdk_CodeGeneratorEnabled)' != 'true' and Exists('$(FalanxSdk_OutputFileName)')">
Condition=" '$(DesignTimeBuild)' == 'true' ">
<ItemGroup>
<Compile Include="$(FalanxSdk_OutputFileName)"/>
<FileWrites Include="$(FalanxSdk_OutputFileName)"/>
<Compile Include="%(ProtoFileCodegen.OutputPath)" />
</ItemGroup>
</Target>

</Project>
2 changes: 1 addition & 1 deletion paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ nuget Expecto ~> 8.4
nuget Expecto.TestResults ~> 8.4
nuget MedallionShell ~> 1.5

github enricosada/dotnet-proj-info test/dotnet-proj-info.Tests/FileUtils.fs
github enricosada/dotnet-proj-info test/dotnet-proj.Tests/FileUtils.fs

group MergeNupkgTool
source https://www.nuget.org/api/v2
Expand Down
2 changes: 1 addition & 1 deletion paket.lock
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ NUGET
System.Runtime.Handles (>= 4.3)
GITHUB
remote: enricosada/dotnet-proj-info
test/dotnet-proj-info.Tests/FileUtils.fs (b691ffbd58b6b418e0afff5f3e5ddc3d6647f636)
test/dotnet-proj.Tests/FileUtils.fs (b80e8c411169387ff92a3ce0e5b2b5fbd04e47e7)
GROUP MergeNupkgTool
STORAGE: NONE
RESTRICTION: || (== netcoreapp2.0) (== netstandard2.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\paket-files\integrationtests\enricosada\dotnet-proj-info\test\dotnet-proj-info.Tests\FileUtils.fs">
<Compile Include="..\..\paket-files\integrationtests\enricosada\dotnet-proj-info\test\dotnet-proj.Tests\FileUtils.fs">
<Paket>True</Paket>
<Link>paket-files/FileUtils.fs</Link>
</Compile>
Expand Down
150 changes: 133 additions & 17 deletions test/Falanx.IntegrationTests/Sample.fs
Original file line number Diff line number Diff line change
Expand Up @@ -249,62 +249,87 @@ let tests pkgUnderTestVersion =

let sdkIntegrationMocks =

let dotnetBuildWithFalanxArgsMock (fs: FileUtils) testDir projPath =
let replaceRealFalanxEnvVar realPath mockFilename =
let replaceText f path =
let content = File.ReadAllText(path)
let newContent = f content
File.WriteAllText(path, newContent)

(sprintf "%s.bat" mockFilename)
|> replaceText (fun text -> text.Replace("%REAL_FALANX%", realPath))

mockFilename
|> replaceText (fun text -> text.Replace("$REAL_FALANX", realPath))

let dotnetBuildWithFalanxArgsMockAndArgs (fs: FileUtils) testDir args projPath =

fs.mkdir_p (testDir/"mocktool")
copyDirFromAssets fs ``mock write args``.ProjDir (testDir/"mocktool")
let falanxMock = testDir/"mocktool"/``mock write args``.FileName
let falanxMockArgsPath = testDir/"mocktool"/"falanx-args.txt"

fs.cd testDir
falanxMock |> replaceRealFalanxEnvVar (TestRunDirToolDir/"bin"/"falanx")

fs.rm_rf falanxMockArgsPath

dotnet fs ["build"; projPath; sprintf "/p:FalanxSdk_GeneratorExe=%s" falanxMock; "/p:FalanxSdk_GeneratorExeHost=" ]
|> ignore
fs.cd testDir

Expect.isTrue (File.Exists falanxMockArgsPath) "mock should create a file who contains the args of invocation"
let cmd = dotnet fs (["build"; projPath; sprintf "/p:FalanxSdk_GeneratorExe=%s" falanxMock; "/p:FalanxSdk_GeneratorExeHost=" ] @ args)

let lines =
File.ReadLines falanxMockArgsPath
|> List.ofSeq
if File.Exists falanxMockArgsPath then
File.ReadLines falanxMockArgsPath
|> List.ofSeq
else
[]

cmd, lines

lines
let dotnetBuildWithFalanxArgsMock fs testDir projPath =
dotnetBuildWithFalanxArgsMockAndArgs fs testDir [] projPath

testList "sdk integration" [

testCase |> withLog "check invocation binary" (fun _ fs ->
let testDir = inDir fs "sdkint_invocation_binary"
copyDirFromAssets fs ``template1 binary``.ProjDir testDir

testDir
|> copyExampleWithTemplate fs ``template1 binary`` ``sample6 bundle``

let projPath = testDir/ (``template1 binary``.ProjectFile)

let lines = dotnetBuildWithFalanxArgsMock fs testDir projPath
let cmd, lines = dotnetBuildWithFalanxArgsMock fs testDir projPath

let expected =
[ "--inputfile"
(testDir/``template1 binary``.ProtoFile)
"--outputfile"
(testDir/"l1.Contracts"/"obj"/"Debug"/"netstandard2.0"/"l1.Contracts.FalanxSdk.g.fs")
sprintf "%s.fs" (testDir/``template1 binary``.ProtoFile)
"--defaultnamespace"
"l1.Contracts"
"--serializer"
"binary" ]

Expect.equal lines expected "check invocation args"

cmd |> checkExitCodeZero
)

testCase |> withLog "check invocation json" (fun _ fs ->
let testDir = inDir fs "sdkint_invocation_json"
copyDirFromAssets fs ``template2 json``.ProjDir testDir

testDir
|> copyExampleWithTemplate fs ``template2 json`` ``sample6 bundle``

let projPath = testDir/ (``template2 json``.ProjectFile)

let lines = dotnetBuildWithFalanxArgsMock fs testDir projPath
let _, lines = dotnetBuildWithFalanxArgsMock fs testDir projPath

let expected =
[ "--inputfile"
(testDir/``template2 json``.ProtoFile)
"--outputfile"
(testDir/"l1.Contracts"/"obj"/"Debug"/"netstandard2.0"/"l1.Contracts.FalanxSdk.g.fs")
sprintf "%s.fs" (testDir/``template2 json``.ProtoFile)
"--defaultnamespace"
"l1.Contracts"
"--serializer"
Expand All @@ -315,17 +340,19 @@ let tests pkgUnderTestVersion =

testCase |> withLog "check invocation binary+json" (fun _ fs ->
let testDir = inDir fs "sdkint_invocation_binaryjson"
copyDirFromAssets fs ``template3 binary+json``.ProjDir testDir

testDir
|> copyExampleWithTemplate fs ``template3 binary+json`` ``sample6 bundle``

let projPath = testDir/ (``template3 binary+json``.ProjectFile)

let lines = dotnetBuildWithFalanxArgsMock fs testDir projPath
let _, lines = dotnetBuildWithFalanxArgsMock fs testDir projPath

let expected =
[ "--inputfile"
(testDir/``template3 binary+json``.ProtoFile)
"--outputfile"
(testDir/"l1.Contracts"/"obj"/"Debug"/"netstandard2.0"/"l1.Contracts.FalanxSdk.g.fs")
sprintf "%s.fs" (testDir/``template3 binary+json``.ProtoFile)
"--defaultnamespace"
"l1.Contracts"
"--serializer"
Expand All @@ -336,6 +363,95 @@ let tests pkgUnderTestVersion =
Expect.equal lines expected "check invocation args"
)

testCase |> withLog "check custom namespace" (fun _ fs ->
let testDir = inDir fs "sdkint_custom_namespace"

testDir
|> copyExampleWithTemplate fs ``template1 binary`` ``sample6 bundle``

let projPath = testDir/ (``template1 binary``.ProjectFile)

let ns = "abcd"

let _, lines = dotnetBuildWithFalanxArgsMockAndArgs fs testDir [sprintf "/p:RootNamespace=%s" ns] projPath

let expected =
[ "--inputfile"
(testDir/``template1 binary``.ProtoFile)
"--outputfile"
sprintf "%s.fs" (testDir/``template1 binary``.ProtoFile)
"--defaultnamespace"
ns
"--serializer"
"binary" ]

Expect.equal lines expected "check custom namespace"
)

testCase |> withLog "check no double generation" (fun _ fs ->
let testDir = inDir fs "sdkint_no_regen"

testDir
|> copyExampleWithTemplate fs ``template1 binary`` ``sample6 bundle``

let projPath = testDir/ (``template1 binary``.ProjectFile)

let cmd, lines = dotnetBuildWithFalanxArgsMock fs testDir projPath

let expected =
[ "--inputfile"
(testDir/``template1 binary``.ProtoFile)
"--outputfile"
sprintf "%s.fs" (testDir/``template1 binary``.ProtoFile)
"--defaultnamespace"
"l1.Contracts"
"--serializer"
"binary" ]

Expect.equal lines expected "check invocation args"

cmd |> checkExitCodeZero

let cmd, lines = dotnetBuildWithFalanxArgsMock fs testDir projPath

Expect.equal lines [] "check is not invoked the second time"

cmd |> checkExitCodeZero
)

testCase |> withLog "check regen if proto file is changed" (fun _ fs ->
let testDir = inDir fs "sdkint_proto_changed"

testDir
|> copyExampleWithTemplate fs ``template1 binary`` ``sample6 bundle``

let projPath = testDir/ (``template1 binary``.ProjectFile)

let cmd, lines = dotnetBuildWithFalanxArgsMock fs testDir projPath

let expected =
[ "--inputfile"
(testDir/``template1 binary``.ProtoFile)
"--outputfile"
sprintf "%s.fs" (testDir/``template1 binary``.ProtoFile)
"--defaultnamespace"
"l1.Contracts"
"--serializer"
"binary" ]

Expect.equal lines expected "check invocation args"

cmd |> checkExitCodeZero

fs.touch (testDir/``template1 binary``.ProtoFile)

let cmd, lines = dotnetBuildWithFalanxArgsMock fs testDir projPath

Expect.equal lines expected "check is invoked the second time"

cmd |> checkExitCodeZero
)

]

let interop =
Expand Down
Loading

0 comments on commit 9584bfe

Please sign in to comment.