mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
doctor: use dbus for checking on services (#1384)
* doctor: use dbus for checking on services * doctor: show docs URL for failed checks * core: remove unused function
This commit is contained in:
@@ -477,7 +477,7 @@ func checkWindowManagers() []checkResult {
|
|||||||
results = append(results, checkResult{
|
results = append(results, checkResult{
|
||||||
catCompositor, c.name, statusOK,
|
catCompositor, c.name, statusOK,
|
||||||
getVersionFromCommand(c.versionCmd, c.versionArg, c.versionRegex), details,
|
getVersionFromCommand(c.versionCmd, c.versionArg, c.versionRegex), details,
|
||||||
doctorDocsURL + "#compositor",
|
doctorDocsURL + "#compositor-checks",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +486,7 @@ func checkWindowManagers() []checkResult {
|
|||||||
catCompositor, "Compositor", statusError,
|
catCompositor, "Compositor", statusError,
|
||||||
"No supported Wayland compositor found",
|
"No supported Wayland compositor found",
|
||||||
"Install Hyprland, niri, Sway, River, or Wayfire",
|
"Install Hyprland, niri, Sway, River, or Wayfire",
|
||||||
doctorDocsURL + "#compositor",
|
doctorDocsURL + "#compositor-checks",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,19 +634,14 @@ func checkI2CAvailability() checkResult {
|
|||||||
return checkResult{catOptionalFeatures, "I2C/DDC", statusOK, fmt.Sprintf("%d monitor(s) detected", len(devices)), "External monitor brightness control", doctorDocsURL + "#optional-features"}
|
return checkResult{catOptionalFeatures, "I2C/DDC", statusOK, fmt.Sprintf("%d monitor(s) detected", len(devices)), "External monitor brightness control", doctorDocsURL + "#optional-features"}
|
||||||
}
|
}
|
||||||
|
|
||||||
func detectNetworkBackend() string {
|
func detectNetworkBackend(stackResult *network.DetectResult) string {
|
||||||
result, err := network.DetectNetworkStack()
|
switch stackResult.Backend {
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
switch result.Backend {
|
|
||||||
case network.BackendNetworkManager:
|
case network.BackendNetworkManager:
|
||||||
return "NetworkManager"
|
return "NetworkManager"
|
||||||
case network.BackendIwd:
|
case network.BackendIwd:
|
||||||
return "iwd"
|
return "iwd"
|
||||||
case network.BackendNetworkd:
|
case network.BackendNetworkd:
|
||||||
if result.HasIwd {
|
if stackResult.HasIwd {
|
||||||
return "iwd + systemd-networkd"
|
return "iwd + systemd-networkd"
|
||||||
}
|
}
|
||||||
return "systemd-networkd"
|
return "systemd-networkd"
|
||||||
@@ -657,75 +652,73 @@ func detectNetworkBackend() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getOptionalDBusStatus(busName string) (status, string) {
|
||||||
|
if utils.IsDBusServiceAvailable(busName) {
|
||||||
|
return statusOK, "Available"
|
||||||
|
} else {
|
||||||
|
return statusWarn, "Not available"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkOptionalDependencies() []checkResult {
|
func checkOptionalDependencies() []checkResult {
|
||||||
var results []checkResult
|
var results []checkResult
|
||||||
|
|
||||||
if utils.IsServiceActive("accounts-daemon", false) {
|
optionalFeaturesURL := doctorDocsURL + "#optional-features"
|
||||||
results = append(results, checkResult{catOptionalFeatures, "accountsservice", statusOK, "Running", "User accounts", doctorDocsURL + "#optional-features"})
|
|
||||||
} else {
|
|
||||||
results = append(results, checkResult{catOptionalFeatures, "accountsservice", statusWarn, "Not running", "User accounts", doctorDocsURL + "#optional-features"})
|
|
||||||
}
|
|
||||||
|
|
||||||
if utils.IsServiceActive("power-profiles-daemon", false) {
|
accountsStatus, accountsMsg := getOptionalDBusStatus("org.freedesktop.Accounts")
|
||||||
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", statusOK, "Running", "Power profile management", doctorDocsURL + "#optional-features"})
|
results = append(results, checkResult{catOptionalFeatures, "accountsservice", accountsStatus, accountsMsg, "User accounts", optionalFeaturesURL})
|
||||||
} else {
|
|
||||||
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", statusInfo, "Not running", "Power profile management", doctorDocsURL + "#optional-features"})
|
ppdStatus, ppdMsg := getOptionalDBusStatus("org.freedesktop.UPower.PowerProfiles")
|
||||||
}
|
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", ppdStatus, ppdMsg, "Power profile management", optionalFeaturesURL})
|
||||||
|
|
||||||
|
logindStatus, logindMsg := getOptionalDBusStatus("org.freedesktop.login1")
|
||||||
|
results = append(results, checkResult{catOptionalFeatures, "logind", logindStatus, logindMsg, "Session management", optionalFeaturesURL})
|
||||||
|
|
||||||
results = append(results, checkI2CAvailability())
|
results = append(results, checkI2CAvailability())
|
||||||
|
|
||||||
terminals := []string{"ghostty", "kitty", "alacritty", "foot", "wezterm"}
|
terminals := []string{"ghostty", "kitty", "alacritty", "foot", "wezterm"}
|
||||||
if idx := slices.IndexFunc(terminals, utils.CommandExists); idx >= 0 {
|
if idx := slices.IndexFunc(terminals, utils.CommandExists); idx >= 0 {
|
||||||
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusOK, terminals[idx], "", doctorDocsURL + "#optional-features"})
|
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusOK, terminals[idx], "", optionalFeaturesURL})
|
||||||
} else {
|
} else {
|
||||||
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusWarn, "None found", "Install ghostty, kitty, or alacritty", doctorDocsURL + "#optional-features"})
|
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusWarn, "None found", "Install ghostty, kitty, or alacritty", optionalFeaturesURL})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
networkResult, err := network.DetectNetworkStack()
|
||||||
|
networkStatus, networkMessage, networkDetails := statusOK, "Not available", "Network management"
|
||||||
|
|
||||||
|
if err == nil && networkResult.Backend != network.BackendNone {
|
||||||
|
networkMessage = detectNetworkBackend(networkResult)
|
||||||
|
if doctorVerbose {
|
||||||
|
networkDetails = networkResult.ChosenReason
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
networkStatus = statusInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
results = append(results, checkResult{catOptionalFeatures, "Network", networkStatus, networkMessage, networkDetails, optionalFeaturesURL})
|
||||||
|
|
||||||
deps := []struct {
|
deps := []struct {
|
||||||
name, cmd, altCmd, desc string
|
name, cmd, desc string
|
||||||
important bool
|
important bool
|
||||||
}{
|
}{
|
||||||
{"matugen", "matugen", "", "Dynamic theming", true},
|
{"matugen", "matugen", "Dynamic theming", true},
|
||||||
{"dgop", "dgop", "", "System monitoring", true},
|
{"dgop", "dgop", "System monitoring", true},
|
||||||
{"cava", "cava", "", "Audio visualizer", true},
|
{"cava", "cava", "Audio visualizer", true},
|
||||||
{"khal", "khal", "", "Calendar events", false},
|
{"khal", "khal", "Calendar events", false},
|
||||||
{"Network", "nmcli", "iwctl", "Network management", false},
|
{"danksearch", "dsearch", "File search", false},
|
||||||
{"danksearch", "dsearch", "", "File search", false},
|
{"fprintd", "fprintd-list", "Fingerprint auth", false},
|
||||||
{"loginctl", "loginctl", "", "Session management", false},
|
|
||||||
{"fprintd", "fprintd-list", "", "Fingerprint auth", false},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range deps {
|
for _, d := range deps {
|
||||||
found, foundCmd := utils.CommandExists(d.cmd), d.cmd
|
found := utils.CommandExists(d.cmd)
|
||||||
if !found && d.altCmd != "" && utils.CommandExists(d.altCmd) {
|
|
||||||
found, foundCmd = true, d.altCmd
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case found:
|
case found:
|
||||||
message := "Installed"
|
results = append(results, checkResult{catOptionalFeatures, d.name, statusOK, "Installed", d.desc, optionalFeaturesURL})
|
||||||
details := d.desc
|
|
||||||
if d.name == "Network" {
|
|
||||||
result, err := network.DetectNetworkStack()
|
|
||||||
if err == nil && result.Backend != network.BackendNone {
|
|
||||||
message = detectNetworkBackend() + " (active)"
|
|
||||||
if doctorVerbose {
|
|
||||||
details = result.ChosenReason
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch foundCmd {
|
|
||||||
case "nmcli":
|
|
||||||
message = "NetworkManager (installed)"
|
|
||||||
case "iwctl":
|
|
||||||
message = "iwd (installed)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
results = append(results, checkResult{catOptionalFeatures, d.name, statusOK, message, details, doctorDocsURL + "#optional-features"})
|
|
||||||
case d.important:
|
case d.important:
|
||||||
results = append(results, checkResult{catOptionalFeatures, d.name, statusWarn, "Missing", d.desc, doctorDocsURL + "#optional-features"})
|
results = append(results, checkResult{catOptionalFeatures, d.name, statusWarn, "Missing", d.desc, optionalFeaturesURL})
|
||||||
default:
|
default:
|
||||||
results = append(results, checkResult{catOptionalFeatures, d.name, statusInfo, "Not installed", d.desc, doctorDocsURL + "#optional-features"})
|
results = append(results, checkResult{catOptionalFeatures, d.name, statusInfo, "Not installed", d.desc, optionalFeaturesURL})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -893,6 +886,10 @@ func printResultLine(r checkResult, styles tui.Styles) {
|
|||||||
if doctorVerbose && r.details != "" {
|
if doctorVerbose && r.details != "" {
|
||||||
fmt.Printf(" %s\n", styles.Subtle.Render("└─ "+r.details))
|
fmt.Printf(" %s\n", styles.Subtle.Render("└─ "+r.details))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (r.status == statusError || r.status == statusWarn) && r.url != "" {
|
||||||
|
fmt.Printf(" %s\n", styles.Subtle.Render("→ "+r.url))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printSummary(results []checkResult, qsMissingFeatures bool) {
|
func printSummary(results []checkResult, qsMissingFeatures bool) {
|
||||||
|
|||||||
20
core/internal/utils/dbus.go
Normal file
20
core/internal/utils/dbus.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/godbus/dbus/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsDBusServiceAvailable(busName string) bool {
|
||||||
|
conn, err := dbus.ConnectSystemBus()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
obj := conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
|
||||||
|
var owned bool
|
||||||
|
if err := obj.Call("org.freedesktop.DBus.NameHasOwner", 0, busName).Store(&owned); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return owned
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type AppChecker interface {
|
type AppChecker interface {
|
||||||
@@ -43,16 +42,3 @@ func AnyCommandExists(cmds ...string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsServiceActive(name string, userService bool) bool {
|
|
||||||
if !CommandExists("systemctl") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{"is-active", name}
|
|
||||||
if userService {
|
|
||||||
args = []string{"--user", "is-active", name}
|
|
||||||
}
|
|
||||||
output, _ := exec.Command("systemctl", args...).Output()
|
|
||||||
return strings.EqualFold(strings.TrimSpace(string(output)), "active")
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user