File indexing completed on 2025-01-05 04:46:51
0001 /* 0002 SPDX-FileCopyrightText: 2024 g10 Code GmbH 0003 SPDX-FileContributor: Daniel Vrátil <dvratil@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "akonadifull-version.h" 0009 #include "dbmigrator.h" 0010 0011 #include <KAboutData> 0012 #include <KAboutLicense> 0013 #include <KLocalizedString> 0014 0015 #include <QCommandLineOption> 0016 #include <QCommandLineParser> 0017 #include <QCoreApplication> 0018 0019 #include <iostream> 0020 0021 using namespace Akonadi::Server; 0022 0023 class CLIDelegate : public UIDelegate 0024 { 0025 public: 0026 Result questionYesNo(const QString &question) override 0027 { 0028 std::cout << qUtf8Printable(question) 0029 << qUtf8Printable(i18nc("Options for user to input to command line prompt, parenthesis indicate " 0030 "which letter to type, capitalized option is default", 0031 " [(y)es/(N)o] ")); 0032 std::cout.flush(); 0033 std::string answer; 0034 std::getline(std::cin, answer); 0035 0036 const auto yes = i18nc("Letter for option \"(y)es\" prompted from command line", "y"); 0037 0038 if (answer.size() > 0 && std::tolower(answer[0]) == yes[0].toLatin1()) { 0039 return Result::Yes; 0040 } 0041 return Result::No; 0042 } 0043 0044 Result questionYesNoSkip(const QString &question) override 0045 { 0046 std::cout << qUtf8Printable(question) 0047 << qUtf8Printable(i18nc("Options for user to input to command line prompt, parenthesis indicate " 0048 "which letter to type, capitalized option is default", 0049 " [(y)es/(N)o/(s)kip] ")); 0050 0051 std::cout.flush(); 0052 std::string answer; 0053 std::getline(std::cin, answer); 0054 0055 const auto yes = i18nc("Letter for option \"(y)es\" prompted from command line", "y"); 0056 const auto skip = i18nc("Letter for option \"(s)kip\" prompted from command line", "s"); 0057 0058 if (answer.size() > 0 && std::tolower(answer[0]) == yes[0].toLatin1()) { 0059 return Result::Yes; 0060 } 0061 if (answer.size() > 0 && std::tolower(answer[0]) == skip[0].toLatin1()) { 0062 return Result::Skip; 0063 } 0064 return Result::No; 0065 } 0066 }; 0067 0068 int main(int argc, char **argv) 0069 { 0070 Q_INIT_RESOURCE(akonadidb); 0071 0072 QCoreApplication app(argc, argv); 0073 KLocalizedString::setApplicationDomain("akonadi-db-migrator"); 0074 KAboutData about(QStringLiteral("akonadi-db-migrator"), 0075 i18n("Akonadi DB Migrator"), 0076 QStringLiteral(AKONADI_FULL_VERSION), 0077 i18n("Akonadi DB Migrator"), 0078 KAboutLicense::LGPL, 0079 i18n("(c) 2024 g10 Code GmbH")); 0080 KAboutData::setApplicationData(about); 0081 0082 QCommandLineParser parser; 0083 about.setupCommandLine(&parser); 0084 const QCommandLineOption engineOpt{QStringLiteral("newengine"), 0085 i18n("The new DB engine to use. Possible values are \"sqlite\", \"mysql\" and \"postgres\""), 0086 QStringLiteral("ENGINE")}; 0087 parser.addOption(engineOpt); 0088 parser.process(app); 0089 0090 const auto targetEngine = parser.value(engineOpt).toLower(); 0091 if (targetEngine != QLatin1StringView("sqlite") && targetEngine != QLatin1StringView("mysql") && targetEngine != QLatin1StringView("postgres")) { 0092 std::cerr << qUtf8Printable(i18nc("@info:shell", "Invalid target engine: %1.", targetEngine)) << std::endl; 0093 return 1; 0094 } 0095 0096 CLIDelegate delegate; 0097 DbMigrator migrator(targetEngine, &delegate); 0098 QObject::connect(&migrator, &DbMigrator::info, &app, [](const QString &message) { 0099 std::cout << qUtf8Printable(message) << std::endl; 0100 }); 0101 QObject::connect(&migrator, &DbMigrator::error, &app, [](const QString &message) { 0102 std::cerr << qUtf8Printable(message) << std::endl; 0103 }); 0104 QObject::connect(&migrator, &DbMigrator::migrationCompleted, &app, [](bool success) { 0105 if (success) { 0106 std::cout << qUtf8Printable(i18nc("@info:status", "Migration completed successfully.")) << std::endl; 0107 } else { 0108 std::cout << qUtf8Printable(i18nc("@info:status", "Migration failed.")) << std::endl; 0109 } 0110 qApp->quit(); 0111 }); 0112 QObject::connect(&migrator, &DbMigrator::progress, &app, [](const QString &table, int tablesDone, int tablesTotal) { 0113 std::cout << qUtf8Printable(i18nc("@info:progress", "Migrating table %1 (%2/%3)...", table, tablesDone, tablesTotal)) << std::endl; 0114 }); 0115 QString lastTable; 0116 int lastPerc = -1; 0117 QObject::connect(&migrator, &DbMigrator::tableProgress, &app, [&lastTable, &lastPerc](const QString &table, int rowsDone, int rowsTotal) { 0118 const int perc = rowsDone * 100 / rowsTotal; 0119 if (lastTable != table) { 0120 lastPerc = -1; 0121 } 0122 if (perc % 10 != 0 || perc == lastPerc) { 0123 return; 0124 } 0125 lastPerc = perc; 0126 lastTable = table; 0127 std::cout << qUtf8Printable(i18nc("@info:progress", "%1%...", perc)) << std::endl; 0128 }); 0129 0130 QMetaObject::invokeMethod(&migrator, &DbMigrator::startMigration, Qt::QueuedConnection); 0131 0132 return app.exec(); 0133 }