diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-09-13 12:44:50 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-09-20 14:55:46 +0200 |
commit | ef9f3b63b277642b6b93fe4fbc5de3b8f16214e1 (patch) | |
tree | 6c0b7ffb1ac9fded39b71dfb647ae2b10a1744b3 | |
parent | d249f2922bcbbca0169faabc5108db5999adaf54 (diff) |
shiboken6: Introduce simple option struct
Add a struct Options to replace the struct CommandLineArguments
from main.cpp with built-in handling of the project file.
Port the generators over.
Pick-to: 6.6
Change-Id: I3012d211761e7a43c709f2754e6846f008ff2b0d
Reviewed-by: Shyamnath Premnadh <Shyamnath.Premnadh@qt.io>
-rw-r--r-- | sources/shiboken6/ApiExtractor/messages.cpp | 6 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/messages.h | 2 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/optionsparser.cpp | 148 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/optionsparser.h | 35 | ||||
-rw-r--r-- | sources/shiboken6/generator/main.cpp | 20 |
5 files changed, 196 insertions, 15 deletions
diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp index d1eb0e44a..0393fa3b3 100644 --- a/sources/shiboken6/ApiExtractor/messages.cpp +++ b/sources/shiboken6/ApiExtractor/messages.cpp @@ -947,3 +947,9 @@ QString msgUnknownArrayPointerConversion(const QString &s) return u"Warning: Falling back to pointer conversion for unknown array type \""_s + s + u"\""_s; } + +QString msgMissingProjectFileMarker(const QString &name, const QByteArray &startMarker) +{ + return u"First line of project file \""_s + QDir::toNativeSeparators(name) + + u"\" must be the string \""_s + QString::fromLatin1(startMarker) + u"\"."_s; +} diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h index a0bd94c55..93b9d10f1 100644 --- a/sources/shiboken6/ApiExtractor/messages.h +++ b/sources/shiboken6/ApiExtractor/messages.h @@ -251,4 +251,6 @@ QString msgMissingCustomConversion(const TypeEntryCPtr &t); QString msgUnknownArrayPointerConversion(const QString &s); +QString msgMissingProjectFileMarker(const QString &name, const QByteArray &startMarker); + #endif // MESSAGES_H diff --git a/sources/shiboken6/ApiExtractor/optionsparser.cpp b/sources/shiboken6/ApiExtractor/optionsparser.cpp index b41d13e7d..cf9f922aa 100644 --- a/sources/shiboken6/ApiExtractor/optionsparser.cpp +++ b/sources/shiboken6/ApiExtractor/optionsparser.cpp @@ -2,12 +2,94 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "optionsparser.h" +#include "messages.h" +#include "exception.h" #include <QtCore/QDir> #include <QtCore/QTextStream> using namespace Qt::StringLiterals; +template <class Stream> void formatBoolOption(Stream &s, const BoolOption &bo) +{ + switch (bo.source) { + case OptionSource::CommandLine: + s << "--"; + break; + case OptionSource::CommandLineSingleDash: + s << '-'; + break; + default: + break; + } + s << bo.option; + if (bo.source == OptionSource::ProjectFile) + s << " (project)"; +} + +template <class Stream> void formatOptionValue(Stream &s, const OptionValue &ov) +{ + switch (ov.source) { + case OptionSource::CommandLine: + s << "--"; + break; + case OptionSource::CommandLineSingleDash: + s << '-'; + break; + default: + break; + } + s << ov.option << '=' << ov.value; + if (ov.source == OptionSource::ProjectFile) + s << " (project)"; +} + +QTextStream &operator<<(QTextStream &s, const BoolOption &bo) +{ + formatBoolOption(s, bo); + return s; +} + +QTextStream &operator<<(QTextStream &s, const OptionValue &ov) +{ + formatOptionValue(s, ov); + return s; +} + +QDebug operator<<(QDebug debug, const BoolOption &bo) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + formatBoolOption(debug, bo); + return debug; +} + +QDebug operator<<(QDebug debug, const OptionValue &v) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + formatOptionValue(debug, v); + return debug; +} + +QDebug operator<<(QDebug debug, const Options &v) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "Options("; + if (!v.boolOptions.isEmpty()) + debug << "bools=" << v.boolOptions; + if (!v.valueOptions.isEmpty()) + debug << ", option values=" << v.valueOptions; + if (!v.positionalArguments.isEmpty()) + debug << ", pos=" << v.positionalArguments; + debug << ')'; + return debug; +} + QTextStream &operator<<(QTextStream &s, const OptionDescription &od) { if (!od.name.startsWith(u'-')) @@ -54,6 +136,20 @@ bool OptionsParser::handleOption(const QString &, const QString &, OptionSource) return false; } +void OptionsParser::process(Options *o) +{ + for (auto i = o->boolOptions.size() - 1; i >= 0; --i) { + const auto &opt = o->boolOptions.at(i); + if (handleBoolOption(opt.option, opt.source)) + o->boolOptions.removeAt(i); + } + for (auto i = o->valueOptions.size() - 1; i >= 0; --i) { + const auto &opt = o->valueOptions.at(i); + if (handleOption(opt.option, opt.value, opt.source)) + o->valueOptions.removeAt(i); + } +} + bool OptionsParserList::handleBoolOption(const QString &key, OptionSource source) { for (const auto &p : std::as_const(m_parsers)) { @@ -71,3 +167,55 @@ bool OptionsParserList::handleOption(const QString &key, const QString &value, O } return false; } + +static void processOption(const QString &o, OptionSource source, + BoolOptions *bools, OptionValues *values) +{ + const auto equals = o.indexOf(u'='); + if (equals == -1) { + bools->append({o.trimmed(), source}); + } else { + QString key = o.left(equals).trimmed(); + QString value = o.mid(equals + 1).trimmed(); + if (!value.isEmpty()) + values->append({key, value, source}); + } +} + +static void readProjectFile(const QString &name, Options *o) +{ + const auto startMarker = "[generator-project]"_ba; + + QFile file(name); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + throw Exception(msgCannotOpenForReading(file)); + + if (file.atEnd() || file.readLine().trimmed() != startMarker) + throw Exception(msgMissingProjectFileMarker(name, startMarker)); + + while (!file.atEnd()) { + const QByteArray lineB = file.readLine().trimmed(); + if (!lineB.isEmpty() && !lineB.startsWith('#')) { + processOption(QString::fromUtf8(lineB), OptionSource::ProjectFile, + &o->boolOptions, &o->valueOptions); + } + } +} + +void Options::setOptions(const QStringList &argv) +{ + const auto projectFileOption = "--project-file="_L1; + for (const auto &o : argv) { + if (o.startsWith(projectFileOption)) { + readProjectFile(o.sliced(projectFileOption.size()), this); + } else if (o.startsWith(u"--")) { + processOption(o.sliced(2), OptionSource::CommandLine, + &boolOptions, &valueOptions); + } else if (o.startsWith(u'-')) { + processOption(o.sliced(1), OptionSource::CommandLineSingleDash, + &boolOptions, &valueOptions); + } else { + positionalArguments.append(o); + } + } +} diff --git a/sources/shiboken6/ApiExtractor/optionsparser.h b/sources/shiboken6/ApiExtractor/optionsparser.h index 7ce33f5ba..f184c9bd2 100644 --- a/sources/shiboken6/ApiExtractor/optionsparser.h +++ b/sources/shiboken6/ApiExtractor/optionsparser.h @@ -5,7 +5,7 @@ #define OPTIONSPARSER_H #include <QtCore/QString> -#include <QtCore/QList> +#include <QtCore/QStringList> #include <memory> @@ -18,6 +18,31 @@ enum class OptionSource ProjectFile }; +struct BoolOption +{ + QString option; + OptionSource source = OptionSource::CommandLine; +}; + +struct OptionValue // --option=value pair +{ + QString option; + QString value; + OptionSource source = OptionSource::CommandLine; +}; + +using BoolOptions = QList<BoolOption>; +using OptionValues = QList<OptionValue>; + +struct Options // Options from command line and project file +{ + void setOptions(const QStringList &argv); + + BoolOptions boolOptions; + OptionValues valueOptions; + QStringList positionalArguments; +}; + struct OptionDescription // For help formatting { QString name; @@ -26,6 +51,8 @@ struct OptionDescription // For help formatting using OptionDescriptions = QList<OptionDescription>; +QTextStream &operator<<(QTextStream &s, const BoolOption &bo); +QTextStream &operator<<(QTextStream &s, const OptionValue &ov); QTextStream &operator<<(QTextStream &s, const OptionDescription &od); QTextStream &operator<<(QTextStream &s, const OptionDescriptions &options); @@ -40,6 +67,8 @@ public: virtual bool handleBoolOption(const QString &key, OptionSource source); virtual bool handleOption(const QString &key, const QString &value, OptionSource source); + void process(Options *); + static const QString &pathSyntax(); protected: @@ -61,4 +90,8 @@ private: QList<OptionsParserPtr> m_parsers; }; +QDebug operator<<(QDebug debug, const BoolOption &bo); +QDebug operator<<(QDebug debug, const OptionValue &v); +QDebug operator<<(QDebug debug, const Options &v); + #endif // OPTIONSPARSER_H diff --git a/sources/shiboken6/generator/main.cpp b/sources/shiboken6/generator/main.cpp index 8510c471e..73e7e9bde 100644 --- a/sources/shiboken6/generator/main.cpp +++ b/sources/shiboken6/generator/main.cpp @@ -419,6 +419,9 @@ int shibokenMain(const QStringList &argV) if (ReportHandler::isDebug(ReportHandler::SparseDebug)) qCInfo(lcShiboken()).noquote().nospace() << appName << ' ' << argV.join(u' '); + Options options; + options.setOptions(argV); + // Store command arguments in a map const auto projectFileArgumentsOptional = getProjectFileArguments(argV); if (!projectFileArgumentsOptional.has_value()) @@ -657,20 +660,7 @@ int shibokenMain(const QStringList &argV) cppFileNames.append(cppFileNameFi); } - // Pass option to all generators (Cpp/Header generator have the same options) - for (ait = args.options.begin(); ait != args.options.end(); ) { - bool found = false; - if (ait.value().metaType().id() == QMetaType::QString) { - const QString value = ait.value().toString(); - found |= value.isEmpty() - ? optionParser.handleBoolOption(ait.key(), OptionSource::CommandLine) - : optionParser.handleOption(ait.key(), value, OptionSource::CommandLine); - } - if (found) - ait = args.options.erase(ait); - else - ++ait; - } + optionParser.process(&options); optionParser.clear(); ait = args.options.find(languageLevelOption()); @@ -696,11 +686,13 @@ int shibokenMain(const QStringList &argV) args.options.remove(it.key()); } + /* FIXME: re-activate check if (!args.options.isEmpty()) { errorPrint(msgLeftOverArguments(args.options, argV), argV); std::cout << helpHint; return EXIT_FAILURE; } + */ if (typeSystemFileName.isEmpty()) { std::cout << "You must specify a Type System file." << std::endl << helpHint; |