diff --git a/Assets/Tests/Editor/CliInstallationDetectorTests.cs b/Assets/Tests/Editor/CliInstallationDetectorTests.cs
index 3b94f0eab2..a927b75f25 100644
--- a/Assets/Tests/Editor/CliInstallationDetectorTests.cs
+++ b/Assets/Tests/Editor/CliInstallationDetectorTests.cs
@@ -108,7 +108,7 @@ public void SelectPreferredDetection_WhenShellVersionExistsWithoutPathUsesShellV
public void BuildShellCliDetectionCommand_UsesShortVersionFlag()
{
// Verifies that shell detection asks the command itself for its terminal-visible version.
- string command = CliInstallationDetector.BuildShellCliDetectionCommand("uloop");
+ string command = CliShellInstallationProbe.BuildShellCliDetectionCommand("uloop");
Assert.That(command, Does.Contain("command -v uloop"));
Assert.That(command, Does.Contain("uloop --version --json"));
@@ -123,7 +123,7 @@ public void BuildShellCliDetectionCommand_UsesShortVersionFlag()
public void BuildShellCliDetectionCommandForShell_WhenRuntimeShellIsFish_UsesFishStatusSyntax()
{
// Verifies that command syntax follows the actual shell process, not PATH setup support.
- string command = CliInstallationDetector.BuildShellCliDetectionCommandForShell(
+ string command = CliShellInstallationProbe.BuildShellCliDetectionCommandForShell(
"uloop",
"/opt/homebrew/bin/fish");
@@ -154,7 +154,7 @@ public void ParseShellCliInstallationOutput_WhenPathAndVersionExist_ReturnsDetec
+ "__ULOOP_VERSION_STATUS_END__\n";
CliInstallationDetection detection =
- CliInstallationDetector.ParseShellCliInstallationOutput(output);
+ CliShellInstallationProbe.ParseShellCliInstallationOutput(output);
Assert.That(detection.Version, Is.EqualTo("2.1.1"));
Assert.That(detection.IsDispatcher, Is.False);
@@ -182,7 +182,7 @@ public void ParseShellCliInstallationOutput_WhenLegacyCliJsonExists_ReturnsVersi
+ "__ULOOP_VERSION_STATUS_END__\n";
CliInstallationDetection detection =
- CliInstallationDetector.ParseShellCliInstallationOutput(output);
+ CliShellInstallationProbe.ParseShellCliInstallationOutput(output);
Assert.That(detection.Version, Is.EqualTo("3.0.0-beta.31"));
Assert.That(detection.IsDispatcher, Is.False);
@@ -210,7 +210,7 @@ public void ParseShellCliInstallationOutput_WhenDispatcherJsonExists_ReturnsDisp
+ "__ULOOP_VERSION_STATUS_END__\n";
CliInstallationDetection detection =
- CliInstallationDetector.ParseShellCliInstallationOutput(output);
+ CliShellInstallationProbe.ParseShellCliInstallationOutput(output);
Assert.That(detection.Version, Is.EqualTo("3.0.0"));
Assert.That(detection.IsDispatcher, Is.True);
@@ -225,7 +225,7 @@ public void IsShellDetectionUsableForPathSetup_WhenLegacyCliVersionIsHigh_Return
"3.0.0-beta.40",
"/Users/ExampleUser/.npm-global/bin/uloop");
- bool result = CliInstallationDetector.IsShellDetectionUsableForPathSetup(
+ bool result = CliShellInstallationProbe.IsShellDetectionUsableForPathSetup(
detection,
UnityEngine.RuntimePlatform.OSXEditor,
(path, platform) => false,
@@ -255,7 +255,7 @@ public void ParseShellCliInstallationOutput_WhenProtocolVersionIsOutsideIntRange
+ "__ULOOP_VERSION_STATUS_END__\n";
CliInstallationDetection detection =
- CliInstallationDetector.ParseShellCliInstallationOutput(output);
+ CliShellInstallationProbe.ParseShellCliInstallationOutput(output);
Assert.That(detection.Version, Is.EqualTo("3.0.0-beta.31"));
Assert.That(detection.ExecutablePath, Is.EqualTo("/tmp/uloop"));
@@ -275,7 +275,7 @@ public void ParseShellCliInstallationOutput_WhenOnlyVersionExists_ReturnsInstall
+ "__ULOOP_VERSION_STATUS_END__\n";
CliInstallationDetection detection =
- CliInstallationDetector.ParseShellCliInstallationOutput(output);
+ CliShellInstallationProbe.ParseShellCliInstallationOutput(output);
Assert.That(detection.Version, Is.EqualTo("2.1.1"));
Assert.That(detection.ExecutablePath, Is.Null);
@@ -296,7 +296,7 @@ public void ParseShellCliInstallationOutput_WhenVersionCommandFails_ReturnsPathW
+ "__ULOOP_VERSION_STATUS_END__\n";
CliInstallationDetection detection =
- CliInstallationDetector.ParseShellCliInstallationOutput(output);
+ CliShellInstallationProbe.ParseShellCliInstallationOutput(output);
Assert.That(detection.Version, Is.Null);
Assert.That(detection.ExecutablePath, Is.EqualTo("/Users/ExampleUser/.npm-global/bin/uloop"));
diff --git a/Assets/Tests/Editor/ThirdPartyToolMigrationAssemblyUsageScanStateTests.cs b/Assets/Tests/Editor/ThirdPartyToolMigrationAssemblyUsageScanStateTests.cs
new file mode 100644
index 0000000000..ed7e5eee22
--- /dev/null
+++ b/Assets/Tests/Editor/ThirdPartyToolMigrationAssemblyUsageScanStateTests.cs
@@ -0,0 +1,277 @@
+using System.Collections.Generic;
+
+using NUnit.Framework;
+
+using io.github.hatayama.UnityCliLoop.Infrastructure;
+
+namespace io.github.hatayama.UnityCliLoop.Tests.Editor
+{
+ ///
+ /// Characterization tests that pin the current scan-state aggregation behavior before Extract Class.
+ ///
+ public sealed class ThirdPartyToolMigrationAssemblyUsageScanStateTests
+ {
+ private const string ProjectRoot = "/Project";
+ private const string AssemblyDirectory = "/Project/Assets/VendorTools";
+ private const string SourceFilePath = "/Project/Assets/VendorTools/Foo.cs";
+
+ private static ThirdPartyToolMigrationAssemblyUsageScanState CreateScanState()
+ {
+ return new ThirdPartyToolMigrationAssemblyUsageScanState(
+ ProjectRoot,
+ new List { AssemblyDirectory },
+ new List());
+ }
+
+ [Test]
+ public void Constructor_WhenCreated_ExposesGivenAsmdefAndAssemblyReferenceDirectories()
+ {
+ // Verifies that scan-state construction stores caller-provided directory lists without copying.
+ List asmdefDirectories = new() { AssemblyDirectory };
+ List assemblyReferenceDirectories = new()
+ {
+ new AssemblyReferenceDirectory("/Project/Assets/VendorTools/Sub", AssemblyDirectory)
+ };
+
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = new(
+ ProjectRoot,
+ asmdefDirectories,
+ assemblyReferenceDirectories);
+
+ Assert.That(scanState.AsmdefDirectories, Is.SameAs(asmdefDirectories));
+ Assert.That(scanState.AssemblyReferenceDirectories, Is.SameAs(assemblyReferenceDirectories));
+ }
+
+ [Test]
+ public void RecordInitialSourceFacts_WhenSourceHasNoMigrationCandidateText_ReturnsFalseAndRecordsNothing()
+ {
+ // Verifies that unrelated source text leaves every aggregation set untouched.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ bool recorded = scanState.RecordInitialSourceFacts(
+ "public class Foo { }",
+ SourceFilePath);
+
+ Assert.That(recorded, Is.False);
+ Assert.That(scanState.LegacyAssemblyDirectories, Is.Empty);
+ Assert.That(scanState.AssemblyDeclaredTypeNamesByDirectory, Is.Empty);
+ }
+
+ [Test]
+ public void RecordInitialSourceFacts_WhenSourceContainsLegacyNamespaceUsage_RecordsLegacyDirectoryAndDeclaredTypeNames()
+ {
+ // Verifies that legacy namespace text marks the owning assembly as legacy and captures declared types.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ bool recorded = scanState.RecordInitialSourceFacts(
+ "using io.github.hatayama.uLoopMCP;\npublic class Foo { }\n",
+ SourceFilePath);
+
+ Assert.That(recorded, Is.True);
+ Assert.That(scanState.LegacyAssemblyDirectories, Is.EquivalentTo(new[] { AssemblyDirectory }));
+ Assert.That(
+ scanState.AssemblyDeclaredTypeNamesByDirectory[AssemblyDirectory],
+ Is.EquivalentTo(new[] { "Foo" }));
+ }
+
+ [Test]
+ public void RecordInitialSourceFacts_WhenSourceHasGlobalUsingAliasForLegacyNamespace_RecordsAssemblyScopedAliasAndDirectory()
+ {
+ // Verifies that a global-using alias for the legacy namespace is captured per assembly directory.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ scanState.RecordInitialSourceFacts(
+ "global using LegacyAlias = io.github.hatayama.uLoopMCP;\n",
+ SourceFilePath);
+
+ Assert.That(scanState.AssemblyScopedLegacyDirectories, Is.EquivalentTo(new[] { AssemblyDirectory }));
+ Assert.That(
+ scanState.AssemblyScopedLegacyAliasesByDirectory[AssemblyDirectory],
+ Is.EquivalentTo(new[] { "LegacyAlias" }));
+ }
+
+ [Test]
+ public void RecordInitialSourceFacts_WhenSourceHasGlobalUsingForCurrentDomainNamespace_RecordsDomainScopeAndReference()
+ {
+ // Verifies that a global using for the current domain namespace scopes the assembly and adds a reference.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ scanState.RecordInitialSourceFacts(
+ "global using io.github.hatayama.UnityCliLoop.Domain;\n",
+ SourceFilePath);
+
+ Assert.That(
+ scanState.AssemblyScopedCurrentDomainDirectories,
+ Is.EquivalentTo(new[] { AssemblyDirectory }));
+ Assert.That(
+ scanState.DomainReferenceAssemblyDirectories,
+ Is.EquivalentTo(new[] { AssemblyDirectory }));
+ }
+
+ [Test]
+ public void RecordInitialSourceFacts_WhenSourceHasGlobalUsingForCurrentApplicationNamespace_RecordsApplicationScopeAndReference()
+ {
+ // Verifies that a global using for the current application namespace scopes the assembly and adds a reference.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ scanState.RecordInitialSourceFacts(
+ "global using io.github.hatayama.UnityCliLoop.Application;\n",
+ SourceFilePath);
+
+ Assert.That(
+ scanState.AssemblyScopedCurrentApplicationDirectories,
+ Is.EquivalentTo(new[] { AssemblyDirectory }));
+ Assert.That(
+ scanState.ApplicationReferenceAssemblyDirectories,
+ Is.EquivalentTo(new[] { AssemblyDirectory }));
+ }
+
+ [Test]
+ public void RecordInitialSourceFacts_WhenSourceHasGlobalUsingForCurrentFirstPartyToolsNamespace_RecordsFirstPartyScopeAndReference()
+ {
+ // Verifies that a global using for the first-party tools namespace scopes the assembly and adds a reference.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ scanState.RecordInitialSourceFacts(
+ "global using io.github.hatayama.UnityCliLoop.FirstPartyTools;\n",
+ SourceFilePath);
+
+ Assert.That(
+ scanState.AssemblyScopedCurrentFirstPartyToolsDirectories,
+ Is.EquivalentTo(new[] { AssemblyDirectory }));
+ Assert.That(
+ scanState.FirstPartyScreenshotReferenceAssemblyDirectories,
+ Is.EquivalentTo(new[] { AssemblyDirectory }));
+ }
+
+ [Test]
+ public void RecordInitialSourceFacts_WhenSourceContainsBareCustomToolManager_ReturnsTrueWithoutToolContractsReference()
+ {
+ // why: CustomToolManager is a migration-candidate fragment, but bare registrar API recording requires legacy assembly/namespace context
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ bool recorded = scanState.RecordInitialSourceFacts(
+ "public void Foo() { CustomToolManager.Register(); }",
+ SourceFilePath);
+
+ Assert.That(recorded, Is.True);
+ Assert.That(scanState.ToolContractsReferenceAssemblyDirectories, Is.Empty);
+ }
+
+ [Test]
+ public void RecordTargetScanInitialSourceFacts_WhenSourceContainsLegacyRegistrarApi_DoesNotRecordToolContractsReference()
+ {
+ // Verifies that the fast target scan skips registrar-API-based tool-contracts requirement recording.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ scanState.RecordTargetScanInitialSourceFacts(
+ "public void Foo() { CustomToolManager.Register(); }",
+ SourceFilePath);
+
+ Assert.That(scanState.ToolContractsReferenceAssemblyDirectories, Is.Empty);
+ }
+
+ [Test]
+ public void RecordInitialSourceFacts_WhenSourceContainsCurrentDomainMetadataApi_RecordsDomainAndToolContractsReferences()
+ {
+ // Verifies that the full initial scan records both domain and tool-contracts references for domain metadata usage.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ scanState.RecordInitialSourceFacts(
+ "object info = io.github.hatayama.UnityCliLoop.Domain.ToolInfo.Empty;",
+ SourceFilePath);
+
+ Assert.That(
+ scanState.DomainReferenceAssemblyDirectories,
+ Is.EquivalentTo(new[] { AssemblyDirectory }));
+ Assert.That(
+ scanState.ToolContractsReferenceAssemblyDirectories,
+ Is.EquivalentTo(new[] { AssemblyDirectory }));
+ }
+
+ [Test]
+ public void RecordTargetScanInitialSourceFacts_WhenSourceContainsCurrentDomainMetadataApi_RecordsNeitherDomainNorToolContractsReferences()
+ {
+ // Verifies that the fast target scan skips domain-metadata-based reference recording entirely.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ scanState.RecordTargetScanInitialSourceFacts(
+ "object info = io.github.hatayama.UnityCliLoop.Domain.ToolInfo.Empty;",
+ SourceFilePath);
+
+ Assert.That(scanState.DomainReferenceAssemblyDirectories, Is.Empty);
+ Assert.That(scanState.ToolContractsReferenceAssemblyDirectories, Is.Empty);
+ }
+
+ [Test]
+ public void RecordInitialSourceFacts_WhenSourceContainsCurrentRegistrarApi_CreateUsageBridgesRegistrarIntoApplicationReference()
+ {
+ // Verifies that CreateUsage folds registrar-owning assemblies into the application reference set.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+ scanState.RecordInitialSourceFacts(
+ "public void Foo() { UnityCliLoopToolRegistrar.Register(); }",
+ SourceFilePath);
+
+ MigrationAssemblyUsage usage = scanState.CreateUsage();
+
+ Assert.That(
+ usage.ApplicationReferenceAssemblyDirectories,
+ Is.EquivalentTo(new[] { AssemblyDirectory }));
+ }
+
+ [Test]
+ public void RecordInitialSourceFacts_WhenSourceContainsCurrentRegistrarApi_CreateReferenceRequirementUsageDoesNotBridgeRegistrar()
+ {
+ // Verifies that CreateReferenceRequirementUsage does not fold registrar-owning assemblies into the application set.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+ scanState.RecordInitialSourceFacts(
+ "public void Foo() { UnityCliLoopToolRegistrar.Register(); }",
+ SourceFilePath);
+
+ MigrationAssemblyUsage usage = scanState.CreateReferenceRequirementUsage();
+
+ Assert.That(usage.ApplicationReferenceAssemblyDirectories, Is.Empty);
+ }
+
+ [Test]
+ public void RecordReferenceRequirements_WhenSourceHasNoMigrationCandidateText_RecordsNothing()
+ {
+ // Verifies that reference-requirement scanning ignores source without any migration candidate text.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ scanState.RecordReferenceRequirements("public class Foo { }", SourceFilePath);
+
+ Assert.That(scanState.ToolContractsReferenceAssemblyDirectories, Is.Empty);
+ Assert.That(scanState.HasReferenceRequirements, Is.False);
+ }
+
+ [Test]
+ public void RecordReferenceRequirements_WhenSourceContainsCurrentRegistrarDomainReturnApi_RecordsToolContractsReference()
+ {
+ // Verifies that a current registrar domain-return call is recorded as a tool-contracts requirement.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ scanState.RecordReferenceRequirements(
+ "var tools = UnityCliLoopToolRegistrar.GetRegisteredCustomTools();",
+ SourceFilePath);
+
+ Assert.That(
+ scanState.ToolContractsReferenceAssemblyDirectories,
+ Is.EquivalentTo(new[] { AssemblyDirectory }));
+ Assert.That(scanState.HasReferenceRequirements, Is.True);
+ }
+
+ [Test]
+ public void CreateUsage_WhenNothingRecorded_ReturnsEmptyUsageWithGivenDirectories()
+ {
+ // Verifies that CreateUsage on a fresh scan state yields an otherwise-empty usage snapshot.
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState = CreateScanState();
+
+ MigrationAssemblyUsage usage = scanState.CreateUsage();
+
+ Assert.That(usage.AsmdefDirectories, Is.EquivalentTo(new[] { AssemblyDirectory }));
+ Assert.That(usage.LegacyAssemblyDirectories, Is.Empty);
+ Assert.That(usage.ToolContractsReferenceAssemblyDirectories, Is.Empty);
+ }
+ }
+}
diff --git a/Assets/Tests/Editor/ThirdPartyToolMigrationAssemblyUsageScanStateTests.cs.meta b/Assets/Tests/Editor/ThirdPartyToolMigrationAssemblyUsageScanStateTests.cs.meta
new file mode 100644
index 0000000000..d80bee57e8
--- /dev/null
+++ b/Assets/Tests/Editor/ThirdPartyToolMigrationAssemblyUsageScanStateTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 812724901c23a4d37af04f9b1cd9a585
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/src/Editor/Infrastructure/CLI/CliInstallationDetector.cs b/Packages/src/Editor/Infrastructure/CLI/CliInstallationDetector.cs
index 52d819f9e1..6168cc7965 100644
--- a/Packages/src/Editor/Infrastructure/CLI/CliInstallationDetector.cs
+++ b/Packages/src/Editor/Infrastructure/CLI/CliInstallationDetector.cs
@@ -3,8 +3,6 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
using UnityEngine;
using io.github.hatayama.UnityCliLoop.Application;
@@ -32,21 +30,6 @@ public CliInstallationDetection(string version, string executablePath, bool isDi
///
public sealed class CliInstallationDetector : ICliInstallationDetector
{
- private const string SHELL_PATH_START_MARKER = "__ULOOP_PATH_START__";
- private const string SHELL_PATH_END_MARKER = "__ULOOP_PATH_END__";
- private const string SHELL_VERSION_START_MARKER = "__ULOOP_VERSION_START__";
- private const string SHELL_VERSION_END_MARKER = "__ULOOP_VERSION_END__";
- private const string SHELL_VERSION_STATUS_START_MARKER = "__ULOOP_VERSION_STATUS_START__";
- private const string SHELL_VERSION_STATUS_END_MARKER = "__ULOOP_VERSION_STATUS_END__";
- private const string SHELL_CONTRACT_START_MARKER = "__ULOOP_CONTRACT_START__";
- private const string SHELL_CONTRACT_END_MARKER = "__ULOOP_CONTRACT_END__";
- private const string SHELL_CONTRACT_STATUS_START_MARKER = "__ULOOP_CONTRACT_STATUS_START__";
- private const string SHELL_CONTRACT_STATUS_END_MARKER = "__ULOOP_CONTRACT_STATUS_END__";
- private const string SHELL_SUCCESS_EXIT_CODE = "0";
- private const string VERSION_JSON_PROJECT_RUNNER_VERSION_PROPERTY = "ProjectRunnerVersion";
- private const string VERSION_JSON_LEGACY_CLI_VERSION_PROPERTY = "CliVersion";
- private const string VERSION_JSON_DISPATCHER_VERSION_PROPERTY = "DispatcherVersion";
-
private readonly ICliPinReader _cliPinReader;
private string _cachedCliVersion;
@@ -133,7 +116,7 @@ public Task IsCliVisibleFromShellAsync(RuntimePlatform platform, Cancellat
() =>
{
CliInstallationDetection detection = DetectShellCliInstallationBlocking(platform, ct);
- return IsShellDetectionUsableForPathSetup(
+ return CliShellInstallationProbe.IsShellDetectionUsableForPathSetup(
detection,
platform,
NativeCliInstallPathResolver.IsPackageOwnedCurrentUserInstallPath,
@@ -209,7 +192,7 @@ private static CliInstallationDetection DetectShellCliInstallationFromLoginShell
{
string shell = NodeEnvironmentResolver.GetUserShell();
CliPathSetupPlan pathSetupPlan = CliPathSetupProfileResolver.ResolveCurrentUserPlan(platform);
- ProcessStartInfo startInfo = BuildShellCliDetectionStartInfo(
+ ProcessStartInfo startInfo = CliShellInstallationProbe.BuildShellCliDetectionStartInfo(
shell,
platform,
pathSetupPlan,
@@ -219,240 +202,7 @@ private static CliInstallationDetection DetectShellCliInstallationFromLoginShell
string output = commandResult == null
? null
: string.Join(Environment.NewLine, commandResult.StandardOutputLines).Trim();
- return ParseShellCliInstallationOutput(output);
- }
-
- internal static ProcessStartInfo BuildShellCliDetectionStartInfo(
- string shell,
- RuntimePlatform platform,
- CliPathSetupPlan pathSetupPlan,
- string currentPath)
- {
- UnityEngine.Debug.Assert(!string.IsNullOrWhiteSpace(shell), "shell must not be null or empty");
-
- ProcessStartInfo startInfo = new()
- {
- FileName = shell,
- Arguments = "-l -i -c " + QuoteProcessArgument(BuildShellCliDetectionCommandForShell(
- CliConstants.EXECUTABLE_NAME,
- shell)),
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- };
- if (platform != RuntimePlatform.WindowsEditor)
- {
- startInfo.EnvironmentVariables[CliConstants.POSIX_PATH_ENVIRONMENT_VARIABLE] =
- NativeCliInstallPathResolver.BuildPathWithoutInstallDirectory(
- currentPath,
- pathSetupPlan.InstallDirectory,
- platform);
- }
-
- return startInfo;
- }
-
- internal static bool IsShellDetectionUsableForPathSetup(
- CliInstallationDetection detection,
- RuntimePlatform platform,
- Func isPackageOwnedCurrentUserInstallPath,
- string minimumDispatcherVersion)
- {
- UnityEngine.Debug.Assert(isPackageOwnedCurrentUserInstallPath != null, "isPackageOwnedCurrentUserInstallPath must not be null");
- UnityEngine.Debug.Assert(!string.IsNullOrEmpty(minimumDispatcherVersion), "minimumDispatcherVersion must not be null or empty");
-
- if (isPackageOwnedCurrentUserInstallPath(detection.ExecutablePath, platform))
- {
- return true;
- }
-
- if (!detection.IsDispatcher)
- {
- return false;
- }
-
- return CliVersionComparer.IsVersionGreaterThanOrEqual(
- detection.Version,
- minimumDispatcherVersion);
- }
-
- internal static string BuildShellCliDetectionCommandForShell(
- string executableName,
- string shellPath)
- {
- string shellName = string.IsNullOrWhiteSpace(shellPath)
- ? string.Empty
- : Path.GetFileName(shellPath.Trim()).ToLowerInvariant();
- if (string.Equals(shellName, "fish", StringComparison.Ordinal))
- {
- return BuildFishShellCliDetectionCommand(executableName);
- }
-
- return BuildShellCliDetectionCommand(executableName);
- }
-
- internal static string BuildShellCliDetectionCommand(string executableName)
- {
- UnityEngine.Debug.Assert(!string.IsNullOrEmpty(executableName), "executableName must not be null or empty");
-
- return "echo " + SHELL_PATH_START_MARKER + "\n"
- + "command -v " + executableName + "\n"
- + "echo " + SHELL_PATH_END_MARKER + "\n"
- + "echo " + SHELL_CONTRACT_START_MARKER + "\n"
- + executableName + " " + CliConstants.VERSION_FLAG + " " + CliConstants.JSON_FLAG + "\n"
- + "uloop_contract_status=$?\n"
- + "echo " + SHELL_CONTRACT_END_MARKER + "\n"
- + "echo " + SHELL_CONTRACT_STATUS_START_MARKER + "\n"
- + "echo $uloop_contract_status\n"
- + "echo " + SHELL_CONTRACT_STATUS_END_MARKER + "\n"
- + "echo " + SHELL_VERSION_START_MARKER + "\n"
- + executableName + " " + CliConstants.SHORT_VERSION_FLAG + "\n"
- + "uloop_version_status=$?\n"
- + "echo " + SHELL_VERSION_END_MARKER + "\n"
- + "echo " + SHELL_VERSION_STATUS_START_MARKER + "\n"
- + "echo $uloop_version_status\n"
- + "echo " + SHELL_VERSION_STATUS_END_MARKER;
- }
-
- private static string BuildFishShellCliDetectionCommand(string executableName)
- {
- UnityEngine.Debug.Assert(!string.IsNullOrEmpty(executableName), "executableName must not be null or empty");
-
- return "echo " + SHELL_PATH_START_MARKER + "\n"
- + "command -v " + executableName + "\n"
- + "echo " + SHELL_PATH_END_MARKER + "\n"
- + "echo " + SHELL_CONTRACT_START_MARKER + "\n"
- + executableName + " " + CliConstants.VERSION_FLAG + " " + CliConstants.JSON_FLAG + "\n"
- + "set uloop_contract_status $status\n"
- + "echo " + SHELL_CONTRACT_END_MARKER + "\n"
- + "echo " + SHELL_CONTRACT_STATUS_START_MARKER + "\n"
- + "echo $uloop_contract_status\n"
- + "echo " + SHELL_CONTRACT_STATUS_END_MARKER + "\n"
- + "echo " + SHELL_VERSION_START_MARKER + "\n"
- + executableName + " " + CliConstants.SHORT_VERSION_FLAG + "\n"
- + "set uloop_version_status $status\n"
- + "echo " + SHELL_VERSION_END_MARKER + "\n"
- + "echo " + SHELL_VERSION_STATUS_START_MARKER + "\n"
- + "echo $uloop_version_status\n"
- + "echo " + SHELL_VERSION_STATUS_END_MARKER;
- }
-
- internal static CliInstallationDetection ParseShellCliInstallationOutput(string output)
- {
- string pathBlock = NodeEnvironmentResolver.ExtractBetweenMarkers(
- output,
- SHELL_PATH_START_MARKER,
- SHELL_PATH_END_MARKER);
- string versionBlock = NodeEnvironmentResolver.ExtractBetweenMarkers(
- output,
- SHELL_VERSION_START_MARKER,
- SHELL_VERSION_END_MARKER);
- string versionStatusBlock = NodeEnvironmentResolver.ExtractBetweenMarkers(
- output,
- SHELL_VERSION_STATUS_START_MARKER,
- SHELL_VERSION_STATUS_END_MARKER);
- string contractBlock = NodeEnvironmentResolver.ExtractBetweenMarkers(
- output,
- SHELL_CONTRACT_START_MARKER,
- SHELL_CONTRACT_END_MARKER);
- string contractStatusBlock = NodeEnvironmentResolver.ExtractBetweenMarkers(
- output,
- SHELL_CONTRACT_STATUS_START_MARKER,
- SHELL_CONTRACT_STATUS_END_MARKER);
- string executablePath = NodeEnvironmentResolver.ExtractAbsolutePathLine(pathBlock);
- if (IsSuccessfulShellStatus(contractStatusBlock))
- {
- CliInstallationDetection contractDetection = ParseCliContractOutput(contractBlock, executablePath);
- if (!string.IsNullOrEmpty(contractDetection.Version))
- {
- return contractDetection;
- }
- }
-
- string version = IsSuccessfulShellStatus(versionStatusBlock)
- ? ExtractFirstNonEmptyLine(versionBlock)
- : null;
- return new CliInstallationDetection(version, executablePath);
- }
-
- private static CliInstallationDetection ParseCliContractOutput(string output, string executablePath)
- {
- string jsonLine = ExtractFirstNonEmptyLine(output);
- if (string.IsNullOrEmpty(jsonLine))
- {
- return new CliInstallationDetection(null, executablePath);
- }
-
- try
- {
- JObject parsed = JObject.Parse(jsonLine);
- CliInstallationDetection dispatcherDetection = ParseDispatcherContract(parsed, executablePath);
- if (!string.IsNullOrEmpty(dispatcherDetection.Version))
- {
- return dispatcherDetection;
- }
-
- string version = parsed[VERSION_JSON_PROJECT_RUNNER_VERSION_PROPERTY]?.ToString();
- if (string.IsNullOrEmpty(version))
- {
- version = parsed[VERSION_JSON_LEGACY_CLI_VERSION_PROPERTY]?.ToString();
- }
- return new CliInstallationDetection(version, executablePath);
- }
- catch (JsonException)
- {
- return new CliInstallationDetection(null, executablePath);
- }
- }
-
- private static CliInstallationDetection ParseDispatcherContract(JObject parsed, string executablePath)
- {
- // Why: dispatcher compatibility is enforced by the pin's minimumDispatcherVersion (semver floor),
- // so identifying the dispatcher only needs its release version.
- string dispatcherVersion = parsed[VERSION_JSON_DISPATCHER_VERSION_PROPERTY]?.ToString();
- if (string.IsNullOrEmpty(dispatcherVersion))
- {
- return new CliInstallationDetection(null, executablePath);
- }
-
- return new CliInstallationDetection(
- dispatcherVersion,
- executablePath,
- true);
- }
-
- private static bool IsSuccessfulShellStatus(string statusBlock)
- {
- string status = ExtractFirstNonEmptyLine(statusBlock);
- return string.Equals(status, SHELL_SUCCESS_EXIT_CODE, StringComparison.Ordinal);
- }
-
- private static string ExtractFirstNonEmptyLine(string block)
- {
- if (string.IsNullOrEmpty(block))
- {
- return null;
- }
-
- string[] lines = block.Split('\n');
- foreach (string rawLine in lines)
- {
- string line = rawLine.Trim();
- if (!string.IsNullOrEmpty(line))
- {
- return line;
- }
- }
-
- return null;
- }
-
- private static string QuoteProcessArgument(string value)
- {
- UnityEngine.Debug.Assert(value != null, "value must not be null");
-
- return "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
+ return CliShellInstallationProbe.ParseShellCliInstallationOutput(output);
}
private static CliInstallationDetection DetectCliInstallationAtExecutablePath(
@@ -461,7 +211,7 @@ private static CliInstallationDetection DetectCliInstallationAtExecutablePath(
{
string fileName = executablePath ?? CliConstants.EXECUTABLE_NAME;
string contractOutput = ExecuteCliVersionCommand(fileName, CliConstants.VERSION_FLAG + " " + CliConstants.JSON_FLAG, ct);
- CliInstallationDetection contractDetection = ParseCliContractOutput(contractOutput, executablePath);
+ CliInstallationDetection contractDetection = CliShellInstallationProbe.ParseCliContractOutput(contractOutput, executablePath);
if (!string.IsNullOrEmpty(contractDetection.Version))
{
return contractDetection;
diff --git a/Packages/src/Editor/Infrastructure/CLI/CliShellInstallationProbe.cs b/Packages/src/Editor/Infrastructure/CLI/CliShellInstallationProbe.cs
new file mode 100644
index 0000000000..3429742e2e
--- /dev/null
+++ b/Packages/src/Editor/Infrastructure/CLI/CliShellInstallationProbe.cs
@@ -0,0 +1,268 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+using UnityEngine;
+
+using io.github.hatayama.UnityCliLoop.Application;
+using io.github.hatayama.UnityCliLoop.Domain;
+
+namespace io.github.hatayama.UnityCliLoop.Infrastructure
+{
+ ///
+ /// Builds login-shell CLI probe commands and parses their marker-delimited output.
+ ///
+ internal static class CliShellInstallationProbe
+ {
+ private const string SHELL_PATH_START_MARKER = "__ULOOP_PATH_START__";
+ private const string SHELL_PATH_END_MARKER = "__ULOOP_PATH_END__";
+ private const string SHELL_VERSION_START_MARKER = "__ULOOP_VERSION_START__";
+ private const string SHELL_VERSION_END_MARKER = "__ULOOP_VERSION_END__";
+ private const string SHELL_VERSION_STATUS_START_MARKER = "__ULOOP_VERSION_STATUS_START__";
+ private const string SHELL_VERSION_STATUS_END_MARKER = "__ULOOP_VERSION_STATUS_END__";
+ private const string SHELL_CONTRACT_START_MARKER = "__ULOOP_CONTRACT_START__";
+ private const string SHELL_CONTRACT_END_MARKER = "__ULOOP_CONTRACT_END__";
+ private const string SHELL_CONTRACT_STATUS_START_MARKER = "__ULOOP_CONTRACT_STATUS_START__";
+ private const string SHELL_CONTRACT_STATUS_END_MARKER = "__ULOOP_CONTRACT_STATUS_END__";
+ private const string SHELL_SUCCESS_EXIT_CODE = "0";
+ private const string VERSION_JSON_PROJECT_RUNNER_VERSION_PROPERTY = "ProjectRunnerVersion";
+ private const string VERSION_JSON_LEGACY_CLI_VERSION_PROPERTY = "CliVersion";
+ private const string VERSION_JSON_DISPATCHER_VERSION_PROPERTY = "DispatcherVersion";
+
+ public static ProcessStartInfo BuildShellCliDetectionStartInfo(
+ string shell,
+ RuntimePlatform platform,
+ CliPathSetupPlan pathSetupPlan,
+ string currentPath)
+ {
+ UnityEngine.Debug.Assert(!string.IsNullOrWhiteSpace(shell), "shell must not be null or empty");
+
+ ProcessStartInfo startInfo = new()
+ {
+ FileName = shell,
+ Arguments = "-l -i -c " + QuoteProcessArgument(BuildShellCliDetectionCommandForShell(
+ CliConstants.EXECUTABLE_NAME,
+ shell)),
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = true
+ };
+ if (platform != RuntimePlatform.WindowsEditor)
+ {
+ startInfo.EnvironmentVariables[CliConstants.POSIX_PATH_ENVIRONMENT_VARIABLE] =
+ NativeCliInstallPathResolver.BuildPathWithoutInstallDirectory(
+ currentPath,
+ pathSetupPlan.InstallDirectory,
+ platform);
+ }
+
+ return startInfo;
+ }
+
+ public static bool IsShellDetectionUsableForPathSetup(
+ CliInstallationDetection detection,
+ RuntimePlatform platform,
+ Func isPackageOwnedCurrentUserInstallPath,
+ string minimumDispatcherVersion)
+ {
+ UnityEngine.Debug.Assert(isPackageOwnedCurrentUserInstallPath != null, "isPackageOwnedCurrentUserInstallPath must not be null");
+ UnityEngine.Debug.Assert(!string.IsNullOrEmpty(minimumDispatcherVersion), "minimumDispatcherVersion must not be null or empty");
+
+ if (isPackageOwnedCurrentUserInstallPath(detection.ExecutablePath, platform))
+ {
+ return true;
+ }
+
+ if (!detection.IsDispatcher)
+ {
+ return false;
+ }
+
+ return CliVersionComparer.IsVersionGreaterThanOrEqual(
+ detection.Version,
+ minimumDispatcherVersion);
+ }
+
+ public static string BuildShellCliDetectionCommandForShell(
+ string executableName,
+ string shellPath)
+ {
+ string shellName = string.IsNullOrWhiteSpace(shellPath)
+ ? string.Empty
+ : Path.GetFileName(shellPath.Trim()).ToLowerInvariant();
+ if (string.Equals(shellName, "fish", StringComparison.Ordinal))
+ {
+ return BuildFishShellCliDetectionCommand(executableName);
+ }
+
+ return BuildShellCliDetectionCommand(executableName);
+ }
+
+ public static string BuildShellCliDetectionCommand(string executableName)
+ {
+ UnityEngine.Debug.Assert(!string.IsNullOrEmpty(executableName), "executableName must not be null or empty");
+
+ return "echo " + SHELL_PATH_START_MARKER + "\n"
+ + "command -v " + executableName + "\n"
+ + "echo " + SHELL_PATH_END_MARKER + "\n"
+ + "echo " + SHELL_CONTRACT_START_MARKER + "\n"
+ + executableName + " " + CliConstants.VERSION_FLAG + " " + CliConstants.JSON_FLAG + "\n"
+ + "uloop_contract_status=$?\n"
+ + "echo " + SHELL_CONTRACT_END_MARKER + "\n"
+ + "echo " + SHELL_CONTRACT_STATUS_START_MARKER + "\n"
+ + "echo $uloop_contract_status\n"
+ + "echo " + SHELL_CONTRACT_STATUS_END_MARKER + "\n"
+ + "echo " + SHELL_VERSION_START_MARKER + "\n"
+ + executableName + " " + CliConstants.SHORT_VERSION_FLAG + "\n"
+ + "uloop_version_status=$?\n"
+ + "echo " + SHELL_VERSION_END_MARKER + "\n"
+ + "echo " + SHELL_VERSION_STATUS_START_MARKER + "\n"
+ + "echo $uloop_version_status\n"
+ + "echo " + SHELL_VERSION_STATUS_END_MARKER;
+ }
+
+ private static string BuildFishShellCliDetectionCommand(string executableName)
+ {
+ UnityEngine.Debug.Assert(!string.IsNullOrEmpty(executableName), "executableName must not be null or empty");
+
+ return "echo " + SHELL_PATH_START_MARKER + "\n"
+ + "command -v " + executableName + "\n"
+ + "echo " + SHELL_PATH_END_MARKER + "\n"
+ + "echo " + SHELL_CONTRACT_START_MARKER + "\n"
+ + executableName + " " + CliConstants.VERSION_FLAG + " " + CliConstants.JSON_FLAG + "\n"
+ + "set uloop_contract_status $status\n"
+ + "echo " + SHELL_CONTRACT_END_MARKER + "\n"
+ + "echo " + SHELL_CONTRACT_STATUS_START_MARKER + "\n"
+ + "echo $uloop_contract_status\n"
+ + "echo " + SHELL_CONTRACT_STATUS_END_MARKER + "\n"
+ + "echo " + SHELL_VERSION_START_MARKER + "\n"
+ + executableName + " " + CliConstants.SHORT_VERSION_FLAG + "\n"
+ + "set uloop_version_status $status\n"
+ + "echo " + SHELL_VERSION_END_MARKER + "\n"
+ + "echo " + SHELL_VERSION_STATUS_START_MARKER + "\n"
+ + "echo $uloop_version_status\n"
+ + "echo " + SHELL_VERSION_STATUS_END_MARKER;
+ }
+
+ public static CliInstallationDetection ParseShellCliInstallationOutput(string output)
+ {
+ string pathBlock = NodeEnvironmentResolver.ExtractBetweenMarkers(
+ output,
+ SHELL_PATH_START_MARKER,
+ SHELL_PATH_END_MARKER);
+ string versionBlock = NodeEnvironmentResolver.ExtractBetweenMarkers(
+ output,
+ SHELL_VERSION_START_MARKER,
+ SHELL_VERSION_END_MARKER);
+ string versionStatusBlock = NodeEnvironmentResolver.ExtractBetweenMarkers(
+ output,
+ SHELL_VERSION_STATUS_START_MARKER,
+ SHELL_VERSION_STATUS_END_MARKER);
+ string contractBlock = NodeEnvironmentResolver.ExtractBetweenMarkers(
+ output,
+ SHELL_CONTRACT_START_MARKER,
+ SHELL_CONTRACT_END_MARKER);
+ string contractStatusBlock = NodeEnvironmentResolver.ExtractBetweenMarkers(
+ output,
+ SHELL_CONTRACT_STATUS_START_MARKER,
+ SHELL_CONTRACT_STATUS_END_MARKER);
+ string executablePath = NodeEnvironmentResolver.ExtractAbsolutePathLine(pathBlock);
+ if (IsSuccessfulShellStatus(contractStatusBlock))
+ {
+ CliInstallationDetection contractDetection = ParseCliContractOutput(contractBlock, executablePath);
+ if (!string.IsNullOrEmpty(contractDetection.Version))
+ {
+ return contractDetection;
+ }
+ }
+
+ string version = IsSuccessfulShellStatus(versionStatusBlock)
+ ? ExtractFirstNonEmptyLine(versionBlock)
+ : null;
+ return new CliInstallationDetection(version, executablePath);
+ }
+
+ public static CliInstallationDetection ParseCliContractOutput(string output, string executablePath)
+ {
+ string jsonLine = ExtractFirstNonEmptyLine(output);
+ if (string.IsNullOrEmpty(jsonLine))
+ {
+ return new CliInstallationDetection(null, executablePath);
+ }
+
+ try
+ {
+ JObject parsed = JObject.Parse(jsonLine);
+ CliInstallationDetection dispatcherDetection = ParseDispatcherContract(parsed, executablePath);
+ if (!string.IsNullOrEmpty(dispatcherDetection.Version))
+ {
+ return dispatcherDetection;
+ }
+
+ string version = parsed[VERSION_JSON_PROJECT_RUNNER_VERSION_PROPERTY]?.ToString();
+ if (string.IsNullOrEmpty(version))
+ {
+ version = parsed[VERSION_JSON_LEGACY_CLI_VERSION_PROPERTY]?.ToString();
+ }
+ return new CliInstallationDetection(version, executablePath);
+ }
+ catch (JsonException)
+ {
+ return new CliInstallationDetection(null, executablePath);
+ }
+ }
+
+ private static CliInstallationDetection ParseDispatcherContract(JObject parsed, string executablePath)
+ {
+ // Why: dispatcher compatibility is enforced by the pin's minimumDispatcherVersion (semver floor),
+ // so identifying the dispatcher only needs its release version.
+ string dispatcherVersion = parsed[VERSION_JSON_DISPATCHER_VERSION_PROPERTY]?.ToString();
+ if (string.IsNullOrEmpty(dispatcherVersion))
+ {
+ return new CliInstallationDetection(null, executablePath);
+ }
+
+ return new CliInstallationDetection(
+ dispatcherVersion,
+ executablePath,
+ true);
+ }
+
+ private static bool IsSuccessfulShellStatus(string statusBlock)
+ {
+ string status = ExtractFirstNonEmptyLine(statusBlock);
+ return string.Equals(status, SHELL_SUCCESS_EXIT_CODE, StringComparison.Ordinal);
+ }
+
+ private static string ExtractFirstNonEmptyLine(string block)
+ {
+ if (string.IsNullOrEmpty(block))
+ {
+ return null;
+ }
+
+ string[] lines = block.Split('\n');
+ foreach (string rawLine in lines)
+ {
+ string line = rawLine.Trim();
+ if (!string.IsNullOrEmpty(line))
+ {
+ return line;
+ }
+ }
+
+ return null;
+ }
+
+ private static string QuoteProcessArgument(string value)
+ {
+ UnityEngine.Debug.Assert(value != null, "value must not be null");
+
+ return "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
+ }
+ }
+}
diff --git a/Packages/src/Editor/Infrastructure/CLI/CliShellInstallationProbe.cs.meta b/Packages/src/Editor/Infrastructure/CLI/CliShellInstallationProbe.cs.meta
new file mode 100644
index 0000000000..9cc61a29e6
--- /dev/null
+++ b/Packages/src/Editor/Infrastructure/CLI/CliShellInstallationProbe.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5adfd558b96847638990c9dcf3a51025
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/src/Editor/Infrastructure/ThirdPartyToolMigration/ThirdPartyToolMigrationAssemblyUsageReferenceRequirementRecorder.cs b/Packages/src/Editor/Infrastructure/ThirdPartyToolMigration/ThirdPartyToolMigrationAssemblyUsageReferenceRequirementRecorder.cs
new file mode 100644
index 0000000000..f408393bd6
--- /dev/null
+++ b/Packages/src/Editor/Infrastructure/ThirdPartyToolMigration/ThirdPartyToolMigrationAssemblyUsageReferenceRequirementRecorder.cs
@@ -0,0 +1,258 @@
+using System.Diagnostics;
+
+using static io.github.hatayama.UnityCliLoop.Infrastructure.ThirdPartyToolMigrationAssemblyScopedNameMap;
+
+using io.github.hatayama.UnityCliLoop.Domain;
+
+namespace io.github.hatayama.UnityCliLoop.Infrastructure
+{
+ ///
+ /// Records asmdef reference requirements from a single source file against scan-state collections.
+ ///
+ internal static class ThirdPartyToolMigrationAssemblyUsageReferenceRequirementRecorder
+ {
+ public static void Record(
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState,
+ string source,
+ string assemblyDirectory)
+ {
+ Debug.Assert(scanState != null, "scanState must not be null");
+ Debug.Assert(source != null, "source must not be null");
+ Debug.Assert(!string.IsNullOrEmpty(assemblyDirectory), "assemblyDirectory must not be null or empty");
+
+ string[] legacyAssemblyAliases = GetAssemblyScopedNames(
+ scanState.AssemblyScopedLegacyAliasesByDirectory,
+ assemblyDirectory);
+ string[] assemblyDeclaredTypeNames = GetAssemblyScopedNames(
+ scanState.AssemblyDeclaredTypeNamesByDirectory,
+ assemblyDirectory);
+ bool hasLegacyCSharpApi = ThirdPartyToolMigrationRules.ContainsLegacyCSharpApi(source);
+ RecordToolContractsRequirement(
+ scanState,
+ source,
+ assemblyDirectory,
+ legacyAssemblyAliases,
+ assemblyDeclaredTypeNames,
+ hasLegacyCSharpApi);
+ RecordRegistrarDomainReturnRequirement(scanState, source, assemblyDirectory, legacyAssemblyAliases);
+ RecordDomainContractRequirement(scanState, source, assemblyDirectory);
+ RecordFirstPartyScreenshotRequirement(
+ scanState,
+ source,
+ assemblyDirectory,
+ legacyAssemblyAliases,
+ assemblyDeclaredTypeNames,
+ hasLegacyCSharpApi);
+ RecordEditorWindowCaptureTimeoutRequirement(
+ scanState,
+ source,
+ assemblyDirectory,
+ legacyAssemblyAliases,
+ assemblyDeclaredTypeNames,
+ hasLegacyCSharpApi);
+ }
+
+ private static void RecordToolContractsRequirement(
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState,
+ string source,
+ string assemblyDirectory,
+ string[] legacyAssemblyAliases,
+ string[] assemblyDeclaredTypeNames,
+ bool hasLegacyCSharpApi)
+ {
+ string[] currentApplicationAssemblyAliases = GetAssemblyScopedNames(
+ scanState.AssemblyScopedCurrentApplicationAliasesByDirectory,
+ assemblyDirectory);
+ bool hasCurrentApplicationSourceTarget =
+ ThirdPartyToolMigrationRules.ContainsCurrentApplicationApiForAssembly(
+ source,
+ scanState.AssemblyScopedCurrentApplicationDirectories.Contains(assemblyDirectory),
+ currentApplicationAssemblyAliases,
+ assemblyDeclaredTypeNames);
+ if (!ContainsToolContractsReferenceRequirement(
+ scanState,
+ source,
+ assemblyDirectory,
+ legacyAssemblyAliases,
+ currentApplicationAssemblyAliases,
+ assemblyDeclaredTypeNames,
+ hasLegacyCSharpApi,
+ hasCurrentApplicationSourceTarget))
+ {
+ return;
+ }
+
+ scanState.ToolContractsReferenceAssemblyDirectories.Add(assemblyDirectory);
+ }
+
+ private static bool ContainsToolContractsReferenceRequirement(
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState,
+ string source,
+ string assemblyDirectory,
+ string[] legacyAssemblyAliases,
+ string[] currentApplicationAssemblyAliases,
+ string[] assemblyDeclaredTypeNames,
+ bool hasLegacyCSharpApi,
+ bool hasCurrentApplicationSourceTarget)
+ {
+ bool canUseLegacyAssemblyApi =
+ scanState.AssemblyScopedLegacyDirectories.Contains(assemblyDirectory) ||
+ hasLegacyCSharpApi ||
+ ThirdPartyToolMigrationRules.ContainsCurrentToolContractsApi(source) ||
+ scanState.AssemblyScopedCurrentToolContractsDirectories.Contains(assemblyDirectory) ||
+ scanState.AssemblyScopedCurrentApplicationDirectories.Contains(assemblyDirectory);
+ return ThirdPartyToolMigrationRules.ContainsLegacyRegistrarApiForAssembly(
+ source,
+ scanState.AssemblyScopedLegacyDirectories.Contains(assemblyDirectory),
+ legacyAssemblyAliases) ||
+ ThirdPartyToolMigrationRules.ContainsLegacyApplicationApiForAssembly(
+ source,
+ canUseLegacyAssemblyApi,
+ legacyAssemblyAliases,
+ currentApplicationAssemblyAliases,
+ assemblyDeclaredTypeNames) ||
+ hasCurrentApplicationSourceTarget;
+ }
+
+ private static void RecordRegistrarDomainReturnRequirement(
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState,
+ string source,
+ string assemblyDirectory,
+ string[] legacyAssemblyAliases)
+ {
+ if (!ThirdPartyToolMigrationRules.ContainsRegistrarDomainReturnApiForAssembly(
+ source,
+ scanState.AssemblyScopedLegacyDirectories.Contains(assemblyDirectory),
+ legacyAssemblyAliases))
+ {
+ return;
+ }
+
+ scanState.ToolContractsReferenceAssemblyDirectories.Add(assemblyDirectory);
+ }
+
+ private static void RecordDomainContractRequirement(
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState,
+ string source,
+ string assemblyDirectory)
+ {
+ string[] currentDomainAssemblyAliases = GetAssemblyScopedNames(
+ scanState.AssemblyScopedCurrentDomainAliasesByDirectory,
+ assemblyDirectory);
+ string[] currentDomainNamespaceAliases =
+ ThirdPartyToolMigrationAliasRules.GetCombinedCurrentDomainNamespaceAliases(
+ source,
+ currentDomainAssemblyAliases);
+ if (!ThirdPartyToolMigrationRules.ContainsCurrentDomainMetadataApiForAssembly(
+ source,
+ scanState.AssemblyScopedCurrentDomainDirectories.Contains(assemblyDirectory)) &&
+ !ThirdPartyToolMigrationRules.ContainsCurrentDomainContractAliasReference(
+ source,
+ currentDomainNamespaceAliases))
+ {
+ return;
+ }
+
+ scanState.ToolContractsReferenceAssemblyDirectories.Add(assemblyDirectory);
+ }
+
+ private static void RecordFirstPartyScreenshotRequirement(
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState,
+ string source,
+ string assemblyDirectory,
+ string[] legacyAssemblyAliases,
+ string[] assemblyDeclaredTypeNames,
+ bool hasLegacyCSharpApi)
+ {
+ string[] currentFirstPartyToolsAssemblyAliases = GetAssemblyScopedNames(
+ scanState.AssemblyScopedCurrentFirstPartyToolsAliasesByDirectory,
+ assemblyDirectory);
+ bool hasCurrentFirstPartyScreenshotReferenceRequirement =
+ ThirdPartyToolMigrationRules.ContainsCurrentFirstPartyScreenshotApiForAssembly(
+ source,
+ scanState.AssemblyScopedCurrentFirstPartyToolsDirectories.Contains(assemblyDirectory),
+ currentFirstPartyToolsAssemblyAliases,
+ assemblyDeclaredTypeNames);
+ if (ContainsFirstPartyScreenshotToolContractsRequirement(
+ scanState,
+ source,
+ assemblyDirectory,
+ legacyAssemblyAliases,
+ currentFirstPartyToolsAssemblyAliases,
+ assemblyDeclaredTypeNames,
+ hasLegacyCSharpApi,
+ hasCurrentFirstPartyScreenshotReferenceRequirement))
+ {
+ scanState.ToolContractsReferenceAssemblyDirectories.Add(assemblyDirectory);
+ }
+
+ if (hasCurrentFirstPartyScreenshotReferenceRequirement)
+ {
+ scanState.FirstPartyScreenshotReferenceAssemblyDirectories.Add(assemblyDirectory);
+ }
+ }
+
+ private static bool ContainsFirstPartyScreenshotToolContractsRequirement(
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState,
+ string source,
+ string assemblyDirectory,
+ string[] legacyAssemblyAliases,
+ string[] currentFirstPartyToolsAssemblyAliases,
+ string[] assemblyDeclaredTypeNames,
+ bool hasLegacyCSharpApi,
+ bool hasCurrentFirstPartyScreenshotReferenceRequirement)
+ {
+ bool hasAssemblyScopedCurrentToolContractsUsing =
+ scanState.AssemblyScopedCurrentToolContractsDirectories.Contains(assemblyDirectory);
+ bool hasAssemblyScopedCurrentFirstPartyToolsUsing =
+ scanState.AssemblyScopedCurrentFirstPartyToolsDirectories.Contains(assemblyDirectory);
+ return ThirdPartyToolMigrationRules.ContainsLegacyFirstPartyScreenshotApiForAssembly(
+ source,
+ scanState.AssemblyScopedLegacyDirectories.Contains(assemblyDirectory) ||
+ hasLegacyCSharpApi ||
+ ThirdPartyToolMigrationRules.ContainsCurrentToolContractsApi(source) ||
+ hasAssemblyScopedCurrentToolContractsUsing,
+ legacyAssemblyAliases,
+ assemblyDeclaredTypeNames) ||
+ ThirdPartyToolMigrationRules.ContainsLegacyEditorWindowCaptureUtilityMigrationForAssembly(
+ source,
+ scanState.AssemblyScopedLegacyDirectories.Contains(assemblyDirectory) || hasLegacyCSharpApi,
+ hasAssemblyScopedCurrentToolContractsUsing,
+ hasAssemblyScopedCurrentFirstPartyToolsUsing,
+ legacyAssemblyAliases,
+ currentFirstPartyToolsAssemblyAliases,
+ assemblyDeclaredTypeNames) ||
+ ThirdPartyToolMigrationRules.ContainsCurrentFirstPartyScreenshotContractApiForAssembly(
+ source,
+ hasAssemblyScopedCurrentFirstPartyToolsUsing,
+ currentFirstPartyToolsAssemblyAliases,
+ assemblyDeclaredTypeNames) ||
+ hasCurrentFirstPartyScreenshotReferenceRequirement;
+ }
+
+ private static void RecordEditorWindowCaptureTimeoutRequirement(
+ ThirdPartyToolMigrationAssemblyUsageScanState scanState,
+ string source,
+ string assemblyDirectory,
+ string[] legacyAssemblyAliases,
+ string[] assemblyDeclaredTypeNames,
+ bool hasLegacyCSharpApi)
+ {
+ if (!ThirdPartyToolMigrationRules.ContainsLegacyEditorWindowCaptureUtilityTimeoutMigrationForAssembly(
+ source,
+ scanState.AssemblyScopedLegacyDirectories.Contains(assemblyDirectory) || hasLegacyCSharpApi,
+ scanState.AssemblyScopedCurrentToolContractsDirectories.Contains(assemblyDirectory),
+ scanState.AssemblyScopedCurrentFirstPartyToolsDirectories.Contains(assemblyDirectory),
+ legacyAssemblyAliases,
+ GetAssemblyScopedNames(
+ scanState.AssemblyScopedCurrentFirstPartyToolsAliasesByDirectory,
+ assemblyDirectory),
+ assemblyDeclaredTypeNames))
+ {
+ return;
+ }
+
+ scanState.ToolContractsReferenceAssemblyDirectories.Add(assemblyDirectory);
+ }
+ }
+}
diff --git a/Packages/src/Editor/Infrastructure/ThirdPartyToolMigration/ThirdPartyToolMigrationAssemblyUsageReferenceRequirementRecorder.cs.meta b/Packages/src/Editor/Infrastructure/ThirdPartyToolMigration/ThirdPartyToolMigrationAssemblyUsageReferenceRequirementRecorder.cs.meta
new file mode 100644
index 0000000000..0fc4ad22de
--- /dev/null
+++ b/Packages/src/Editor/Infrastructure/ThirdPartyToolMigration/ThirdPartyToolMigrationAssemblyUsageReferenceRequirementRecorder.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d231db7e7c4c4bc0be5ae98261e4d23c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/src/Editor/Infrastructure/ThirdPartyToolMigration/ThirdPartyToolMigrationAssemblyUsageScanState.cs b/Packages/src/Editor/Infrastructure/ThirdPartyToolMigration/ThirdPartyToolMigrationAssemblyUsageScanState.cs
index b0b55b060b..8c881ca693 100644
--- a/Packages/src/Editor/Infrastructure/ThirdPartyToolMigration/ThirdPartyToolMigrationAssemblyUsageScanState.cs
+++ b/Packages/src/Editor/Infrastructure/ThirdPartyToolMigration/ThirdPartyToolMigrationAssemblyUsageScanState.cs
@@ -131,33 +131,10 @@ public void RecordReferenceRequirements(string source, string csharpFilePath)
}
string assemblyDirectory = FindAssemblyDirectory(csharpFilePath);
- string[] legacyAssemblyAliases = GetAssemblyScopedNames(
- AssemblyScopedLegacyAliasesByDirectory,
- assemblyDirectory);
- string[] assemblyDeclaredTypeNames = GetAssemblyScopedNames(
- AssemblyDeclaredTypeNamesByDirectory,
- assemblyDirectory);
- bool hasLegacyCSharpApi = ThirdPartyToolMigrationRules.ContainsLegacyCSharpApi(source);
- RecordToolContractsRequirement(
- source,
- assemblyDirectory,
- legacyAssemblyAliases,
- assemblyDeclaredTypeNames,
- hasLegacyCSharpApi);
- RecordRegistrarDomainReturnRequirement(source, assemblyDirectory, legacyAssemblyAliases);
- RecordDomainContractRequirement(source, assemblyDirectory);
- RecordFirstPartyScreenshotRequirement(
- source,
- assemblyDirectory,
- legacyAssemblyAliases,
- assemblyDeclaredTypeNames,
- hasLegacyCSharpApi);
- RecordEditorWindowCaptureTimeoutRequirement(
+ ThirdPartyToolMigrationAssemblyUsageReferenceRequirementRecorder.Record(
+ this,
source,
- assemblyDirectory,
- legacyAssemblyAliases,
- assemblyDeclaredTypeNames,
- hasLegacyCSharpApi);
+ assemblyDirectory);
}
public MigrationAssemblyUsage CreateUsage()
@@ -353,196 +330,6 @@ private void RecordDomainMetadataSourceFacts(string source, string assemblyDirec
}
}
- private void RecordToolContractsRequirement(
- string source,
- string assemblyDirectory,
- string[] legacyAssemblyAliases,
- string[] assemblyDeclaredTypeNames,
- bool hasLegacyCSharpApi)
- {
- string[] currentApplicationAssemblyAliases = GetAssemblyScopedNames(
- AssemblyScopedCurrentApplicationAliasesByDirectory,
- assemblyDirectory);
- bool hasCurrentApplicationSourceTarget =
- ThirdPartyToolMigrationRules.ContainsCurrentApplicationApiForAssembly(
- source,
- AssemblyScopedCurrentApplicationDirectories.Contains(assemblyDirectory),
- currentApplicationAssemblyAliases,
- assemblyDeclaredTypeNames);
- if (!ContainsToolContractsReferenceRequirement(
- source,
- assemblyDirectory,
- legacyAssemblyAliases,
- currentApplicationAssemblyAliases,
- assemblyDeclaredTypeNames,
- hasLegacyCSharpApi,
- hasCurrentApplicationSourceTarget))
- {
- return;
- }
-
- ToolContractsReferenceAssemblyDirectories.Add(assemblyDirectory);
- }
-
- private bool ContainsToolContractsReferenceRequirement(
- string source,
- string assemblyDirectory,
- string[] legacyAssemblyAliases,
- string[] currentApplicationAssemblyAliases,
- string[] assemblyDeclaredTypeNames,
- bool hasLegacyCSharpApi,
- bool hasCurrentApplicationSourceTarget)
- {
- bool canUseLegacyAssemblyApi =
- AssemblyScopedLegacyDirectories.Contains(assemblyDirectory) ||
- hasLegacyCSharpApi ||
- ThirdPartyToolMigrationRules.ContainsCurrentToolContractsApi(source) ||
- AssemblyScopedCurrentToolContractsDirectories.Contains(assemblyDirectory) ||
- AssemblyScopedCurrentApplicationDirectories.Contains(assemblyDirectory);
- return ThirdPartyToolMigrationRules.ContainsLegacyRegistrarApiForAssembly(
- source,
- AssemblyScopedLegacyDirectories.Contains(assemblyDirectory),
- legacyAssemblyAliases) ||
- ThirdPartyToolMigrationRules.ContainsLegacyApplicationApiForAssembly(
- source,
- canUseLegacyAssemblyApi,
- legacyAssemblyAliases,
- currentApplicationAssemblyAliases,
- assemblyDeclaredTypeNames) ||
- hasCurrentApplicationSourceTarget;
- }
-
- private void RecordRegistrarDomainReturnRequirement(
- string source,
- string assemblyDirectory,
- string[] legacyAssemblyAliases)
- {
- if (!ThirdPartyToolMigrationRules.ContainsRegistrarDomainReturnApiForAssembly(
- source,
- AssemblyScopedLegacyDirectories.Contains(assemblyDirectory),
- legacyAssemblyAliases))
- {
- return;
- }
-
- ToolContractsReferenceAssemblyDirectories.Add(assemblyDirectory);
- }
-
- private void RecordDomainContractRequirement(string source, string assemblyDirectory)
- {
- string[] currentDomainAssemblyAliases = GetAssemblyScopedNames(
- AssemblyScopedCurrentDomainAliasesByDirectory,
- assemblyDirectory);
- string[] currentDomainNamespaceAliases =
- ThirdPartyToolMigrationAliasRules.GetCombinedCurrentDomainNamespaceAliases(
- source,
- currentDomainAssemblyAliases);
- if (!ThirdPartyToolMigrationRules.ContainsCurrentDomainMetadataApiForAssembly(
- source,
- AssemblyScopedCurrentDomainDirectories.Contains(assemblyDirectory)) &&
- !ThirdPartyToolMigrationRules.ContainsCurrentDomainContractAliasReference(
- source,
- currentDomainNamespaceAliases))
- {
- return;
- }
-
- ToolContractsReferenceAssemblyDirectories.Add(assemblyDirectory);
- }
-
- private void RecordFirstPartyScreenshotRequirement(
- string source,
- string assemblyDirectory,
- string[] legacyAssemblyAliases,
- string[] assemblyDeclaredTypeNames,
- bool hasLegacyCSharpApi)
- {
- string[] currentFirstPartyToolsAssemblyAliases = GetAssemblyScopedNames(
- AssemblyScopedCurrentFirstPartyToolsAliasesByDirectory,
- assemblyDirectory);
- bool hasCurrentFirstPartyScreenshotReferenceRequirement =
- ThirdPartyToolMigrationRules.ContainsCurrentFirstPartyScreenshotApiForAssembly(
- source,
- AssemblyScopedCurrentFirstPartyToolsDirectories.Contains(assemblyDirectory),
- currentFirstPartyToolsAssemblyAliases,
- assemblyDeclaredTypeNames);
- if (ContainsFirstPartyScreenshotToolContractsRequirement(
- source,
- assemblyDirectory,
- legacyAssemblyAliases,
- currentFirstPartyToolsAssemblyAliases,
- assemblyDeclaredTypeNames,
- hasLegacyCSharpApi,
- hasCurrentFirstPartyScreenshotReferenceRequirement))
- {
- ToolContractsReferenceAssemblyDirectories.Add(assemblyDirectory);
- }
-
- if (hasCurrentFirstPartyScreenshotReferenceRequirement)
- {
- FirstPartyScreenshotReferenceAssemblyDirectories.Add(assemblyDirectory);
- }
- }
-
- private bool ContainsFirstPartyScreenshotToolContractsRequirement(
- string source,
- string assemblyDirectory,
- string[] legacyAssemblyAliases,
- string[] currentFirstPartyToolsAssemblyAliases,
- string[] assemblyDeclaredTypeNames,
- bool hasLegacyCSharpApi,
- bool hasCurrentFirstPartyScreenshotReferenceRequirement)
- {
- bool hasAssemblyScopedCurrentToolContractsUsing =
- AssemblyScopedCurrentToolContractsDirectories.Contains(assemblyDirectory);
- bool hasAssemblyScopedCurrentFirstPartyToolsUsing =
- AssemblyScopedCurrentFirstPartyToolsDirectories.Contains(assemblyDirectory);
- return ThirdPartyToolMigrationRules.ContainsLegacyFirstPartyScreenshotApiForAssembly(
- source,
- AssemblyScopedLegacyDirectories.Contains(assemblyDirectory) ||
- hasLegacyCSharpApi ||
- ThirdPartyToolMigrationRules.ContainsCurrentToolContractsApi(source) ||
- hasAssemblyScopedCurrentToolContractsUsing,
- legacyAssemblyAliases,
- assemblyDeclaredTypeNames) ||
- ThirdPartyToolMigrationRules.ContainsLegacyEditorWindowCaptureUtilityMigrationForAssembly(
- source,
- AssemblyScopedLegacyDirectories.Contains(assemblyDirectory) || hasLegacyCSharpApi,
- hasAssemblyScopedCurrentToolContractsUsing,
- hasAssemblyScopedCurrentFirstPartyToolsUsing,
- legacyAssemblyAliases,
- currentFirstPartyToolsAssemblyAliases,
- assemblyDeclaredTypeNames) ||
- ThirdPartyToolMigrationRules.ContainsCurrentFirstPartyScreenshotContractApiForAssembly(
- source,
- hasAssemblyScopedCurrentFirstPartyToolsUsing,
- currentFirstPartyToolsAssemblyAliases,
- assemblyDeclaredTypeNames) ||
- hasCurrentFirstPartyScreenshotReferenceRequirement;
- }
-
- private void RecordEditorWindowCaptureTimeoutRequirement(
- string source,
- string assemblyDirectory,
- string[] legacyAssemblyAliases,
- string[] assemblyDeclaredTypeNames,
- bool hasLegacyCSharpApi)
- {
- if (!ThirdPartyToolMigrationRules.ContainsLegacyEditorWindowCaptureUtilityTimeoutMigrationForAssembly(
- source,
- AssemblyScopedLegacyDirectories.Contains(assemblyDirectory) || hasLegacyCSharpApi,
- AssemblyScopedCurrentToolContractsDirectories.Contains(assemblyDirectory),
- AssemblyScopedCurrentFirstPartyToolsDirectories.Contains(assemblyDirectory),
- legacyAssemblyAliases,
- GetAssemblyScopedNames(AssemblyScopedCurrentFirstPartyToolsAliasesByDirectory, assemblyDirectory),
- assemblyDeclaredTypeNames))
- {
- return;
- }
-
- ToolContractsReferenceAssemblyDirectories.Add(assemblyDirectory);
- }
-
private void AddRegistrarApplicationReferences()
{
foreach (string registrarAssemblyDirectory in RegistrarAssemblyDirectories)