Skip to content

Commit 9e86356

Browse files
committed
Console. Framework selection algoritm has changed
1 parent 6593e00 commit 9e86356

File tree

4 files changed

+495
-41
lines changed

4 files changed

+495
-41
lines changed

src/ApiCodeGenerator.MSBuild/ApiCodeGenerator.MSBuild.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<TargetFrameworks>net9.0;net8.0;netstandard2.0</TargetFrameworks>
44
<IsPackable>true</IsPackable>
55
<Nullable>enable</Nullable>
6+
<InvariantGlobalization>true</InvariantGlobalization>
67
<!--Параметры пакета в Directory.Build.targets-->
78
</PropertyGroup>
89

@@ -34,6 +35,10 @@
3435
<ProjectReference Include="..\ApiCodeGenerator.AsyncApi\ApiCodeGenerator.AsyncApi.csproj" ReferenceOutputAssembly="false" />
3536
</ItemGroup>
3637

38+
<ItemGroup Label="Nswag prerequiries">
39+
<PackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="9.0.0" />
40+
</ItemGroup>
41+
3742
<Import Project="./ApiCodeGenerator.MSBuild.Console.targets" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
3843
<Import Project="./ApiCodeGenerator.MSBuild.Task.targets" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
3944

src/ApiCodeGenerator.MSBuild/Console/GenerateCommand.cs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ private IGenerationTaskFactory GetGenerationTaskFactory(string? nswagToolsPath)
7777
AssemblyResolver.Register(context);
7878

7979
var thisAssemblyPath = GetThisAssemblyPath();
80-
AssemblyResolver.AddProbingPath(SelectToolsFrameworkFolder(nswagToolsPath ?? Path.Combine(thisAssemblyPath, NswagToolsDirName)));
80+
AssemblyResolver.AddProbingPath(nswagToolsPath ?? Path.Combine(thisAssemblyPath, NswagToolsDirName));
8181
AssemblyResolver.AddProbingPath(thisAssemblyPath);
8282

8383
var coreAsm = context.LoadFromAssemblyName(new AssemblyName("ApiCodeGenerator.Core"));
@@ -103,24 +103,5 @@ private static string GetThisAssemblyPath()
103103
var thisAsmPath = Assembly.GetExecutingAssembly().Location;
104104
return Path.GetDirectoryName(thisAsmPath)!;
105105
}
106-
107-
private static string[] SelectToolsFrameworkFolder(string path)
108-
{
109-
// Для NET >= 6 добавляем в список источников папку с фрейворком AspNetCore
110-
var aspVersion = $"{Environment.Version.Major}.{Environment.Version.Minor}.*";
111-
return new[]
112-
{
113-
path,
114-
GetAspSharedFrameworkFolder(aspVersion),
115-
};
116-
117-
static string GetAspSharedFrameworkFolder(string version)
118-
{
119-
var asm = Assembly.Load("System.Threading");
120-
var shared = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(asm.Location)))!;
121-
var asp = Path.Combine(shared, "Microsoft.AspNetCore.App");
122-
return Directory.GetDirectories(asp, version).OrderBy(_ => _).Last();
123-
}
124-
}
125106
}
126107
}

src/ApiCodeGenerator.MSBuild/build/Console.targets

Lines changed: 142 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,117 @@
11
<Project>
2+
3+
<UsingTask TaskName="AcgGetTools"
4+
TaskFactory="RoslynCodeTaskFactory"
5+
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
6+
<ParameterGroup>
7+
<NetRuntimes ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
8+
<AcgRuntimes ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
9+
<NswagRuntimes ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
10+
<AcgToolDir ParameterType="Microsoft.Build.Framework.ITaskItem" Output="true" />
11+
<AcgNswagToolDir ParameterType="Microsoft.Build.Framework.ITaskItem" Output="true" />
12+
</ParameterGroup>
13+
<Task>
14+
<Using Namespace="System" />
15+
<Using Namespace="System.Linq" />
16+
<Code Type="Fragment" Language="cs">
17+
<!-- For develop and testing code, use test\ApiCodeGenerator.Core.Tests\MSBuild\SelectGeneratorRuntimeTaskTest.cs -->
18+
<![CDATA[var netRuntimeRegex = new System.Text.RegularExpressions.Regex(@"^Microsoft\.NETCore\.App\s(\S+)\s\[[^\]]+\]$");
19+
Func<string, int> parseMajorVersion = delegate (string versionString)
20+
{
21+
Exception innerEx = null;
22+
try
23+
{
24+
if (char.IsDigit(versionString.FirstOrDefault()))
25+
{
26+
return int.Parse(versionString.Substring(0, versionString.IndexOf('.')));
27+
}
28+
29+
if (versionString.StartsWith("net"))
30+
{
31+
var pos = versionString.IndexOf('.');
32+
if (pos > 3)
33+
{
34+
return int.Parse(versionString.Substring(3, pos - 3));
35+
}
36+
}
37+
else if (versionString.StartsWith("Net"))
38+
{
39+
return int.Parse(versionString.Substring(3)) / 10;
40+
}
41+
}
42+
catch (FormatException ex)
43+
{
44+
innerEx = ex;
45+
}
46+
47+
throw new FormatException("Unknown version format: '" + versionString + "'.", innerEx);
48+
};
49+
50+
Func<string, int> parseNetRuntimeMajorVersion = delegate (string versionString)
51+
{
52+
var match = netRuntimeRegex.Match(versionString);
53+
if (match.Success)
54+
{
55+
return parseMajorVersion(match.Groups[1].Value);
56+
}
57+
58+
throw new FormatException(
59+
string.Format(
60+
"Invalid .NET runtime data format: '{0}'. Expected: 'Microsoft.NETCore.App 8.0.8 [/usr/share/dotnet/shared/Microsoft.NETCore.App]'",
61+
versionString));
62+
};
63+
64+
try
65+
{
66+
var runtimes = NetRuntimes
67+
.Select(r => parseNetRuntimeMajorVersion(r.ItemSpec))
68+
.OrderByDescending(v => v)
69+
.ToArray();
70+
71+
var map = AcgRuntimes
72+
.Join(
73+
NswagRuntimes,
74+
l => parseMajorVersion(l.ItemSpec),
75+
r => parseMajorVersion(r.ItemSpec),
76+
(l, r) =>
77+
{
78+
var v = parseMajorVersion(l.ItemSpec);
79+
return new
80+
{
81+
Version = v,
82+
Acg = l,
83+
Nswag = r,
84+
Net = runtimes.Contains(v) ? v : runtimes.FirstOrDefault(r => r > v),
85+
};
86+
})
87+
.OrderByDescending(i => i.Version);
88+
89+
var selected =
90+
map.FirstOrDefault(i => i.Version == i.Net)
91+
?? map.FirstOrDefault(i => i.Version < i.Net);
92+
93+
if (selected != null)
94+
{
95+
AcgToolDir = selected.Acg;
96+
AcgNswagToolDir = selected.Nswag;
97+
98+
return true;
99+
}
100+
101+
AcgToolDir = null;
102+
AcgNswagToolDir = null;
103+
Log.LogErrorFromException(new Exception("No compatible runtime version found."), false, false, null);
104+
return false;
105+
}
106+
catch (FormatException ex)
107+
{
108+
Log.LogErrorFromException(ex, false, false, null);
109+
Success = false;
110+
}]]>
111+
</Code>
112+
</Task>
113+
</UsingTask>
114+
2115
<!-- Запрашиваем список установленных сред выполнения .NET и выбираем поддерживаемую -->
3116
<Target Name="SelectGeneratorRuntime"
4117
BeforeTargets="_GetMetadataForOpenApiReferences">
@@ -11,28 +124,35 @@
11124
</Exec>
12125

13126
<ItemGroup>
14-
<_AcgDotnetRuntimes>
15-
<!-- ищем установленный рантайм приложений заменяя его префикс и берем первые 6 символов
16-
чтоб получить например net6.0 -->
17-
<Folder>$([System.String]::Copy('%(Identity)').Replace('Microsoft.NETCore.App ','net').Substring(0,6))</Folder>
18-
<NswagFolder>$([System.String]::Copy('%(Identity)').Replace('Microsoft.NETCore.App ', 'Net').Substring(0,6).Replace('.', ''))</NswagFolder>
19-
</_AcgDotnetRuntimes>
20-
<ttt Include="@(_AcgDotnetRuntimes)">
21-
<t>$(__AcgToolsDir)%(_AcgDotnetRuntimes.Folder)</t>
22-
</ttt>
23-
<_AcgTools Include="$(__AcgToolsDir)%(_AcgDotnetRuntimes.Folder)"
24-
Condition="Exists('$(__AcgToolsDir)%(_AcgDotnetRuntimes.Folder)') AND Exists('$(NSwagDir)../%(_AcgDotnetRuntimes.NswagFolder)')">
25-
<NswagToolDir>$(NSwagDir)../%(_AcgDotnetRuntimes.NswagFolder)</NswagToolDir>
26-
</_AcgTools>
27-
<!-- проставляем на все ссылки пути к инструментам -->
127+
<_AcgDotnetRuntimes Remove="@(_AcgDotnetRuntimes)" Condition="!$([System.String]::new('%(Identity)').StartsWith('Microsoft.NETCore.App '))" />
128+
129+
<_AcgRuntimes Include="$(__AcgToolsDir)**\ApiCodeGenerator.MSBuild.exe" />
130+
<_AcgRuntimes Include="$([System.IO.Path]::GetFileName($([System.IO.Path]::GetDirectoryName(%(_AcgRuntimes.Identity)))))">
131+
<Path>$([System.IO.Path]::GetDirectoryName(%(_AcgRuntimes.Identity)))</Path>
132+
</_AcgRuntimes>
133+
<_AcgRuntimes Remove="$(__AcgToolsDir)**\ApiCodeGenerator.MSBuild.exe" />
134+
135+
<_AcgNswagRuntimes Include="$(NSwagDir)../**/dotnet-nswag.exe" />
136+
<_AcgNswagRuntimes Include="$([System.IO.Path]::GetFileName($([System.IO.Path]::GetDirectoryName(%(_AcgNswagRuntimes.Identity)))))">
137+
<Path>$([System.IO.Path]::GetDirectoryName(%(_AcgNswagRuntimes.Identity)))</Path>
138+
</_AcgNswagRuntimes>
139+
<_AcgNswagRuntimes Remove="$(NSwagDir)../**/dotnet-nswag.exe" />
140+
</ItemGroup>
141+
142+
<AcgGetTools NetRuntimes="@(_AcgDotnetRuntimes)" AcgRuntimes="@(_AcgRuntimes)" NswagRuntimes="@(_AcgNswagRuntimes)">
143+
<Output TaskParameter="AcgToolDir" ItemName="_AcgTargetToolDir" />
144+
<Output TaskParameter="AcgNswagToolDir" ItemName="_AcgTargetNswagToolDir" />
145+
</AcgGetTools>
146+
147+
<ItemGroup>
148+
<!-- проставляем на все ссылки пути к инструментам. Установка сразу двух не срабатывает -->
28149
<OpenApiReference>
29-
<AcgToolDir>%(_AcgTools.Identity)</AcgToolDir>
30-
<AcgNswagToolDir>%(_AcgTools.NswagToolDir)</AcgNswagToolDir>
150+
<AcgToolDir>%(_AcgTargetToolDir.Path)</AcgToolDir>
151+
</OpenApiReference>
152+
<OpenApiReference>
153+
<AcgNswagToolDir>%(_AcgTargetNswagToolDir.Path)</AcgNswagToolDir>
31154
</OpenApiReference>
32155
</ItemGroup>
33-
34-
<Error Condition="!Exists('%(_AcgTools.NswagToolDir)')"
35-
Text="Nswag tools not found (%(_AcgTools.NswagToolDir)). ApiCodeGenerator tool in %(_AcgTools.Identity)" />
36156
</Target>
37157

38158
<Target Name="GenerateAcg">
@@ -51,7 +171,7 @@
51171
<__acgExtAssemblies Include="@(__acgBiExtAssemblies)" Condition="Exists(%(__acgBiExtAssemblies.Identity))" />
52172
<__acgExtAssemblies Include="$(AcgExtensionAssemblies)" />
53173
<CurrentOpenApiReference>
54-
<Command>dotnet %(AcgToolDir)/ApiCodeGenerator.MSBuild.dll "%(FullPath)" "%(Options)" "%(OutputPath)" -v "Namespace=%(Namespace),ClassName=%(ClassName)</Command>
174+
<Command>dotnet --roll-forward Major %(AcgToolDir)/ApiCodeGenerator.MSBuild.dll "%(FullPath)" "%(Options)" "%(OutputPath)" -v "Namespace=%(Namespace),ClassName=%(ClassName)</Command>
55175
</CurrentOpenApiReference>
56176
<CurrentOpenApiReference>
57177
<Command Condition="'%(CurrentOpenApiReference.Variables)' != ''">%(Command),%(CurrentOpenApiReference.Variables)</Command>
@@ -72,6 +192,7 @@
72192
<Warning Condition="'@(__acgNotExistsBiExtAssemblies)' != ''" Text="File '%(__acgNotExistsBiExtAssemblies.Identity)' not found." />
73193
<Exec Command="%(CurrentOpenApiReference.Command)"
74194
LogStandardErrorAsError="true"
75-
CustomWarningRegularExpression="^WARNING .*" />
195+
CustomWarningRegularExpression="^WARNING .*"
196+
StdErrEncoding="utf-8" />
76197
</Target>
77198
</Project>

0 commit comments

Comments
 (0)