7b13644421
ci/woodpecker/tag/docker Pipeline was successful
## Summary - Virtual engine detects local members and generates indexes in-memory - MemberIndex.RepoType drives correct URL prefix in merged output - PyPI merger rewrites links to /api/v1/local/ or /api/v1/remote/ appropriately - Includes local PyPI support (cherry-picked from #50) ## Test plan - [x] Upload wheel to local PyPI → install from direct local URL - [x] Create virtual with local + remote → install from virtual URL - [x] Both paths produce correct absolute download URLs Reviewed-on: #51 Co-authored-by: Ben Vincent <ben@unkin.net> Co-committed-by: Ben Vincent <ben@unkin.net>
95 lines
1.8 KiB
Go
95 lines
1.8 KiB
Go
package virtual
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.unkin.net/unkin/artifactapi/pkg/models"
|
|
)
|
|
|
|
func init() {
|
|
RegisterMerger(models.PackagePyPI, &PyPIMerger{})
|
|
}
|
|
|
|
type PyPIMerger struct{}
|
|
|
|
func (m *PyPIMerger) MergeIndexes(members []MemberIndex, proxyBaseURL string) ([]byte, error) {
|
|
links := map[string]string{}
|
|
|
|
for _, member := range members {
|
|
body := string(member.Body)
|
|
for _, line := range strings.Split(body, "\n") {
|
|
line = strings.TrimSpace(line)
|
|
if !strings.HasPrefix(line, "<a ") {
|
|
continue
|
|
}
|
|
|
|
href := extractHref(line)
|
|
text := extractLinkText(line)
|
|
if text == "" {
|
|
continue
|
|
}
|
|
|
|
if _, exists := links[text]; exists {
|
|
continue
|
|
}
|
|
|
|
if proxyBaseURL != "" && href != "" {
|
|
routePrefix := "remote"
|
|
if member.RepoType == "local" {
|
|
routePrefix = "local"
|
|
}
|
|
href = fmt.Sprintf("%s/api/v1/%s/%s/%s",
|
|
strings.TrimRight(proxyBaseURL, "/"),
|
|
routePrefix,
|
|
member.RemoteName,
|
|
strings.TrimLeft(href, "/"))
|
|
}
|
|
|
|
links[text] = href
|
|
}
|
|
}
|
|
|
|
keys := make([]string, 0, len(links))
|
|
for k := range links {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
var sb strings.Builder
|
|
sb.WriteString("<!DOCTYPE html>\n<html><body>\n")
|
|
for _, name := range keys {
|
|
sb.WriteString(fmt.Sprintf(" <a href=\"%s\">%s</a>\n", links[name], name))
|
|
}
|
|
sb.WriteString("</body></html>\n")
|
|
|
|
return []byte(sb.String()), nil
|
|
}
|
|
|
|
func extractHref(tag string) string {
|
|
idx := strings.Index(tag, `href="`)
|
|
if idx == -1 {
|
|
return ""
|
|
}
|
|
rest := tag[idx+6:]
|
|
end := strings.Index(rest, `"`)
|
|
if end == -1 {
|
|
return rest
|
|
}
|
|
return rest[:end]
|
|
}
|
|
|
|
func extractLinkText(tag string) string {
|
|
start := strings.Index(tag, ">")
|
|
if start == -1 {
|
|
return ""
|
|
}
|
|
rest := tag[start+1:]
|
|
end := strings.Index(rest, "</a>")
|
|
if end == -1 {
|
|
return strings.TrimSpace(rest)
|
|
}
|
|
return strings.TrimSpace(rest[:end])
|
|
}
|