Compare commits

...

20 Commits
1.0 ... main

Author SHA1 Message Date
Lain Iwakura
c12782dfc9
fix url 2025-07-07 23:26:02 +03:00
wheelchairy
72cd03aded Windows compatibilty mode warning 2025-02-08 12:00:16 +03:00
wheelchairy
2640d53ec9 windows режим совместимости 2025-02-08 11:40:45 +03:00
wheelchairy
92880855ea Fixed config.json 2025-02-08 11:38:40 +03:00
wheelchairy
da4c6edf2a mehh 2025-02-05 19:31:30 +03:00
wheelchairy
8d5d845376 mehh 2025-02-05 19:31:23 +03:00
wheelchairy
7f632f4188 upd emojis 2025-02-05 17:25:52 +03:00
wheelchairy
bd5c28e76a 1.1 2025-02-05 17:21:00 +03:00
wheelchairy
bf5a670f80 upd repo.json 2025-02-05 17:17:25 +03:00
wheelchairy
b9fe96e56c upd repo.json 2025-02-05 17:17:10 +03:00
wheelchairy
00a56fa985 mehh 2025-02-04 21:53:22 +03:00
wheelchairy
a606043450 mehh 2025-02-04 21:38:46 +03:00
wheelchairy
9b4e21691c mehh 2025-02-04 21:38:28 +03:00
wheelchairy
aaab254cc9 mehh 2025-02-04 20:49:22 +03:00
d401a16b3d Обновить pkg/version/current.go 2025-02-04 17:49:02 +00:00
85c79827db Обновить README.md 2025-02-04 17:48:47 +00:00
15a1a7f8f0 Обновить README.md 2025-02-04 17:09:05 +00:00
c504b6c7cc Добавить README.md 2025-02-04 17:08:04 +00:00
wheelchairy
3d9a1e38df mehh 2025-02-04 19:42:18 +03:00
wheelchairy
72211036c1 upd 2025-02-04 19:38:37 +03:00
13 changed files with 366 additions and 94 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ installed*
repo repo
train train
pkg/*/*.save pkg/*/*.save
train-pkg*

31
README.md Normal file
View File

@ -0,0 +1,31 @@
# Train
#### РЖД - Российские Железные Дороги
Сборка:
```
go mod tidy
go build -o train
```
Из бинарника в команды:
```
./train install-all
```
Дальше пропишите у себя в .*rc:
```
export PATH="$HOME/.rails/bin:$PATH"
export PATH="$HOME/.rails/installed_bins:$PATH"
```
И будет вам счастье
## Пока-что есть два пакета
* choochoo-build
* fastfetch/neofetch (later)
## Обновлятся вот так
```
train selfupd
```

View File

@ -1,14 +1,21 @@
package cmd package cmd
import ( import (
"os"
"fmt" "fmt"
"os"
"runtime"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "train", Use: "train",
Short: "Train - легковесный пакетный менеджер", Short: "Train - Лёгкий пакетный менеджер",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if runtime.GOOS == "windows" {
fmt.Println("[WARNING] Train работает на Windows в режиме совместимости. Гарантий работы нет.")
}
},
} }
func Execute() { func Execute() {

63
cmd/selfupd.go Normal file
View 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 := "https://git.iwakurahome.ru/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
View 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)
}

View File

@ -1,5 +1,5 @@
{ {
"repositories": [ "repo": "https://xn--80abmlgju2eo3byb.xn--p1ai/repo/repo.json",
"https://xn--80abmlgju2eo3byb.xn--p1ai/sklad" "repositories": [],
] "packages": {}
} }

View File

@ -1,58 +1,129 @@
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)
}
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 { if err != nil {
return err return err
} }
defer resp.Body.Close() defer gzr.Close()
data, err := ioutil.ReadAll(resp.Body) tr := tar.NewReader(gzr)
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if err != nil { if err != nil {
return err return err
} }
tmpFile := "/tmp/train_new" target := filepath.Join(destDir, header.Name)
if err := ioutil.WriteFile(tmpFile, data, 0755); err != nil { switch header.Typeflag {
case tar.TypeDir:
if err := os.MkdirAll(target, os.FileMode(header.Mode)); err != nil {
return err return err
} }
cmd := exec.Command(tmpFile) case tar.TypeReg:
if err := cmd.Start(); err != nil { outFile, err := os.Create(target)
if err != nil {
return err return err
} }
os.Exit(0) if _, err := io.Copy(outFile, tr); err != nil {
} else { outFile.Close()
fmt.Println("Обновлений не найдено.") return err
}
outFile.Close()
}
} }
return nil return nil
} }

View File

@ -2,33 +2,35 @@ package config
import ( import (
"encoding/json" "encoding/json"
"errors"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"train/pkg/paths"
) )
type Config struct {
Repo string `json:"repo"`
Repositories []string `json:"repositories"`
Packages map[string]string `json:"packages"`
}
var configFile string var configFile string
func init() { func init() {
railsConfig := filepath.Join(paths.BaseDir(), "config", "config.json") home, err := os.UserHomeDir()
if err == nil {
railsConfig := filepath.Join(home, ".rails", "config", "config.json")
if _, err := os.Stat(railsConfig); err == nil { if _, err := os.Stat(railsConfig); err == nil {
configFile = railsConfig configFile = railsConfig
} else { return
configFile = "./config.json"
} }
} }
configFile = "./config.json"
type Config struct {
Repositories []string `json:"repositories"`
Packages map[string]string `json:"packages"`
} }
func LoadConfig() (*Config, error) { func LoadConfig() (*Config, error) {
if _, err := os.Stat(configFile); os.IsNotExist(err) { if _, err := os.Stat(configFile); os.IsNotExist(err) {
cfg := &Config{ cfg := &Config{
Repo: "",
Repositories: []string{}, Repositories: []string{},
Packages: make(map[string]string), Packages: make(map[string]string),
} }
@ -63,7 +65,7 @@ func AddRepository(repo string) error {
} }
for _, r := range cfg.Repositories { for _, r := range cfg.Repositories {
if r == repo { if r == repo {
return errors.New("репозиторий уже добавлен") return nil
} }
} }
cfg.Repositories = append(cfg.Repositories, repo) cfg.Repositories = append(cfg.Repositories, repo)
@ -76,16 +78,10 @@ func RemoveRepository(repo string) error {
return err return err
} }
newRepos := []string{} newRepos := []string{}
found := false
for _, r := range cfg.Repositories { for _, r := range cfg.Repositories {
if r == repo { if r != repo {
found = true
continue
}
newRepos = append(newRepos, r) newRepos = append(newRepos, r)
} }
if !found {
return errors.New("репозиторий не найден")
} }
cfg.Repositories = newRepos cfg.Repositories = newRepos
return SaveConfig(cfg) return SaveConfig(cfg)

View File

@ -26,8 +26,14 @@ var (
buildInstallDir = filepath.Join(paths.BaseDir(), "installed_packages") buildInstallDir = filepath.Join(paths.BaseDir(), "installed_packages")
) )
func logMessage(msg string) { func logInfo(format string, args ...interface{}) {
fmt.Println(msg) msg := fmt.Sprintf(format, args...)
fmt.Printf("\033[32m==>\033[0m %s\n", msg)
}
func logTrain(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
fmt.Printf("\U0001F682 %s\n", msg)
} }
func computeChecksum(filePath string) (string, error) { func computeChecksum(filePath string) (string, error) {
@ -40,7 +46,7 @@ func computeChecksum(filePath string) (string, error) {
} }
func downloadFile(url string) (string, error) { func downloadFile(url string) (string, error) {
logMessage("Downloading " + url + "...") logInfo("Downloading %s", url)
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return "", err return "", err
@ -52,16 +58,17 @@ func downloadFile(url string) (string, error) {
} }
_, err = io.Copy(tmpFile, resp.Body) _, err = io.Copy(tmpFile, resp.Body)
if err != nil { if err != nil {
tmpFile.Close()
return "", err return "", err
} }
tmpFile.Close() tmpFile.Close()
logMessage("File downloaded to temporary location") logInfo("File downloaded to temporary location")
return tmpFile.Name(), nil return tmpFile.Name(), nil
} }
func unpackPackage(filePath, packageName string) error { func unpackPackage(filePath, packageName string) error {
logInfo("Unpacking package into %s", filepath.Join(buildInstallDir, packageName))
destDir := filepath.Join(buildInstallDir, packageName) destDir := filepath.Join(buildInstallDir, packageName)
logMessage("Unpacking package into " + destDir)
if err := os.MkdirAll(destDir, os.ModePerm); err != nil { if err := os.MkdirAll(destDir, os.ModePerm); err != nil {
return err return err
} }
@ -102,28 +109,27 @@ func unpackPackage(filePath, packageName string) error {
outFile.Close() outFile.Close()
} }
} }
logMessage("Unpacking completed") logInfo("Unpacking completed")
return nil return nil
} }
func executeBuildCommands(commands []string, packageName string) error { func executeBuildCommands(commands []string, packageName string) error {
packagePath := filepath.Join(buildInstallDir, packageName) packagePath := filepath.Join(buildInstallDir, packageName)
for _, commandStr := range commands { for _, commandStr := range commands {
logMessage("Executing build command: " + commandStr) logInfo("Executing build command: %s", commandStr)
cmd := exec.Command("sh", "-c", commandStr) cmd := exec.Command("sh", "-c", commandStr)
cmd.Dir = packagePath cmd.Dir = packagePath
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("command '%s' failed: %s", commandStr, string(output)) return fmt.Errorf("command '%s' failed: %s", commandStr, string(output))
} }
logMessage("Command output: " + string(output))
} }
return nil return nil
} }
func saveInstalledPackage(name string, m *manifest.Manifest) error { func saveInstalledPackage(name string, m *manifest.Manifest) error {
logInfo("Saving manifest to %s", filepath.Join(buildInstallDir, name))
packagePath := filepath.Join(buildInstallDir, name) packagePath := filepath.Join(buildInstallDir, name)
logMessage("Saving manifest to " + packagePath)
if err := os.MkdirAll(packagePath, os.ModePerm); err != nil { if err := os.MkdirAll(packagePath, os.ModePerm); err != nil {
return err return err
} }
@ -135,29 +141,29 @@ func saveInstalledPackage(name string, m *manifest.Manifest) error {
} }
func InstallPackage(name string) error { func InstallPackage(name string) error {
logMessage("Fetching manifest for package " + name) logTrain("Installing package: %s", name)
m, err := manifest.FetchManifest(name) m, err := manifest.FetchManifest(name)
if err != nil { if err != nil {
return fmt.Errorf("failed to fetch manifest: %w", err) return fmt.Errorf("failed to fetch manifest: %w", err)
} }
if strings.ToLower(m.Mode) == "bin" { if strings.ToLower(m.Mode) == "bin" {
logMessage("Installing in binary mode") logInfo("Installing in binary mode")
platformKey := runtime.GOOS + "_" + runtime.GOARCH platformKey := runtime.GOOS + "_" + runtime.GOARCH
binaryURL, ok := m.Binaries[platformKey] binaryInfo, ok := m.Binaries[platformKey]
if !ok { if !ok {
return fmt.Errorf("no binary available for platform %s", platformKey) return fmt.Errorf("no binary available for platform %s", platformKey)
} }
packageFile, err := downloadFile(binaryURL) packageFile, err := downloadFile(binaryInfo.URL)
if err != nil { if err != nil {
return fmt.Errorf("failed to download binary: %w", err) return fmt.Errorf("failed to download binary: %w", err)
} }
defer os.Remove(packageFile) defer os.Remove(packageFile)
checksum, err := computeChecksum(packageFile) computedChecksum, err := computeChecksum(packageFile)
if err != nil { if err != nil {
return fmt.Errorf("failed to compute checksum: %w", err) return fmt.Errorf("failed to compute checksum: %w", err)
} }
if checksum != m.Checksum { if computedChecksum != binaryInfo.Checksum {
return fmt.Errorf("checksum mismatch: expected %s, got %s", m.Checksum, checksum) return fmt.Errorf("checksum mismatch: expected %s, got %s", binaryInfo.Checksum, computedChecksum)
} }
if err := os.MkdirAll(binInstallDir, os.ModePerm); err != nil { if err := os.MkdirAll(binInstallDir, os.ModePerm); err != nil {
return err return err
@ -170,21 +176,22 @@ func InstallPackage(name string) error {
if err := ioutil.WriteFile(destPath, data, 0755); err != nil { if err := ioutil.WriteFile(destPath, data, 0755); err != nil {
return err return err
} }
logMessage("Binary package " + m.Name + " installed to " + destPath) logInfo("Binary package %s installed in %s", m.Name, destPath)
logTrain("Package %s successfully installed.", m.Name)
return nil return nil
} else if strings.ToLower(m.Mode) == "build" { } else if strings.ToLower(m.Mode) == "build" {
logMessage("Installing in build mode") logInfo("Installing in build mode")
packageFile, err := downloadFile(m.Source) packageFile, err := downloadFile(m.Source)
if err != nil { if err != nil {
return fmt.Errorf("failed to download package: %w", err) return fmt.Errorf("failed to download package: %w", err)
} }
defer os.Remove(packageFile) defer os.Remove(packageFile)
checksum, err := computeChecksum(packageFile) computedChecksum, err := computeChecksum(packageFile)
if err != nil { if err != nil {
return fmt.Errorf("failed to compute checksum: %w", err) return fmt.Errorf("failed to compute checksum: %w", err)
} }
if checksum != m.Checksum { if computedChecksum != m.Checksum {
return fmt.Errorf("checksum mismatch: expected %s, got %s", m.Checksum, checksum) return fmt.Errorf("checksum mismatch: expected %s, got %s", m.Checksum, computedChecksum)
} }
if err := unpackPackage(packageFile, name); err != nil { if err := unpackPackage(packageFile, name); err != nil {
return fmt.Errorf("failed to unpack package: %w", err) return fmt.Errorf("failed to unpack package: %w", err)
@ -197,34 +204,53 @@ func InstallPackage(name string) error {
if err := saveInstalledPackage(name, m); err != nil { if err := saveInstalledPackage(name, m); err != nil {
return fmt.Errorf("failed to save manifest: %w", err) return fmt.Errorf("failed to save manifest: %w", err)
} }
logMessage("Build package " + m.Name + " installed successfully") logTrain("Build package %s installed successfully.", m.Name)
return nil return nil
} }
return errors.New("unknown package mode") return errors.New("unknown package mode")
} }
func RemovePackage(name string) error { func RemovePackage(name string) error {
logTrain("Removing package: %s", name)
packagePath := filepath.Join(buildInstallDir, name) packagePath := filepath.Join(buildInstallDir, name)
logMessage("Removing package " + name + " from " + packagePath)
if _, err := os.Stat(packagePath); os.IsNotExist(err) { if _, err := os.Stat(packagePath); os.IsNotExist(err) {
return errors.New("package not found") return errors.New("package not found")
} }
manifestPath := filepath.Join(packagePath, "manifest.json")
data, err := ioutil.ReadFile(manifestPath)
if err == nil {
var m manifest.Manifest
if err := json.Unmarshal(data, &m); err == nil {
if len(m.Uninstall) > 0 {
for _, cmdStr := range m.Uninstall {
logInfo("Executing uninstall command: %s", cmdStr)
cmd := exec.Command("sh", "-c", cmdStr)
cmd.Dir = packagePath
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("uninstall command '%s' failed: %s", cmdStr, string(output))
}
}
}
}
}
logInfo("Removing directory %s", packagePath)
if err := os.RemoveAll(packagePath); err != nil { if err := os.RemoveAll(packagePath); err != nil {
return fmt.Errorf("failed to remove package: %w", err) return fmt.Errorf("failed to remove package: %w", err)
} }
logMessage("Package " + name + " removed successfully") logTrain("Package %s removed.", name)
return nil return nil
} }
func UpdatePackage(name string) error { func UpdatePackage(name string) error {
logMessage("Updating package " + name) logTrain("Updating package: %s", name)
if err := RemovePackage(name); err != nil { if err := RemovePackage(name); err != nil {
return fmt.Errorf("failed to remove package for update: %w", err) return fmt.Errorf("failed to remove package for update: %w", err)
} }
if err := InstallPackage(name); err != nil { if err := InstallPackage(name); err != nil {
return fmt.Errorf("failed to install package during update: %w", err) return fmt.Errorf("failed to install package: %w", err)
} }
logMessage("Package " + name + " updated successfully") logTrain("Package %s updated successfully.", name)
return nil return nil
} }

BIN
pkg/manifest/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -9,6 +9,11 @@ import (
"train/pkg/config" "train/pkg/config"
) )
type BinaryInfo struct {
URL string `json:"url"`
Checksum string `json:"checksum"`
}
type Manifest struct { type Manifest struct {
Name string `json:"name"` Name string `json:"name"`
Version string `json:"version"` Version string `json:"version"`
@ -17,7 +22,8 @@ type Manifest struct {
Checksum string `json:"checksum"` Checksum string `json:"checksum"`
Dependencies []string `json:"dependencies"` Dependencies []string `json:"dependencies"`
Build []string `json:"build"` Build []string `json:"build"`
Binaries map[string]string `json:"binaries"` Binaries map[string]BinaryInfo `json:"binaries"`
Uninstall []string `json:"uninstall"`
} }
func FetchManifest(name string) (*Manifest, error) { func FetchManifest(name string) (*Manifest, error) {
@ -25,6 +31,12 @@ func FetchManifest(name string) (*Manifest, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if cfg.Repo != "" {
m, err := FetchManifestFromRepo(cfg.Repo, name)
if err == nil {
return m, nil
}
}
if url, ok := cfg.Packages[name]; ok { if url, ok := cfg.Packages[name]; ok {
return fetchManifestFromURL(url) return fetchManifestFromURL(url)
} }
@ -38,7 +50,7 @@ func FetchManifest(name string) (*Manifest, error) {
lastErr = err lastErr = err
} }
if lastErr == nil { if lastErr == nil {
lastErr = errors.New("не найден ни один репозиторий") lastErr = errors.New("no repository found")
} }
return nil, lastErr return nil, lastErr
} }
@ -50,7 +62,7 @@ func fetchManifestFromURL(url string) (*Manifest, error) {
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
return nil, errors.New("манифест пакета не найден по ссылке " + url) return nil, errors.New("manifest not found at " + url)
} }
data, err := ioutil.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {

42
pkg/manifest/repo.go Normal file
View File

@ -0,0 +1,42 @@
package manifest
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type RepoPackage struct {
Name string `json:"name"`
Manifest string `json:"manifest"`
}
type RepoFile struct {
Packages []RepoPackage `json:"packages"`
}
func FetchManifestFromRepo(repoURL, pkgName string) (*Manifest, error) {
resp, err := http.Get(repoURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("repo file not found at %s", repoURL)
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var rf RepoFile
if err := json.Unmarshal(data, &rf); err != nil {
return nil, err
}
for _, rp := range rf.Packages {
if rp.Name == pkgName {
return fetchManifestFromURL(rp.Manifest)
}
}
return nil, fmt.Errorf("package %s not found in repo", pkgName)
}

3
pkg/version/current.go Normal file
View File

@ -0,0 +1,3 @@
package version
const CurrentVersion = "1.1"