mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-20 18:23:47 +00:00
9bc050371b
The ConfigHandlers were calling config.SaveConfig() which uses globalPersistence initialized at startup with potentially wrong path. Now handlers use their own persistence instance directly which is initialized with the correct DataPath. This was causing Docker configurations to still save to /etc/pulse even though we thought we fixed it in v4.0.6. Fixes #253 (for real this time)
202 lines
4.6 KiB
Go
202 lines
4.6 KiB
Go
package updates
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Version represents a semantic version
|
|
type Version struct {
|
|
Major int
|
|
Minor int
|
|
Patch int
|
|
Prerelease string
|
|
Build string
|
|
}
|
|
|
|
// VersionInfo contains detailed version information
|
|
type VersionInfo struct {
|
|
Version string `json:"version"`
|
|
Build string `json:"build"`
|
|
Runtime string `json:"runtime"`
|
|
Channel string `json:"channel,omitempty"`
|
|
IsDocker bool `json:"isDocker"`
|
|
IsDevelopment bool `json:"isDevelopment"`
|
|
}
|
|
|
|
// ParseVersion parses a version string into a Version struct
|
|
func ParseVersion(versionStr string) (*Version, error) {
|
|
// Remove 'v' prefix if present
|
|
versionStr = strings.TrimPrefix(versionStr, "v")
|
|
|
|
// Regular expression for semantic versioning
|
|
re := regexp.MustCompile(`^(\d+)\.(\d+)\.(\d+)(?:-([^+]+))?(?:\+(.+))?$`)
|
|
matches := re.FindStringSubmatch(versionStr)
|
|
|
|
if len(matches) == 0 {
|
|
return nil, fmt.Errorf("invalid version format: %s", versionStr)
|
|
}
|
|
|
|
major, _ := strconv.Atoi(matches[1])
|
|
minor, _ := strconv.Atoi(matches[2])
|
|
patch, _ := strconv.Atoi(matches[3])
|
|
|
|
return &Version{
|
|
Major: major,
|
|
Minor: minor,
|
|
Patch: patch,
|
|
Prerelease: matches[4],
|
|
Build: matches[5],
|
|
}, nil
|
|
}
|
|
|
|
// String returns the string representation of the version
|
|
func (v *Version) String() string {
|
|
version := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
|
|
if v.Prerelease != "" {
|
|
version += "-" + v.Prerelease
|
|
}
|
|
if v.Build != "" {
|
|
version += "+" + v.Build
|
|
}
|
|
return version
|
|
}
|
|
|
|
// Compare compares two versions
|
|
// Returns:
|
|
// -1 if v < other
|
|
// 0 if v == other
|
|
// 1 if v > other
|
|
func (v *Version) Compare(other *Version) int {
|
|
if v.Major != other.Major {
|
|
return compareInts(v.Major, other.Major)
|
|
}
|
|
if v.Minor != other.Minor {
|
|
return compareInts(v.Minor, other.Minor)
|
|
}
|
|
if v.Patch != other.Patch {
|
|
return compareInts(v.Patch, other.Patch)
|
|
}
|
|
|
|
// Handle prerelease versions
|
|
if v.Prerelease == "" && other.Prerelease != "" {
|
|
return 1 // v is release, other is prerelease
|
|
}
|
|
if v.Prerelease != "" && other.Prerelease == "" {
|
|
return -1 // v is prerelease, other is release
|
|
}
|
|
if v.Prerelease != other.Prerelease {
|
|
return strings.Compare(v.Prerelease, other.Prerelease)
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
// IsNewerThan returns true if v is newer than other
|
|
func (v *Version) IsNewerThan(other *Version) bool {
|
|
return v.Compare(other) > 0
|
|
}
|
|
|
|
// IsPrerelease returns true if this is a prerelease version
|
|
func (v *Version) IsPrerelease() bool {
|
|
return v.Prerelease != ""
|
|
}
|
|
|
|
// GetCurrentVersion gets the current running version
|
|
func GetCurrentVersion() (*VersionInfo, error) {
|
|
// Try to get version from git first (development)
|
|
gitVersion, err := getGitVersion()
|
|
if err == nil && gitVersion != "" {
|
|
return &VersionInfo{
|
|
Version: gitVersion,
|
|
Build: "development",
|
|
Runtime: "go",
|
|
IsDevelopment: true,
|
|
IsDocker: isDockerEnvironment(),
|
|
}, nil
|
|
}
|
|
|
|
// Try to read from VERSION file in multiple locations
|
|
versionPaths := []string{
|
|
"VERSION",
|
|
"/opt/pulse/VERSION",
|
|
filepath.Join(filepath.Dir(os.Args[0]), "VERSION"),
|
|
}
|
|
|
|
for _, path := range versionPaths {
|
|
versionBytes, err := os.ReadFile(path)
|
|
if err == nil {
|
|
return &VersionInfo{
|
|
Version: strings.TrimSpace(string(versionBytes)),
|
|
Build: "release",
|
|
Runtime: "go",
|
|
IsDevelopment: false,
|
|
IsDocker: isDockerEnvironment(),
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
// Final fallback
|
|
return &VersionInfo{
|
|
Version: "4.0.7",
|
|
Build: "release",
|
|
Runtime: "go",
|
|
IsDevelopment: false,
|
|
IsDocker: isDockerEnvironment(),
|
|
}, nil
|
|
}
|
|
|
|
// getGitVersion gets version information from git
|
|
func getGitVersion() (string, error) {
|
|
// Get the latest tag
|
|
cmd := exec.Command("git", "describe", "--tags", "--always", "--dirty")
|
|
output, err := cmd.Output()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
version := strings.TrimSpace(string(output))
|
|
if version == "" {
|
|
return "", fmt.Errorf("no version found")
|
|
}
|
|
|
|
return version, nil
|
|
}
|
|
|
|
// isDockerEnvironment checks if running in Docker
|
|
func isDockerEnvironment() bool {
|
|
// Check for Docker-specific files
|
|
if fileExists("/.dockerenv") {
|
|
return true
|
|
}
|
|
|
|
// Check cgroup for Docker
|
|
data, err := exec.Command("cat", "/proc/1/cgroup").Output()
|
|
if err == nil && strings.Contains(string(data), "docker") {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// fileExists checks if a file exists
|
|
func fileExists(path string) bool {
|
|
cmd := exec.Command("test", "-f", path)
|
|
return cmd.Run() == nil
|
|
}
|
|
|
|
// compareInts compares two integers
|
|
func compareInts(a, b int) int {
|
|
if a < b {
|
|
return -1
|
|
}
|
|
if a > b {
|
|
return 1
|
|
}
|
|
return 0
|
|
} |