mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-25 04:59:01 +08:00
- 删除所有手动维护的 buildTransitive props 文件 - 从项目文件中移除静态的 global usings 配置 - 删除废弃的 global-usings.modules.json 清单文件 - 移除旧的 TransitiveGlobalUsingsGenerationTests 测试 - 添加新的 TransitiveGlobalUsingsPackagingTests 验证自动化生成 - 在 Directory.Build.targets 中集成 MSBuild 自动化生成任务 - 实现基于源码扫描的动态命名空间发现机制
172 lines
9.3 KiB
XML
172 lines
9.3 KiB
XML
<Project>
|
|
|
|
<!--
|
|
为 GFramework 运行时包生成可选的模块级 transitive global usings。
|
|
该逻辑只在明确启用的可打包项目中生效,并在构建/打包期间自动扫描源码命名空间。
|
|
-->
|
|
<UsingTask TaskName="GenerateGFrameworkTransitiveGlobalUsingsProps"
|
|
TaskFactory="RoslynCodeTaskFactory"
|
|
AssemblyFile="$(MSBuildToolsPath)/Microsoft.Build.Tasks.Core.dll">
|
|
<ParameterGroup>
|
|
<SourceFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true"/>
|
|
<ExcludedNamespaces ParameterType="Microsoft.Build.Framework.ITaskItem[]"/>
|
|
<ExcludedNamespacePrefixes ParameterType="Microsoft.Build.Framework.ITaskItem[]"/>
|
|
<OutputFile ParameterType="System.String" Required="true"/>
|
|
<NamespaceItemName ParameterType="System.String" Required="true"/>
|
|
</ParameterGroup>
|
|
<Task>
|
|
<Code Type="Fragment"
|
|
Language="cs"><![CDATA[
|
|
var discoveredNamespaces = new global::System.Collections.Generic.SortedSet<string>(global::System.StringComparer.Ordinal);
|
|
var exactExclusions = new global::System.Collections.Generic.HashSet<string>(global::System.StringComparer.Ordinal);
|
|
var prefixExclusions = new global::System.Collections.Generic.List<string>();
|
|
var namespacePattern = new global::System.Text.RegularExpressions.Regex(
|
|
@"^\s*namespace\s+([A-Za-z_][A-Za-z0-9_.]*)\s*(?:;|\{)",
|
|
global::System.Text.RegularExpressions.RegexOptions.Compiled);
|
|
|
|
if (ExcludedNamespaces != null)
|
|
{
|
|
foreach (var excludedNamespace in ExcludedNamespaces)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(excludedNamespace.ItemSpec))
|
|
{
|
|
exactExclusions.Add(excludedNamespace.ItemSpec.Trim());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ExcludedNamespacePrefixes != null)
|
|
{
|
|
foreach (var excludedPrefix in ExcludedNamespacePrefixes)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(excludedPrefix.ItemSpec))
|
|
{
|
|
prefixExclusions.Add(excludedPrefix.ItemSpec.Trim());
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var sourceFile in SourceFiles)
|
|
{
|
|
var path = sourceFile.ItemSpec;
|
|
if (!global::System.IO.File.Exists(path))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach (var line in global::System.IO.File.ReadLines(path))
|
|
{
|
|
var match = namespacePattern.Match(line);
|
|
if (!match.Success)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var namespaceName = match.Groups[1].Value;
|
|
if (!namespaceName.StartsWith("GFramework.", global::System.StringComparison.Ordinal))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (exactExclusions.Contains(namespaceName))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var excludedByPrefix = false;
|
|
foreach (var prefix in prefixExclusions)
|
|
{
|
|
if (namespaceName.StartsWith(prefix, global::System.StringComparison.Ordinal))
|
|
{
|
|
excludedByPrefix = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!excludedByPrefix)
|
|
{
|
|
discoveredNamespaces.Add(namespaceName);
|
|
}
|
|
}
|
|
}
|
|
|
|
static string Escape(string value)
|
|
{
|
|
return global::System.Security.SecurityElement.Escape(value) ?? value;
|
|
}
|
|
|
|
var directory = global::System.IO.Path.GetDirectoryName(OutputFile);
|
|
if (!string.IsNullOrEmpty(directory))
|
|
{
|
|
global::System.IO.Directory.CreateDirectory(directory);
|
|
}
|
|
|
|
var builder = new global::System.Text.StringBuilder();
|
|
var msbuildPropertyOpen = new string(new[] { '$', '(' });
|
|
var msbuildItemOpen = new string(new[] { '@', '(' });
|
|
builder.AppendLine("<Project>");
|
|
builder.AppendLine(" <!-- This file is generated by GFramework's MSBuild transitive global usings pipeline. -->");
|
|
builder.AppendLine(" <!-- EnableGFrameworkGlobalUsings=true enables the transitive global usings from this package. -->");
|
|
builder.AppendLine(" <!-- Add <GFrameworkExcludedUsing Include=\"Namespace\" /> to opt out of specific namespaces. -->");
|
|
builder.Append(" <ItemGroup Condition=\"'");
|
|
builder.Append(msbuildPropertyOpen);
|
|
builder.AppendLine("EnableGFrameworkGlobalUsings)' == 'true'\">");
|
|
|
|
foreach (var namespaceName in discoveredNamespaces)
|
|
{
|
|
builder.Append(" <");
|
|
builder.Append(NamespaceItemName);
|
|
builder.Append(" Include=\"");
|
|
builder.Append(Escape(namespaceName));
|
|
builder.AppendLine("\" />");
|
|
}
|
|
|
|
builder.Append(" <");
|
|
builder.Append(NamespaceItemName);
|
|
builder.Append(" Remove=\"");
|
|
builder.Append(msbuildItemOpen);
|
|
builder.AppendLine("GFrameworkExcludedUsing)\" />");
|
|
builder.Append(" <Using Include=\"");
|
|
builder.Append(msbuildItemOpen);
|
|
builder.Append(NamespaceItemName);
|
|
builder.AppendLine(")\" />");
|
|
builder.AppendLine(" </ItemGroup>");
|
|
builder.AppendLine("</Project>");
|
|
|
|
global::System.IO.File.WriteAllText(OutputFile, builder.ToString(), new global::System.Text.UTF8Encoding(false));
|
|
Log.LogMessage(global::Microsoft.Build.Framework.MessageImportance.Low,
|
|
$"Generated {discoveredNamespaces.Count} transitive global usings for {OutputFile}.");
|
|
]]></Code>
|
|
</Task>
|
|
</UsingTask>
|
|
|
|
<PropertyGroup>
|
|
<_GFrameworkTransitiveGlobalUsingsEnabled Condition="'$(EnableGFrameworkPackageTransitiveGlobalUsings)' == 'true' and '$(IsPackable)' != 'false'">true</_GFrameworkTransitiveGlobalUsingsEnabled>
|
|
<_GFrameworkTransitiveGlobalUsingsPrimaryTargetFramework Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and '$(TargetFrameworks)' != ''">$([System.String]::Copy('$(TargetFrameworks)').Split(';')[0])</_GFrameworkTransitiveGlobalUsingsPrimaryTargetFramework>
|
|
<_GFrameworkTransitiveGlobalUsingsGenerationBuild Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and ('$(TargetFrameworks)' == '' or '$(TargetFramework)' == '$(_GFrameworkTransitiveGlobalUsingsPrimaryTargetFramework)')">true</_GFrameworkTransitiveGlobalUsingsGenerationBuild>
|
|
<_GFrameworkTransitiveGlobalUsingsPackageId Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and '$(PackageId)' != ''">$(PackageId)</_GFrameworkTransitiveGlobalUsingsPackageId>
|
|
<_GFrameworkTransitiveGlobalUsingsPackageId Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and '$(_GFrameworkTransitiveGlobalUsingsPackageId)' == ''">$(AssemblyName)</_GFrameworkTransitiveGlobalUsingsPackageId>
|
|
<_GFrameworkTransitiveGlobalUsingsOutputFile Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true'">$(BaseIntermediateOutputPath)gframework/$(_GFrameworkTransitiveGlobalUsingsPackageId).props</_GFrameworkTransitiveGlobalUsingsOutputFile>
|
|
<_GFrameworkTransitiveGlobalUsingsItemName Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true'">_$([System.Text.RegularExpressions.Regex]::Replace('$(MSBuildProjectName)', '[^A-Za-z0-9_]', '_'))_TransitiveUsing</_GFrameworkTransitiveGlobalUsingsItemName>
|
|
</PropertyGroup>
|
|
|
|
<ItemGroup Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true'">
|
|
<None Include="$(_GFrameworkTransitiveGlobalUsingsOutputFile)"
|
|
Pack="true"
|
|
PackagePath="buildTransitive"
|
|
Visible="false"/>
|
|
</ItemGroup>
|
|
|
|
<Target Name="GenerateGFrameworkModuleTransitiveGlobalUsings"
|
|
Condition="'$(_GFrameworkTransitiveGlobalUsingsGenerationBuild)' == 'true'"
|
|
BeforeTargets="CoreCompile;GenerateNuspec">
|
|
<GenerateGFrameworkTransitiveGlobalUsingsProps
|
|
SourceFiles="@(Compile->'%(FullPath)')"
|
|
ExcludedNamespaces="@(GFrameworkTransitiveUsingExclude)"
|
|
ExcludedNamespacePrefixes="@(GFrameworkTransitiveUsingExcludePrefix)"
|
|
OutputFile="$(_GFrameworkTransitiveGlobalUsingsOutputFile)"
|
|
NamespaceItemName="$(_GFrameworkTransitiveGlobalUsingsItemName)"/>
|
|
</Target>
|
|
|
|
</Project>
|