diff --git a/cli/dispatcher/internal/dispatcher/dispatcher_pin.go b/cli/dispatcher/internal/dispatcher/dispatcher_pin.go index 9f52f7d69..3ddef159d 100644 --- a/cli/dispatcher/internal/dispatcher/dispatcher_pin.go +++ b/cli/dispatcher/internal/dispatcher/dispatcher_pin.go @@ -53,16 +53,16 @@ func dispatcherPinCandidatePaths(projectRoot string) []dispatcherPinCandidatePat {Path: filepath.Join(projectRoot, "Packages", "src", dispatcherPackagePinFileName)}, {Path: filepath.Join(projectRoot, "Packages", dispatcherUnityPackageName, dispatcherPackagePinFileName)}, } - packageCachePattern := filepath.Join( - projectRoot, - "Library", - "PackageCache", - dispatcherUnityPackageName+"@*", - dispatcherPackagePinFileName) - matches, err := filepath.Glob(packageCachePattern) + packageCacheDirectory := filepath.Join(projectRoot, "Library", "PackageCache") + entries, err := os.ReadDir(packageCacheDirectory) if err == nil { - for _, match := range matches { - paths = append(paths, dispatcherPinCandidatePath{Path: match}) + packageDirectoryPrefix := dispatcherUnityPackageName + "@" + for _, entry := range entries { + if !entry.IsDir() || !strings.HasPrefix(entry.Name(), packageDirectoryPrefix) { + continue + } + pinPath := filepath.Join(packageCacheDirectory, entry.Name(), dispatcherPackagePinFileName) + paths = append(paths, dispatcherPinCandidatePath{Path: pinPath}) } } return paths diff --git a/cli/dispatcher/internal/dispatcher/dispatcher_test.go b/cli/dispatcher/internal/dispatcher/dispatcher_test.go index 8db78cd3c..ec605ee86 100644 --- a/cli/dispatcher/internal/dispatcher/dispatcher_test.go +++ b/cli/dispatcher/internal/dispatcher/dispatcher_test.go @@ -852,6 +852,26 @@ func TestLoadDispatcherPinSkipsInvalidPackageCandidate(t *testing.T) { } } +func TestLoadDispatcherPinFindsPackageCachePinWithBracketedProjectPath(t *testing.T) { + // Verifies PackageCache pin discovery treats glob metacharacters in the project path literally. + projectRoot := filepath.Join(t.TempDir(), "project[legacy]") + for _, directory := range []string{"Assets", "ProjectSettings"} { + if err := os.MkdirAll(filepath.Join(projectRoot, directory), 0o755); err != nil { + t.Fatalf("failed to create Unity project directory: %v", err) + } + } + cachePackageRoot := filepath.Join(projectRoot, "Library", "PackageCache", dispatcherUnityPackageName+"@3.0.0-beta.57") + writeDispatcherPinFile(t, filepath.Join(cachePackageRoot, dispatcherPackagePinFileName), "3.0.0-beta.57") + + pin, err := loadDispatcherPin(projectRoot) + if err != nil { + t.Fatalf("loadDispatcherPin failed: %v", err) + } + if pin.ProjectRunnerVersion != "3.0.0-beta.57" { + t.Fatalf("projectRunnerVersion mismatch: %s", pin.ProjectRunnerVersion) + } +} + func TestLoadDispatcherPinNormalizesVersionPrefixes(t *testing.T) { // Verifies v-prefixed pin versions are normalized before semantic-version validation. projectRoot := createDispatcherUnityProject(t)