package forge import ( "errors" "fmt" "net/url" "os" "regexp" "runtime" "strings" ) var ( amd64Re = regexp.MustCompile(`amd64|x86_64|64-bit|[^mhv]64`) linuxRe = regexp.MustCompile(`(?i)linux`) windowsRe = regexp.MustCompile(`(?i)windows|\Awin`) installerRe = regexp.MustCompile(`\.deb|\.msi`) ) type Release struct { Name string Assets []Asset } type Asset struct { Name string DownloadURL string Version string // Release.Name } type Forger interface { Name() string latestRelease() (Release, error) tagRelease(tag string) (Release, error) } func splitURI(uri string) (string, []string, error) { if !strings.HasPrefix(uri, "http") { uri = "https://" + uri } u, err := url.ParseRequestURI(uri) if err != nil { return "", nil, fmt.Errorf("could not parse URI: %w", err) } u.Scheme = "https" paths := strings.FieldsFunc(u.Path, func(r rune) bool { return r == '/' }) u.Path = "" return u.String(), paths, nil } func TagRelease(f Forger, tag, override string) (Asset, error) { var asset Asset var re *regexp.Regexp switch runtime.GOOS { case "linux": re = linuxRe case "windows": re = windowsRe default: return asset, fmt.Errorf("%q is not a supported OS", runtime.GOOS) } release, err := f.tagRelease(tag) if err != nil { return asset, fmt.Errorf("could not get %q release: %w", tag, err) } overrideName := os.Expand(override, func(s string) string { switch strings.ToLower(s) { case "os", "goos": return runtime.GOOS case "arch", "goarch": return runtime.GOARCH case "version": return release.Name default: return "" } }) for _, a := range release.Assets { match := strings.EqualFold(a.Name, overrideName) if overrideName == "" { match = amd64Re.MatchString(a.Name) && re.MatchString(a.Name) && !installerRe.MatchString(a.Name) } if match { fmt.Printf("found %q\n", a.Name) asset = a break } } if asset.Name == "" { return asset, errors.New("no release found for this OS") } asset.Version = release.Name return asset, nil } func LatestRelease(f Forger, override string) (Asset, error) { var asset Asset release, err := f.latestRelease() if err != nil { return asset, fmt.Errorf("could not get latest release: %w", err) } return TagRelease(f, release.Name, override) }