train-osource/pkg/autoupdate/autoupdate.go
wheelchairy 72211036c1 upd
2025-02-04 19:38:37 +03:00

131 lines
3.2 KiB
Go

package autoupdate
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"os/exec"
"path/filepath"
)
func BuildNewBinary(tarballURL string) (buildDir string, newBinPath string, err error) {
fmt.Printf("Downloading tarball: %s\n", tarballURL)
resp, err := http.Get(tarballURL)
if err != nil {
return "", "", fmt.Errorf("failed to download tarball: %w", err)
}
defer resp.Body.Close()
tmpTarball, err := ioutil.TempFile("", "source_*.tar.gz")
if err != nil {
return "", "", fmt.Errorf("failed to create temp file: %w", err)
}
_, err = io.Copy(tmpTarball, resp.Body)
if err != nil {
tmpTarball.Close()
return "", "", fmt.Errorf("failed to write tarball: %w", err)
}
tmpTarball.Close()
defer os.Remove(tmpTarball.Name())
tmpDir, err := ioutil.TempDir("", "build_")
if err != nil {
return "", "", fmt.Errorf("failed to create temp directory: %w", err)
}
fmt.Printf("Unpacking tarball to: %s\n", tmpDir)
if err := unpackTarball(tmpTarball.Name(), tmpDir); err != nil {
os.RemoveAll(tmpDir)
return "", "", fmt.Errorf("failed to unpack tarball: %w", err)
}
// Пытаемся найти go.mod в корне распакованного архива
goModPath := filepath.Join(tmpDir, "go.mod")
if _, err := os.Stat(goModPath); os.IsNotExist(err) {
// Если не найден, проверяем, есть ли ровно один подкаталог
entries, err := ioutil.ReadDir(tmpDir)
if err != nil {
os.RemoveAll(tmpDir)
return "", "", fmt.Errorf("failed to list unpacked directory: %w", err)
}
var subDir string
count := 0
for _, entry := range entries {
if entry.IsDir() {
subDir = filepath.Join(tmpDir, entry.Name())
count++
}
}
if count == 1 {
goModPath = filepath.Join(subDir, "go.mod")
if _, err := os.Stat(goModPath); err != nil {
os.RemoveAll(tmpDir)
return "", "", fmt.Errorf("go.mod not found in subdirectory")
}
buildDir = subDir
} else {
os.RemoveAll(tmpDir)
return "", "", fmt.Errorf("go.mod not found in unpacked directory")
}
} else {
buildDir = tmpDir
}
newBinPath = filepath.Join(buildDir, "train")
fmt.Println("go.mod found, building using go build...")
cmd := exec.Command("go", "build", "-o", "train")
cmd.Dir = buildDir
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
os.RemoveAll(tmpDir)
return "", "", fmt.Errorf("go build failed: %w", err)
}
fmt.Println("Build completed successfully using go build")
return buildDir, newBinPath, nil
}
func unpackTarball(archivePath, destDir string) error {
f, err := os.Open(archivePath)
if err != nil {
return err
}
defer f.Close()
gzr, err := gzip.NewReader(f)
if err != nil {
return err
}
defer gzr.Close()
tr := tar.NewReader(gzr)
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
target := filepath.Join(destDir, header.Name)
switch header.Typeflag {
case tar.TypeDir:
if err := os.MkdirAll(target, os.FileMode(header.Mode)); err != nil {
return err
}
case tar.TypeReg:
outFile, err := os.Create(target)
if err != nil {
return err
}
if _, err := io.Copy(outFile, tr); err != nil {
outFile.Close()
return err
}
outFile.Close()
}
}
return nil
}