xplshn
·
2025-08-13
findURL.go
Go
1package main
2
3import (
4 "fmt"
5 "path/filepath"
6 "strings"
7
8 "github.com/zeebo/errs"
9)
10
11func findMatchingBins(bEntry binaryEntry, uRepoIndex []binaryEntry) []binaryEntry {
12 var matchingBins []binaryEntry
13
14 for _, bin := range uRepoIndex {
15 // Match based on the format hierarchy: name#id:version@repo, name#id@repo, name#id:version, name#id, name@repo, name
16 matches := false
17 if bin.Name == bEntry.Name {
18 // name#id:version@repo
19 if bEntry.PkgID != "" && bEntry.Version != "" && bEntry.Repository.Name != "" {
20 if bin.PkgID == bEntry.PkgID && (bin.Version == bEntry.Version || hasMatchingSnapshot(&bin, bEntry.Version)) && bin.Repository.Name == bEntry.Repository.Name {
21 matches = true
22 }
23 // name#id:version
24 } else if bEntry.PkgID != "" && bEntry.Version != "" && bEntry.Repository.Name == "" {
25 if bin.PkgID == bEntry.PkgID && (bin.Version == bEntry.Version || hasMatchingSnapshot(&bin, bEntry.Version)) {
26 matches = true
27 }
28 // name#id@repo
29 } else if bEntry.PkgID != "" && bEntry.Repository.Name != "" && bEntry.Version == "" {
30 if bin.PkgID == bEntry.PkgID && bin.Repository.Name == bEntry.Repository.Name {
31 matches = true
32 }
33 // name#id
34 } else if bEntry.PkgID != "" && bEntry.Version == "" && bEntry.Repository.Name == "" {
35 if bin.PkgID == bEntry.PkgID {
36 matches = true
37 }
38 // name@repo
39 } else if bEntry.PkgID == "" && bEntry.Repository.Name != "" && bEntry.Version == "" {
40 if bin.Repository.Name == bEntry.Repository.Name {
41 matches = true
42 }
43 // name
44 } else if bEntry.PkgID == "" && bEntry.Version == "" && bEntry.Repository.Name == "" {
45 matches = true
46 }
47 }
48
49 if matches {
50 matchingBins = append(matchingBins, bin)
51 }
52 }
53
54 return matchingBins
55}
56
57// Helper function to check if a snapshot matches the requested version or commit, and if so, modify the DownloadURL
58func hasMatchingSnapshot(bin *binaryEntry, version string) bool {
59 if !strings.HasPrefix(bin.DownloadURL, "oci://") {
60 return false
61 }
62
63 // First, check all snapshot commits
64 for _, snap := range bin.Snapshots {
65 if version == snap.Commit {
66 // Modify the URL to use the snapshot's commit for OCI URLs
67 idx := strings.LastIndex(bin.DownloadURL, ":")
68 if idx != -1 {
69 bin.DownloadURL = bin.DownloadURL[:idx+1] + snap.Commit
70 bin.Bsum = "!no_check"
71 bin.Version = snap.Version
72 }
73 return true
74 }
75 }
76
77 // Then, check all snapshot versions
78 for _, snap := range bin.Snapshots {
79 if version == snap.Version {
80 // Modify the URL to use the snapshot's commit for OCI URLs
81 idx := strings.LastIndex(bin.DownloadURL, ":")
82 if idx != -1 {
83 bin.DownloadURL = bin.DownloadURL[:idx+1] + snap.Commit
84 bin.Bsum = "!no_check"
85 bin.Version = snap.Version
86 }
87 return true
88 }
89 }
90 return false
91}
92
93func findURL(bEntries []binaryEntry, uRepoIndex []binaryEntry, config *config) ([]binaryEntry, error) {
94 // Check for duplicate names in bEntries
95 nameCount := make(map[string]int)
96 for _, bEntry := range bEntries {
97 nameCount[bEntry.Name]++
98 if nameCount[bEntry.Name] > 1 {
99 return nil, errs.New("duplicate binary name '%s' provided in input", bEntry.Name)
100 }
101 }
102
103 var results []binaryEntry
104 var allErrors []error
105 allFailed := true
106
107 for _, bEntry := range bEntries {
108 if bEntry.Bsum == "!no_check" {
109 results = append(results, bEntry)
110 if verbosityLevel >= extraVerbose {
111 fmt.Printf("\033[2K\rSkipping resolution for \"%s\" (its Bsum was marked as \"!no_check\" by stringToBinaryEntry())\n", bEntry.Name)
112 }
113 allFailed = false
114 continue
115 } else {
116 // Check if the binary is installed and update bEntry with installed metadata if available
117 if instBEntry := bEntryOfinstalledBinary(filepath.Join(config.InstallDir, bEntry.Name)); instBEntry.Name != "" {
118 if bEntry.PkgID == "" {
119 bEntry.PkgID = instBEntry.PkgID
120 }
121 if bEntry.Version == "" {
122 bEntry.Version = instBEntry.Version
123 }
124 if bEntry.Repository.Name == "" {
125 bEntry.Repository.Name = instBEntry.Repository.Name
126 }
127 }
128
129 matchingBins := findMatchingBins(bEntry, uRepoIndex)
130
131 if len(matchingBins) == 0 {
132 results = append(results, binaryEntry{
133 Name: bEntry.Name,
134 DownloadURL: "!not_found",
135 Bsum: "!no_check",
136 })
137 allErrors = append(allErrors, fmt.Errorf("didn't find download URL for [%s]", parseBinaryEntry(bEntry, false)))
138 continue
139 }
140
141 allFailed = false
142
143 // If a repository is specified, select the binary from that repository
144 if bEntry.Repository.Name != "" {
145 for _, bin := range matchingBins {
146 if bin.Repository.Name == bEntry.Repository.Name {
147 results = append(results, bin)
148 if verbosityLevel >= extraVerbose {
149 fmt.Printf("\033[2K\rFound \"%s\" with id=%s version=%s repo=%s\n", bEntry.Name, bin.PkgID, bin.Version, bin.Repository.Name)
150 }
151 break
152 }
153 }
154 // If no match with the specified repo, add an error
155 if len(results) == len(bEntries)-1 {
156 results = append(results, binaryEntry{
157 Name: bEntry.Name,
158 DownloadURL: "!not_found",
159 Bsum: "!no_check",
160 })
161 allErrors = append(allErrors, fmt.Errorf("no binary found for [%s] in repository %s", parseBinaryEntry(bEntry, false), bEntry.Repository.Name))
162 }
163 continue
164 }
165
166 // If no repository is specified, include the first matching binary
167 results = append(results, matchingBins[0])
168 if verbosityLevel >= extraVerbose {
169 fmt.Printf("\033[2K\rFound \"%s\" with id=%s version=%s repo=%s\n", bEntry.Name, matchingBins[0].PkgID, matchingBins[0].Version, matchingBins[0].Repository.Name)
170 }
171 }
172 }
173
174 if allFailed {
175 var errorMessages []string
176 for _, e := range allErrors {
177 errorMessages = append(errorMessages, e.Error())
178 }
179 return nil, errs.New(ternary(len(bEntries) != 1, "no valid download URLs found for any of the requested binaries.\n%s\n", "%s\n"), strings.Join(errorMessages, "\n"))
180 }
181
182 return results, nil
183}