335 lines
14 KiB
C++
335 lines
14 KiB
C++
#include "./config.h"
|
|
#include "./manager.h"
|
|
|
|
#include <c++utilities/conversion/stringconversion.h>
|
|
|
|
#include <QFile>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QJsonArray>
|
|
|
|
#include <iostream>
|
|
|
|
using namespace std;
|
|
using namespace ApplicationUtilities;
|
|
using namespace ConversionUtilities;
|
|
|
|
namespace RepoIndex {
|
|
|
|
bool useShSyntax = false;
|
|
const char *shchar = "";
|
|
|
|
/*!
|
|
* \class Alpm::Config
|
|
* \brief The ConfigArgs class bundles the command line arguments for the application.
|
|
*/
|
|
|
|
/*!
|
|
* \brief Initializes the command line arguments for the configuration of the application.
|
|
*/
|
|
ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
|
helpArg(parser),
|
|
buildOrderArg("build-order", "b", "calculates the build order to build the specified packages"),
|
|
serverArg("server", "s", "runs a websocket server providing the web interface with information"),
|
|
upgradeLookupArg("upgrade-lookup", "u", "checks available upgrades for the specified repository"),
|
|
mingwBundleArg("mingw-w64-bundle", "m", "creates an archive with the runtime-relevant files from the specified mingw-w64-packages and their dependencies"),
|
|
repoindexConfArg("repoindex-conf", "c", "specifies the path of the repo index config file (default is /etc/repoindex.conf"),
|
|
rootdirArg("root-dir", "r", "specifies the root directory (default is /)"),
|
|
dbpathArg("db-path", "d", "specifies the pacman database path (default is /var/lib/pacman)"),
|
|
pacmanConfArg("pacman-conf", "p", "specifies the path of the pacman config file (default is /etc/pacman.conf"),
|
|
websocketAddrArg("addr", string(), "specifies the listening address for the websocket server, default is 127.0.0.1"),
|
|
websocketPortArg("port", string(), "specifies the listening port for the websocket server, default is 1234"),
|
|
certFileArg("cert-file", string(), "specifies the SSL certificate"),
|
|
keyFileArg("key-file", string(), "specifies the private SSL key"),
|
|
insecureArg("insecure", string(), "forces the server to run in insecure mode"),
|
|
aurArg("aur", string(), "enables/disables AUR queries"),
|
|
verboseArg("verbose", "v", "be verbose"),
|
|
outputFileArg("output-file", "f", "specifies the output file"),
|
|
targetDirArg("target-dir", "t", "the directory to store the target archive"),
|
|
targetNameArg("target-name", "n", "specifies the name of the target archive"),
|
|
targetFormatArg("target-format", "e", "specifies the format of the target archive"),
|
|
iconThemesArg("icon-packages", "i", "specifies the names of the icon packages to include"),
|
|
defaultIconThemeArg("default-icon-theme", string(), "specifies the name of the default icon theme (should be included in --icon-packages)"),
|
|
extraPackagesArg("extra-packages", string(), "specifies extra packages to be included"),
|
|
shSyntaxArg("sh-syntax", string(), "prints the output using shell syntax: export REPOINDEX_RESULTS=('res1' 'res2' 'res3') or export REPOINDEX_ERROR='some error message'"),
|
|
repoArg("repo", string(), "specifies the repository")
|
|
{
|
|
const initializer_list<string> pathValueName = {"path"};
|
|
const initializer_list<string> pkgValueNames = {"package 1", "package 2", "package 3"};
|
|
buildOrderArg.setDenotesOperation(true);
|
|
buildOrderArg.setRequiredValueCount(-1);
|
|
buildOrderArg.setValueNames(pkgValueNames);
|
|
serverArg.setDenotesOperation(true);
|
|
upgradeLookupArg.setDenotesOperation(true);
|
|
upgradeLookupArg.setRequiredValueCount(1);
|
|
upgradeLookupArg.setValueNames({"repo"});
|
|
mingwBundleArg.setDenotesOperation(true);
|
|
mingwBundleArg.setRequiredValueCount(-1);
|
|
mingwBundleArg.setValueNames(pkgValueNames);
|
|
repoindexConfArg.setCombinable(true);
|
|
repoindexConfArg.setValueNames(pathValueName);
|
|
repoindexConfArg.setRequiredValueCount(1);
|
|
rootdirArg.setCombinable(true);
|
|
rootdirArg.setValueNames({"directory"});
|
|
rootdirArg.setRequiredValueCount(1);
|
|
dbpathArg.setCombinable(true);
|
|
dbpathArg.setValueNames(pathValueName);
|
|
dbpathArg.setRequiredValueCount(1);
|
|
pacmanConfArg.setCombinable(true);
|
|
pacmanConfArg.setValueNames(pathValueName);
|
|
pacmanConfArg.setRequiredValueCount(1);
|
|
websocketAddrArg.setCombinable(true);
|
|
websocketAddrArg.setValueNames({"IP address"});
|
|
websocketAddrArg.setRequiredValueCount(1);
|
|
websocketPortArg.setCombinable(true);
|
|
websocketPortArg.setValueNames({"port number"});
|
|
websocketPortArg.setRequiredValueCount(1);
|
|
certFileArg.setCombinable(true);
|
|
certFileArg.setValueNames(pathValueName);
|
|
certFileArg.setRequiredValueCount(1);
|
|
keyFileArg.setCombinable(true);
|
|
keyFileArg.setValueNames(pathValueName);
|
|
keyFileArg.setRequiredValueCount(1);
|
|
insecureArg.setCombinable(true);
|
|
aurArg.setCombinable(true);
|
|
aurArg.setRequiredValueCount(1);
|
|
aurArg.setValueNames({"enabled/disabled"});
|
|
verboseArg.setCombinable(true);
|
|
outputFileArg.setCombinable(true);
|
|
outputFileArg.setRequired(true);
|
|
outputFileArg.setRequiredValueCount(1);
|
|
outputFileArg.setValueNames(pathValueName);
|
|
targetDirArg.setCombinable(true);
|
|
targetDirArg.setRequiredValueCount(1);
|
|
targetDirArg.setValueNames(pathValueName);
|
|
targetNameArg.setCombinable(true);
|
|
targetNameArg.setRequired(true);
|
|
targetNameArg.setRequiredValueCount(1);
|
|
targetNameArg.setValueNames({"name"});
|
|
targetFormatArg.setCombinable(true);
|
|
targetFormatArg.setRequiredValueCount(1);
|
|
targetFormatArg.setValueNames({"zip/7z/tar.gz/tar.bz/tar.xz"});
|
|
iconThemesArg.setCombinable(true);
|
|
iconThemesArg.setRequiredValueCount(-1);
|
|
iconThemesArg.setValueNames(pkgValueNames);
|
|
defaultIconThemeArg.setCombinable(true);
|
|
defaultIconThemeArg.setRequiredValueCount(1);
|
|
defaultIconThemeArg.setValueNames({"theme name"});
|
|
extraPackagesArg.setCombinable(true);
|
|
extraPackagesArg.setRequiredValueCount(-1);
|
|
extraPackagesArg.setValueNames(pkgValueNames);
|
|
shSyntaxArg.setCombinable(true);
|
|
repoArg.setRequiredValueCount(1);
|
|
repoArg.setValueNames({"repo name"});
|
|
serverArg.setSecondaryArguments({&rootdirArg, &dbpathArg, &pacmanConfArg, &certFileArg, &keyFileArg, &websocketAddrArg, &websocketPortArg, &insecureArg, &aurArg, &shSyntaxArg});
|
|
upgradeLookupArg.setSecondaryArguments({&shSyntaxArg});
|
|
buildOrderArg.setSecondaryArguments({&aurArg, &verboseArg, &shSyntaxArg});
|
|
mingwBundleArg.setSecondaryArguments({&targetDirArg, &targetNameArg, &targetFormatArg, &iconThemesArg, &defaultIconThemeArg, &extraPackagesArg});
|
|
parser.setMainArguments({&buildOrderArg, &upgradeLookupArg, &serverArg, &mingwBundleArg, &repoindexConfArg, &repoindexConfArg, &helpArg});
|
|
}
|
|
|
|
/*!
|
|
* \class Alpm::Config
|
|
* \brief The Config class represents the configuration for the application.
|
|
*/
|
|
|
|
/*!
|
|
* \brief Creates the default configuration for the application.
|
|
*/
|
|
Config::Config() :
|
|
m_alpmRootDir(QStringLiteral("/")),
|
|
m_alpmDbPath(QStringLiteral("/var/lib/pacman")),
|
|
m_pacmanConfFile(QStringLiteral("/etc/pacman.conf")),
|
|
m_cacheDir(QStringLiteral(".")),
|
|
m_websocketServerListeningAddr(QHostAddress::LocalHost),
|
|
m_websocketServerListeningPort(1234),
|
|
m_serverInsecure(false),
|
|
m_reposFromPacmanConf(false),
|
|
m_aurEnabled(true),
|
|
m_verbose(false),
|
|
m_runServer(false)
|
|
{}
|
|
|
|
/*!
|
|
* \cond
|
|
*/
|
|
|
|
inline void assign(quint16 &num, const QJsonValue &val)
|
|
{
|
|
if(!val.isUndefined()) {
|
|
auto n = val.toInt(-1);
|
|
if(n > 0 && n <= static_cast<quint16>(-1)) {
|
|
num = static_cast<quint16>(n);
|
|
} else {
|
|
cerr << shchar << "Error: The specified value \"" << n << "\" is not a number." << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void assign(QHostAddress &addr, const QString &val)
|
|
{
|
|
if(!val.isEmpty() && !addr.setAddress(val)) {
|
|
// checking some special values might be useful
|
|
if(val == QLatin1String("localhost")) {
|
|
addr = QHostAddress::LocalHost;
|
|
} else if(val == QLatin1String("localhost-IPv6")) {
|
|
addr = QHostAddress::LocalHostIPv6;
|
|
} else if(val == QLatin1String("any-IPv4")) {
|
|
addr = QHostAddress::AnyIPv4;
|
|
} else if(val == QLatin1String("any-IPv6")) {
|
|
addr = QHostAddress::AnyIPv6;
|
|
} else if(val == QLatin1String("any")) {
|
|
addr = QHostAddress::Any;
|
|
} else {
|
|
cerr << shchar << "Error: Unable to parse the specified host address \"" << val.toStdString() << "\"." << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void assign(QString &str, const Argument &arg)
|
|
{
|
|
if(arg.isPresent()) {
|
|
str = QString::fromLocal8Bit(arg.values().front().data(), arg.values().front().size());
|
|
}
|
|
}
|
|
|
|
inline void assign(quint16 &num, const Argument &arg)
|
|
{
|
|
if(arg.isPresent()) {
|
|
try {
|
|
num = stringToNumber<quint16>(arg.values().front());
|
|
} catch(const ConversionException &) {
|
|
cerr << shchar << "Error: The specified argument value \"" << arg.values().front() << "\" is not a number." << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void assign(bool &num, const Argument &arg)
|
|
{
|
|
num |= arg.isPresent();
|
|
}
|
|
|
|
/*!
|
|
* \endcond
|
|
*/
|
|
|
|
/*!
|
|
* \brief Loads the configuration from the specified configuration file.
|
|
*/
|
|
void Config::loadFromConfigFile(const QString &configFilePath)
|
|
{
|
|
QFile file(configFilePath);
|
|
if(file.open(QFile::ReadOnly)) {
|
|
QJsonParseError error;
|
|
auto doc = QJsonDocument::fromJson(file.readAll(), &error);
|
|
if(error.error == QJsonParseError::NoError) {
|
|
auto mainObj = doc.object();
|
|
auto alpmObj = mainObj.value(QStringLiteral("alpm")).toObject();
|
|
m_alpmRootDir = alpmObj.value(QStringLiteral("rootDir")).toString(m_alpmRootDir);
|
|
m_alpmDbPath = alpmObj.value(QStringLiteral("dbPath")).toString(m_alpmDbPath);
|
|
m_pacmanConfFile = alpmObj.value(QStringLiteral("pacmanConfigFile")).toString(m_pacmanConfFile);
|
|
m_cacheDir = mainObj.value(QStringLiteral("cacheDir")).toString(m_cacheDir);
|
|
auto aurObj = mainObj.value(QStringLiteral("aur")).toObject();
|
|
m_aurEnabled = aurObj.value(QStringLiteral("enabled")).toBool(m_aurEnabled);
|
|
auto serverObj = mainObj.value(QStringLiteral("server")).toObject();
|
|
assign(m_websocketServerListeningAddr, serverObj.value(QStringLiteral("websocketListeningAddr")).toString());
|
|
assign(m_websocketServerListeningPort, serverObj.value(QStringLiteral("websocketListeningPort")));
|
|
m_serverCertFile = serverObj.value(QStringLiteral("certFile")).toString(m_serverCertFile);
|
|
m_serverKeyFile = serverObj.value(QStringLiteral("keyFile")).toString(m_serverKeyFile);
|
|
m_serverInsecure = serverObj.value(QStringLiteral("insecure")).toBool(m_serverInsecure);
|
|
auto reposObj = mainObj.value(QStringLiteral("repos")).toObject();
|
|
m_reposFromPacmanConf = serverObj.value(QStringLiteral("fromPacmanConfig")).toBool(m_reposFromPacmanConf);
|
|
for(const auto &repo : reposObj.value(QStringLiteral("add")).toArray()) {
|
|
m_repoEntries << RepoEntry();
|
|
m_repoEntries.back().load(repo);
|
|
}
|
|
} else {
|
|
cerr << shchar << "Error: Unable to parse config file \"" << configFilePath.toLocal8Bit().data() << "\": "
|
|
<< error.errorString().toLocal8Bit().data() << " at character " << error.offset << endl;
|
|
}
|
|
} else {
|
|
cerr << shchar << "Error: Unable to open config file \"" << configFilePath.toLocal8Bit().data() << "\"." << endl;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* \brief Loads the configuration from the configuration file.
|
|
*
|
|
* The config file is obtained from the specified config args. If no such argument is present,
|
|
* some default locations are checked.
|
|
*/
|
|
void Config::loadFromConfigFile(const ConfigArgs &args)
|
|
{
|
|
if(args.repoindexConfArg.isPresent()) {
|
|
loadFromConfigFile(QString::fromLocal8Bit(args.repoindexConfArg.values().front().data()));
|
|
return;
|
|
} else {
|
|
for(const auto &defaultPath : {QStringLiteral("./repoindex.conf"), QStringLiteral("/etc/repoindex.conf")}) {
|
|
if(QFile::exists(defaultPath)) {
|
|
loadFromConfigFile(defaultPath);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* \brief Loads the config from the specified configuration arguments.
|
|
*/
|
|
void Config::loadFromArgs(const ConfigArgs &args)
|
|
{
|
|
assign(m_alpmRootDir, args.rootdirArg);
|
|
assign(m_alpmDbPath, args.dbpathArg);
|
|
assign(m_pacmanConfFile, args.pacmanConfArg);
|
|
if(args.aurArg.isPresent()) {
|
|
auto val = args.aurArg.values().front();
|
|
if(val == "enabled") {
|
|
m_aurEnabled = true;
|
|
} else if(val == "disabled") {
|
|
m_aurEnabled = false;
|
|
} else {
|
|
cerr << shchar << "Warning: The specified value for the argument --aur-enabled is invalid and will be ignored." << endl;
|
|
}
|
|
}
|
|
assign(m_websocketServerListeningPort, args.websocketPortArg);
|
|
assign(m_serverCertFile, args.certFileArg);
|
|
assign(m_serverKeyFile, args.keyFileArg);
|
|
assign(m_serverInsecure, args.insecureArg);
|
|
if(args.websocketAddrArg.isPresent()) {
|
|
assign(m_websocketServerListeningAddr, QString::fromLocal8Bit(args.websocketAddrArg.values().front().data(), args.websocketAddrArg.values().front().size()));
|
|
}
|
|
m_verbose = args.verboseArg.isPresent();
|
|
m_runServer = args.serverArg.isPresent();
|
|
}
|
|
|
|
/*!
|
|
* \brief Loads the values from the specified JSON value.
|
|
*/
|
|
void RepoEntry::load(const QJsonValue &jsonValue)
|
|
{
|
|
auto obj = jsonValue.toObject();
|
|
m_name = obj.value(QStringLiteral("name")).toString(m_name);
|
|
m_dataBaseFile = obj.value(QStringLiteral("dataBaseFile")).toString(m_dataBaseFile);
|
|
m_sourceDir = obj.value(QStringLiteral("sourcesDir")).toString(m_sourceDir);
|
|
m_packageDir = obj.value(QStringLiteral("packagesDir")).toString(m_packageDir);
|
|
for(const auto &server : obj.value(QStringLiteral("servers")).toArray()) {
|
|
auto str = server.toString();
|
|
if(!str.isEmpty()) {
|
|
m_servers << str;
|
|
}
|
|
}
|
|
for(const auto &upgradeSources : obj.value(QStringLiteral("upgradeSources")).toArray()) {
|
|
auto str = upgradeSources.toString();
|
|
if(!str.isEmpty()) {
|
|
m_upgradeSources << str;
|
|
}
|
|
}
|
|
const auto sigLevelValue = obj.value(QStringLiteral("sigLevel"));
|
|
if(sigLevelValue.isString()) {
|
|
m_sigLevel = Manager::parseSigLevel(sigLevelValue.toString().toLocal8Bit().data());
|
|
}
|
|
}
|
|
|
|
} // namespace Alpm
|
|
|