1
0
Fork 0
telegraf/tools/update_goversion/main.go

217 lines
5.1 KiB
Go
Raw Permalink Normal View History

package main
import (
"errors"
"fmt"
"io"
"log"
"net/http"
"os"
"regexp"
"strings"
"github.com/coreos/go-semver/semver"
"golang.org/x/net/html"
)
type FileInfo struct {
FileName string
Regex string
Replace string
}
func (f FileInfo) Update() error {
b, err := os.ReadFile(f.FileName)
if err != nil {
return err
}
re := regexp.MustCompile(f.Regex)
newContents := re.ReplaceAll(b, []byte(f.Replace))
err = os.WriteFile(f.FileName, newContents, 0640)
if err != nil {
return err
}
return nil
}
// removePatch cleans version from "1.20.1" to "1.20" (think go.mod entry)
func removePatch(version string) string {
verInfo := semver.New(version)
return fmt.Sprintf("%d.%d", verInfo.Major, verInfo.Minor)
}
// findHash will search the downloads table for the hashes matching the artifacts list
func findHashes(body io.Reader, version string) (map[string]string, error) {
htmlTokens := html.NewTokenizer(body)
artifacts := []string{
fmt.Sprintf("go%s.linux-amd64.tar.gz", version),
fmt.Sprintf("go%s.darwin-arm64.tar.gz", version),
fmt.Sprintf("go%s.darwin-amd64.tar.gz", version),
}
var insideDownloadTable bool
var currentRow string
hashes := make(map[string]string)
for {
tokenType := htmlTokens.Next()
// if it's an error token, we either reached
// the end of the file, or the HTML was malformed
if tokenType == html.ErrorToken {
err := htmlTokens.Err()
if errors.Is(err, io.EOF) {
// end of the file, break out of the loop
break
}
return nil, htmlTokens.Err()
}
if tokenType == html.StartTagToken {
// get the token
token := htmlTokens.Token()
if token.Data == "table" && len(token.Attr) == 1 && token.Attr[0].Val == "downloadtable" {
insideDownloadTable = true
}
if insideDownloadTable && token.Data == "a" && len(token.Attr) == 2 {
for _, f := range artifacts {
// Check if the current row matches a desired file
if strings.Contains(token.Attr[1].Val, f) {
currentRow = f
break
}
}
}
if currentRow != "" && token.Data == "tt" {
// the next token should be the page title
tokenType = htmlTokens.Next()
// just make sure it's actually a text token
if tokenType == html.TextToken {
hashes[currentRow] = htmlTokens.Token().Data
currentRow = ""
}
}
}
// Found a hash for each filename
if len(hashes) == len(artifacts) {
break
}
// Reached end of table
if tokenType == html.EndTagToken && htmlTokens.Token().Data == "table" {
if len(hashes) == 0 {
return nil, fmt.Errorf("could not find version %q on downloads page", version)
}
return nil, fmt.Errorf("only found %d hashes expected %d: %v", len(hashes), len(artifacts), hashes)
}
}
return hashes, nil
}
func getHashes(version string) (map[string]string, error) {
resp, err := http.Get(`https://go.dev/dl/`)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return findHashes(resp.Body, version)
}
func main() {
version := os.Args[1]
// Handle situation user accidentally provides version as "v1.19.2"
if strings.HasPrefix(version, "v") {
version = strings.TrimLeft(version, "v")
}
hashes, err := getHashes(version)
if err != nil {
log.Fatal(err)
}
for file, hash := range hashes {
fmt.Printf("%s %s\n", hash, file)
}
noPatchVersion := removePatch(version)
files := []FileInfo{
{
FileName: ".circleci/config.yml",
Regex: `(quay\.io\/influxdb\/telegraf-ci):(\d.\d*.\d)`,
Replace: "$1:" + version,
},
{
FileName: "go.mod",
Regex: `(go)\s(\d.\d*)`,
Replace: "$1 " + noPatchVersion,
},
{
FileName: "Makefile",
Regex: `(quay\.io\/influxdb\/telegraf-ci):(\d.\d*.\d)`,
Replace: "$1:" + version,
},
{
FileName: "README.md",
Regex: `(Telegraf requires Go version) (\d.\d*)`,
Replace: "$1 " + noPatchVersion,
},
{
FileName: "scripts/ci.docker",
Regex: `(FROM golang):(\d.\d*.\d)`,
Replace: "$1:" + version,
},
{
FileName: "scripts/installgo_linux.sh",
Regex: `(GO_VERSION)=("\d.\d*.\d")`,
Replace: fmt.Sprintf("$1=%q", version),
},
{
FileName: "scripts/installgo_mac.sh",
Regex: `(GO_VERSION)=("\d.\d*.\d")`,
Replace: fmt.Sprintf("$1=%q", version),
},
{
FileName: "scripts/installgo_windows.sh",
Regex: `(GO_VERSION)=("\d.\d*.\d")`,
Replace: fmt.Sprintf("$1=%q", version),
},
{
FileName: "scripts/installgo_linux.sh",
Regex: `(GO_VERSION_SHA)=".*"`,
Replace: fmt.Sprintf("$1=%q", hashes[fmt.Sprintf("go%s.linux-amd64.tar.gz", version)]),
},
{
FileName: "scripts/installgo_mac.sh",
Regex: `(GO_VERSION_SHA_arm64)=".*"`,
Replace: fmt.Sprintf("$1=%q", hashes[fmt.Sprintf("go%s.darwin-arm64.tar.gz", version)]),
},
{
FileName: "scripts/installgo_mac.sh",
Regex: `(GO_VERSION_SHA_amd64)=".*"`,
Replace: fmt.Sprintf("$1=%q", hashes[fmt.Sprintf("go%s.darwin-amd64.tar.gz", version)]),
},
{
FileName: ".github/workflows/readme-linter.yml",
Regex: `(go-version): '\d.\d*.\d'`,
Replace: fmt.Sprintf("$1: '%s'", version),
},
}
for _, f := range files {
fmt.Printf("Updating %s \n", f.FileName)
err := f.Update()
if err != nil {
log.Panic(err)
}
}
}