Skip to content

Commit

Permalink
asyncapi#207 generate code from spec: msbuild target file refining (i…
Browse files Browse the repository at this point in the history
…ncremental build should be working now)
  • Loading branch information
Senn Geerts authored and Senn Geerts committed Jul 20, 2024
1 parent b123783 commit 4af2a99
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -598,3 +598,5 @@ fabric.properties

# End of https://www.gitignore.io/api/csharp,jetbrains,visualstudio
/examples/StreetlightsAPI/Properties/launchSettings.json

*g.cs
6 changes: 6 additions & 0 deletions Saunter.sln
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,18 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncAPI.Saunter.Generator.Cli.Tests", "test\AsyncAPI.Saunter.Generator.Cli.Tests\AsyncAPI.Saunter.Generator.Cli.Tests.csproj", "{18AD0249-0436-4A26-9972-B97BA6905A54}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreetlightsAPI.TopLevelStatement", "examples\StreetlightsAPI.TopLevelStatement\StreetlightsAPI.TopLevelStatement.csproj", "{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}"
ProjectSection(ProjectDependencies) = postProject
{A320E670-5CB0-4815-AF67-D8D09FC92A2A} = {A320E670-5CB0-4815-AF67-D8D09FC92A2A}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncAPI.Saunter.Generator.Build", "src\AsyncAPI.Saunter.Generator.Build\AsyncAPI.Saunter.Generator.Build.csproj", "{A320E670-5CB0-4815-AF67-D8D09FC92A2A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncAPI.Saunter.Generator.Build.Tests", "test\AsyncAPI.Saunter.Generator.Build.Tests\AsyncAPI.Saunter.Generator.Build.Tests.csproj", "{61142B10-7B49-436E-AE32-2737658BD1E5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreetlightsAPI.AsyncApiSpecFirst", "examples\StreetlightsAPI.AsyncApiSpecFirst\StreetlightsAPI.AsyncApiSpecFirst.csproj", "{19A30A6D-1E91-44FD-BB5D-428D12D0160D}"
ProjectSection(ProjectDependencies) = postProject
{A320E670-5CB0-4815-AF67-D8D09FC92A2A} = {A320E670-5CB0-4815-AF67-D8D09FC92A2A}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

<ItemGroup>
<!-- Instruct "AsyncAPI.Saunter.Generator.Build" to generate classes for this AsyncAPI specifiction -->
<AsyncAPISpecs Include="specs/streetlights.yml" Namespace="Saunter" />
<AsyncAPISpecs Include="specs/streetlights.yml" OutputPath="generated" Namespace="Saunter" />
<AsyncAPISpecs Include="specs/test.yml" OutputPath="generated2" Namespace="SaunterX" />
</ItemGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
Expand Down Expand Up @@ -45,7 +46,6 @@
</ItemGroup>

<ItemGroup>
<Folder Include="specs\" />

<Compile Include="../StreetlightsAPI/API.cs" />
<Compile Include="../StreetlightsAPI/Messaging.cs" />
Expand All @@ -59,5 +59,9 @@
<PackageReference Include="NLog" Version="5.3.2" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.11" />
</ItemGroup>

<ItemGroup>
<Folder Include="generated\" />
</ItemGroup>

</Project>
94 changes: 94 additions & 0 deletions examples/StreetlightsAPI.AsyncApiSpecFirst/specs/streetlights.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"asyncapi": "2.6.0",
"info": {
"title": "Streetlights API",
"version": "1.0.0",
"description": "The Smartylighting Streetlights API allows you to remotely manage the city lights.",
"license": {
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0"
}
},
"servers": {
"mosquitto": {
"url": "test.mosquitto.org",
"protocol": "mqtt"
},
"webapi": {
"url": "localhost:5000",
"protocol": "http"
}
},
"defaultContentType": "application/json",
"channels": {
"publish/light/measured": {
"servers": [
"webapi"
],
"publish": {
"operationId": "MeasureLight",
"summary": "Inform about environmental lighting conditions for a particular streetlight.",
"tags": [
{
"name": "Light"
}
],
"message": {
"$ref": "#/components/messages/lightMeasuredEvent"
}
}
},
"subscribe/light/measured": {
"servers": [
"mosquitto"
],
"subscribe": {
"operationId": "PublishLightMeasurement",
"summary": "Subscribe to environmental lighting conditions for a particular streetlight.",
"tags": [
{
"name": "Light"
}
],
"message": {
"payload": {
"$ref": "#/components/schemas/lightMeasuredEvent"
}
}
}
}
},
"components": {
"schemas": {
"lightMeasuredEvent": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32",
"description": "Id of the streetlight."
},
"lumens": {
"type": "integer",
"format": "int32",
"description": "Light intensity measured in lumens."
},
"sentAt": {
"type": "string",
"format": "date-time",
"description": "Light intensity measured in lumens."
}
},
"additionalProperties": false
}
},
"messages": {
"lightMeasuredEvent": {
"payload": {
"$ref": "#/components/schemas/lightMeasuredEvent"
},
"name": "lightMeasuredEvent"
}
}
}
}
61 changes: 61 additions & 0 deletions examples/StreetlightsAPI.AsyncApiSpecFirst/specs/streetlights.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
asyncapi: 2.6.0
info:
title: Streetlights API 44
version: 1.0.0
description: The Smartylighting Streetlights API allows you to remotely manage the city lights.
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0
servers:
mosquitto:
url: test.mosquitto.org
protocol: mqtt
webapi:
url: localhost:5000
protocol: http
defaultContentType: application/json
channels:
publish/light/measured:
servers:
- webapi
publish:
operationId: MeasureLight
summary: Inform about environmental lighting conditions for a particular streetlight.
tags:
- name: Light
message:
$ref: '#/components/messages/lightMeasuredEvent'
subscribe/light/measured:
servers:
- mosquitto
subscribe:
operationId: PublishLightMeasurement
summary: Subscribe to environmental lighting conditions for a particular streetlight.
tags:
- name: Light
message:
payload:
$ref: '#/components/schemas/lightMeasuredEvent'
components:
schemas:
lightMeasuredEvent:
type: object
properties:
id:
type: integer
format: int32
description: Id of the streetlight.
lumens:
type: integer
format: int32
description: Light intensity measured in lumens.
sentAt:
type: string
format: date-time
description: Light intensity measured in lumens.
additionalProperties: false
messages:
lightMeasuredEvent:
payload:
$ref: '#/components/schemas/lightMeasuredEvent'
name: lightMeasuredEvent
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
</PropertyGroup>

<ItemGroup>
<AsyncAPISpecs Include="asyncapi.json" />
<AsyncAPIOutput Include="generated/*" />
<!-- Example how to specify .json or .yml AsyncApi spec files -->
<!-- <AsyncAPISpecs Include="asyncapi.json" OutputPath="generated" Namespace="Saunter.Generated" /> -->
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project>
<Project InitialTargets="AsyncAPIInitial" >

<Target Name="AsyncAPIInitial">
<Message Text="===== AsyncAPI 999.$([System.DateTime]::Now.ToString(&quot;yy&quot;))$([System.DateTime]::Now.DayOfYear).$([System.DateTime]::Now.ToString(&quot;HHmm.ss&quot;)) ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI ===== AsyncAPI =====" Importance="High" />
<Message Text="AsyncAPI.Generator.Build; AsyncAPISpecs: @(AsyncAPISpecs->'%(DefiningProjectDirectory)%(Identity)')" Importance="High" />
<Message Text="AsyncAPI.Generator.Build; AsyncAPISpecs.Outputs: @(AsyncAPISpecs->'%(DefiningProjectDirectory)%(OutputPath)/%(Filename).g.cs')" Importance="High" />
</Target>

<Target Name="AsyncAPICommonBuildProperties">
<!-- Calculate some common paths -->
Expand All @@ -14,6 +20,7 @@
<Message Text="AsyncAPI.Generator.Build; AsyncAPIBuildToolRoot: $(AsyncAPIBuildToolRoot)" />
</Target>

<!-- AsyncAPIGenerateDocumentsOnBuild: Generate .json/.yml spec at build time from code-first attributes -->
<Target Name="PostBuild" AfterTargets="PostBuildEvent" DependsOnTargets="AsyncAPICommonBuildProperties"
Condition=" '$(AsyncAPIGenerateDocumentsOnBuild)' == 'true' ">
<PropertyGroup>
Expand All @@ -39,16 +46,13 @@
WorkingDirectory="$(AsyncAPIBuildToolRoot)" />
</Target>

<ItemGroup Condition=" '$(AsyncAPIOutput)' == '' ">
<AsyncAPIOutput Include="g" />
</ItemGroup>

<!-- AsyncAPISpecs: Generate dataclasses from .json/.yml AsyncAPI spec files -->
<Target Name="GenerateCodeForAsyncAPI" BeforeTargets="BeforeBuild" DependsOnTargets="AsyncAPICommonBuildProperties"
Inputs="@(AsyncAPISpecs)" Outputs="@(AsyncAPIOutput)">
Inputs="@(AsyncAPISpecs)" Outputs="@(AsyncAPISpecs->'%(DefiningProjectDirectory)%(OutputPath)/%(Filename).g.cs')">
<!-- https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-well-known-item-metadata -->
<Message Text="Generate: --specs @(AsyncAPISpecs->'&quot;%(Namespace),%(Identity)&quot;', ' ')" />
<Message Text="Generate: --specs @(AsyncAPISpecs->'&quot;%(Namespace),%(OutputPath),%(Identity)&quot;', ' ')" Importance="High" />

<Exec Command="dotnet &quot;$(AsyncAPICliToolPath)&quot; fromspec --specs @(AsyncAPISpecs->'&quot;%(Namespace),%(Identity)&quot;', ' ')"
<Exec Command="dotnet &quot;$(AsyncAPICliToolPath)&quot; fromspec --specs @(AsyncAPISpecs->'&quot;%(Namespace),%(DefiningProjectDirectory)%(OutputPath),%(DefiningProjectDirectory)%(Identity)&quot;', ' ')"
WorkingDirectory="$(AsyncAPIBuildToolRoot)" />
</Target>

Expand Down
26 changes: 23 additions & 3 deletions src/AsyncAPI.Saunter.Generator.Cli/FromSpec/FromSpecCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,38 @@
using LEGO.AsyncAPI.Models;
using Microsoft.Extensions.Logging;

namespace AsyncAPI.Saunter.Generator.Cli.FromSpecCommand;
namespace AsyncAPI.Saunter.Generator.Cli.FromSpec;

internal class FromSpecCommand(ILogger<FromSpecCommand> logger)
{
/// <summary>
/// Retrieves AsyncAPI spec from a startup assembly and writes to file.
/// </summary>
/// <param name="specs">The AsyncAPI specification to generate code for. Parameter should include the namespace: namespace,asyncapi.json</param>
/// <param name="specs">the AsyncAPI specification to generate code for. Parameter should include the namespace: namespace,outputPath,asyncapi.json</param>
[Command("fromspec")]
public int FromSpec(params string[] specs)
{
logger.LogInformation($"FromSpec(#{specs.Length}): {string.Join(';', specs)}");
logger.LogInformation($"FromSpec(#{specs.Length}): --specs {string.Join(';', specs)}");

foreach (var (namespaceName, output, specName) in Split(specs))
{
Directory.CreateDirectory(output);
var outputFile = Path.Combine(output, $"{Path.GetFileNameWithoutExtension(specName)}.g.cs");
File.Create(outputFile);
logger.LogInformation($"Created {Path.GetFullPath(outputFile)}");
}
return 0;
}

private static IEnumerable<(string namespaceName, string output, string specName)> Split(IEnumerable<string> input)
{
foreach (var spec in input)
{
var split = spec.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList();
if (split.Count == 3 && !split.Any(string.IsNullOrWhiteSpace))
{
yield return (split[0], split[1], split[2]);
}
}
}
}
2 changes: 1 addition & 1 deletion src/AsyncAPI.Saunter.Generator.Cli/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using AsyncAPI.Saunter.Generator.Cli.FromSpecCommand;
using AsyncAPI.Saunter.Generator.Cli.FromSpec;
using AsyncAPI.Saunter.Generator.Cli.ToFile;
using ConsoleAppFramework;
using Microsoft.Extensions.DependencyInjection;
Expand Down
2 changes: 1 addition & 1 deletion src/Common.NugetPackage.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<!-- 999.* are local builds numbers, they must be unique each build to bypass all nuget caching -->
<Version>999.$([System.DateTime]::Now.ToString("yy"))$([System.DateTime]::Now.DayOfYear).$([System.DateTime]::Now.ToString("HHmm"))</Version>
<Version>999.$([System.DateTime]::Now.ToString("yy"))$([System.DateTime]::Now.DayOfYear).$([System.DateTime]::Now.ToString("HHmm.ss"))</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageOutputPath>../../local-nuget-source</PackageOutputPath>
</PropertyGroup>
Expand Down

0 comments on commit 4af2a99

Please sign in to comment.