Files
test/Assets/Editor/AddAnalyzerPostprocessor.cs
2026-03-13 12:34:01 +07:00

158 lines
6.0 KiB
C#

#if UNITY_EDITOR
using System.IO;
using UnityEditor;
using UnityEngine;
/// <summary>
/// Tự động thêm UnityEditorOnlyAnalyzer vào các .csproj files khi Unity generate chúng
/// Analyzer phải ở project root, KHÔNG trong Assets/ để tránh Unity load như runtime assembly
/// </summary>
public class AddAnalyzerPostprocessor : AssetPostprocessor
{
private static string GetAnalyzerPath()
{
string projectRoot = Path.GetDirectoryName(Application.dataPath);
string analyzerPath = Path.Combine(projectRoot, "UnityEditorOnlyAnalyzer/bin/Release/netstandard2.0/UnityEditorOnlyAnalyzer.dll");
return Path.GetFullPath(analyzerPath);
}
/// <summary>
/// Unity gọi method này cho từng .csproj file được generate
/// Return content đã được modify - Unity sẽ ghi content này vào file
/// </summary>
public static string OnGeneratedCSProject(string path, string content)
{
string fileName = Path.GetFileName(path);
// Chỉ thêm vào các runtime assemblies, không thêm vào Editor assemblies
if (fileName != "Assembly-CSharp.csproj" && fileName != "Assembly-CSharp-firstpass.csproj")
{
return content;
}
// Kiểm tra xem đã có analyzer chưa
if (content.Contains("UnityEditorOnlyAnalyzer.dll"))
{
return content;
}
string analyzerPath = GetAnalyzerPath();
// Kiểm tra analyzer có tồn tại không
if (!File.Exists(analyzerPath))
{
Debug.LogWarning($"[UnityEditorOnlyAnalyzer] Analyzer not found at {analyzerPath}. " +
"Please build the analyzer first: cd UnityEditorOnlyAnalyzer && dotnet build -c Release");
return content;
}
// Bug fix 1: Tìm "</Project>" không có dấu cách ở đầu
int lastProjectTag = content.LastIndexOf("</Project>");
if (lastProjectTag < 0)
{
Debug.LogWarning($"[UnityEditorOnlyAnalyzer] Could not find </Project> tag in {fileName}");
return content;
}
// Bug fix 2: Không double-escape backslash trong XML - XML tự động escape
// Chỉ cần đảm bảo path có backslash đúng format Windows
string analyzerInclude = $@" <ItemGroup>
<Analyzer Include=""{analyzerPath}"" />
</ItemGroup>
</Project>";
string modifiedContent = content.Substring(0, lastProjectTag) + analyzerInclude;
Debug.Log($"[UnityEditorOnlyAnalyzer] ✅ Added analyzer to {fileName}");
return modifiedContent;
}
/// <summary>
/// Public method để menu item có thể gọi thủ công
/// </summary>
public static void AddAnalyzerToProjects()
{
// Trigger Unity regenerate .csproj files để OnGeneratedCSProject được gọi
UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal("", 0);
AssetDatabase.Refresh();
// Cũng gọi fallback method để đảm bảo
OnGeneratedCSProjectFiles();
}
/// <summary>
/// Backup method: Unity gọi method này sau khi generate tất cả .csproj files
/// Chỉ dùng nếu OnGeneratedCSProject không hoạt động
/// </summary>
private static void OnGeneratedCSProjectFiles()
{
// Fallback: patch files sau khi đã được generate
string projectRoot = Path.GetDirectoryName(Application.dataPath);
string analyzerPath = GetAnalyzerPath();
if (!File.Exists(analyzerPath))
{
Debug.LogWarning($"[UnityEditorOnlyAnalyzer] Analyzer not found at {analyzerPath}. " +
"Please build the analyzer first: cd UnityEditorOnlyAnalyzer && dotnet build -c Release");
return;
}
string[] csprojFiles = Directory.GetFiles(projectRoot, "*.csproj", SearchOption.TopDirectoryOnly);
bool anyModified = false;
foreach (string csprojFile in csprojFiles)
{
string fileName = Path.GetFileName(csprojFile);
if (fileName == "Assembly-CSharp.csproj" || fileName == "Assembly-CSharp-firstpass.csproj")
{
string content = File.ReadAllText(csprojFile);
if (!content.Contains("UnityEditorOnlyAnalyzer.dll"))
{
// Bug fix: Tìm "</Project>" không có dấu cách
int lastProjectTag = content.LastIndexOf("</Project>");
if (lastProjectTag >= 0)
{
string analyzerInclude = $@" <ItemGroup>
<Analyzer Include=""{analyzerPath}"" />
</ItemGroup>
</Project>";
content = content.Substring(0, lastProjectTag) + analyzerInclude;
File.WriteAllText(csprojFile, content);
anyModified = true;
Debug.Log($"[UnityEditorOnlyAnalyzer] ✅ Added analyzer to {fileName} (fallback method)");
}
}
}
}
if (anyModified)
{
Debug.Log("[UnityEditorOnlyAnalyzer] ✅ Analyzer added to .csproj files! Please reload your IDE.");
}
}
}
/// <summary>
/// Menu item để trigger thủ công việc thêm analyzer
/// </summary>
public class UnityEditorOnlyAnalyzerMenu
{
[MenuItem("Tools/Unity Editor Only Analyzer/Add Analyzer to Projects")]
public static void AddAnalyzerManually()
{
AddAnalyzerPostprocessor.AddAnalyzerToProjects();
}
[MenuItem("Tools/Unity Editor Only Analyzer/Regenerate Project Files")]
public static void RegenerateProjectFiles()
{
// Trigger Unity regenerate .csproj files
UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal("", 0);
AssetDatabase.Refresh();
Debug.Log("[UnityEditorOnlyAnalyzer] Project files regeneration triggered. Check Console for analyzer messages.");
}
}
#endif