oh right
This commit is contained in:
parent
9a95178095
commit
631964469f
26 changed files with 482 additions and 335 deletions
|
@ -10,10 +10,10 @@
|
|||
#include <toml++/impl/table.hpp> // toml::table
|
||||
#include <unistd.h> // getuid
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/helpers.hpp"
|
||||
#include "src/core/util/logging.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/helpers.hpp"
|
||||
#include "src/util/logging.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
#include <pwd.h> // getpwuid, passwd
|
||||
#include <unistd.h> // getuid
|
||||
|
||||
#include "src/core/util/helpers.hpp"
|
||||
#include "src/util/helpers.hpp"
|
||||
#endif
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/logging.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/logging.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
#include "weather.hpp"
|
||||
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
#include <glaze/json/read.hpp> // NOLINT(misc-include-cleaner) - glaze/json/read.hpp is needed for glz::read<glz::opts>
|
||||
#include <ios> // std::ios::{binary, trunc}
|
||||
#include <iterator> // std::istreambuf_iterator
|
||||
#include <system_error> // std::error_code
|
||||
#include <utility> // std::move
|
||||
#include <variant> // std::{get, holds_alternative}
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/logging.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/cache.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/logging.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
|
@ -35,109 +35,10 @@ namespace {
|
|||
using util::error::DracError, util::error::DracErrorCode;
|
||||
using util::types::usize, util::types::Err, util::types::Exception;
|
||||
using weather::Coords;
|
||||
using namespace util::cache;
|
||||
|
||||
constexpr opts glaze_opts = { .error_on_unknown_keys = false };
|
||||
|
||||
fn GetCachePath() -> Result<fs::path, String> {
|
||||
std::error_code errc;
|
||||
fs::path cachePath = fs::temp_directory_path(errc);
|
||||
|
||||
if (errc)
|
||||
return Err("Failed to get temp directory: " + errc.message());
|
||||
|
||||
cachePath /= "weather_cache.beve";
|
||||
return cachePath;
|
||||
}
|
||||
|
||||
fn ReadCacheFromFile() -> Result<Output, String> {
|
||||
Result<fs::path, String> cachePath = GetCachePath();
|
||||
|
||||
if (!cachePath)
|
||||
return Err(cachePath.error());
|
||||
|
||||
std::ifstream ifs(*cachePath, std::ios::binary);
|
||||
|
||||
if (!ifs.is_open())
|
||||
return Err("Cache file not found: " + cachePath->string());
|
||||
|
||||
debug_log("Reading from cache file...");
|
||||
|
||||
try {
|
||||
const String content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
ifs.close();
|
||||
|
||||
if (content.empty())
|
||||
return Err(std::format("BEVE cache file is empty: {}", cachePath->string()));
|
||||
|
||||
Output result;
|
||||
|
||||
if (const error_ctx glazeErr = read_beve(result, content); glazeErr.ec != error_code::none)
|
||||
return Err(std::format(
|
||||
"BEVE parse error reading cache (code {}): {}", static_cast<int>(glazeErr.ec), cachePath->string()
|
||||
));
|
||||
|
||||
debug_log("Successfully read from cache file.");
|
||||
return result;
|
||||
} catch (const Exception& e) { return Err(std::format("Error reading cache: {}", e.what())); }
|
||||
}
|
||||
|
||||
fn WriteCacheToFile(const Output& data) -> Result<void, String> {
|
||||
using util::types::isize;
|
||||
|
||||
Result<fs::path, String> cachePath = GetCachePath();
|
||||
|
||||
if (!cachePath)
|
||||
return Err(cachePath.error());
|
||||
|
||||
debug_log("Writing to cache file...");
|
||||
fs::path tempPath = *cachePath;
|
||||
tempPath += ".tmp";
|
||||
|
||||
try {
|
||||
String binaryBuffer;
|
||||
|
||||
if (const error_ctx glazeErr = write_beve(data, binaryBuffer); glazeErr)
|
||||
return Err(std::format("BEVE serialization error writing cache (code {})", static_cast<int>(glazeErr.ec)));
|
||||
|
||||
{
|
||||
std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc);
|
||||
if (!ofs.is_open())
|
||||
return Err("Failed to open temp file: " + tempPath.string());
|
||||
|
||||
ofs.write(binaryBuffer.data(), static_cast<isize>(binaryBuffer.size()));
|
||||
if (!ofs) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err("Failed to write to temp BEVE cache file");
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code errc;
|
||||
fs::rename(tempPath, *cachePath, errc);
|
||||
if (errc) {
|
||||
if (!fs::remove(tempPath, errc))
|
||||
debug_log("Failed to remove temp file: {}", errc.message());
|
||||
|
||||
return Err(std::format("Failed to replace cache file: {}", errc.message()));
|
||||
}
|
||||
|
||||
debug_log("Successfully wrote to cache file.");
|
||||
return {};
|
||||
} catch (const std::ios_base::failure& e) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(std::format("Filesystem error writing BEVE cache file {}: {}", tempPath.string(), e.what()));
|
||||
} catch (const Exception& e) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(std::format("File operation error during BEVE cache write: {}", e.what()));
|
||||
} catch (...) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(std::format("Unknown error writing BEVE cache file: {}", tempPath.string()));
|
||||
}
|
||||
}
|
||||
|
||||
fn WriteCallback(void* contents, const usize size, const usize nmemb, String* str) -> usize {
|
||||
const usize totalSize = size * nmemb;
|
||||
str->append(static_cast<char*>(contents), totalSize);
|
||||
|
@ -177,7 +78,7 @@ fn Weather::getWeatherInfo() const -> Result<Output, DracError> {
|
|||
using namespace std::chrono;
|
||||
using util::types::i32;
|
||||
|
||||
if (Result<Output, String> data = ReadCacheFromFile()) {
|
||||
if (Result<Output, DracError> data = ReadCache<Output>("weather")) {
|
||||
const Output& dataVal = *data;
|
||||
|
||||
if (const duration<double> cacheAge = system_clock::now() - system_clock::time_point(seconds(dataVal.dt));
|
||||
|
@ -188,15 +89,15 @@ fn Weather::getWeatherInfo() const -> Result<Output, DracError> {
|
|||
|
||||
debug_log("Cache expired");
|
||||
} else {
|
||||
debug_log("Cache error: {}", data.error());
|
||||
error_at(data.error());
|
||||
}
|
||||
|
||||
fn handleApiResult = [](const Result<Output, String>& result) -> Result<Output, DracError> {
|
||||
if (!result)
|
||||
return Err(DracError(DracErrorCode::ApiUnavailable, result.error()));
|
||||
|
||||
if (Result<void, String> writeResult = WriteCacheToFile(*result); !writeResult)
|
||||
error_log("Failed to write cache: {}", writeResult.error());
|
||||
if (Result<void, DracError> writeResult = WriteCache("weather", *result); !writeResult)
|
||||
error_at(writeResult.error());
|
||||
|
||||
return *result;
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <glaze/core/common.hpp> // object
|
||||
#include <glaze/core/meta.hpp> // Object
|
||||
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
namespace weather {
|
||||
using glz::detail::Object, glz::object;
|
||||
|
|
91
src/core/package.hpp
Normal file
91
src/core/package.hpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
#pragma once
|
||||
|
||||
#include <filesystem> // std::filesystem::path
|
||||
#include <future> // std::future
|
||||
#include <glaze/core/common.hpp> // glz::object
|
||||
#include <glaze/core/meta.hpp> // glz::detail::Object
|
||||
#include <vector> // std::vector
|
||||
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
namespace packages {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using util::error::DracError;
|
||||
using util::types::Result, util::types::u64, util::types::i64, util::types::String, util::types::Vec,
|
||||
util::types::Future;
|
||||
|
||||
/**
|
||||
* @struct PkgCountCacheData
|
||||
* @brief Structure for caching package count results along with a timestamp.
|
||||
*
|
||||
* Used to avoid redundant lookups in package manager databases or directories
|
||||
* if the underlying data source hasn't changed recently.
|
||||
*/
|
||||
struct PkgCountCacheData {
|
||||
u64 count {}; ///< The cached package count.
|
||||
i64 timestampEpochSeconds {}; ///< The UNIX timestamp (seconds since epoch) when the count was cached.
|
||||
|
||||
// NOLINTBEGIN(readability-identifier-naming)
|
||||
struct [[maybe_unused]] glaze {
|
||||
using T = PkgCountCacheData;
|
||||
static constexpr glz::detail::Object value =
|
||||
glz::object("count", &T::count, "timestamp", &T::timestampEpochSeconds);
|
||||
};
|
||||
// NOLINTEND(readability-identifier-naming)
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct PackageManagerInfo
|
||||
* @brief Holds information needed to query a database-backed package manager.
|
||||
*/
|
||||
struct PackageManagerInfo {
|
||||
String id; ///< Unique identifier for the package manager (used for cache key).
|
||||
fs::path dbPath; ///< Filesystem path to the package manager's database.
|
||||
String countQuery; ///< SQL query string to count the packages.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Gets the total package count by querying all relevant package managers for the current OS.
|
||||
* @details This function orchestrates the process:
|
||||
* 1. Determines the set of relevant package managers (platform-specific + shared).
|
||||
* 2. Launches asynchronous tasks to query each manager.
|
||||
* 3. Aggregates the results, summing counts and logging errors.
|
||||
* @return Result containing the total package count (u64) on success,
|
||||
* or a DracError if the aggregation fails (though individual manager errors are logged).
|
||||
*/
|
||||
fn GetTotalCount() -> Result<u64, DracError>;
|
||||
|
||||
fn GetCountFromDb(const PackageManagerInfo& pmInfo) -> Result<u64, DracError>;
|
||||
|
||||
fn GetCountFromDirectory(
|
||||
const String& pmId,
|
||||
const fs::path& dirPath,
|
||||
const String& fileExtensionFilter = "",
|
||||
bool subtractOne = false
|
||||
) -> Result<u64, DracError>;
|
||||
|
||||
#ifdef __linux__
|
||||
fn GetDpkgCount() -> Result<u64, DracError>;
|
||||
fn GetPacmanCount() -> Result<u64, DracError>;
|
||||
fn GetMossCount() -> Result<u64, DracError>;
|
||||
fn GetRpmCount() -> Result<u64, DracError>;
|
||||
fn GetZypperCount() -> Result<u64, DracError>;
|
||||
fn GetPortageCount() -> Result<u64, DracError>;
|
||||
fn GetApkCount() -> Result<u64, DracError>;
|
||||
#elif defined(__APPLE__)
|
||||
fn GetHomebrewCount() -> Result<u64, DracError>;
|
||||
fn GetMacPortsCount() -> Result<u64, DracError>;
|
||||
#elif defined(_WIN32)
|
||||
fn GetWinRTCount() -> Result<u64, DracError>;
|
||||
fn GetChocolateyCount() -> Result<u64, DracError>;
|
||||
fn GetScoopCount() -> Result<u64, DracError>;
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
fn GetNixCount() -> Result<u64, DracError>;
|
||||
#endif
|
||||
fn GetCargoCount() -> Result<u64, DracError>;
|
||||
} // namespace packages
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
#include "src/config/config.hpp"
|
||||
#include "src/config/weather.hpp"
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/os/os.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
using util::error::DracError, util::error::DracErrorCode;
|
||||
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
|
||||
#include "src/config/config.hpp" // Config
|
||||
#include "src/config/weather.hpp" // weather::Output
|
||||
|
||||
#include "util/defs.hpp"
|
||||
#include "util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
struct Config;
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#include "src/config/config.hpp"
|
||||
#include "src/config/weather.hpp"
|
||||
#include "src/core/system_data.hpp"
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/logging.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/logging.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
namespace ui {
|
||||
using ftxui::Color;
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
#include <unistd.h> // readlink
|
||||
#include <utility> // std::move
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/helpers.hpp"
|
||||
#include "src/core/util/logging.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/helpers.hpp"
|
||||
#include "src/util/logging.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
#include "src/wrappers/dbus.hpp"
|
||||
#include "src/wrappers/wayland.hpp"
|
||||
#include "src/wrappers/xcb.hpp"
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
#include <iterator> // std::istreambuf_iterator
|
||||
#include <glaze/beve/read.hpp> // glz::read_beve
|
||||
#include <glaze/beve/write.hpp> // glz::write_beve
|
||||
#include <glaze/core/context.hpp> // glz::{context, error_code, error_ctx}
|
||||
#include <system_error> // std::error_code
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/logging.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/cache.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/logging.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
// clang-format on
|
||||
|
||||
using util::error::DracError, util::error::DracErrorCode;
|
||||
|
@ -31,6 +31,7 @@ using util::types::u64, util::types::i64, util::types::Result, util::types::Err,
|
|||
namespace {
|
||||
namespace fs = std::filesystem;
|
||||
using namespace std::chrono;
|
||||
using namespace util::cache;
|
||||
using os::linux::PkgCountCacheData, os::linux::PackageManagerInfo;
|
||||
|
||||
fn GetPackageCountInternalDir(
|
||||
|
@ -111,6 +112,68 @@ namespace {
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
fn GetPackageCountInternalDb(const PackageManagerInfo& pmInfo) -> Result<u64, DracError> {
|
||||
const auto& [pmId, dbPath, countQuery] = pmInfo;
|
||||
|
||||
if (Result<PkgCountCacheData, DracError> cachedDataResult = ReadCache<PkgCountCacheData>(pmId)) {
|
||||
const auto& [count, timestamp] = *cachedDataResult;
|
||||
std::error_code errc;
|
||||
const std::filesystem::file_time_type dbModTime = fs::last_write_time(dbPath, errc);
|
||||
|
||||
if (errc) {
|
||||
warn_log(
|
||||
"Could not get modification time for '{}': {}. Invalidating {} cache.", dbPath.string(), errc.message(), pmId
|
||||
);
|
||||
} else {
|
||||
if (const system_clock::time_point cacheTimePoint = system_clock::time_point(seconds(timestamp));
|
||||
cacheTimePoint.time_since_epoch() >= dbModTime.time_since_epoch()) {
|
||||
debug_log(
|
||||
"Using valid {} package count cache (DB file unchanged since {}).",
|
||||
pmId,
|
||||
std::format("{:%F %T %Z}", floor<seconds>(cacheTimePoint))
|
||||
);
|
||||
return count;
|
||||
}
|
||||
debug_log("{} package count cache stale (DB file modified).", pmId);
|
||||
}
|
||||
} else {
|
||||
if (cachedDataResult.error().code != DracErrorCode::NotFound)
|
||||
debug_at(cachedDataResult.error());
|
||||
debug_log("{} package count cache not found or unreadable.", pmId);
|
||||
}
|
||||
|
||||
debug_log("Fetching fresh {} package count from database: {}", pmId, dbPath.string());
|
||||
u64 count = 0;
|
||||
|
||||
try {
|
||||
const SQLite::Database database(dbPath.string(), SQLite::OPEN_READONLY);
|
||||
if (SQLite::Statement query(database, countQuery); query.executeStep()) {
|
||||
const i64 countInt64 = query.getColumn(0).getInt64();
|
||||
if (countInt64 < 0)
|
||||
return Err(
|
||||
DracError(DracErrorCode::ParseError, std::format("Negative count returned by {} DB COUNT query.", pmId))
|
||||
);
|
||||
count = static_cast<u64>(countInt64);
|
||||
} else {
|
||||
return Err(DracError(DracErrorCode::ParseError, std::format("No rows returned by {} DB COUNT query.", pmId)));
|
||||
}
|
||||
} catch (const SQLite::Exception& e) {
|
||||
return Err(DracError(
|
||||
DracErrorCode::ApiUnavailable, std::format("SQLite error occurred accessing {} DB: {}", pmId, e.what())
|
||||
));
|
||||
} catch (const Exception& e) { return Err(DracError(DracErrorCode::InternalError, e.what())); } catch (...) {
|
||||
return Err(DracError(DracErrorCode::Other, std::format("Unknown error occurred accessing {} DB", pmId)));
|
||||
}
|
||||
|
||||
const i64 nowEpochSeconds = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
|
||||
const PkgCountCacheData dataToCache = { .count = count, .timestampEpochSeconds = nowEpochSeconds };
|
||||
|
||||
if (Result<void, DracError> writeResult = WriteCache(pmId, dataToCache); !writeResult)
|
||||
error_at(writeResult.error());
|
||||
|
||||
return count;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace os::linux {
|
||||
|
@ -159,10 +222,9 @@ namespace os::linux {
|
|||
fn GetTotalPackageCount() -> Result<u64, DracError> {
|
||||
using util::types::Array, util::types::Future;
|
||||
|
||||
Array<Future<Result<u64, DracError>>, 4> futures = {
|
||||
Array<Future<Result<u64, DracError>>, 3> futures = {
|
||||
std::async(std::launch::async, GetDpkgPackageCount),
|
||||
std::async(std::launch::async, GetMossPackageCount),
|
||||
std::async(std::launch::async, GetNixPackageCount),
|
||||
std::async(std::launch::async, GetPacmanPackageCount),
|
||||
};
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
#include <glaze/core/common.hpp> // glz::object
|
||||
#include <glaze/core/meta.hpp> // glz::detail::Object
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
// clang-format on
|
||||
|
||||
namespace os::linux {
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
#include "macos/bridge.hpp"
|
||||
#include "os.hpp"
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
// clang-format on
|
||||
|
||||
using namespace util::types;
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#ifdef __APPLE__
|
||||
|
||||
// clang-format off
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
// clang-format on
|
||||
using util::error::DracError;
|
||||
using util::types::MediaInfo, util::types::String, util::types::Result;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
// clang-format on
|
||||
|
||||
using util::error::DracErrorCode;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
/**
|
||||
* @namespace os
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
#include <SQLiteCpp/Database.h> // SQLite::{Database, OPEN_READONLY}
|
||||
#include <SQLiteCpp/Exception.h> // SQLite::Exception
|
||||
#include <SQLiteCpp/Statement.h> // SQLite::Statement
|
||||
#include <chrono> // std::chrono
|
||||
#include <filesystem> // std::filesystem
|
||||
#include <format> // std::format
|
||||
#include <fstream> // std::{ifstream, ofstream}
|
||||
#include <glaze/beve/read.hpp> // glz::read_beve
|
||||
#include <glaze/beve/write.hpp> // glz::write_beve
|
||||
#include <glaze/core/common.hpp> // glz::object
|
||||
#include <glaze/core/context.hpp> // glz::{context, error_code, error_ctx}
|
||||
#include <glaze/core/meta.hpp> // glz::detail::Object
|
||||
#include <ios> // std::ios::{binary, trunc}, std::ios_base
|
||||
#include <iterator> // std::istreambuf_iterator
|
||||
#include <system_error> // std::error_code
|
||||
#include <SQLiteCpp/Database.h> // SQLite::{Database, OPEN_READONLY}
|
||||
#include <SQLiteCpp/Exception.h> // SQLite::Exception
|
||||
#include <SQLiteCpp/Statement.h> // SQLite::Statement
|
||||
#include <chrono> // std::chrono
|
||||
#include <filesystem> // std::filesystem
|
||||
#include <format> // std::format
|
||||
#include <fstream> // std::{ifstream, ofstream}
|
||||
#include <glaze/beve/read.hpp> // glz::read_beve
|
||||
#include <glaze/beve/write.hpp> // glz::write_beve
|
||||
#include <glaze/core/common.hpp> // glz::object
|
||||
#include <glaze/core/meta.hpp> // glz::detail::Object
|
||||
#include <ios> // std::ios::{binary, trunc}, std::ios_base
|
||||
#include <iterator> // std::istreambuf_iterator
|
||||
#include <system_error> // std::error_code
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/helpers.hpp"
|
||||
#include "src/core/util/logging.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/cache.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/helpers.hpp"
|
||||
#include "src/util/logging.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
#include "os.hpp"
|
||||
|
||||
|
@ -30,6 +30,7 @@ namespace fs = std::filesystem;
|
|||
|
||||
namespace {
|
||||
using namespace std::chrono;
|
||||
using namespace util::cache;
|
||||
|
||||
struct PackageManagerInfo {
|
||||
String id;
|
||||
|
@ -51,136 +52,10 @@ namespace {
|
|||
// NOLINTEND(readability-identifier-naming)
|
||||
};
|
||||
|
||||
constexpr StringView ALLOWED_PMID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
|
||||
|
||||
fn GetPkgCountCachePath(const String& pmId) -> Result<fs::path, DracError> {
|
||||
std::error_code errc;
|
||||
const fs::path cacheDir = fs::temp_directory_path(errc);
|
||||
|
||||
if (errc)
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to get temp directory: " + errc.message()));
|
||||
|
||||
if (pmId.empty() || pmId.find_first_not_of(ALLOWED_PMID_CHARS) != String::npos)
|
||||
return Err(DracError(DracErrorCode::ParseError, "Invalid package manager ID for cache path: " + pmId));
|
||||
|
||||
return cacheDir / (pmId + "_pkg_count_cache.beve");
|
||||
}
|
||||
|
||||
fn ReadPkgCountCache(const String& pmId) -> Result<PkgCountCacheData, DracError> {
|
||||
Result<fs::path, DracError> cachePathResult = GetPkgCountCachePath(pmId);
|
||||
|
||||
if (!cachePathResult)
|
||||
return Err(cachePathResult.error());
|
||||
|
||||
const fs::path& cachePath = *cachePathResult;
|
||||
|
||||
if (!fs::exists(cachePath))
|
||||
return Err(DracError(DracErrorCode::NotFound, "Cache file not found: " + cachePath.string()));
|
||||
|
||||
std::ifstream ifs(cachePath, std::ios::binary);
|
||||
if (!ifs.is_open())
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to open cache file for reading: " + cachePath.string()));
|
||||
|
||||
try {
|
||||
const String content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
ifs.close();
|
||||
|
||||
if (content.empty())
|
||||
return Err(DracError(DracErrorCode::ParseError, "BEVE cache file is empty: " + cachePath.string()));
|
||||
|
||||
PkgCountCacheData result;
|
||||
const glz::context ctx {};
|
||||
|
||||
if (glz::error_ctx glazeResult = glz::read_beve(result, content); glazeResult.ec != glz::error_code::none)
|
||||
return Err(DracError(
|
||||
DracErrorCode::ParseError,
|
||||
std::format(
|
||||
"BEVE parse error reading cache (code {}): {}", static_cast<int>(glazeResult.ec), cachePath.string()
|
||||
)
|
||||
));
|
||||
|
||||
return result;
|
||||
} catch (const std::ios_base::failure& e) {
|
||||
return Err(DracError(
|
||||
DracErrorCode::IoError, std::format("Filesystem error reading cache file {}: {}", cachePath.string(), e.what())
|
||||
));
|
||||
} catch (const Exception& e) {
|
||||
return Err(DracError(DracErrorCode::InternalError, std::format("Error reading package count cache: {}", e.what()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn WritePkgCountCache(const String& pmId, const PkgCountCacheData& data) -> Result<void, DracError> {
|
||||
using util::types::isize;
|
||||
|
||||
Result<fs::path, DracError> cachePathResult = GetPkgCountCachePath(pmId);
|
||||
|
||||
if (!cachePathResult)
|
||||
return Err(cachePathResult.error());
|
||||
|
||||
const fs::path& cachePath = *cachePathResult;
|
||||
fs::path tempPath = cachePath;
|
||||
tempPath += ".tmp";
|
||||
|
||||
try {
|
||||
String binaryBuffer;
|
||||
|
||||
PkgCountCacheData mutableData = data;
|
||||
|
||||
if (glz::error_ctx glazeErr = glz::write_beve(mutableData, binaryBuffer); glazeErr)
|
||||
return Err(DracError(
|
||||
DracErrorCode::ParseError,
|
||||
std::format("BEVE serialization error writing cache (code {})", static_cast<int>(glazeErr.ec))
|
||||
));
|
||||
|
||||
{
|
||||
std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc);
|
||||
if (!ofs.is_open())
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to open temp cache file: " + tempPath.string()));
|
||||
|
||||
ofs.write(binaryBuffer.data(), static_cast<isize>(binaryBuffer.size()));
|
||||
|
||||
if (!ofs) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to write to temp cache file: " + tempPath.string()));
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code errc;
|
||||
fs::rename(tempPath, cachePath, errc);
|
||||
if (errc) {
|
||||
fs::remove(tempPath, errc);
|
||||
return Err(DracError(
|
||||
DracErrorCode::IoError,
|
||||
std::format("Failed to replace cache file '{}': {}", cachePath.string(), errc.message())
|
||||
));
|
||||
}
|
||||
|
||||
return {};
|
||||
} catch (const std::ios_base::failure& e) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(DracError(
|
||||
DracErrorCode::IoError, std::format("Filesystem error writing cache file {}: {}", tempPath.string(), e.what())
|
||||
));
|
||||
} catch (const Exception& e) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(DracError(DracErrorCode::InternalError, std::format("Error writing package count cache: {}", e.what()))
|
||||
);
|
||||
} catch (...) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(DracError(DracErrorCode::Other, std::format("Unknown error writing cache file: {}", tempPath.string()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn GetPackageCountInternalDb(const PackageManagerInfo& pmInfo) -> Result<u64, DracError> {
|
||||
const auto& [pmId, dbPath, countQuery] = pmInfo;
|
||||
|
||||
if (Result<PkgCountCacheData, DracError> cachedDataResult = ReadPkgCountCache(pmId)) {
|
||||
if (Result<PkgCountCacheData, DracError> cachedDataResult = ReadCache<PkgCountCacheData>(pmId)) {
|
||||
const auto& [count, timestamp] = *cachedDataResult;
|
||||
std::error_code errc;
|
||||
const std::filesystem::file_time_type dbModTime = fs::last_write_time(dbPath, errc);
|
||||
|
@ -233,12 +108,13 @@ namespace {
|
|||
const i64 nowEpochSeconds = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
|
||||
const PkgCountCacheData dataToCache = { .count = count, .timestampEpochSeconds = nowEpochSeconds };
|
||||
|
||||
if (Result<void, DracError> writeResult = WritePkgCountCache(pmId, dataToCache); !writeResult)
|
||||
if (Result<void, DracError> writeResult = WriteCache(pmId, dataToCache); !writeResult)
|
||||
error_at(writeResult.error());
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
fn GetNixPackageCount() -> Result<u64, DracError> {
|
||||
debug_log("Attempting to get Nix package count.");
|
||||
|
||||
|
@ -259,6 +135,7 @@ namespace {
|
|||
|
||||
return GetPackageCountInternalDb(nixInfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
fn GetCargoPackageCount() -> Result<u64, DracError> {
|
||||
using util::helpers::GetEnv;
|
||||
|
@ -288,12 +165,15 @@ namespace {
|
|||
namespace os::shared {
|
||||
fn GetPackageCount() -> Result<u64, DracError> {
|
||||
u64 count = 0;
|
||||
if (Result<u64, DracError> pkgCount = GetNixPackageCount())
|
||||
|
||||
#ifndef _WIN32
|
||||
if (const Result<u64, DracError> pkgCount = GetNixPackageCount())
|
||||
count += *pkgCount;
|
||||
else
|
||||
debug_at(pkgCount.error());
|
||||
#endif
|
||||
|
||||
if (Result<u64, DracError> pkgCount = GetCargoPackageCount())
|
||||
if (const Result<u64, DracError> pkgCount = GetCargoPackageCount())
|
||||
count += *pkgCount;
|
||||
else
|
||||
debug_at(pkgCount.error());
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
#include <winrt/base.h>
|
||||
#include <winrt/impl/Windows.Media.Control.2.h>
|
||||
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/helpers.hpp"
|
||||
#include "src/core/util/logging.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/helpers.hpp"
|
||||
#include "src/util/logging.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
#include "os.hpp"
|
||||
// clang-format on
|
||||
|
|
216
src/util/cache.hpp
Normal file
216
src/util/cache.hpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
#pragma once
|
||||
|
||||
#include <filesystem> // std::filesystem
|
||||
#include <fstream> // std::{ifstream, ofstream}
|
||||
#include <glaze/beve/read.hpp> // glz::read_beve
|
||||
#include <glaze/beve/write.hpp> // glz::write_beve
|
||||
#include <glaze/core/context.hpp> // glz::{context, error_code, error_ctx}
|
||||
#include <iterator> // std::istreambuf_iterator
|
||||
#include <string> // std::string
|
||||
#include <system_error> // std::error_code
|
||||
#include <type_traits> // std::decay_t
|
||||
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/logging.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
namespace util::cache {
|
||||
namespace fs = std::filesystem;
|
||||
using error::DracError, error::DracErrorCode;
|
||||
using types::Err, types::Exception, types::Result, types::String, types::isize;
|
||||
|
||||
/**
|
||||
* @brief Gets the full path for a cache file based on a unique key.
|
||||
* @param cache_key A unique identifier for the cache (e.g., "weather", "pkg_count_pacman").
|
||||
* Should ideally only contain filesystem-safe characters.
|
||||
* @return Result containing the filesystem path on success, or a DracError on failure.
|
||||
*/
|
||||
inline fn GetCachePath(const String& cache_key) -> Result<fs::path, DracError> {
|
||||
if (cache_key.empty())
|
||||
return Err(DracError(DracErrorCode::InvalidArgument, "Cache key cannot be empty."));
|
||||
|
||||
// Basic check for potentially problematic characters in the key for filename safety.
|
||||
// You might want to expand this or implement more robust sanitization if needed.
|
||||
if (cache_key.find_first_of("/\\:*?\"<>|") != String::npos)
|
||||
return Err(
|
||||
DracError(DracErrorCode::InvalidArgument, std::format("Cache key '{}' contains invalid characters.", cache_key))
|
||||
);
|
||||
|
||||
std::error_code errc;
|
||||
const fs::path cacheDir = fs::temp_directory_path(errc);
|
||||
|
||||
if (errc)
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to get system temporary directory: " + errc.message()));
|
||||
|
||||
// Use a consistent naming scheme
|
||||
return cacheDir / (cache_key + "_cache.beve");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads and deserializes data from a BEVE cache file.
|
||||
* @tparam T The type of the object to deserialize from the cache. Must be Glaze-compatible.
|
||||
* @param cache_key The unique identifier for the cache.
|
||||
* @return Result containing the deserialized object of type T on success, or a DracError on failure.
|
||||
*/
|
||||
template <typename T>
|
||||
fn ReadCache(const String& cache_key) -> Result<T, DracError> {
|
||||
Result<fs::path, DracError> cachePathResult = GetCachePath(cache_key);
|
||||
if (!cachePathResult)
|
||||
return Err(cachePathResult.error());
|
||||
|
||||
const fs::path& cachePath = *cachePathResult;
|
||||
|
||||
if (std::error_code exists_ec; !fs::exists(cachePath, exists_ec) || exists_ec) {
|
||||
if (exists_ec) {
|
||||
// Log if there was an error checking existence, but still return NotFound
|
||||
warn_log("Error checking existence of cache file '{}': {}", cachePath.string(), exists_ec.message());
|
||||
}
|
||||
return Err(DracError(DracErrorCode::NotFound, "Cache file not found: " + cachePath.string()));
|
||||
}
|
||||
|
||||
std::ifstream ifs(cachePath, std::ios::binary);
|
||||
if (!ifs.is_open())
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to open cache file for reading: " + cachePath.string()));
|
||||
|
||||
debug_log("Reading cache for key '{}' from: {}", cache_key, cachePath.string());
|
||||
|
||||
try {
|
||||
// Read the entire file content
|
||||
const String content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
ifs.close(); // Close the file as soon as content is read
|
||||
|
||||
if (content.empty())
|
||||
return Err(DracError(DracErrorCode::ParseError, "BEVE cache file is empty: " + cachePath.string()));
|
||||
|
||||
// Ensure T is default constructible for Glaze
|
||||
static_assert(std::is_default_constructible_v<T>, "Cache type T must be default constructible for Glaze.");
|
||||
T result {};
|
||||
|
||||
if (glz::error_ctx glazeErr = glz::read_beve(result, content); glazeErr.ec != glz::error_code::none) {
|
||||
return Err(DracError(
|
||||
DracErrorCode::ParseError,
|
||||
std::format(
|
||||
"BEVE parse error reading cache '{}' (code {}): {}",
|
||||
cachePath.string(),
|
||||
static_cast<int>(glazeErr.ec),
|
||||
glz::format_error(glazeErr, content)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
debug_log("Successfully read cache for key '{}'.", cache_key);
|
||||
return result;
|
||||
} catch (const std::ios_base::failure& e) {
|
||||
return Err(DracError(
|
||||
DracErrorCode::IoError, std::format("Filesystem error reading cache file {}: {}", cachePath.string(), e.what())
|
||||
));
|
||||
} catch (const Exception& e) {
|
||||
// Catching std::exception or a project-specific base exception
|
||||
return Err(DracError(
|
||||
DracErrorCode::InternalError,
|
||||
std::format("Standard exception reading cache file {}: {}", cachePath.string(), e.what())
|
||||
));
|
||||
} catch (...) {
|
||||
return Err(DracError(DracErrorCode::Other, "Unknown error reading cache file: " + cachePath.string()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serializes and writes data to a BEVE cache file safely.
|
||||
* @tparam T The type of the object to serialize. Must be Glaze-compatible.
|
||||
* @param cache_key The unique identifier for the cache.
|
||||
* @param data The data object of type T to write to the cache.
|
||||
* @return Result containing void on success, or a DracError on failure.
|
||||
*/
|
||||
template <typename T>
|
||||
fn WriteCache(const String& cache_key, const T& data) -> Result<void, DracError> {
|
||||
Result<fs::path, DracError> cachePathResult = GetCachePath(cache_key);
|
||||
if (!cachePathResult)
|
||||
return Err(cachePathResult.error());
|
||||
|
||||
const fs::path& cachePath = *cachePathResult;
|
||||
fs::path tempPath = cachePath;
|
||||
tempPath += ".tmp"; // Use a temporary file for atomic write
|
||||
|
||||
debug_log("Writing cache for key '{}' to: {}", cache_key, cachePath.string());
|
||||
|
||||
try {
|
||||
String binaryBuffer;
|
||||
|
||||
// Use Glaze to serialize
|
||||
// Need to decay T in case it's a reference type from the caller
|
||||
using DecayedT = std::decay_t<T>;
|
||||
DecayedT dataToSerialize = data; // Make a copy if needed for non-const Glaze operations
|
||||
|
||||
if (glz::error_ctx glazeErr = glz::write_beve(dataToSerialize, binaryBuffer); glazeErr) {
|
||||
return Err(DracError(
|
||||
DracErrorCode::ParseError,
|
||||
std::format(
|
||||
"BEVE serialization error writing cache for key '{}' (code {}): {}",
|
||||
cache_key,
|
||||
static_cast<int>(glazeErr.ec),
|
||||
glz::format_error(glazeErr, binaryBuffer)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
// Scope for ofstream to ensure it's closed before rename
|
||||
{
|
||||
std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc);
|
||||
if (!ofs.is_open())
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to open temporary cache file: " + tempPath.string()));
|
||||
|
||||
ofs.write(binaryBuffer.data(), static_cast<isize>(binaryBuffer.size()));
|
||||
|
||||
if (!ofs) {
|
||||
// Attempt cleanup before returning error
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc); // Ignore error on cleanup attempt
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to write to temporary cache file: " + tempPath.string())
|
||||
);
|
||||
}
|
||||
// ofstream automatically closed here
|
||||
}
|
||||
|
||||
// Attempt to atomically replace the old cache file
|
||||
std::error_code rename_ec;
|
||||
fs::rename(tempPath, cachePath, rename_ec);
|
||||
if (rename_ec) {
|
||||
// If rename failed, attempt to clean up the temp file
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc); // Ignore error on cleanup attempt
|
||||
return Err(DracError(
|
||||
DracErrorCode::IoError,
|
||||
std::format(
|
||||
"Failed to replace cache file '{}' with temporary file '{}': {}",
|
||||
cachePath.string(),
|
||||
tempPath.string(),
|
||||
rename_ec.message()
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
debug_log("Successfully wrote cache for key '{}'.", cache_key);
|
||||
return {}; // Success
|
||||
} catch (const std::ios_base::failure& e) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc); // Cleanup attempt
|
||||
return Err(DracError(
|
||||
DracErrorCode::IoError, std::format("Filesystem error writing cache file {}: {}", tempPath.string(), e.what())
|
||||
));
|
||||
} catch (const Exception& e) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc); // Cleanup attempt
|
||||
return Err(DracError(
|
||||
DracErrorCode::InternalError,
|
||||
std::format("Standard exception writing cache file {}: {}", tempPath.string(), e.what())
|
||||
));
|
||||
} catch (...) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc); // Cleanup attempt
|
||||
return Err(DracError(DracErrorCode::Other, "Unknown error writing cache file: " + tempPath.string()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace util::cache
|
|
@ -9,7 +9,7 @@
|
|||
#include <winrt/base.h> // winrt::hresult_error
|
||||
#endif
|
||||
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
namespace util::error {
|
||||
using types::u8, types::i32, types::String, types::StringView, types::Exception;
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "defs.hpp"
|
||||
#include "error.hpp"
|
||||
#include "types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
namespace util::helpers {
|
||||
using error::DracError, error::DracErrorCode;
|
|
@ -1,9 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <chrono> // std::chrono::{days, floor, seconds, system_clock}
|
||||
#include <ctime> // For time_t, tm, localtime_s, localtime_r, strftime (needed for cross-platform local time)
|
||||
#include <filesystem> // std::filesystem::path
|
||||
#include <format> // std::format
|
||||
#include <chrono> // std::chrono::{days, floor, seconds, system_clock}
|
||||
#include <filesystem> // std::filesystem::path
|
||||
#include <format> // std::format
|
||||
#include <ftxui/screen/color.hpp> // ftxui::Color
|
||||
#include <print> // std::print
|
||||
#include <utility> // std::forward
|
||||
|
@ -12,9 +11,9 @@
|
|||
#include <source_location> // std::source_location
|
||||
#endif
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
namespace util::logging {
|
||||
using types::usize, types::u8, types::i32, types::i64, types::CStr, types::String, types::StringView, types::Array,
|
||||
|
@ -74,10 +73,8 @@ namespace util::logging {
|
|||
* @param color The FTXUI color
|
||||
* @return Styled string with ANSI codes
|
||||
*/
|
||||
inline fn Colorize(StringView text, const ftxui::Color::Palette16& color) -> String {
|
||||
std::ostringstream oss;
|
||||
oss << LogLevelConst::COLOR_CODE_LITERALS.at(static_cast<i32>(color)) << text << LogLevelConst::RESET_CODE;
|
||||
return oss.str();
|
||||
inline fn Colorize(const StringView text, const ftxui::Color::Palette16& color) -> String {
|
||||
return std::format("{}{}{}", LogLevelConst::COLOR_CODE_LITERALS.at(color), text, LogLevelConst::RESET_CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,7 +83,7 @@ namespace util::logging {
|
|||
* @return Bold text
|
||||
*/
|
||||
inline fn Bold(const StringView text) -> String {
|
||||
return String(LogLevelConst::BOLD_START) + String(text) + String(LogLevelConst::BOLD_END);
|
||||
return std::format("{}{}{}", LogLevelConst::BOLD_START, text, LogLevelConst::BOLD_END);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,7 +92,7 @@ namespace util::logging {
|
|||
* @return Italic text
|
||||
*/
|
||||
inline fn Italic(const StringView text) -> String {
|
||||
return String(LogLevelConst::ITALIC_START) + String(text) + String(LogLevelConst::ITALIC_END);
|
||||
return std::format("{}{}{}", LogLevelConst::ITALIC_START, text, LogLevelConst::ITALIC_END);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,11 +140,14 @@ namespace util::logging {
|
|||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once CppDoxygenUnresolvedReference
|
||||
/**
|
||||
* @brief Logs a message with the specified log level, source location, and format string.
|
||||
* @tparam Args Parameter pack for format arguments.
|
||||
* @param level The log level (DEBUG, INFO, WARN, ERROR).
|
||||
* \ifnot NDEBUG
|
||||
* @param loc The source location of the log message (only in Debug builds).
|
||||
* \endif
|
||||
* @param fmt The format string.
|
||||
* @param args The arguments for the format string.
|
||||
*/
|
||||
|
@ -163,8 +163,6 @@ namespace util::logging {
|
|||
using namespace std::chrono;
|
||||
using std::filesystem::path;
|
||||
|
||||
using Buffer = Array<char, 512>;
|
||||
|
||||
const auto nowTp = system_clock::now();
|
||||
const std::time_t nowTt = system_clock::to_time_t(nowTp);
|
||||
std::tm localTm;
|
||||
|
@ -176,7 +174,7 @@ namespace util::logging {
|
|||
#else
|
||||
if (localtime_r(&nowTt, &localTm) != nullptr) {
|
||||
#endif
|
||||
Array<char, 64> timeBuffer;
|
||||
Array<char, 64> timeBuffer {};
|
||||
|
||||
if (std::strftime(timeBuffer.data(), sizeof(timeBuffer), LogLevelConst::TIMESTAMP_FORMAT, &localTm) > 0)
|
||||
timestamp = timeBuffer.data();
|
||||
|
@ -187,7 +185,7 @@ namespace util::logging {
|
|||
|
||||
const String message = std::format(fmt, std::forward<Args>(args)...);
|
||||
|
||||
Buffer buffer {};
|
||||
Array<char, 128> buffer {};
|
||||
|
||||
// Use the locally formatted timestamp string here
|
||||
auto* iter = std::format_to(
|
|
@ -9,9 +9,9 @@
|
|||
#include <format> // std::format
|
||||
#include <type_traits> // std::is_convertible_v
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/error.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
// clang-format on
|
||||
|
||||
namespace dbus {
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
// clang-format off
|
||||
#include <wayland-client.h> // Wayland client library
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
// clang-format on
|
||||
|
||||
struct wl_display;
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
// clang-format off
|
||||
#include <xcb/xcb.h> // XCB library
|
||||
|
||||
#include "src/core/util/defs.hpp"
|
||||
#include "src/core/util/types.hpp"
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
// clang-format on
|
||||
|
||||
namespace xcb {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue