From f6e80af39524e3b79bde17f5de49681a96fb318c Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Tue, 9 Jul 2024 10:11:56 -0400 Subject: [PATCH] Add support for GOPROXY env var (#34) --- internal/modproxy/modproxy.go | 64 +++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/internal/modproxy/modproxy.go b/internal/modproxy/modproxy.go index b0e98a0..2b4b348 100644 --- a/internal/modproxy/modproxy.go +++ b/internal/modproxy/modproxy.go @@ -2,12 +2,12 @@ package modproxy import ( "bufio" - "bytes" "encoding/json" "errors" "fmt" "io" "net/http" + neturl "net/url" "os" "path" "slices" @@ -22,6 +22,49 @@ import ( "github.com/icholy/gomajor/internal/packages" ) +// Proxies returns the module proxies. +func Proxies() []string { + var proxies []string + if s := os.Getenv("GOPROXY"); s != "" { + for _, proxy := range strings.Split(s, ",") { + proxy = strings.TrimSpace(proxy) + if proxy != "" && proxy != "direct" { + proxies = append(proxies, proxy) + } + } + } + if len(proxies) == 0 { + proxies = append(proxies, "https://proxy.golang.org") + } + return proxies +} + +// Request sends requests to the module proxies in order and returns +// the first 200 response. +func Request(path string, cached bool) (*http.Response, error) { + var last *http.Response + for _, proxy := range Proxies() { + url, err := neturl.JoinPath(proxy, path) + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return nil, err + } + req.Header.Set("User-Agent", "GoMajor/1.0") + if cached { + req.Header.Set("Disable-Module-Fetch", "true") + } + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + if res.StatusCode == http.StatusOK { + return res, nil + } + last = res + } + return last, nil +} + // Module contains the module path and versions type Module struct { Path string @@ -149,23 +192,14 @@ func Query(modpath string, cached bool) (*Module, bool, error) { if err != nil { return nil, false, err } - url := fmt.Sprintf("https://proxy.golang.org/%s/@v/list", escaped) - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - return nil, false, err - } - req.Header.Set("User-Agent", "GoMajor/1.0") - if cached { - req.Header.Set("Disable-Module-Fetch", "true") - } - res, err := http.DefaultClient.Do(req) + res, err := Request(path.Join(escaped, "@v", "list"), cached) if err != nil { return nil, false, err } defer res.Body.Close() if res.StatusCode != http.StatusOK { body, _ := io.ReadAll(res.Body) - if res.StatusCode == http.StatusNotFound && bytes.HasPrefix(body, []byte("not found:")) { + if res.StatusCode == http.StatusNotFound { return nil, false, nil } msg := string(body) @@ -300,11 +334,7 @@ func FetchRetractions(mod *Module) (Retractions, error) { if err != nil { return nil, err } - req, err := http.NewRequest("GET", "https://proxy.golang.org/"+escaped+"/@v/"+max+".mod", nil) - if err != nil { - return nil, err - } - res, err := http.DefaultClient.Do(req) + res, err := Request(path.Join(escaped, "@v", max+".mod"), false) if err != nil { return nil, err }