diff --git a/internal/core/domain/cacheInfo_test.go b/internal/core/domain/cacheInfo_test.go index 2032091e..08207f5d 100644 --- a/internal/core/domain/cacheInfo_test.go +++ b/internal/core/domain/cacheInfo_test.go @@ -16,8 +16,8 @@ func TestNewRepoInfo(t *testing.T) { t.Errorf("NewRepoInfo().Key = %q, want %q", info.Key, dep.HashName()) } - if info.Name != "horse" { - t.Errorf("NewRepoInfo().Name = %q, want %q", info.Name, "horse") + if info.Name != "github_com_hashload_horse" { + t.Errorf("NewRepoInfo().Name = %q, want %q", info.Name, "github_com_hashload_horse") } if len(info.Versions) != 3 { diff --git a/internal/core/domain/dependency.go b/internal/core/domain/dependency.go index d041c69e..142b6cf1 100644 --- a/internal/core/domain/dependency.go +++ b/internal/core/domain/dependency.go @@ -121,9 +121,30 @@ func GetDependenciesNames(deps []Dependency) []string { return dependencies } -// Name returns the name of the dependency extracted from the repository URL. +// Name returns the unique, collision-free name of the dependency based on its repository URL. func (p *Dependency) Name() string { - return reDepName.FindString(p.Repository) + repo := p.Repository + // Trim protocol and credentials + repo = strings.TrimPrefix(repo, "https://") + repo = strings.TrimPrefix(repo, "http://") + if idx := strings.Index(repo, "@"); idx != -1 { + repo = repo[idx+1:] + } + // Replace colon with slash (for SSH format like git@github.com:owner/repo) + repo = strings.ReplaceAll(repo, ":", "/") + // Trim trailing .git and slashes + repo = strings.TrimSuffix(repo, ".git") + repo = strings.TrimSuffix(repo, "/") + + parts := strings.Split(repo, "/") + if len(parts) <= 1 { + return repo + } + + // Join with underscore and replace dots in host/domain to get a clean, safe folder name + res := strings.Join(parts, "_") + res = strings.ReplaceAll(res, ".", "_") + return res } // GetKey returns the normalized key for the dependency (lowercase repository). diff --git a/internal/core/domain/dependency_test.go b/internal/core/domain/dependency_test.go index cc2d0bd9..4d7b214e 100644 --- a/internal/core/domain/dependency_test.go +++ b/internal/core/domain/dependency_test.go @@ -15,27 +15,27 @@ func TestDependency_Name(t *testing.T) { { name: "github repository", repository: "github.com/hashload/boss", - expected: "boss", + expected: "github_com_hashload_boss", }, { name: "gitlab repository", repository: "gitlab.com/user/project", - expected: "project", + expected: "gitlab_com_user_project", }, { name: "bitbucket repository", repository: "bitbucket.org/team/repo", - expected: "repo", + expected: "bitbucket_org_team_repo", }, { name: "nested path repository", repository: "github.com/org/group/subgroup/repo", - expected: "repo", + expected: "github_com_org_group_subgroup_repo", }, { name: "repository with trailing slash", repository: "github.com/hashload/boss/", - expected: "boss/", + expected: "github_com_hashload_boss", }, { name: "simple name", @@ -263,7 +263,7 @@ func TestGetDependenciesNames(t *testing.T) { t.Errorf("GetDependenciesNames() returned %d names, want 3", len(names)) } - expectedNames := []string{"boss", "horse", "repo"} + expectedNames := []string{"github_com_hashload_boss", "github_com_hashload_horse", "github_com_user_repo"} for i, expected := range expectedNames { if names[i] != expected { t.Errorf("GetDependenciesNames()[%d] = %q, want %q", i, names[i], expected) diff --git a/internal/core/services/cache/cache_service_test.go b/internal/core/services/cache/cache_service_test.go index e8692485..a4ee0773 100644 --- a/internal/core/services/cache/cache_service_test.go +++ b/internal/core/services/cache/cache_service_test.go @@ -115,8 +115,8 @@ func TestService_SaveAndLoadRepositoryDetails(t *testing.T) { t.Fatalf("LoadRepositoryData() error = %v", err) } - if info.Name != "horse" { - t.Errorf("LoadRepositoryData().Name = %q, want %q", info.Name, "horse") + if info.Name != "github_com_hashload_horse" { + t.Errorf("LoadRepositoryData().Name = %q, want %q", info.Name, "github_com_hashload_horse") } if len(info.Versions) != 3 { diff --git a/internal/core/services/installer/core.go b/internal/core/services/installer/core.go index b22c080c..5621d416 100644 --- a/internal/core/services/installer/core.go +++ b/internal/core/services/installer/core.go @@ -440,7 +440,9 @@ func (ic *installContext) reportInstallResult(depName, warning string) { } func (ic *installContext) shouldSkipDependency(dep domain.Dependency) bool { - if utils.Contains(ic.options.ForceUpdate, dep.Name()) { + if utils.Contains(ic.options.ForceUpdate, dep.Repository) || + utils.Contains(ic.options.ForceUpdate, dep.Name()) || + utils.Contains(ic.options.ForceUpdate, ParseDependency(dep.Name())) { return false } diff --git a/internal/core/services/paths/paths_test.go b/internal/core/services/paths/paths_test.go index 514d6939..df1c4d73 100644 --- a/internal/core/services/paths/paths_test.go +++ b/internal/core/services/paths/paths_test.go @@ -94,6 +94,10 @@ func TestEnsureCleanModulesDir_RemovesOldDependencies(t *testing.T) { t.Fatalf("Failed to create modules dir: %v", err) } + // Define current dependencies + dep := domain.ParseDependency("github.com/hashload/horse", "^1.0.0") + deps := []domain.Dependency{dep} + // Create an old dependency directory that should be removed oldDepDir := filepath.Join(modulesDir, "old-dependency") if err := os.MkdirAll(oldDepDir, 0755); err != nil { @@ -101,14 +105,10 @@ func TestEnsureCleanModulesDir_RemovesOldDependencies(t *testing.T) { } // Create a current dependency directory that should be kept - currentDepDir := filepath.Join(modulesDir, "horse") + currentDepDir := filepath.Join(modulesDir, dep.Name()) if err := os.MkdirAll(currentDepDir, 0755); err != nil { t.Fatalf("Failed to create current dependency dir: %v", err) } - - // Define current dependencies - dep := domain.ParseDependency("github.com/hashload/horse", "^1.0.0") - deps := []domain.Dependency{dep} lock := domain.PackageLock{ Installed: map[string]domain.LockedDependency{}, } diff --git a/utils/librarypath/dproj_util.go b/utils/librarypath/dproj_util.go index c9006275..c7a10f9f 100644 --- a/utils/librarypath/dproj_util.go +++ b/utils/librarypath/dproj_util.go @@ -24,10 +24,9 @@ var ( // updateDprojLibraryPath updates the library path in the project file. func updateDprojLibraryPath(pkg *domain.Package) { - var isLazarus = isLazarus() var projectNames = GetProjectNames(pkg) for _, projectName := range projectNames { - if isLazarus { + if isLazarusFile(projectName) { updateOtherUnitFilesProject(projectName) } else { updateLibraryPathProject(projectName) @@ -35,6 +34,13 @@ func updateDprojLibraryPath(pkg *domain.Package) { } } +// isLazarusFile checks if a specific project file is a Lazarus project or package. +func isLazarusFile(filename string) bool { + lower := strings.ToLower(filename) + return strings.HasSuffix(lower, consts.FileExtensionLpi) || + strings.HasSuffix(lower, consts.FileExtensionLpk) +} + // updateOtherUnitFilesProject updates the other unit files in the project file. func updateOtherUnitFilesProject(lpiName string) { doc := etree.NewDocument() @@ -100,10 +106,9 @@ func createTagOtherUnitFiles(node *etree.Element) *etree.Element { // updateGlobalBrowsingPath updates the global browsing path. func updateGlobalBrowsingPath(pkg *domain.Package) { - var isLazarus = isLazarus() var projectNames = GetProjectNames(pkg) for i, projectName := range projectNames { - if !isLazarus { + if !isLazarusFile(projectName) { updateGlobalBrowsingByProject(projectName, i == 0) } } @@ -160,7 +165,13 @@ func GetProjectNames(pkg *domain.Package) []string { var result []string if len(pkg.Projects) > 0 { - result = pkg.Projects + for _, project := range pkg.Projects { + if filepath.IsAbs(project) { + result = append(result, project) + } else { + result = append(result, filepath.Join(env.GetCurrentDir(), project)) + } + } } else { files, err := os.ReadDir(env.GetCurrentDir()) if err != nil {