Init
This commit is contained in:
commit
d0187f94d7
23 changed files with 2489 additions and 0 deletions
214
spm/installed_pacakges.go
Normal file
214
spm/installed_pacakges.go
Normal file
|
@ -0,0 +1,214 @@
|
|||
package spm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
// getInstalledPackagesPath determines the path for the installed.ini file.
|
||||
func getInstalledPackagesPath(installDir string) string {
|
||||
spmDir := filepath.Join(installDir, "spm")
|
||||
_ = os.MkdirAll(spmDir, 0755)
|
||||
return filepath.Join(spmDir, "installed.ini")
|
||||
}
|
||||
|
||||
// loadInstalledPackages reads the installed.ini file and parses it.
|
||||
func loadInstalledPackages(installDir string) ([]AppIndexEntry, error) {
|
||||
installedFile := getInstalledPackagesPath(installDir)
|
||||
|
||||
cfg, err := ini.LoadSources(ini.LoadOptions{AllowNonUniqueSections: true}, installedFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return []AppIndexEntry{}, nil // Return empty slice if file doesn't exist
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var installed []AppIndexEntry
|
||||
for _, section := range cfg.Sections() {
|
||||
if section.Name() == "DEFAULT" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Read fields
|
||||
name := section.Key("P").String()
|
||||
version := section.Key("V").String()
|
||||
release := section.Key("R").String()
|
||||
typeVal := section.Key("o").String()
|
||||
arch := section.Key("A").MustString(runtime.GOARCH) // Default to system arch
|
||||
osName := section.Key("p").MustString(runtime.GOOS) // Default to system OS
|
||||
|
||||
// Append to slice
|
||||
installed = append(installed, AppIndexEntry{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Release: release,
|
||||
Type: typeVal,
|
||||
Arch: arch,
|
||||
OS: osName,
|
||||
})
|
||||
}
|
||||
|
||||
return installed, nil
|
||||
}
|
||||
|
||||
// saveInstalledPackages writes the installed packages into installed.ini.
|
||||
func saveInstalledPackages(installDir string, pkgs []AppIndexEntry) error {
|
||||
installedFile := getInstalledPackagesPath(installDir)
|
||||
|
||||
cfg := ini.Empty()
|
||||
for _, pkg := range pkgs {
|
||||
section, err := cfg.NewSection(pkg.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
section.Key("P").SetValue(pkg.Name)
|
||||
section.Key("V").SetValue(pkg.Version)
|
||||
section.Key("R").SetValue(pkg.Release)
|
||||
section.Key("o").SetValue(pkg.Type)
|
||||
|
||||
// Save arch if different from current runtime architecture
|
||||
if pkg.Arch != runtime.GOARCH {
|
||||
section.Key("A").SetValue(pkg.Arch)
|
||||
}
|
||||
|
||||
// Save OS if different from current runtime OS
|
||||
if pkg.OS != runtime.GOOS {
|
||||
section.Key("p").SetValue(pkg.OS)
|
||||
}
|
||||
}
|
||||
|
||||
return cfg.SaveTo(installedFile)
|
||||
}
|
||||
|
||||
// isNewerVersion compares two version strings and determines if `newVer` is newer than `oldVer`.
|
||||
func isNewerVersion(oldVer, newVer string) bool {
|
||||
// Handle date-based versions (e.g., nightly: YYYY.MM.DD)
|
||||
if isDateVersion(oldVer) && isDateVersion(newVer) {
|
||||
return strings.Compare(newVer, oldVer) > 0
|
||||
}
|
||||
|
||||
// Handle semantic versions (e.g., stable: v1.0.1)
|
||||
if isSemVer(oldVer) && isSemVer(newVer) {
|
||||
return compareSemVer(oldVer, newVer) > 0
|
||||
}
|
||||
|
||||
// Fallback to lexicographical comparison for unknown formats
|
||||
return strings.Compare(newVer, oldVer) > 0
|
||||
}
|
||||
|
||||
// isDateVersion checks if a version string is in the format YYYY.MM.DD.
|
||||
func isDateVersion(version string) bool {
|
||||
parts := strings.Split(version, ".")
|
||||
if len(parts) != 3 {
|
||||
return false
|
||||
}
|
||||
for _, part := range parts {
|
||||
if _, err := strconv.Atoi(part); err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isSemVer checks if a version string is in the format vMAJOR.MINOR.PATCH.
|
||||
func isSemVer(version string) bool {
|
||||
if !strings.HasPrefix(version, "v") {
|
||||
return false
|
||||
}
|
||||
parts := strings.Split(strings.TrimPrefix(version, "v"), ".")
|
||||
if len(parts) != 3 {
|
||||
return false
|
||||
}
|
||||
for _, part := range parts {
|
||||
if _, err := strconv.Atoi(part); err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// compareSemVer compares two semantic version strings (vMAJOR.MINOR.PATCH).
|
||||
// Returns:
|
||||
// - 1 if `v2` is newer than `v1`
|
||||
// - 0 if `v1` and `v2` are equal
|
||||
// - -1 if `v1` is newer than `v2`
|
||||
func compareSemVer(v1, v2 string) int {
|
||||
parts1 := strings.Split(strings.TrimPrefix(v1, "v"), ".")
|
||||
parts2 := strings.Split(strings.TrimPrefix(v2, "v"), ".")
|
||||
|
||||
for i := 0; i < len(parts1); i++ {
|
||||
num1, _ := strconv.Atoi(parts1[i])
|
||||
num2, _ := strconv.Atoi(parts2[i])
|
||||
if num1 > num2 {
|
||||
return 1
|
||||
}
|
||||
if num1 < num2 {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IsUpdateNeeded checks if the given package version is newer than what's installed.
|
||||
func IsUpdateNeeded(installDir, name, release, newVersion, arch, osName string) (bool, error) {
|
||||
installed, err := loadInstalledPackages(installDir)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, pkg := range installed {
|
||||
if pkg.Name == name && pkg.Release == release && pkg.Arch == arch && pkg.OS == osName {
|
||||
fmt.Printf("Found installed package: %v\n", pkg)
|
||||
if isNewerVersion(pkg.Version, newVersion) {
|
||||
fmt.Println("Update is needed")
|
||||
return true, nil
|
||||
}
|
||||
fmt.Println("No update needed")
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Package not installed, update needed")
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// UpdateInstalledPackage writes/updates the new package version in installed.ini.
|
||||
func UpdateInstalledPackage(installDir string, pkg AppIndexEntry) error {
|
||||
installed, err := loadInstalledPackages(installDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updated := false
|
||||
for i, p := range installed {
|
||||
if p.Name == pkg.Name && p.Release == pkg.Release && p.Arch == pkg.Arch && p.OS == pkg.OS {
|
||||
installed[i].Version = pkg.Version
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !updated {
|
||||
installed = append(installed, pkg)
|
||||
}
|
||||
|
||||
return saveInstalledPackages(installDir, installed)
|
||||
}
|
||||
|
||||
// // DebugInstalled prints installed packages for debugging.
|
||||
// func DebugInstalled(installDir string) {
|
||||
// pkgs, err := loadInstalledPackages(installDir)
|
||||
// if err != nil {
|
||||
// fmt.Println("DebugInstalled error:", err)
|
||||
// return
|
||||
// }
|
||||
// for _, p := range pkgs {
|
||||
// fmt.Printf("Installed: %s v%s [%s] (arch=%s, os=%s)\n", p.Name, p.Version, p.Release, p.Arch, p.OS)
|
||||
// }
|
||||
// }
|
Loading…
Add table
Add a link
Reference in a new issue