diff options
Diffstat (limited to 'src/tools')
-rw-r--r-- | src/tools/androiddeployqt/main.cpp | 26 | ||||
-rw-r--r-- | src/tools/androidtestrunner/main.cpp | 155 | ||||
-rw-r--r-- | src/tools/moc/moc.cpp | 7 | ||||
-rw-r--r-- | src/tools/moc/moc.h | 3 | ||||
-rw-r--r-- | src/tools/uic/ui4.cpp | 7 | ||||
-rw-r--r-- | src/tools/uic/ui4.h | 8 |
6 files changed, 146 insertions, 60 deletions
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index e93c3038fca..a27c52f5a99 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -1475,10 +1475,23 @@ bool readInputFile(Options *options) for (const QJsonValue &value : permissions) { if (value.isObject()) { QJsonObject permissionObj = value.toObject(); - QString name = permissionObj.value("name"_L1).toString(); + QString name; QString extras; - if (permissionObj.contains("extras"_L1)) - extras = permissionObj.value("extras"_L1).toString().trimmed(); + for (auto it = permissionObj.begin(); it != permissionObj.end(); ++it) { + if (it.key() == "name"_L1) { + name = it.value().toString(); + } else { + extras.append(" android:"_L1) + .append(it.key()) + .append("=\""_L1) + .append(it.value().toString()) + .append("\""_L1); + } + } + if (name.isEmpty()) { + fprintf(stderr, "Missing permission 'name' in permission specification"); + return false; + } options->applicationPermissions.insert(name, extras); } } @@ -1580,8 +1593,11 @@ bool copyAndroidTemplate(const Options &options) if (options.verbose) fprintf(stdout, "Copying Android package template.\n"); - if (!copyGradleTemplate(options)) - return false; + if (!options.auxMode) { + // Gradle is not configured and is not running in aux mode + if (!copyGradleTemplate(options)) + return false; + } if (!copyAndroidTemplate(options, "/src/android/templates"_L1)) return false; diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp index eb4c84fbd75..564a332c091 100644 --- a/src/tools/androidtestrunner/main.cpp +++ b/src/tools/androidtestrunner/main.cpp @@ -40,6 +40,7 @@ struct Options QString buildPath; QString manifestPath; QString adbCommand{"adb"_L1}; + QString bundletoolPath; QString serial; QString makeCommand; QString package; @@ -48,7 +49,7 @@ struct Options QString stdoutFileName; QHash<QString, QString> outFiles; QStringList amStarttestArgs; - QString apkPath; + QString packagePath; QString ndkStackPath; QList<QStringList> preTestRunAdbCommands; bool showLogcatOutput = false; @@ -114,6 +115,24 @@ static bool execAdbCommand(const QStringList &args, QByteArray *output = nullptr return execCommand(g_options.adbCommand, argsWithSerial, output, verbose); } +static bool execBundletoolCommand(const QStringList &args, QByteArray *output = nullptr, + bool verbose = true) +{ + QString java("java"_L1); + QStringList argsFull = QStringList() << "-jar"_L1 << g_options.bundletoolPath << args; + return execCommand(java, argsFull, output, verbose); +} + +static void setPackagePath(const QString &path) +{ + if (!g_options.packagePath.isEmpty()) { + qCritical("Both --aab and --apk options provided. This is not supported."); + g_options.helpRequested = true; + return; + } + g_options.packagePath = path; +} + static bool execCommand(const QString &command, QByteArray *output = nullptr, bool verbose = true) { auto args = QProcess::splitCommand(command); @@ -133,6 +152,11 @@ static bool parseOptions() g_options.helpRequested = true; else g_options.adbCommand = arguments.at(++i); + } else if (argument.compare("--bundletool"_L1, Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + g_options.helpRequested = true; + else + g_options.bundletoolPath = arguments.at(++i); } else if (argument.compare("--path"_L1, Qt::CaseInsensitive) == 0) { if (i + 1 == arguments.size()) g_options.helpRequested = true; @@ -152,7 +176,12 @@ static bool parseOptions() if (i + 1 == arguments.size()) g_options.helpRequested = true; else - g_options.apkPath = arguments.at(++i); + setPackagePath(arguments.at(++i)); + } else if (argument.compare("--aab"_L1, Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + g_options.helpRequested = true; + else + setPackagePath(arguments.at(++i)); } else if (argument.compare("--activity"_L1, Qt::CaseInsensitive) == 0) { if (i + 1 == arguments.size()) g_options.helpRequested = true; @@ -200,7 +229,7 @@ static bool parseOptions() for (;i < arguments.size(); ++i) g_options.testArgsList << arguments.at(i); - if (g_options.helpRequested || g_options.buildPath.isEmpty() || g_options.apkPath.isEmpty()) + if (g_options.helpRequested || g_options.buildPath.isEmpty() || g_options.packagePath.isEmpty()) return false; g_options.serial = qEnvironmentVariable("ANDROID_SERIAL"); @@ -222,52 +251,57 @@ static bool parseOptions() static void printHelp() { - qWarning( "Syntax: %s <options> -- [TESTARGS] \n" - "\n" - " Runs a Qt for Android test on an emulator or a device. Specify a device\n" - " using the environment variables ANDROID_SERIAL or ANDROID_DEVICE_SERIAL.\n" - " Returns the number of failed tests, -1 on test runner deployment related\n" - " failures or zero on success." - "\n" - " Mandatory arguments:\n" - " --path <path>: The path where androiddeployqt builds the android package.\n" - "\n" - " --make <make cmd>: make command to create an APK, for example:\n" - " \"cmake --build <build-dir> --target <target>_make_apk\".\n" - "\n" - " --apk <apk path>: The test apk path. The apk has to exist already, if it\n" - " does not exist the make command must be provided for building the apk.\n" - "\n" - " Optional arguments:\n" - " --adb <adb cmd>: The Android ADB command. If missing the one from\n" - " $PATH will be used.\n" - "\n" - " --activity <acitvity>: The Activity to run. If missing the first\n" - " activity from AndroidManifest.qml file will be used.\n" - "\n" - " --timeout <seconds>: Timeout to run the test. Default is 10 minutes.\n" - "\n" - " --skip-install-root: Do not append INSTALL_ROOT=... to the make command.\n" - "\n" - " --show-logcat: Print Logcat output to stdout. If an ANR occurs during\n" - " the test run, logs from the system_server process are included.\n" - " This argument is implied if a test crashes.\n" - "\n" - " --ndk-stack: Path to ndk-stack tool that symbolizes crash stacktraces.\n" - " By default, ANDROID_NDK_ROOT env var is used to deduce the tool path.\n" - "\n" - " -- Arguments that will be passed to the test application.\n" - "\n" - " --verbose: Prints out information during processing.\n" - "\n" - " --pre-test-adb-command <command>: call the adb <command> after\n" - " installation and before the test run.\n" - "\n" - " --manifest <path>: Custom path to the AndroidManifest.xml.\n" - "\n" - " --help: Displays this information.\n", - qPrintable(QCoreApplication::arguments().at(0)) - ); + qWarning("Syntax: %s <options> -- [TESTARGS] \n" + "\n" + " Runs a Qt for Android test on an emulator or a device. Specify a device\n" + " using the environment variables ANDROID_SERIAL or ANDROID_DEVICE_SERIAL.\n" + " Returns the number of failed tests, -1 on test runner deployment related\n" + " failures or zero on success." + "\n" + " Mandatory arguments:\n" + " --path <path>: The path where androiddeployqt builds the android package.\n" + "\n" + " --make <make cmd>: make command to create an APK, for example:\n" + " \"cmake --build <build-dir> --target <target>_make_apk\".\n" + "\n" + " --apk <apk path>: The test apk path. The apk has to exist already, if it\n" + " does not exist the make command must be provided for building the apk.\n" + "\n" + " --aab <aab path>: The test aab path. The aab has to exist already, if it\n" + " does not exist the make command must be provided for building the aab.\n" + "\n" + " Optional arguments:\n" + " --adb <adb cmd>: The Android ADB command. If missing the one from\n" + " $PATH will be used.\n" + "\n" + " --activity <acitvity>: The Activity to run. If missing the first\n" + " activity from AndroidManifest.qml file will be used.\n" + "\n" + " --timeout <seconds>: Timeout to run the test. Default is 10 minutes.\n" + "\n" + " --skip-install-root: Do not append INSTALL_ROOT=... to the make command.\n" + "\n" + " --show-logcat: Print Logcat output to stdout. If an ANR occurs during\n" + " the test run, logs from the system_server process are included.\n" + " This argument is implied if a test crashes.\n" + "\n" + " --ndk-stack: Path to ndk-stack tool that symbolizes crash stacktraces.\n" + " By default, ANDROID_NDK_ROOT env var is used to deduce the tool path.\n" + "\n" + " -- Arguments that will be passed to the test application.\n" + "\n" + " --verbose: Prints out information during processing.\n" + "\n" + " --pre-test-adb-command <command>: call the adb <command> after\n" + " installation and before the test run.\n" + "\n" + " --manifest <path>: Custom path to the AndroidManifest.xml.\n" + "\n" + " --bundletool <bundletool path>: The path to Android bundletool.\n" + " See https://developer.android.com/tools/bundletool for details.\n" + "\n" + " --help: Displays this information.\n", + qPrintable(QCoreApplication::arguments().at(0))); } static QString packageNameFromAndroidManifest(const QString &androidManifestPath) @@ -850,10 +884,10 @@ int main(int argc, char *argv[]) return EXIT_ERROR; } - if (!QFile::exists(g_options.apkPath)) { + if (!QFile::exists(g_options.packagePath)) { qCritical("No apk \"%s\" found after running the make command. " "Check the provided path and the make command.", - qPrintable(g_options.apkPath)); + qPrintable(g_options.packagePath)); return EXIT_ERROR; } @@ -886,11 +920,22 @@ int main(int argc, char *argv[]) // do not install or run packages while another test is running testRunnerLock.acquire(); - const QStringList installArgs = { "install"_L1, "-r"_L1, "-g"_L1, g_options.apkPath }; - g_testInfo.isPackageInstalled.store(execAdbCommand(installArgs, nullptr)); - if (!g_testInfo.isPackageInstalled) - return EXIT_ERROR; + if (g_options.packagePath.endsWith(".apk"_L1)) { + const QStringList installArgs = { "install"_L1, "-r"_L1, "-g"_L1, g_options.packagePath }; + g_testInfo.isPackageInstalled.store(execAdbCommand(installArgs, nullptr)); + if (!g_testInfo.isPackageInstalled) + return EXIT_ERROR; + } else if (g_options.packagePath.endsWith(".aab"_L1)) { + QFileInfo aab(g_options.packagePath); + const auto apksFilePath = aab.absoluteDir().absoluteFilePath(aab.baseName() + ".apks"_L1); + if (!execBundletoolCommand({ "build-apks"_L1, "--bundle"_L1, g_options.packagePath, + "--output"_L1, apksFilePath, "--local-testing"_L1, + "--overwrite"_L1 })) + return EXIT_ERROR; + if (!execBundletoolCommand({ "install-apks"_L1, "--apks"_L1, apksFilePath })) + return EXIT_ERROR; + } // Call additional adb command if set after installation and before starting the test for (const auto &command : g_options.preTestRunAdbCommands) { QByteArray output; diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 14280712154..64fd334d467 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -259,6 +259,7 @@ bool Moc::parseEnum(EnumDef *def, ClassDef *containingClass) return false; // anonymous enum isTypdefEnum = true; } + def->lineNumber = symbol().lineNum; if (test(COLON)) { // C++11 strongly typed enum // enum Foo : unsigned long { ... }; def->type = normalizeType(parseType().name); @@ -464,6 +465,8 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro) } next(LPAREN, "Not a signal or slot declaration"); def->name = tempType.name; + def->lineNumber = symbol().lineNum; + scopedFunctionName = tempType.isScoped; if (!test(RPAREN)) { @@ -1366,6 +1369,7 @@ void Moc::createPropertyDef(PropertyDef &propDef, int propertyIndex, Moc::Proper { propDef.location = index; propDef.relativeIndex = propertyIndex; + propDef.lineNumber = symbol().lineNum; Type t = parseType(); QByteArray type = t.name; @@ -2156,6 +2160,7 @@ QJsonObject FunctionDef::toJson(int index) const if (revision > 0) fdef["revision"_L1] = revision; + fdef["lineNumber"_L1] = lineNumber; if (wasCloned) fdef["isCloned"_L1] = true; @@ -2220,6 +2225,7 @@ QJsonObject PropertyDef::toJson() const prop["final"_L1] = final; prop["required"_L1] = required; prop["index"_L1] = relativeIndex; + prop["lineNumber"_L1] = lineNumber; if (revision > 0) prop["revision"_L1] = revision; @@ -2231,6 +2237,7 @@ QJsonObject EnumDef::toJson(const ClassDef &cdef) const QJsonObject def; uint flags = this->flags | cdef.enumDeclarations.value(name); def["name"_L1] = QString::fromUtf8(name); + def["lineNumber"_L1] = lineNumber; if (!enumName.isEmpty()) def["alias"_L1] = QString::fromUtf8(enumName); if (!type.isEmpty()) diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index f08edb3f0d2..fcf000c655f 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -58,6 +58,7 @@ struct EnumDef QFlags<QtMocConstants::EnumFlags> flags = {}; QJsonObject toJson(const ClassDef &cdef) const; QByteArray qualifiedType(const ClassDef *cdef) const; + int lineNumber = 0; }; Q_DECLARE_TYPEINFO(EnumDef, Q_RELOCATABLE_TYPE); @@ -84,6 +85,7 @@ struct FunctionDef enum Access { Private, Protected, Public }; Access access = Private; int revision = 0; + int lineNumber = 0; bool isConst = false; bool isVirtual = false; @@ -130,6 +132,7 @@ struct PropertyDef bool final = false; bool required = false; int relativeIndex = -1; // property index in current metaobject + int lineNumber = 0; qsizetype location = -1; // token index, used for error reporting diff --git a/src/tools/uic/ui4.cpp b/src/tools/uic/ui4.cpp index b6a8f4eb4bf..e26d0260682 100644 --- a/src/tools/uic/ui4.cpp +++ b/src/tools/uic/ui4.cpp @@ -54,6 +54,10 @@ void DomUI::read(QXmlStreamReader &reader) setAttributeIdbasedtr(attribute.value() == u"true"_s); continue; } + if (name == u"label"_s) { + setAttributeLabel(attribute.value().toString()); + continue; + } if (name == u"connectslotsbyname"_s) { setAttributeConnectslotsbyname(attribute.value() == u"true"_s); continue; @@ -192,6 +196,9 @@ void DomUI::write(QXmlStreamWriter &writer, const QString &tagName) const if (hasAttributeIdbasedtr()) writer.writeAttribute(u"idbasedtr"_s, (attributeIdbasedtr() ? u"true"_s : u"false"_s)); + if (hasAttributeLabel()) + writer.writeAttribute(u"label"_s, attributeLabel()); + if (hasAttributeConnectslotsbyname()) writer.writeAttribute(u"connectslotsbyname"_s, (attributeConnectslotsbyname() ? u"true"_s : u"false"_s)); diff --git a/src/tools/uic/ui4.h b/src/tools/uic/ui4.h index 333f7f4e6ad..a46a42c6b73 100644 --- a/src/tools/uic/ui4.h +++ b/src/tools/uic/ui4.h @@ -143,6 +143,11 @@ public: inline void setAttributeIdbasedtr(bool a) { m_attr_idbasedtr = a; m_has_attr_idbasedtr = true; } inline void clearAttributeIdbasedtr() { m_has_attr_idbasedtr = false; } + inline bool hasAttributeLabel() const { return m_has_attr_label; } + inline QString attributeLabel() const { return m_attr_label; } + inline void setAttributeLabel(const QString &a) { m_attr_label = a; m_has_attr_label = true; } + inline void clearAttributeLabel() { m_attr_label.clear(); } + inline bool hasAttributeConnectslotsbyname() const { return m_has_attr_connectslotsbyname; } inline bool attributeConnectslotsbyname() const { return m_attr_connectslotsbyname; } inline void setAttributeConnectslotsbyname(bool a) { m_attr_connectslotsbyname = a; m_has_attr_connectslotsbyname = true; } @@ -264,6 +269,9 @@ private: bool m_attr_idbasedtr = false; bool m_has_attr_idbasedtr = false; + QString m_attr_label; + bool m_has_attr_label = false; + bool m_attr_connectslotsbyname = false; bool m_has_attr_connectslotsbyname = false; |