pkg
This commit is contained in:
parent
6ce7ab2b83
commit
7d5d7b488a
5 changed files with 127 additions and 107 deletions
12
meson.build
12
meson.build
|
@ -88,15 +88,15 @@ add_project_arguments(common_cpp_args, language : 'cpp')
|
||||||
# ------- #
|
# ------- #
|
||||||
# Files #
|
# Files #
|
||||||
# ------- #
|
# ------- #
|
||||||
base_sources = files('src/core/system_data.cpp', 'src/os/shared.cpp', 'src/config/config.cpp', 'src/config/weather.cpp', 'src/main.cpp')
|
base_sources = files('src/core/system_data.cpp', 'src/config/config.cpp', 'src/config/weather.cpp', 'src/main.cpp')
|
||||||
|
|
||||||
platform_sources = {
|
platform_sources = {
|
||||||
'linux' : ['src/os/linux.cpp', 'src/os/linux/pkg_count.cpp'],
|
|
||||||
'freebsd' : ['src/os/bsd.cpp'],
|
|
||||||
'netbsd' : ['src/os/bsd.cpp'],
|
|
||||||
'dragonfly' : ['src/os/bsd.cpp'],
|
|
||||||
'haiku' : ['src/os/haiku.cpp'],
|
|
||||||
'darwin' : ['src/os/macos.cpp', 'src/os/macos/bridge.mm'],
|
'darwin' : ['src/os/macos.cpp', 'src/os/macos/bridge.mm'],
|
||||||
|
'dragonfly' : ['src/os/bsd.cpp', 'src/os/bsd/pkg_count.cpp'],
|
||||||
|
'freebsd' : ['src/os/bsd.cpp', 'src/os/bsd/pkg_count.cpp'],
|
||||||
|
'haiku' : ['src/os/haiku.cpp'],
|
||||||
|
'linux' : ['src/os/linux.cpp', 'src/os/linux/pkg_count.cpp'],
|
||||||
|
'netbsd' : ['src/os/bsd.cpp', 'src/os/bsd/pkg_count.cpp'],
|
||||||
'serenity' : ['src/os/serenity.cpp'],
|
'serenity' : ['src/os/serenity.cpp'],
|
||||||
'windows' : ['src/os/windows.cpp'],
|
'windows' : ['src/os/windows.cpp'],
|
||||||
}
|
}
|
||||||
|
|
|
@ -483,8 +483,6 @@ namespace os {
|
||||||
.total_bytes = stat.f_blocks * stat.f_frsize,
|
.total_bytes = stat.f_blocks * stat.f_frsize,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn GetPackageCount() -> Result<u64, DracError> { return shared::GetPackageCount(); }
|
|
||||||
} // namespace os
|
} // namespace os
|
||||||
|
|
||||||
#endif // __FreeBSD__ || __DragonFly__ || __NetBSD__
|
#endif // __FreeBSD__ || __DragonFly__ || __NetBSD__
|
||||||
|
|
|
@ -1,65 +1,93 @@
|
||||||
#ifndef __serenity__
|
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#ifndef _WIN32
|
#include <SQLiteCpp/Database.h> // SQLite::{Database, OPEN_READONLY}
|
||||||
#include <SQLiteCpp/Database.h> // SQLite::{Database, OPEN_READONLY}
|
#include <SQLiteCpp/Exception.h> // SQLite::Exception
|
||||||
#include <SQLiteCpp/Exception.h> // SQLite::Exception
|
#include <SQLiteCpp/Statement.h> // SQLite::Statement
|
||||||
#include <SQLiteCpp/Statement.h> // SQLite::Statement
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <chrono> // std::chrono
|
#include <chrono> // std::chrono
|
||||||
#include <filesystem> // std::filesystem
|
#include <filesystem> // std::filesystem
|
||||||
#include <format> // std::format
|
#include <format> // std::format
|
||||||
#include <fstream> // std::{ifstream, ofstream}
|
|
||||||
#include <glaze/beve/write.hpp> // glz::write_beve
|
#include <glaze/beve/write.hpp> // glz::write_beve
|
||||||
#include <glaze/core/common.hpp> // glz::object
|
#include <glaze/core/common.hpp> // glz::object
|
||||||
#include <glaze/core/meta.hpp> // glz::detail::Object
|
#include <glaze/core/meta.hpp> // glz::detail::Object
|
||||||
#include <iterator> // std::istreambuf_iterator
|
|
||||||
#include <system_error> // std::error_code
|
#include <system_error> // std::error_code
|
||||||
|
|
||||||
|
#include "src/os/bsd/pkg_count.hpp"
|
||||||
|
#include "src/os/os.hpp"
|
||||||
#include "src/util/cache.hpp"
|
#include "src/util/cache.hpp"
|
||||||
#include "src/util/defs.hpp"
|
#include "src/util/defs.hpp"
|
||||||
#include "src/util/error.hpp"
|
#include "src/util/error.hpp"
|
||||||
#include "src/util/helpers.hpp"
|
|
||||||
#include "src/util/logging.hpp"
|
#include "src/util/logging.hpp"
|
||||||
#include "src/util/types.hpp"
|
#include "src/util/types.hpp"
|
||||||
|
|
||||||
#include "os.hpp"
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
using util::error::DracError, util::error::DracErrorCode;
|
using util::error::DracError, util::error::DracErrorCode;
|
||||||
using util::types::u64, util::types::i64, util::types::String, util::types::StringView, util::types::Result,
|
using util::types::u64, util::types::i64, util::types::Result, util::types::Err, util::types::String,
|
||||||
util::types::Err, util::types::Exception;
|
util::types::StringView, util::types::Exception;
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using namespace util::cache;
|
using namespace util::cache;
|
||||||
|
|
||||||
#ifndef _WIN32
|
using os::bsd::PackageManagerInfo, os::bsd::PkgCountCacheData;
|
||||||
struct PackageManagerInfo {
|
|
||||||
String id;
|
|
||||||
fs::path dbPath;
|
|
||||||
String countQuery;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct PkgCountCacheData {
|
#ifdef __NetBSD__
|
||||||
u64 count {};
|
fn GetPackageCountInternalDir(const String& pmId, const fs::path& dirPath) -> Result<u64, DracError> {
|
||||||
i64 timestampEpochSeconds {};
|
debug_log("Attempting to get {} package count.", pmId);
|
||||||
|
|
||||||
// NOLINTBEGIN(readability-identifier-naming)
|
std::error_code errc;
|
||||||
struct [[maybe_unused]] glaze {
|
if (!fs::exists(dirPath, errc)) {
|
||||||
using T = PkgCountCacheData;
|
if (errc)
|
||||||
|
return Err(DracError(
|
||||||
|
DracErrorCode::IoError, std::format("Filesystem error checking {} directory: {}", pmId, errc.message())
|
||||||
|
));
|
||||||
|
|
||||||
static constexpr glz::detail::Object value =
|
return Err(
|
||||||
glz::object("count", &T::count, "timestamp", &T::timestampEpochSeconds);
|
DracError(DracErrorCode::ApiUnavailable, std::format("{} directory not found: {}", pmId, dirPath.string()))
|
||||||
};
|
);
|
||||||
// NOLINTEND(readability-identifier-naming)
|
}
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
if (!fs::is_directory(dirPath, errc)) {
|
||||||
|
if (errc)
|
||||||
|
return Err(DracError(
|
||||||
|
DracErrorCode::IoError, std::format("Filesystem error checking {} path type: {}", pmId, errc.message())
|
||||||
|
));
|
||||||
|
|
||||||
|
warn_log("Expected {} directory at '{}', but it's not a directory.", pmId, dirPath.string());
|
||||||
|
return Err(
|
||||||
|
DracError(DracErrorCode::IoError, std::format("{} path is not a directory: {}", pmId, dirPath.string()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 count = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fs::directory_iterator dirIter(dirPath, fs::directory_options::skip_permission_denied, errc);
|
||||||
|
|
||||||
|
if (errc)
|
||||||
|
return Err(
|
||||||
|
DracError(DracErrorCode::IoError, std::format("Failed to iterate {} directory: {}", pmId, errc.message()))
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const fs::directory_entry& entry : dirIter) { count++; }
|
||||||
|
} catch (const fs::filesystem_error& e) {
|
||||||
|
return Err(DracError(
|
||||||
|
DracErrorCode::IoError,
|
||||||
|
std::format("Filesystem error iterating {} directory '{}': {}", pmId, dirPath.string(), e.what())
|
||||||
|
));
|
||||||
|
} catch (...) {
|
||||||
|
return Err(DracError(
|
||||||
|
DracErrorCode::Other, std::format("Unknown error iterating {} directory '{}'", pmId, dirPath.string())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
count--;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#else
|
||||||
fn GetPackageCountInternalDb(const PackageManagerInfo& pmInfo) -> Result<u64, DracError> {
|
fn GetPackageCountInternalDb(const PackageManagerInfo& pmInfo) -> Result<u64, DracError> {
|
||||||
const auto& [pmId, dbPath, countQuery] = pmInfo;
|
const auto& [pmId, dbPath, countQuery] = pmInfo;
|
||||||
|
|
||||||
|
@ -122,73 +150,31 @@ namespace {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
} // namespace
|
||||||
|
|
||||||
#ifndef _WIN32
|
namespace os {
|
||||||
fn GetNixPackageCount() -> Result<u64, DracError> {
|
fn GetPackageCount() -> Result<u64, DracError> {
|
||||||
debug_log("Attempting to get Nix package count.");
|
#ifdef __NetBSD__
|
||||||
|
return GetPackageCountInternalDir("PkgSrc", fs::current_path().root_path() / "usr" / "pkg" / "pkgdb");
|
||||||
const PackageManagerInfo nixInfo = {
|
#else
|
||||||
.id = "nix",
|
const PackageManagerInfo pkgInfo = {
|
||||||
.dbPath = "/nix/var/nix/db/db.sqlite",
|
.id = "pkg_count",
|
||||||
.countQuery = "SELECT COUNT(path) FROM ValidPaths WHERE sigs IS NOT NULL",
|
.dbPath = "/var/db/pkg/local.sqlite",
|
||||||
|
.countQuery = "SELECT COUNT(*) FROM packages",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (std::error_code errc; !fs::exists(nixInfo.dbPath, errc)) {
|
if (std::error_code errc; !fs::exists(pkgInfo.dbPath, errc)) {
|
||||||
if (errc) {
|
if (errc) {
|
||||||
warn_log("Filesystem error checking for Nix DB at '{}': {}", nixInfo.dbPath.string(), errc.message());
|
warn_log("Filesystem error checking for pkg DB at '{}': {}", pkgInfo.dbPath.string(), errc.message());
|
||||||
return Err(DracError(DracErrorCode::IoError, "Filesystem error checking Nix DB: " + errc.message()));
|
return Err(DracError(DracErrorCode::IoError, "Filesystem error checking Nix DB: " + errc.message()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(DracError(DracErrorCode::ApiUnavailable, "Nix db not found: " + nixInfo.dbPath.string()));
|
return Err(DracError(DracErrorCode::ApiUnavailable, "pkg db not found: " + pkgInfo.dbPath.string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetPackageCountInternalDb(nixInfo);
|
return GetPackageCountInternalDb(pkgInfo);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fn GetCargoPackageCount() -> Result<u64, DracError> {
|
|
||||||
using util::helpers::GetEnv;
|
|
||||||
|
|
||||||
fs::path cargoPath {};
|
|
||||||
|
|
||||||
if (const Result<String, DracError> cargoHome = GetEnv("CARGO_HOME"))
|
|
||||||
cargoPath = fs::path(*cargoHome) / "bin";
|
|
||||||
else if (const Result<String, DracError> homeDir = GetEnv("HOME"))
|
|
||||||
cargoPath = fs::path(*homeDir) / ".cargo" / "bin";
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace os
|
||||||
|
|
||||||
namespace os::shared {
|
#endif // __FreeBSD__ || __DragonFly__ || __NetBSD__
|
||||||
fn GetPackageCount() -> Result<u64, DracError> {
|
|
||||||
u64 count = 0;
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
if (const Result<u64, DracError> pkgCount = GetNixPackageCount())
|
|
||||||
count += *pkgCount;
|
|
||||||
else
|
|
||||||
debug_at(pkgCount.error());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (const Result<u64, DracError> pkgCount = GetCargoPackageCount())
|
|
||||||
count += *pkgCount;
|
|
||||||
else
|
|
||||||
debug_at(pkgCount.error());
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
} // namespace os::shared
|
|
||||||
|
|
||||||
#endif // !__serenity__
|
|
36
src/os/bsd/pkg_count.hpp
Normal file
36
src/os/bsd/pkg_count.hpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include <filesystem> // std::filesystem::path
|
||||||
|
#include <glaze/core/common.hpp> // glz::object
|
||||||
|
#include <glaze/core/meta.hpp> // glz::detail::Object
|
||||||
|
|
||||||
|
#include "src/util/error.hpp"
|
||||||
|
#include "src/util/types.hpp"
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
namespace os::bsd {
|
||||||
|
using util::error::DracError;
|
||||||
|
using util::types::Result, util::types::u64, util::types::i64, util::types::String;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
struct PackageManagerInfo {
|
||||||
|
String id;
|
||||||
|
fs::path dbPath;
|
||||||
|
String countQuery;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PkgCountCacheData {
|
||||||
|
u64 count {};
|
||||||
|
i64 timestampEpochSeconds {};
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
};
|
||||||
|
} // namespace os::bsd
|
|
@ -61,10 +61,10 @@ namespace util::cache {
|
||||||
|
|
||||||
const fs::path& cachePath = *cachePathResult;
|
const fs::path& cachePath = *cachePathResult;
|
||||||
|
|
||||||
if (std::error_code exists_ec; !fs::exists(cachePath, exists_ec) || exists_ec) {
|
if (std::error_code existsEc; !fs::exists(cachePath, existsEc) || existsEc) {
|
||||||
if (exists_ec) {
|
if (existsEc) {
|
||||||
// Log if there was an error checking existence, but still return NotFound
|
// 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());
|
warn_log("Error checking existence of cache file '{}': {}", cachePath.string(), existsEc.message());
|
||||||
}
|
}
|
||||||
return Err(DracError(DracErrorCode::NotFound, "Cache file not found: " + cachePath.string()));
|
return Err(DracError(DracErrorCode::NotFound, "Cache file not found: " + cachePath.string()));
|
||||||
}
|
}
|
||||||
|
@ -174,9 +174,9 @@ namespace util::cache {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to atomically replace the old cache file
|
// Attempt to atomically replace the old cache file
|
||||||
std::error_code rename_ec;
|
std::error_code renameEc;
|
||||||
fs::rename(tempPath, cachePath, rename_ec);
|
fs::rename(tempPath, cachePath, renameEc);
|
||||||
if (rename_ec) {
|
if (renameEc) {
|
||||||
// If rename failed, attempt to clean up the temp file
|
// If rename failed, attempt to clean up the temp file
|
||||||
std::error_code removeEc;
|
std::error_code removeEc;
|
||||||
fs::remove(tempPath, removeEc); // Ignore error on cleanup attempt
|
fs::remove(tempPath, removeEc); // Ignore error on cleanup attempt
|
||||||
|
@ -186,7 +186,7 @@ namespace util::cache {
|
||||||
"Failed to replace cache file '{}' with temporary file '{}': {}",
|
"Failed to replace cache file '{}' with temporary file '{}': {}",
|
||||||
cachePath.string(),
|
cachePath.string(),
|
||||||
tempPath.string(),
|
tempPath.string(),
|
||||||
rename_ec.message()
|
renameEc.message()
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue