This commit is contained in:
Mars 2025-05-05 12:54:03 -04:00
parent ccd20f5461
commit 8709ef9de9
Signed by: pupbrained
GPG key ID: 874E22DF2F9DFCB5
4 changed files with 330 additions and 203 deletions

View file

@ -295,15 +295,7 @@ namespace package {
if (cargoPath.empty() || !fs::exists(cargoPath))
return Err(DracError(DracErrorCode::NotFound, "Could not find cargo directory"));
u64 count = 0;
for (const fs::directory_entry& entry : fs::directory_iterator(cargoPath))
if (entry.is_regular_file())
++count;
debug_log("Found {} packages in cargo directory: {}", count, cargoPath.string());
return count;
return GetCountFromDirectory("cargo", cargoPath);
}
fn GetTotalCount() -> Result<u64> {

View file

@ -5,54 +5,120 @@
#include <sys/statvfs.h>
#include <sys/sysctl.h>
#include "macos/bridge.hpp"
#include "os.hpp"
#include "src/core/package.hpp"
#include "src/util/defs.hpp"
#include "src/util/error.hpp"
#include "src/util/helpers.hpp"
#include "src/util/types.hpp"
#include "macos/bridge.hpp"
#include "os.hpp"
// clang-format on
using namespace util::types;
using util::error::DracError;
using util::error::DracError, util::error::DracErrorCode;
using util::helpers::GetEnv;
fn os::GetMemInfo() -> Result<u64> {
namespace {
fn StrEqualsIgnoreCase(std::string_view strA, std::string_view strB) -> bool {
if (strA.length() != strB.length())
return false;
return std::equal(strA.begin(), strA.end(), strB.begin(), [](char aChar, char bChar) {
return std::tolower(static_cast<unsigned char>(aChar)) == std::tolower(static_cast<unsigned char>(bChar));
});
}
fn Capitalize(std::string_view sview) -> Option<String> {
if (sview.empty())
return None;
String result(sview);
result[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(result[0])));
return result;
}
} // namespace
namespace os {
fn GetMemInfo() -> Result<u64> {
u64 mem = 0;
usize size = sizeof(mem);
if (sysctlbyname("hw.memsize", &mem, &size, nullptr, 0) == -1)
return Err(DracError::withErrno("Failed to get memory info"));
return Err(DracError("Failed to get memory info"));
return mem;
}
}
fn os::GetNowPlaying() -> Result<MediaInfo> { return GetCurrentPlayingInfo(); }
fn GetNowPlaying() -> Result<MediaInfo> { return GetCurrentPlayingInfo(); }
fn os::GetOSVersion() -> Result<String> { return GetMacOSVersion(); }
fn GetOSVersion() -> Result<String> { return GetMacOSVersion(); }
fn os::GetDesktopEnvironment() -> Result<String> {
return "Aqua"; // TODO: Implement
}
fn GetDesktopEnvironment() -> Result<String> { return "Aqua"; }
fn os::GetWindowManager() -> Result<String> {
return "Yabai"; // TODO: Implement
}
fn GetWindowManager() -> Result<String> {
constexpr std::array<std::string_view, 6> knownWms = {
"yabai", "kwm", "chunkwm", "amethyst", "spectacle", "rectangle",
};
fn os::GetKernelVersion() -> Result<String> {
Array<i32, 3> request = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
usize len = 0;
if (sysctl(request.data(), request.size(), nullptr, &len, nullptr, 0) == -1)
return Err(DracError("sysctl size query failed for KERN_PROC_ALL"));
if (len == 0)
return Err(DracError(DracErrorCode::NotFound, "sysctl for KERN_PROC_ALL returned zero length"));
Vec<char> buf(len);
if (sysctl(request.data(), request.size(), buf.data(), &len, nullptr, 0) == -1)
return Err(DracError("sysctl data fetch failed for KERN_PROC_ALL"));
if (len % sizeof(kinfo_proc) != 0)
return Err(DracError(
DracErrorCode::PlatformSpecific,
std::format("sysctl returned size {} which is not a multiple of kinfo_proc size {}", len, sizeof(kinfo_proc))
));
usize count = len / sizeof(kinfo_proc);
std::span<const kinfo_proc> processes = std::span(
reinterpret_cast<const kinfo_proc*>(buf.data()), count // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
);
for (const kinfo_proc& procInfo : processes) {
StringView comm(procInfo.kp_proc.p_comm);
for (const auto& wmName : knownWms)
if (StrEqualsIgnoreCase(comm, wmName)) {
const auto capitalized = Capitalize(comm);
return capitalized ? Result<String>(*capitalized)
: Err(DracError(DracErrorCode::ParseError, "Failed to capitalize window manager name"));
}
}
return "Quartz";
}
fn GetKernelVersion() -> Result<String> {
Array<char, 256> kernelVersion {};
usize kernelVersionLen = sizeof(kernelVersion);
if (sysctlbyname("kern.osrelease", kernelVersion.data(), &kernelVersionLen, nullptr, 0) == -1)
return Err(DracError::withErrno("Failed to get kernel version"));
return Err(DracError("Failed to get kernel version"));
return kernelVersion.data();
}
}
fn os::GetHost() -> Result<String> {
fn GetHost() -> Result<String> {
Array<char, 256> hwModel {};
usize hwModelLen = sizeof(hwModel);
if (sysctlbyname("hw.model", hwModel.data(), &hwModelLen, nullptr, 0) == -1)
return Err(DracError::withErrno("Failed to get host info"));
return Err(DracError("Failed to get host info"));
// taken from https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/host/host_mac.c
// shortened a lot of the entries to remove unnecessary info
@ -207,27 +273,97 @@ fn os::GetHost() -> Result<String> {
const auto iter = modelNameByHwModel.find(hwModel.data());
if (iter == modelNameByHwModel.end())
return Err(DracError::withErrno("Failed to get host info"));
return Err(DracError("Failed to get host info"));
return String(iter->second);
}
}
fn os::GetDiskUsage() -> Result<DiskSpace> {
fn GetDiskUsage() -> Result<DiskSpace> {
struct statvfs vfs;
if (statvfs("/", &vfs) != 0)
return Err(DracError::withErrno("Failed to get disk usage"));
return Err(DracError("Failed to get disk usage"));
return DiskSpace { .used_bytes = (vfs.f_blocks - vfs.f_bfree) * vfs.f_frsize,
.total_bytes = vfs.f_blocks * vfs.f_frsize };
}
return DiskSpace { .usedBytes = (vfs.f_blocks - vfs.f_bfree) * vfs.f_frsize,
.totalBytes = vfs.f_blocks * vfs.f_frsize };
}
fn os::GetPackageCount() -> Result<u64> {
return Err(DracError(DracErrorCode::NotSupported, "Package count is not supported on macOS")); // TODO: Implement
}
fn GetShell() -> Result<String> {
if (const Result<String> shellPath = GetEnv("SHELL")) {
// clang-format off
constexpr Array<Pair<StringView, StringView>, 5> shellMap {{
{ "bash", "Bash" },
{ "zsh", "Zsh" },
{ "fish", "Fish" },
{ "nu", "Nushell" },
{ "sh", "SH" }, // sh last because other shells contain "sh"
}};
// clang-format on
fn os::GetShell() -> Result<String> {
return "Fish"; // TODO: Implement
}
for (const auto& [exe, name] : shellMap)
if (shellPath->contains(exe))
return String(name);
return *shellPath; // fallback to the raw shell path
}
return Err(DracError(DracErrorCode::NotFound, "Could not find SHELL environment variable"));
}
}; // namespace os
namespace package {
fn GetHomebrewCount() -> Result<u64> {
u64 count = 0;
Array<fs::path, 2> cellarPaths {
"/opt/homebrew/Cellar",
"/usr/local/Cellar",
};
for (const auto& cellarPath : cellarPaths) {
if (std::error_code errc; !fs::exists(cellarPath, errc) || errc) {
if (errc && errc != std::errc::no_such_file_or_directory)
return Err(DracError(errc));
return Err(DracError(DracErrorCode::NotFound, "Homebrew Cellar directory not found at: " + cellarPath.string())
);
}
Result<u64> dirCount = GetCountFromDirectory("homebrew", cellarPath, true);
if (!dirCount) {
if (dirCount.error().code != DracErrorCode::NotFound)
return dirCount;
continue;
}
count += *dirCount;
}
return count;
}
fn GetMacPortsCount() -> Result<u64> {
const PackageManagerInfo macPortsInfo = {
.id = "macports",
.dbPath = "/opt/local/var/macports/registry/registry.db",
.countQuery = "SELECT COUNT(*) FROM ports WHERE state='installed';",
};
// Check if the database file exists before trying to query
std::error_code errc;
if (!fs::exists(macPortsInfo.dbPath, errc) || errc) {
if (errc && errc != std::errc::no_such_file_or_directory)
return Err(DracError(errc));
return Err(
DracError(DracErrorCode::NotFound, "MacPorts registry database not found at: " + macPortsInfo.dbPath.string())
);
}
return GetCountFromDb(macPortsInfo);
}
} // namespace package
#endif

View file

@ -99,6 +99,7 @@ namespace util {
: message(std::format("{}: {}", context, std::system_category().message(errno))), location(loc) {
using namespace matchit;
using enum DracErrorCode;
code = match(errno)(
is | EACCES = PermissionDenied,
is | ENOENT = NotFound,

View file

@ -11,8 +11,6 @@
#include <utility> // std::pair (Pair)
#include <vector> // std::vector (Vec)
#include "include/matchit.h"
namespace util::types {
using u8 = std::uint8_t; ///< 8-bit unsigned integer.
using u16 = std::uint16_t; ///< 16-bit unsigned integer.