upd
This commit is contained in:
parent
ca822b5f38
commit
72211036c1
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
Use: "train",
|
Use: "train",
|
||||||
Short: "Train - легковесный пакетный менеджер",
|
Short: "Train - сранный пакетный менеджер",
|
||||||
}
|
}
|
||||||
|
|
||||||
func Execute() {
|
func Execute() {
|
||||||
|
63
cmd/selfupd.go
Normal file
63
cmd/selfupd.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"train/pkg/autoupdate"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var selfupdCmd = &cobra.Command{
|
||||||
|
Use: "selfupd",
|
||||||
|
Short: "Обновляет текущий бинарник Train из исходников",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
tarballURL := "http://212.113.119.5/lain/train-osource/archive/main.tar.gz"
|
||||||
|
fmt.Println("Обновление Train из исходников...")
|
||||||
|
tmpDir, newBinPath, err := autoupdate.BuildNewBinary(tarballURL)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Ошибка сборки: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
currentPath, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Ошибка получения пути текущего бинарника: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("Замена текущего бинарника (%s) на новый\n", currentPath)
|
||||||
|
if err := replaceBinary(newBinPath, currentPath); err != nil {
|
||||||
|
fmt.Printf("Ошибка обновления бинарника: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.RemoveAll(tmpDir)
|
||||||
|
fmt.Println("Обновление успешно. Перезапустите Train.")
|
||||||
|
os.Exit(0)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func replaceBinary(newPath, currentPath string) error {
|
||||||
|
src, err := os.Open(newPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
tmpPath := currentPath + ".new"
|
||||||
|
dst, err := os.Create(tmpPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dst.Close()
|
||||||
|
if _, err = io.Copy(dst, src); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = os.Chmod(tmpPath, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.Rename(tmpPath, currentPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(selfupdCmd)
|
||||||
|
}
|
20
cmd/version.go
Normal file
20
cmd/version.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"train/pkg/version"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var versionCmd = &cobra.Command{
|
||||||
|
Use: "version",
|
||||||
|
Short: "Выводит текущую версию Train",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Printf("Train version %s\n", version.CurrentVersion)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(versionCmd)
|
||||||
|
}
|
@ -1,58 +1,131 @@
|
|||||||
package autoupdate
|
package autoupdate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CheckForUpdates(updateURL string) (bool, string, error) {
|
func BuildNewBinary(tarballURL string) (buildDir string, newBinPath string, err error) {
|
||||||
resp, err := http.Get(updateURL)
|
fmt.Printf("Downloading tarball: %s\n", tarballURL)
|
||||||
|
resp, err := http.Get(tarballURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "", err
|
return "", "", fmt.Errorf("failed to download tarball: %w", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
|
||||||
|
tmpTarball, err := ioutil.TempFile("", "source_*.tar.gz")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "", err
|
return "", "", fmt.Errorf("failed to create temp file: %w", err)
|
||||||
}
|
}
|
||||||
latestVersion := string(data)
|
_, err = io.Copy(tmpTarball, resp.Body)
|
||||||
currentVersion := "1.0.0"
|
if err != nil {
|
||||||
if latestVersion != currentVersion {
|
tmpTarball.Close()
|
||||||
return true, latestVersion, nil
|
return "", "", fmt.Errorf("failed to write tarball: %w", err)
|
||||||
}
|
}
|
||||||
return false, currentVersion, nil
|
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 AutoUpdate(updateURL string) error {
|
func unpackTarball(archivePath, destDir string) error {
|
||||||
available, latest, err := CheckForUpdates(updateURL)
|
f, err := os.Open(archivePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if available {
|
defer f.Close()
|
||||||
fmt.Printf("Доступна новая версия: %s. Запускаем обновление...\n", latest)
|
gzr, err := gzip.NewReader(f)
|
||||||
resp, err := http.Get(updateURL + "/binary") // предположим, что по этому URL лежит бинарник
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
target := filepath.Join(destDir, header.Name)
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
switch header.Typeflag {
|
||||||
if err != nil {
|
case tar.TypeDir:
|
||||||
return err
|
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()
|
||||||
}
|
}
|
||||||
tmpFile := "/tmp/train_new"
|
|
||||||
if err := ioutil.WriteFile(tmpFile, data, 0755); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cmd := exec.Command(tmpFile)
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
os.Exit(0)
|
|
||||||
} else {
|
|
||||||
fmt.Println("Обновлений не найдено.")
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
3
pkg/version/current.go
Normal file
3
pkg/version/current.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package version
|
||||||
|
|
||||||
|
const CurrentVersion = "1.0.5"
|
Loading…
x
Reference in New Issue
Block a user