Experimental project containing INOFFICIAL tools to manage custom Arch Linux repositories; built on top of tools provided by the pacman and devtools packages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
7.6 KiB

#include "./authentication.h"
#include "./buildactions/buildaction.h"
#include "./buildactions/buildactiontemplate.h"
#include "./globallock.h"
#include "../libpkg/data/config.h"
#include "../libpkg/data/lockable.h"
#include <reflective_rapidjson/json/serializable.h>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/asio/ssl/context.hpp>
#include <memory>
#include <thread>
#include <vector>
namespace LibRepoMgr {
struct LIBREPOMGR_EXPORT ThreadPool {
explicit ThreadPool(const char *name, boost::asio::io_context &ioContext, unsigned short threadCount);
const char *const name;
std::vector<std::thread> threads;
struct ServiceStatus;
struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable {
// the overall configuration (databases, packages, ...) used at various places
// -> acquire the config lock for these
LibPkg::Config config;
// service global configuration; only changed when (re)loading config
// -> acquire the setup lock for these
std::string configFilePath = "server.conf";
std::string pacmanConfigFilePath = "/etc/pacman.conf";
std::string workingDirectory = "workingdir";
// variables relevant for the web server; only changed when (re)loading config
struct LIBREPOMGR_EXPORT WebServerSetup {
// only read by build actions and routes; changed when (re)loading config
// -> acquire the setup lock for these
std::string staticFilesPath;
// never changed after setup
boost::asio::ip::address address = boost::asio::ip::make_address("");
unsigned short port = 8090;
unsigned short threadCount = 1;
boost::asio::io_context ioContext;
boost::asio::ssl::context sslContext{ boost::asio::ssl::context::sslv23_client };
bool verifySslCertificates = true;
bool logSslCertificateValidation = false;
void applyConfig(const std::multimap<std::string, std::string> &multimap);
void initSsl();
static bool logCertificateValidation(bool preVerified, boost::asio::ssl::verify_context &context);
} webServer;
// variables relevant for build actions and web server routes dealing with them
struct LIBREPOMGR_EXPORT BuildSetup : public LibPkg::Lockable {
struct LIBREPOMGR_EXPORT Worker : private boost::asio::executor_work_guard<boost::asio::io_context::executor_type>, public ThreadPool {
explicit Worker(BuildSetup &setup);
BuildSetup &setup;
// read/written by build actions and routes
// -> acquire the build lock for these
std::vector<std::shared_ptr<BuildAction>> actions;
std::unordered_set<std::size_t> invalidActions;
// fields which have their own locking
// -> acquire the object's lock
BuildActionMetaInfo metaInfo; // only static data so far but maybe extended to allow defining custom build actions
// only read by build actions and routes; changed when (re)loading config
// -> acquire the setup lock for these
std::string workingDirectory = "building";
std::vector<std::string> pkgbuildsDirs;
std::regex ignoreLocalPkgbuildsRegex;
std::string makePkgPath = "makepkg";
std::string makeChrootPkgPath = "makechrootpkg";
std::string updatePkgSumsPath = "updpkgsums";
std::string repoAddPath = "repo-add";
std::string repoRemovePath = "repo-remove";
std::string gpgPath = "gpg";
std::string ccacheDir;
std::string chrootDir;
std::string chrootRootUser = "root";
std::string chrootDefaultUser = "buildservice";
std::string defaultGpgKey;
std::string pacmanConfigFilePath; // FIXME: not useful after all?; using config-$arch directory within chrootDir instead
std::string makepkgConfigFilePath; // FIXME: not useful after all?; using config-$arch directory within chrootDir instead
std::vector<std::string> makechrootpkgFlags;
std::vector<std::string> makepkgFlags;
std::string packageCacheDir;
std::uint64_t packageDownloadSizeLimit = 500 * 1024 * 1024;
std::string testFilesDir;
BuildPresets presets;
bool loadFilesDbs = false;
// never changed after startup
unsigned short threadCount = 4;
boost::asio::io_context ioContext;
void applyConfig(const std::multimap<std::string, std::string> &multimap);
void readPresets(const std::string &configFilePath, const std::string &presetsFile);
Worker allocateBuildWorker();
BuildAction::IdType allocateBuildActionID();
std::shared_ptr<BuildAction> getBuildAction(BuildAction::IdType id);
std::vector<std::shared_ptr<BuildAction>> getBuildActions(const std::vector<BuildAction::IdType> &ids);
} building;
struct LIBREPOMGR_EXPORT Authentication : public LibPkg::Lockable {
std::unordered_map<std::string, UserInfo> users;
void applyConfig(const std::string &userName, const std::multimap<std::string, std::string> &multimap);
UserPermissions authenticate(std::string_view authorizationHeader) const;
} auth;
using LockTable = std::unordered_map<std::string, GlobalLockable>;
[[nodiscard]] SharedLoggingLock acquireToRead(LogContext &log, std::string &&lockName);
[[nodiscard]] UniqueLoggingLock acquireToWrite(LogContext &log, std::string &&lockName);
[[nodiscard]] std::pair<LockTable *, std::unique_lock<std::mutex>> acquireLockTable();
void clear();
static std::string forDatabase(std::string_view dbName, std::string_view dbArch);
static std::string forDatabase(const LibPkg::Database &db);
std::mutex m_mutex;
LockTable m_locksByName;
} locks;
void loadConfigFiles(bool restoreStateAndDiscardDatabases);
void printDatabases();
std::string_view cacheFilePath() const;
RAPIDJSON_NAMESPACE::Document libraryDependenciesToJson() const;
void restoreLibraryDependenciesFromJson(const std::string &json, ReflectiveRapidJSON::JsonDeserializationErrors *errors);
std::size_t restoreState();
std::size_t saveState();
void run();
ServiceStatus computeStatus() const;
inline std::shared_ptr<BuildAction> ServiceSetup::BuildSetup::getBuildAction(BuildAction::IdType id)
return id < actions.size() ? actions[id] : nullptr;
inline SharedLoggingLock ServiceSetup::Locks::acquireToRead(LogContext &log, std::string &&lockName)
const auto lock = std::lock_guard(m_mutex);
return m_locksByName[lockName].lockToRead(log, std::move(lockName));
inline UniqueLoggingLock ServiceSetup::Locks::acquireToWrite(LogContext &log, std::string &&lockName)
const auto lock = std::lock_guard(m_mutex);
return m_locksByName[lockName].lockToWrite(log, std::move(lockName));
inline std::pair<ServiceSetup::Locks::LockTable *, std::unique_lock<std::mutex>> ServiceSetup::Locks::acquireLockTable()
return std::make_pair(&m_locksByName, std::unique_lock(m_mutex));
struct LIBREPOMGR_EXPORT ServiceStatus : public ReflectiveRapidJSON::JsonSerializable<ServiceStatus> {
ServiceStatus(const ServiceSetup &setup);
const char *const version = nullptr;
const LibPkg::Status config;
const BuildActionMetaInfo &actions;
const BuildPresets &presets;
inline ServiceStatus ServiceSetup::computeStatus() const
return ServiceStatus(*this);
} // namespace LibRepoMgr