Skip to content

Commit

Permalink
Merge pull request #142 from ruiiiijiiiiang/main
Browse files Browse the repository at this point in the history
Enhanced support for Mac OS
  • Loading branch information
iinsertNameHere authored Nov 7, 2024
2 parents fa864cf + ae28b4d commit 7e7b9ae
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 93 deletions.
2 changes: 2 additions & 0 deletions src/catnaplib/global/definitions.nim
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const
"dragonfly": "pkg",
"netbsd": "pkgsrc",
"openbsd": "pkgsrc",
"macos": "homebrew",
}.toOrderedTable
PKGCOUNTCOMMANDS* = static: {
"apx": "apx list -i | wc -l",
Expand All @@ -136,6 +137,7 @@ const
"apk": "apk list --installed | wc -l",
"pkg": "pkg info",
"pkgsrc": "pkg_info",
"homebrew": "brew list | wc -l",
}.toOrderedTable

# Files / Dirs
Expand Down
38 changes: 21 additions & 17 deletions src/catnaplib/platform/fetch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,35 @@ proc fetchSystemInfo*(config: Config, distroId: string = "nil"): FetchInfo =
result.list["terminal"] = proc(): string = return probe.getTerminal()
result.list["shell"] = proc(): string = return probe.getShell()
result.list["memory"] = proc(): string = return probe.getMemory()
result.list["battery"] = proc(): string = return probe.getBattery()
result.list["battery"] = proc(): string = return probe.getBattery()
result.list["cpu"] = proc(): string = return probe.getCpu()
result.list["gpu"] = proc(): string = return probe.getGpu()
result.list["packages"] = proc(): string = return probe.getPackages()
result.list["weather"] = proc(): string = return probe.getWeather()
if defined(linux):
# Add a disk stat for all mounts
let mounts: seq[string] = probe.getMounts()

# Add a disk stat for all mounts
let mounts: seq[string] = probe.getMounts()
if mounts.len > 1:
var index = 0
for mount in mounts:
let name = "disk_" & $index

if mounts.len > 1:
var index = 0
for mount in mounts:
let name = "disk_" & $index
# Capture mount var to prevent value changes
var cap: proc(): string
capture mount:
# Create fetch proc
cap = proc(): string = return probe.getDisk(mount)

# Capture mount var to prevent value changes
var cap: proc(): string
capture mount:
# Create fetch proc
cap = proc(): string = return probe.getDisk(mount)

result.list[name] = cap
result.disk_statnames.add(name)
index += 1
result.list[name] = cap
result.disk_statnames.add(name)
index += 1
else:
result.list["disk_0"] = proc(): string = return probe.getDisk(mounts[0])
result.disk_statnames.add("disk_0")
else:
result.list["disk_0"] = proc(): string = return probe.getDisk(mounts[0])
#TODO: add macos support
result.list["disk_0"] = proc(): string = ""
result.disk_statnames.add("disk_0")

var distroId = (if distroId != "nil": distroId else: result.distroId.id)
Expand Down
191 changes: 115 additions & 76 deletions src/catnaplib/platform/probe.nim
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ proc getDistro*(): string =
when defined(linux) or defined(bsd):
# Returns the name of the running linux distro
result = "/etc/os-release".loadConfig.getSectionValue("", "PRETTY_NAME") & " " & uname().machine
elif defined(macos):
elif defined(macosx):
result = "MacOS X" & " " & uname().machine
else:
result = "Unknown"

writeCache(cacheFile, result, INFINITEDURATION)

Expand All @@ -36,24 +38,35 @@ proc getDistroId*(): DistroId =
result.id = raw_vals[0]
result.like = raw_vals[1]


if fileExists("/boot/issue.txt"): # Check if raspbian else get distroid from /etc/os-release
result.id = "raspbian"
result.like = "debian"
if defined(linux):
if fileExists("/boot/issue.txt"): # Check if raspbian else get distroid from /etc/os-release
result.id = "raspbian"
result.like = "debian"
else:
result.id = "/etc/os-release".loadConfig.getSectionValue("", "ID").toLower()
result.like = "/etc/os-release".loadConfig.getSectionValue("", "ID_LIKE").toLower()
elif defined(macosx):
result.id = "macos"
result.like = "macos"
else:
result.id = "/etc/os-release".loadConfig.getSectionValue("", "ID").toLower()
result.like = "/etc/os-release".loadConfig.getSectionValue("", "ID_LIKE").toLower()

result.id = "Unknown"
result.like = "Unknown"
writeCache(cacheFile, &"{result.id}|{result.like}", INFINITEDURATION)

proc getUptime*(): string =
# Returns the system uptime as a string (DAYS, HOURS, MINUTES)

# Uptime in sec
let uptime = "/proc/uptime".open.readLine.split(".")[0]
var utu: int
if defined(linux):
let uptime = "/proc/uptime".open.readLine.split(".")[0]
utu = uptime.parseInt
else:
let boottime = execProcess("sysctl -n kern.boottime").split(" ")[3].split(",")[0]
let now = epochTime()
utu = toInt(now) - parseInt(boottime)

let
utu = uptime.parseUInt
uth = utu div 3600 mod 24 # hours
utm = utu mod 3600 div 60 # minutes
utd = utu div 3600 div 24 # days
Expand Down Expand Up @@ -96,13 +109,22 @@ proc getProcessName(pid: int): string =

proc getTerminal*(): string =
# Returns the currently running terminal emulator
result = getCurrentProcessID().getParentPid().getParentPid().getProcessName()
if result == "login" or result == "sshd":
result = "tty"
if defined(linux):
result = getCurrentProcessID().getParentPid().getParentPid().getProcessName()
if result == "login" or result == "sshd":
result = "tty"
elif defined(macosx):
result = getEnv("TERM_PROGRAM")
else:
result = "Unknown"

proc getShell*(): string =
# Returns the system shell
result = getCurrentProcessID().getParentPid().getProcessName()
if defined(linux):
result = getCurrentProcessID().getParentPid().getProcessName()
else:
#TODO: add macos support
result = ""

proc getDesktop*(): string =
# Returns the running desktop env
Expand All @@ -127,49 +149,61 @@ proc getDesktop*(): string =

proc getMemory*(mb: bool = true): string =
# Returns statistics about the memory
let
fileSeq: seq[string] = "/proc/meminfo".readLines(3)
if defined(linux):
let
fileSeq: seq[string] = "/proc/meminfo".readLines(3)

dividend: uint = if mb: 1000 else: 1024
suffix: string = if mb: "MB" else: "MiB"
dividend: uint = if mb: 1000 else: 1024
suffix: string = if mb: "MB" else: "MiB"

memTotalString = fileSeq[0].split(" ")[^2]
memAvailableString = fileSeq[2].split(" ")[^2]
memTotalString = fileSeq[0].split(" ")[^2]
memAvailableString = fileSeq[2].split(" ")[^2]

memTotalInt = memTotalString.parseUInt div dividend
memAvailableInt = memAvailableString.parseUInt div dividend
memTotalInt = memTotalString.parseUInt div dividend
memAvailableInt = memAvailableString.parseUInt div dividend

memUsedInt = memTotalInt - memAvailableInt
percentage = ((int(memUsedInt) / int(memTotalInt)) * 100).round().int()
memUsedInt = memTotalInt - memAvailableInt
percentage = ((int(memUsedInt) / int(memTotalInt)) * 100).round().int()

result = &"{memUsedInt} / {memTotalInt} {suffix} ({percentage}%)"
result = &"{memUsedInt} / {memTotalInt} {suffix} ({percentage}%)"
else:
#TODO: add macos support
result = ""

proc getBattery*(): string =
# Credits to https://gitlab.com/prashere/battinfo for regex implementation.

let
BATTERY_REGEX = re"^BAT\d+$"
powerPath = "/sys/class/power_supply/"
if defined(linux):
# Credits to https://gitlab.com/prashere/battinfo for regex implementation.
let
BATTERY_REGEX = re"^BAT\d+$"
powerPath = "/sys/class/power_supply/"

var batterys: seq[tuple[idx: int, path: string]]
var batterys: seq[tuple[idx: int, path: string]]

# Collect all batterys
for dir in os.walk_dir(powerPath):
if re.match(os.last_path_part(dir.path), BATTERY_REGEX):
batterys.add((parseInt($dir.path[^1]), dir.path & "/"))
# Collect all batterys
for dir in os.walk_dir(powerPath):
if re.match(os.last_path_part(dir.path), BATTERY_REGEX):
batterys.add((parseInt($dir.path[^1]), dir.path & "/"))

if batterys.len < 1:
logError("No battery detected!")
if batterys.len < 1:
logError("No battery detected!")

# Sort batterys by number
sort(batterys)
# Sort batterys by number
sort(batterys)

# Get stats for battery with lowest number
let
batteryCapacity = readFile(batterys[0].path & "capacity").strip()
batteryStatus = readFile(batterys[0].path & "status").strip()
# Get stats for battery with lowest number
let
batteryCapacity = readFile(batterys[0].path & "capacity").strip()
batteryStatus = readFile(batterys[0].path & "status").strip()

result = &"{batteryCapacity}% ({batteryStatus})"
result = &"{batteryCapacity}% ({batteryStatus})"
elif defined(macosx):
let
pmset = execProcess("pmset -g batt | tail -n 1").split("\t")[1].split("; ")
batteryCapacity = pmset[0]
batteryStatus = pmset[1]
result = &"{batteryCapacity} ({batteryStatus})"
else:
result = "Unknown"

proc getMounts*(): seq[string] =
proc getMountPoints(): cstring {.importc, varargs, header: "getDisk.h".}
Expand Down Expand Up @@ -213,26 +247,28 @@ proc getCpu*(): string =
if result != "":
return

when defined(macos):
return execCmd("sysctl -n machdep.cpu.brand_string")

let rawLines = readFile("/proc/cpuinfo").split("\n")

var key_name = "model name"
if getDistroId().id == "raspbian": key_name = "Model"

for rawLine in rawLines:
let line = rawLine.split(":")

if line.len < 2: continue
if defined(linux):
let rawLines = readFile("/proc/cpuinfo").split("\n")

var key_name = "model name"
if getDistroId().id == "raspbian": key_name = "Model"

for rawLine in rawLines:
let line = rawLine.split(":")

if line.len < 2: continue

let
key = line[0].strip()
val = line[1].strip()
if key == key_name:
result = val
break
elif defined(macosx):
result = execProcess("sysctl -n machdep.cpu.brand_string").split("\n")[0]
else:
result = "Unknown"

let
key = line[0].strip()
val = line[1].strip()
if key == key_name:
result = val
break

writeCache(cacheFile, result, initDuration(days=1))

proc getPkgManager(distroId: DistroId): string =
Expand All @@ -243,7 +279,7 @@ proc getPkgManager(distroId: DistroId): string =
for key in PKGMANAGERS.keys:
if distroId.like == key:
return PKGMANAGERS[key]

return "Unknown"

proc getPackages*(distroId: DistroId = getDistroId()): string =
Expand Down Expand Up @@ -283,22 +319,25 @@ proc getGpu*(): string =
if result != "":
return

let tmpFile = "lspci.txt".toTmpPath
if defined(linux):
let tmpFile = "lspci.txt".toTmpPath

if execCmd("lspci > " & tmpFile) != 0:
logError("Failed to fetch GPU!")
if execCmd("lspci > " & tmpFile) != 0:
logError("Failed to fetch GPU!")

var vga = "Unknown"
let lspci = readFile(tmpFile)
for line in lspci.split('\n'):
if line.split(' ')[1] == "VGA":
vga = line
break
var vga = "Unknown"
let lspci = readFile(tmpFile)
for line in lspci.split('\n'):
if line.split(' ')[1] == "VGA":
vga = line
break

let vga_parts = vga.split(":")
let vga_parts = vga.split(":")

if vga_parts.len >= 2 or vga != "Unknown":
result = vga_parts[vga_parts.len - 1].split("(")[0].strip()
if vga_parts.len >= 2 or vga != "Unknown":
result = vga_parts[vga_parts.len - 1].split("(")[0].strip()
elif defined(macosx):
result = execProcess("system_profiler SPDisplaysDataType | grep 'Chipset Model'").split(": ")[1].split("\n")[0]
else:
result = "Unknown"

Expand Down

0 comments on commit 7e7b9ae

Please sign in to comment.