From bb0eb7266381d722243518102903ce80fbbf1248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Kubern=C3=A1t?= Date: Fri, 15 Mar 2024 22:49:03 +0100 Subject: [PATCH 1/2] libshvcoreqt: Remove clioptions --- libshvcoreqt/CMakeLists.txt | 2 - .../include/shv/coreqt/utils/clioptions.h | 160 ------ libshvcoreqt/src/utils/clioptions.cpp | 488 ------------------ 3 files changed, 650 deletions(-) delete mode 100644 libshvcoreqt/include/shv/coreqt/utils/clioptions.h delete mode 100644 libshvcoreqt/src/utils/clioptions.cpp diff --git a/libshvcoreqt/CMakeLists.txt b/libshvcoreqt/CMakeLists.txt index e82de7c2e..3b66556ed 100644 --- a/libshvcoreqt/CMakeLists.txt +++ b/libshvcoreqt/CMakeLists.txt @@ -4,12 +4,10 @@ qt_add_library(libshvcoreqt src/log.cpp src/utils.cpp src/rpc.cpp - src/utils/clioptions.cpp src/utils/versioninfo.cpp include/shv/coreqt/shvcoreqtglobal.h include/shv/coreqt/utils/versioninfo.h - include/shv/coreqt/utils/clioptions.h include/shv/coreqt/rpc.h include/shv/coreqt/log.h include/shv/coreqt/data/valuechange.h diff --git a/libshvcoreqt/include/shv/coreqt/utils/clioptions.h b/libshvcoreqt/include/shv/coreqt/utils/clioptions.h deleted file mode 100644 index b41309799..000000000 --- a/libshvcoreqt/include/shv/coreqt/utils/clioptions.h +++ /dev/null @@ -1,160 +0,0 @@ -#pragma once - -#include - -#include - -#include -#include -#include -#include - -class QTextStream; - -namespace shv { -namespace chainpack { class RpcValue; } -namespace coreqt { -namespace utils { - -#define CLIOPTION_QUOTE_ME(x) QStringLiteral(#x) - -#define CLIOPTION_GETTER_SETTER(ptype, getter_prefix, setter_prefix, name_rest) \ - public: ptype getter_prefix##name_rest() const { \ - QVariant val = value(CLIOPTION_QUOTE_ME(getter_prefix##name_rest)); \ - return qvariant_cast(val); \ - } \ - public: bool getter_prefix##name_rest##_isset() const {return isValueSet(CLIOPTION_QUOTE_ME(getter_prefix##name_rest));} \ - public: bool setter_prefix##name_rest(const ptype &val) {return setValue(CLIOPTION_QUOTE_ME(getter_prefix##name_rest), val);} - -#define CLIOPTION_GETTER_SETTER2(ptype, pkey, getter_prefix, setter_prefix, name_rest) \ - public: ptype getter_prefix##name_rest() const { \ - QVariant val = value(QStringLiteral(pkey)); \ - return qvariant_cast(val); \ - } \ - public: bool getter_prefix##name_rest##_isset() const {return isValueSet(QStringLiteral(pkey));} \ - public: bool setter_prefix##name_rest(const ptype &val) {return setValue(QStringLiteral(pkey), val);} - -class [[deprecated("Use shv::core::CLIOptions")]] SHVCOREQT_DECL_EXPORT CLIOptions : public QObject -{ - Q_OBJECT -public: - CLIOptions(QObject *parent = NULL); - virtual ~CLIOptions(); - - CLIOPTION_GETTER_SETTER2(bool, "abortOnException", is, set, AbortOnException) - CLIOPTION_GETTER_SETTER2(bool, "help", is, set, Help) -public: - class SHVCOREQT_DECL_EXPORT Option - { - private: - struct Data : public QSharedData - { - QMetaType::Type type; - QStringList names; - QVariant value; - QVariant defaultValue; - QString comment; - bool mandatory; - - Data(QMetaType::Type type_ = QMetaType::Type::UnknownType) : type(type_), mandatory(false) {} - }; - QSharedDataPointer d; - - class NullConstructor {}; - static const Option& sharedNull(); - Option(NullConstructor); - public: - bool isNull() const {return d == sharedNull().d;} - - Option& setNames(const QStringList &names) {d->names = names; return *this;} - Option& setNames(const QString &name) {d->names = QStringList() << name; return *this;} - Option& setNames(const QString &name1, const QString name2) {d->names = QStringList() << name1 << name2; return *this;} - QStringList names() const {return d->names;} - Option& setType(QMetaType::Type type) {d->type = type; return *this;} - QMetaType::Type type() const {return d->type;} - Option& setValueString(const QString &val_str); - Option& setValue(const QVariant &val) {d->value = val; return *this;} - QVariant value() const {return d->value;} - Option& setDefaultValue(const QVariant &val) {d->defaultValue = val; return *this;} - QVariant defaultValue() const {return d->defaultValue;} - Option& setComment(const QString &s) {d->comment = s; return *this;} - QString comment() const {return d->comment;} - Option& setMandatory(bool b) {d->mandatory = b; return *this;} - bool isMandatory() const {return d->mandatory;} - bool isSet() const {return value().isValid();} - public: - Option(); - Option(QMetaType::Type type); - }; -public: - Option& addOption(const QString key, const Option &opt = Option()); - bool removeOption(const QString key); - Option option(const QString &name, bool throw_exc = true) const; - Option& optionRef(const QString &name); - const QMap& options() const {return m_options;} - - void parse(int argc, char *argv[]); - virtual void parse(const QStringList &cmd_line_args); - bool isParseError() const {return !m_parseErrors.isEmpty();} - bool isAppBreak() const {return m_isAppBreak;} - QStringList parseErrors() const {return m_parseErrors;} - QStringList unusedArguments() {return m_unusedArguments;} - - Q_INVOKABLE QString applicationDir() const; - Q_INVOKABLE QString applicationName() const; - Q_INVOKABLE void printHelp() const; - void printHelp(std::ostream &os) const; - Q_INVOKABLE void dump() const; - void dump(std::ostream &os) const; - - Q_INVOKABLE bool optionExists(const QString &name) const; - Q_INVOKABLE QVariantMap values() const; - Q_INVOKABLE QVariant value(const QString &name) const; - Q_INVOKABLE QVariant value(const QString &name, const QVariant default_value) const; - /// value is explicitly set from command line or in config file - /// defaultValue is not considered to be an explicitly set value - Q_INVOKABLE bool isValueSet(const QString &name) const; - bool setValue(const QString &name, const QVariant val, bool throw_exc = true); - - static QVariant rpcValueToQVariant(const chainpack::RpcValue &v); - static chainpack::RpcValue qVariantToRpcValue(const QVariant &v); -protected: - QVariant value_helper(const QString &name, bool throw_exception) const; - QPair applicationDirAndName() const; - QString takeArg(bool &ok); - QString peekArg(bool &ok) const; - void addParseError(const QString &err); -private: - QMap m_options; - QStringList m_arguments; - int m_parsedArgIndex; - QStringList m_unusedArguments; - QStringList m_parseErrors; - bool m_isAppBreak; - QStringList m_allArgs; -}; - -class [[deprecated("Use shv::core::ConfigCLIOptions")]] SHVCOREQT_DECL_EXPORT ConfigCLIOptions : public CLIOptions -{ - Q_OBJECT -private: - typedef CLIOptions Super; -public: - ConfigCLIOptions(QObject *parent = NULL); - ~ConfigCLIOptions() Q_DECL_OVERRIDE = default; - - CLIOPTION_GETTER_SETTER(QString, c, setC, onfig) - CLIOPTION_GETTER_SETTER(QString, c, setC, onfigDir) - - void parse(const QStringList &cmd_line_args) Q_DECL_OVERRIDE; - bool loadConfigFile(); -protected: - QString configFile(); -protected: - void mergeConfig(const shv::chainpack::RpcValue &config_map) {mergeConfig_helper(QString(), config_map);} - void mergeConfig(const QVariant &config_map); - void mergeConfig_helper(const QString &key_prefix, const shv::chainpack::RpcValue &config_map); -}; - -}}} - diff --git a/libshvcoreqt/src/utils/clioptions.cpp b/libshvcoreqt/src/utils/clioptions.cpp deleted file mode 100644 index d184bc511..000000000 --- a/libshvcoreqt/src/utils/clioptions.cpp +++ /dev/null @@ -1,488 +0,0 @@ -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef Q_OS_WIN -#include // needed by CLIOptions::applicationDirAndName() -#endif - -#include -#include - -namespace shv::coreqt::utils { - -const CLIOptions::Option & CLIOptions::Option::sharedNull() -{ - static Option n = Option(NullConstructor()); - return n; -} - -CLIOptions::Option::Option(CLIOptions::Option::NullConstructor) -{ - d = new Data(); -} - -CLIOptions::Option::Option() -{ - *this = sharedNull(); -} - -CLIOptions::Option::Option(QMetaType::Type type) -{ - d = new Data(type); -} - -CLIOptions::Option& CLIOptions::Option::setValueString(const QString& val_str) -{ - QMetaType::Type t = type(); - switch(t) { - case(QMetaType::UnknownType): - shvWarning() << "Setting value:" << val_str << "to an invalid type option."; - break; - case(QMetaType::Bool): - { - if(val_str.isEmpty()) { - setValue(true); - } - else { - bool ok; - int n = val_str.toInt(&ok); - if(ok) { - setValue(n != 0); - } - else { - bool is_true = true; - for(const char * const s : {"n", "no", "false"}) { - if(val_str.compare(QLatin1String(s), Qt::CaseInsensitive)) { - is_true = false; - break; - } - } - setValue(is_true); - } - } - break; - } - case(QMetaType::Int): - { - bool ok; - setValue(val_str.toInt(&ok)); - if(!ok) - shvWarning() << "Value:" << val_str << "cannot be converted to Int."; - break; - } - case(QMetaType::Double): - { - bool ok; - setValue(val_str.toDouble(&ok)); - if(!ok) - shvWarning() << "Value:" << val_str << "cannot be converted to Double."; - break; - } - default: - setValue(val_str); - } - return *this; -} - -CLIOptions::CLIOptions(QObject *parent) - : QObject(parent), m_parsedArgIndex(), m_isAppBreak() -{ - addOption("abortOnException").setType(QMetaType::Bool).setNames("--abort-on-exception").setComment(tr("Abort application on exception")); - addOption("help").setType(QMetaType::Bool).setNames("-h", "--help").setComment(tr("Print help")); -} - -CLIOptions::~CLIOptions() = default; - -CLIOptions::Option& CLIOptions::addOption(const QString key, const CLIOptions::Option& opt) -{ - m_options[key] = opt; - return m_options[key]; -} - -bool CLIOptions::removeOption(const QString key) -{ - return m_options.remove(key) > 0; -} - -CLIOptions::Option CLIOptions::option(const QString& name, bool throw_exc) const -{ - Option ret = m_options.value(name); - if(ret.isNull() && throw_exc) { - std::string msg = "Key '" + name.toStdString() + "' not found."; - shvWarning() << msg; - SHV_EXCEPTION(msg); - } - return ret; -} - -CLIOptions::Option& CLIOptions::optionRef(const QString& name) -{ - if(!m_options.contains(name)) { - std::string msg = "Key '" + name.toStdString() + "' not found."; - shvWarning() << msg; - SHV_EXCEPTION(msg); - } - return m_options[name]; -} - -QVariantMap CLIOptions::values() const -{ - QVariantMap ret; - QMapIterator it(m_options); - while(it.hasNext()) { - it.next(); - ret[it.key()] = value(it.key()); - } - return ret; -} - -QVariant CLIOptions::value(const QString &name) const -{ - QVariant ret = value_helper(name, shv::core::Exception::Throw); - return ret; -} - -QVariant CLIOptions::value(const QString& name, const QVariant default_value) const -{ - QVariant ret = value_helper(name, !shv::core::Exception::Throw); - if(!ret.isValid()) - ret = default_value; - return ret; -} - -bool CLIOptions::isValueSet(const QString &name) const -{ - return option(name, !shv::core::Exception::Throw).isSet(); -} - -QVariant CLIOptions::value_helper(const QString &name, bool throw_exception) const -{ - Option opt = option(name, throw_exception); - if(opt.isNull()) - return QVariant(); - QVariant ret = opt.value(); - if(!ret.isValid()) - ret = opt.defaultValue(); - return ret; -} - -bool CLIOptions::optionExists(const QString &name) const -{ - return !option(name, !shv::core::Exception::Throw).isNull(); -} - -bool CLIOptions::setValue(const QString& name, const QVariant val, bool throw_exc) -{ - Option o = option(name, false); - if(optionExists(name)) { - Option &orf = optionRef(name); - orf.setValue(val); - return true; - } - - QString msg = "setValue():"%val.toString()%" Key '"%name%"' not found."; - shvWarning() << msg.toStdString(); - if(throw_exc) { - SHV_EXCEPTION(msg.toStdString()); - } - return false; -} - -QString CLIOptions::takeArg(bool &ok) -{ - ok = m_parsedArgIndex < m_arguments.count(); - QString ret = m_arguments.value(m_parsedArgIndex++); - return ret; -} - -QString CLIOptions::peekArg(bool &ok) const -{ - ok = m_parsedArgIndex < m_arguments.count(); - QString ret = m_arguments.value(m_parsedArgIndex); - return ret; -} - -// NOLINTNEXTLINE(modernize-avoid-c-arrays) -void CLIOptions::parse(int argc, char* argv[]) -{ - QStringList args; - for(int i=0; i it(m_options); - while(it.hasNext()) { - it.next(); - Option &opt = it.value(); - QStringList names = opt.names(); - if(names.contains(arg)) { - found = true; - arg = peekArg(ok); - if(arg.startsWith('-') || !ok) { - // switch has no value entered - arg = QString(); - } - else { - arg = takeArg(ok); - } - opt.setValueString(arg); - break; - } - } - if(!found) { - if(arg.startsWith("-")) - m_unusedArguments << arg; - } - - } - { - QMapIterator it(m_options); - while(it.hasNext()) { - it.next(); - Option opt = it.value(); - if(opt.isMandatory() && !opt.value().isValid()) { - addParseError(QString("Mandatory option '%1' not set.").arg(opt.names().value(0))); - } - } - } - shv::core::Exception::setAbortOnException(isAbortOnException()); -} - -QPair CLIOptions::applicationDirAndName() const -{ - static QString app_dir; - static QString app_name; - if(app_name.isEmpty()) { - if(!m_allArgs.empty()) { - #ifdef Q_OS_WIN - QString app_file_path; - wchar_t buffer[MAX_PATH + 2]; - DWORD v = GetModuleFileName(0, buffer, MAX_PATH + 1); - buffer[MAX_PATH + 1] = 0; - if (v <= MAX_PATH) - app_file_path = QString::fromWCharArray(buffer); - QChar sep = '\\'; - #else - QString app_file_path = m_allArgs[0]; - QChar sep = '/'; - #endif - app_dir = app_file_path.section(sep, 0, -2); - app_name = app_file_path.section(sep, -1); - #ifdef Q_OS_WIN - if(app_name.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive)) - app_name = app_name.mid(0, app_name.length() - 4); - #else - if(app_name.endsWith(QLatin1String(".so"), Qt::CaseInsensitive)) { - // for example zygotized Android application - app_name = app_name.mid(0, app_name.length() - 3); - } - #endif - } - } - return QPair(app_dir, app_name); -} - -QString CLIOptions::applicationDir() const -{ - return QDir::fromNativeSeparators(applicationDirAndName().first); -} - -QString CLIOptions::applicationName() const -{ - return applicationDirAndName().second; -} - -void CLIOptions::printHelp(std::ostream &os) const -{ - using namespace std; - os << applicationName().toStdString() << " [OPTIONS]" << std::endl << std::endl; - os << "OPTIONS:" << std::endl << std::endl; - QMapIterator it(m_options); - while(it.hasNext()) { - it.next(); - Option opt = it.value(); - os << opt.names().join(", ").toStdString(); - if(opt.type() != QMetaType::Bool) { - if(opt.type() == QMetaType::Int || opt.type() == QMetaType::Double) os << " " << "number"; - else os << " " << "'string'"; - } - QVariant def_val = opt.defaultValue(); - if(def_val.isValid()) os << " [default(" << def_val.toString().toStdString() << ")]"; - if(opt.isMandatory()) os << " [MANDATORY]"; - os << std::endl; - QString oc = opt.comment(); - if(!oc.isEmpty()) os << "\t" << opt.comment().toStdString() << std::endl; - } - os << NecroLog::cliHelp() << std::endl; -} - -void CLIOptions::printHelp() const -{ - printHelp(std::cout); -} - -void CLIOptions::dump(std::ostream &os) const -{ - QMapIterator it(m_options); - while(it.hasNext()) { - it.next(); - Option opt = it.value(); - os << it.key().toStdString() << '(' << opt.names().join(", ").toStdString() << ')' << ": " << opt.value().toString().toStdString() << std::endl; - } -} - -void CLIOptions::dump() const -{ - std::cout << "=============== options values dump ==============" << std::endl; - dump(std::cout); - std::cout << "-------------------------------------------------" << std::endl; -} - -void CLIOptions::addParseError(const QString& err) -{ - m_parseErrors << err; -} - -QVariant CLIOptions::rpcValueToQVariant(const chainpack::RpcValue &v) -{ - return shv::coreqt::Utils::rpcValueToQVariant(v, nullptr); -} - -chainpack::RpcValue CLIOptions::qVariantToRpcValue(const QVariant &v) -{ - return shv::coreqt::Utils::qVariantToRpcValue(v, nullptr); -} - -ConfigCLIOptions::ConfigCLIOptions(QObject *parent) - : Super(parent) -{ - addOption("config").setType(QMetaType::Type::QString).setNames("--config").setComment("Application config name, it is loaded from {config}[.conf] if file exists in {config-dir}, default value is {app-name}.conf"); - addOption("configDir").setType(QMetaType::QString).setNames("--config-dir").setComment("Directory where application config fields are searched, default value: {app-dir-path}."); -} - -void ConfigCLIOptions::parse(const QStringList &cmd_line_args) -{ - Super::parse(cmd_line_args); -} - -bool ConfigCLIOptions::loadConfigFile() -{ - QString config_file = configFile(); - QFile f(config_file); - shvInfo() << "Checking presence of config file:" << f.fileName().toStdString(); - if(f.open(QFile::ReadOnly)) { - shvInfo() << "Reading config file:" << f.fileName(); - QByteArray ba = f.readAll(); - std::string cpon(ba.constData(), static_cast(ba.size())); - std::string str = shv::chainpack::Utils::removeJsonComments(std::string(ba.constData())); - std::string err; - chainpack::RpcValue rv = shv::chainpack::RpcValue::fromCpon(cpon, &err); - if(err.empty()) { - mergeConfig(rv); - } - else { - shvError() << "Error parsing config file:" << f.fileName() << err; - return false; - } - } - else { - shvInfo() << "Config file:" << f.fileName() << "not found."; - } - return true; -} - -QString ConfigCLIOptions::configFile() -{ - auto config = QStringLiteral("config"); - auto conf_ext = QStringLiteral(".conf"); - QString config_file; - if(isValueSet(config)) { - config_file = value(config).toString(); - if(config_file.isEmpty()) { - /// explicitly set empty config means DO NOT load config from any file - return QString(); - } - } - else { - config_file = applicationName() + conf_ext; - } - if(!QDir::isAbsolutePath(config_file)) { - QString config_dir = configDir(); - if(config_dir.isEmpty()) - config_dir = applicationDir(); - config_file = config_dir + '/' + config_file; - } - if(!config_file.endsWith(conf_ext)) { - if(QFile::exists(config_file + conf_ext)) - config_file += conf_ext; - } - return config_file; -} - -void ConfigCLIOptions::mergeConfig(const QVariant &config_map) -{ - mergeConfig_helper(QString(), qVariantToRpcValue(config_map)); -} - -void ConfigCLIOptions::mergeConfig_helper(const QString &key_prefix, const shv::chainpack::RpcValue &config_map) -{ - const chainpack::RpcValue::Map &cm = config_map.asMap(); - for(const auto &kv : cm) { - QString key = QString::fromStdString(kv.first); - SHV_ASSERT(!key.isEmpty(), "Empty key!", continue); - if(!key_prefix.isEmpty()) { - key = key_prefix + '.' + key; - } - chainpack::RpcValue v = kv.second; - if(options().contains(key)) { - Option &opt = optionRef(key); - if(!opt.isSet()) { - opt.setValue(rpcValueToQVariant(v)); - } - } - else if(v.isMap()) { - mergeConfig_helper(key, v); - } - else { - shvWarning() << "Cannot merge nonexisting option key:" << key; - } - } -} - -} From da2b6ffe95b0f919bf5c8b6856968685ce59127c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Kubern=C3=A1t?= Date: Fri, 15 Mar 2024 22:59:10 +0100 Subject: [PATCH 2/2] CI: Do not lint deleted files --- .github/actions/run-linter/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/run-linter/action.yml b/.github/actions/run-linter/action.yml index 85993f64f..e86425562 100644 --- a/.github/actions/run-linter/action.yml +++ b/.github/actions/run-linter/action.yml @@ -35,7 +35,7 @@ runs: git fetch --depth=1 origin "$BASE_REF" # FIXME: The clang on CI chokes on lambda captures of structured binding variables. Remove the blacklisting of # the files after the CI gets updated. (AFAIK clang-16). - readarray -t CHANGED_FILES < <(git diff --name-only "$BASE_REF" | grep 'cpp$' | grep -v -e "libshviotqt/tests/serialportsocket/test_serialportsocket.cpp" -e "libshvchainpack/tests/test_rpcvalue.cpp") + readarray -t CHANGED_FILES < <(git diff --diff-filter=d --name-only "$BASE_REF" | grep 'cpp$' | grep -v -e "libshviotqt/tests/serialportsocket/test_serialportsocket.cpp" -e "libshvchainpack/tests/test_rpcvalue.cpp") if [[ "${#CHANGED_FILES[@]}" -eq 0 ]]; then echo "No changed cpp files." exit 0