scripts/download-deps.go (158 lines of code) (raw):
//go:build ignore
package main
import (
"bufio"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"regexp"
"strings"
)
const buildserver = "https://buildserver.labs.intellij.net"
var tcToken string
type artifact struct {
buildTypeID string
pattern string
subPath string
destPath string
}
var toolingArtifacts = []artifact{
{"StaticAnalysis_Build_UiAndConverter", "intellij-report-converter.jar", "", "internal/tooling/intellij-report-converter.jar"},
}
var clangArtifacts = []artifact{
{"ijplatform_master_CIDR_ExternalTools_VanillaClangTidyAll", `clang-tidy-[^"]*-linux-x64\.tar\.gz`, "", "clang/clang-tidy-linux-amd64.tar.gz"},
{"ijplatform_master_CIDR_ExternalTools_VanillaClangTidyAll", `clang-tidy-[^"]*-linux-aarch64\.tar\.gz`, "", "clang/clang-tidy-linux-arm64.tar.gz"},
{"ijplatform_master_CIDR_ExternalTools_VanillaClangTidyAll", `clang-tidy-[^"]*-mac-x64\.tar\.gz`, "", "clang/clang-tidy-darwin-amd64.tar.gz"},
{"ijplatform_master_CIDR_ExternalTools_VanillaClangTidyAll", `clang-tidy-[^"]*-mac-aarch64\.tar\.gz`, "", "clang/clang-tidy-darwin-arm64.tar.gz"},
{"ijplatform_master_CIDR_ExternalTools_VanillaClangTidyAll", `clang-tidy-[^"]*-win-x64\.zip`, "", "clang/clang-tidy-windows-amd64.zip"},
{"ijplatform_master_CIDR_ExternalTools_VanillaClangTidyAll", `clang-tidy-[^"]*-win-aarch64\.zip`, "", "clang/clang-tidy-windows-arm64.zip"},
}
var cdnetArtifacts = []artifact{
{"ijplatform_master_Net_PostCompile_TriggerAllInstallers", `JetBrains\.ReSharper\.GlobalTools\.[^"]*\.nupkg`, "Artifacts.InstallersPortablesZips", "cdnet/clt.zip"},
}
func main() {
repoRoot := findRepoRoot()
loadEnv(filepath.Join(repoRoot, ".env"))
tcToken = os.Getenv("TEAMCITY_TOKEN")
if tcToken == "" {
log.Fatal("TEAMCITY_TOKEN not set (check .env file)")
}
log.Printf("Downloading dependencies to %s", repoRoot)
var all []artifact
all = append(all, toolingArtifacts...)
all = append(all, clangArtifacts...)
all = append(all, cdnetArtifacts...)
for _, a := range all {
dest := filepath.Join(repoRoot, a.destPath)
if err := download(a, dest); err != nil {
log.Printf("WARN: %s: %v", a.destPath, err)
}
}
log.Println("Done")
}
func loadEnv(path string) {
f, err := os.Open(path)
if err != nil {
return
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}
line = strings.TrimPrefix(line, "export ")
if k, v, ok := strings.Cut(line, "="); ok {
if os.Getenv(k) == "" {
os.Setenv(k, v)
}
}
}
}
func download(a artifact, dest string) error {
artifactName, err := findArtifact(a.buildTypeID, a.subPath, a.pattern)
if err != nil {
return err
}
urlPath := artifactName
if a.subPath != "" {
urlPath = a.subPath + "/" + artifactName
}
url := fmt.Sprintf("%s/app/rest/builds/buildType:%s,status:SUCCESS,count:1/artifacts/content/%s", buildserver, a.buildTypeID, urlPath)
log.Printf("Downloading %s", a.destPath)
if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
return err
}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer "+tcToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
}
f, err := os.Create(dest)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
return err
}
func findArtifact(buildTypeID, subPath, pattern string) (string, error) {
url := fmt.Sprintf("%s/app/rest/builds/buildType:%s,status:SUCCESS,count:1/artifacts", buildserver, buildTypeID)
if subPath != "" {
url += "/children/" + subPath
}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer "+tcToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
}
var data struct {
File []struct {
Name string `json:"name"`
} `json:"file"`
}
if err := json.Unmarshal(body, &data); err != nil {
re := regexp.MustCompile(`"` + pattern + `"`)
if match := re.FindString(string(body)); match != "" {
return strings.Trim(match, `"`), nil
}
return "", fmt.Errorf("no match for %s", pattern)
}
re := regexp.MustCompile(pattern)
for _, f := range data.File {
if re.MatchString(f.Name) {
return f.Name, nil
}
}
return "", fmt.Errorf("no match for %s", pattern)
}
func findRepoRoot() string {
dir, _ := os.Getwd()
for {
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
return dir
}
parent := filepath.Dir(dir)
if parent == dir {
log.Fatal("Could not find repository root (no go.mod found)")
}
dir = parent
}
}