Files
jbergner 4a48f9b8c5
Citizen Launcher CI / verify (push) Failing after 1m18s
Citizen Launcher CI / arch-package (push) Failing after 1m19s
Citizen Launcher CI / rpm-package (push) Failing after 1m21s
v1.1.1
2026-09-01 19:50:44 +02:00

173 lines
4.8 KiB
Go

package main
import (
"bufio"
"os"
"os/exec"
"strings"
)
type PlatformStatus struct {
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Variant string `json:"variant,omitempty"`
IDLike string `json:"id_like,omitempty"`
Family string `json:"family"`
PackageManager string `json:"package_manager"`
Desktop string `json:"desktop,omitempty"`
Session string `json:"session,omitempty"`
SystemdUser bool `json:"systemd_user"`
Immutable bool `json:"immutable"`
Omarchy bool `json:"omarchy"`
}
func detectPlatform() PlatformStatus {
vals := readOSRelease("/etc/os-release")
p := platformFromOSRelease(vals)
// Prefer the package manager that belongs to the detected distro family. This
// avoids mis-detection on systems that happen to have foreign packaging tools
// installed for development or compatibility purposes.
switch p.Family {
case "debian":
if commandExists("apt-get") {
p.PackageManager = "apt"
}
case "fedora":
if commandExists("rpm-ostree") && p.Immutable {
p.PackageManager = "rpm-ostree"
} else if commandExists("dnf5") {
p.PackageManager = "dnf5"
} else if commandExists("dnf") {
p.PackageManager = "dnf"
}
case "arch":
if commandExists("pacman") {
p.PackageManager = "pacman"
}
case "suse":
if commandExists("transactional-update") && p.Immutable {
p.PackageManager = "transactional-update"
} else if commandExists("zypper") {
p.PackageManager = "zypper"
}
}
if p.PackageManager == "" {
switch {
case commandExists("apt-get"):
p.PackageManager = "apt"
case commandExists("dnf5"):
p.PackageManager = "dnf5"
case commandExists("dnf"):
p.PackageManager = "dnf"
case commandExists("pacman"):
p.PackageManager = "pacman"
case commandExists("zypper"):
p.PackageManager = "zypper"
case commandExists("xbps-install"):
p.PackageManager = "xbps"
case commandExists("emerge"):
p.PackageManager = "portage"
case commandExists("apk"):
p.PackageManager = "apk"
default:
p.PackageManager = "unknown"
}
}
p.Desktop = envOr("XDG_CURRENT_DESKTOP", envOr("DESKTOP_SESSION", ""))
p.Session = envOr("XDG_SESSION_TYPE", "")
if commandExists("systemctl") {
cmd := exec.Command("systemctl", "--user", "show-environment")
p.SystemdUser = cmd.Run() == nil
}
p.Omarchy = commandExists("omarchy")
return p
}
func readOSRelease(path string) map[string]string {
vals := map[string]string{}
f, err := os.Open(path)
if err != nil {
return vals
}
defer f.Close()
sc := bufio.NewScanner(f)
for sc.Scan() {
line := strings.TrimSpace(sc.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}
k, v, ok := strings.Cut(line, "=")
if ok {
vals[k] = strings.Trim(strings.TrimSpace(v), `"'`)
}
}
return vals
}
func platformFromOSRelease(vals map[string]string) PlatformStatus {
p := PlatformStatus{ID: "linux", Name: "Linux", Family: "other"}
if vals["ID"] != "" {
p.ID = strings.ToLower(vals["ID"])
}
if vals["PRETTY_NAME"] != "" {
p.Name = vals["PRETTY_NAME"]
} else if vals["NAME"] != "" {
p.Name = vals["NAME"]
}
p.Version = vals["VERSION_ID"]
p.Variant = vals["VARIANT_ID"]
p.IDLike = strings.ToLower(vals["ID_LIKE"])
p.Family = distroFamily(p.ID, p.IDLike)
p.Immutable = immutableDistro(p.ID, p.Variant) || fileExists("/run/ostree-booted") || fileExists("/run/transactional-update")
return p
}
func distroFamily(id, idLike string) string {
id = strings.ToLower(id)
like := " " + strings.ToLower(idLike) + " "
containsLike := func(v string) bool { return strings.Contains(like, " "+v+" ") }
switch id {
case "debian", "ubuntu", "linuxmint", "pop", "elementary", "zorin", "kali", "neon", "tuxedo":
return "debian"
case "fedora", "nobara", "rhel", "centos", "rocky", "almalinux", "ultramarine":
return "fedora"
case "arch", "manjaro", "endeavouros", "cachyos", "garuda", "steamos":
return "arch"
case "opensuse", "opensuse-tumbleweed", "opensuse-leap", "opensuse-slowroll", "sles", "sled":
return "suse"
}
switch {
case containsLike("debian") || containsLike("ubuntu"):
return "debian"
case containsLike("fedora") || containsLike("rhel") || containsLike("centos"):
return "fedora"
case containsLike("arch"):
return "arch"
case containsLike("suse") || containsLike("opensuse"):
return "suse"
default:
return "other"
}
}
func immutableDistro(id, variant string) bool {
id = strings.ToLower(id)
variant = strings.ToLower(variant)
if id == "steamos" || strings.Contains(id, "microos") || strings.Contains(id, "aeon") || strings.Contains(id, "kalpa") {
return true
}
switch variant {
case "silverblue", "kinoite", "sericea", "onyx", "atomic", "coreos", "steamdeck":
return true
}
return false
}
func fileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}