-
Notifications
You must be signed in to change notification settings - Fork 48
refactor: update FindRepoLatest to prioritize repo priority, version, and architecture with lock support. #202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
e41f4ed
10c4f78
f933de6
32bb6e5
9aa616c
997ae92
5f90456
16e11a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,7 @@ import ( | |
| "net/url" | ||
| "os" | ||
| "path/filepath" | ||
| "sort" | ||
| "strings" | ||
| "time" | ||
|
|
||
|
|
@@ -357,8 +358,7 @@ func decode(index io.ReadCloser, ct, url, cf string) ([]goolib.RepoSpec, error) | |
| return nil, err | ||
| } | ||
|
|
||
| // The .url files aren't used by googet but help developers and the | ||
| // curious figure out which file belongs to which repo/URL. | ||
| // The .url files aren't used by googet but help identify which file belongs to which repo/URL. | ||
| mf := fmt.Sprintf("%s.url", strings.TrimSuffix(cf, filepath.Ext(cf))) | ||
| if err = ioutil.WriteFile(mf, []byte(url), 0644); err != nil { | ||
| logger.Errorf("Failed to write '%s': %v", mf, err) | ||
|
|
@@ -407,62 +407,101 @@ func latest(psm map[string][]*goolib.PkgSpec, rm RepoMap) (*goolib.PkgSpec, stri | |
|
|
||
| // FindRepoLatest returns the latest version of a package along with its repo and arch. | ||
| // It checks both direct name matches and "Provides" entries. | ||
| // The archs are searched in order; if a matching package is found for any arch, it is | ||
| // returned immediately even if a later arch might have a later version. | ||
| func FindRepoLatest(pi goolib.PackageInfo, rm RepoMap, archs []string) (*goolib.PkgSpec, string, string, error) { | ||
| // The search order is: | ||
| // 1. Repo Priority (High > Low) | ||
| // 2. Version (New > Old) | ||
| // 3. Architecture Preference (as defined by archs slice order) | ||
| func FindRepoLatest(pi goolib.PackageInfo, rm RepoMap, archs []string, installedArch string, isLocked bool) (*goolib.PkgSpec, string, string, error) { | ||
| name := pi.Name | ||
| if pi.Arch != "" { | ||
| archs = []string{pi.Arch} | ||
| name = fmt.Sprintf("%s.%s", pi.Name, pi.Arch) | ||
| } | ||
|
|
||
| for _, a := range archs { | ||
| psmDirect := make(map[string][]*goolib.PkgSpec) | ||
| psmProvides := make(map[string][]*goolib.PkgSpec) | ||
| archPref := make(map[string]int) | ||
| for i, a := range archs { | ||
| archPref[a] = i | ||
| } | ||
|
|
||
| for u, r := range rm { | ||
| for _, p := range r.Packages { | ||
| ps := p.PackageSpec | ||
| if ps.Arch != a { | ||
| continue | ||
| } | ||
| type candidate struct { | ||
| spec *goolib.PkgSpec | ||
| repo string | ||
| priority priority.Value | ||
| } | ||
| var directCandidates []candidate | ||
| var providesCandidates []candidate | ||
|
|
||
| // Check exact match | ||
| if ps.Name == pi.Name { | ||
| if satisfiesVersion(ps.Version, pi.Ver) { | ||
| psmDirect[u] = append(psmDirect[u], ps) | ||
| } | ||
| // Skip checking Provides if the package itself is a direct match. | ||
| continue | ||
| for u, r := range rm { | ||
| for _, p := range r.Packages { | ||
| ps := p.PackageSpec | ||
|
|
||
| if _, ok := archPref[ps.Arch]; !ok { | ||
| continue | ||
| } | ||
|
|
||
| if ps.Name == pi.Name { | ||
| if satisfiesVersion(ps.Version, pi.Ver) { | ||
| directCandidates = append(directCandidates, candidate{ps, u, r.Priority}) | ||
| } | ||
| continue | ||
| } | ||
|
|
||
| // Check provides | ||
| for _, prov := range ps.Provides { | ||
| if SatisfiesProvider(prov, pi.Name, pi.Ver) { | ||
| psmProvides[u] = append(psmProvides[u], ps) | ||
| break | ||
| } | ||
| for _, prov := range ps.Provides { | ||
| if SatisfiesProvider(prov, pi.Name, pi.Ver) { | ||
| providesCandidates = append(providesCandidates, candidate{ps, u, r.Priority}) | ||
| break | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Prioritize direct package matches over virtual package providers. | ||
| if len(psmDirect) > 0 { | ||
| pkg, repo := latest(psmDirect, rm) | ||
| if pkg != nil { | ||
| return pkg, repo, a, nil | ||
| sortFunc := func(list []candidate) func(i, j int) bool { | ||
|
jm2 marked this conversation as resolved.
Outdated
|
||
| return func(i, j int) bool { | ||
| if list[i].priority != list[j].priority { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't this duplicating the logic of ComparePriorityVersion? If you need a descending sort, just flip the values or sort ascending and reverse. Alternately use an ascending sort and iterate over the result with slices.Backward. |
||
| return list[i].priority > list[j].priority | ||
| } | ||
| cmp, err := goolib.Compare(list[i].spec.Version, list[j].spec.Version) | ||
| if err != nil { | ||
| logger.Errorf("Error comparing package versions: %v", err) | ||
| return false // maintain order in case of error | ||
| } | ||
| if cmp != 0 { | ||
| return cmp > 0 | ||
| } | ||
| return archPref[list[i].spec.Arch] < archPref[list[j].spec.Arch] | ||
| } | ||
| } | ||
|
|
||
| // If no direct matches, check providers. | ||
| // Note: This matches Arch behavior (prefer real package). | ||
| if len(psmProvides) > 0 { | ||
| pkg, repo := latest(psmProvides, rm) | ||
| if pkg != nil { | ||
| return pkg, repo, a, nil | ||
| filterAndReturn := func(list []candidate) (*goolib.PkgSpec, string, string, error) { | ||
|
jm2 marked this conversation as resolved.
Outdated
|
||
| if len(list) == 0 { | ||
| return nil, "", "", fmt.Errorf("no package found") | ||
| } | ||
| sort.Slice(list, sortFunc(list)) | ||
| for _, cand := range list { | ||
| if isLocked && cand.spec.Arch != installedArch { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Combine nested ifs into the equivalent if isLocked && cand.spec.Arch != installedArch && cand.spec.LockArch { ... } |
||
| if cand.spec.LockArch { | ||
| continue // Ignore this candidate | ||
| } | ||
| } | ||
| return cand.spec, cand.repo, cand.spec.Arch, nil | ||
| } | ||
| return nil, "", "", fmt.Errorf("no package found satisfying lock conditions") | ||
| } | ||
|
|
||
| if len(directCandidates) > 0 { | ||
|
jm2 marked this conversation as resolved.
Outdated
|
||
| spec, repo, arch, err := filterAndReturn(directCandidates) | ||
| if err == nil { | ||
| return spec, repo, arch, nil | ||
| } | ||
| } | ||
|
|
||
| if len(providesCandidates) > 0 { | ||
| spec, repo, arch, err := filterAndReturn(providesCandidates) | ||
| if err == nil { | ||
| return spec, repo, arch, nil | ||
| } | ||
| } | ||
|
|
||
| return nil, "", "", fmt.Errorf("no package found satisfying %s in any repo", name) | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.