File indexing completed on 2024-05-19 05:16:11
0001 /* 0002 * SPDX-FileCopyrightText: 2013 Christian Mollekopf <mollekopf@kolabsys.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 * 0006 */ 0007 0008 #include "migratorbase.h" 0009 #include "migration_debug.h" 0010 #include <Akonadi/ServerManager> 0011 #include <KLocalizedString> 0012 #include <QCoreApplication> 0013 #include <QDateTime> 0014 #include <QDir> 0015 #include <QFileInfo> 0016 #include <QStandardPaths> 0017 0018 static QString messageTypeToString(MigratorBase::MessageType type) 0019 { 0020 switch (type) { 0021 case MigratorBase::Success: 0022 return QStringLiteral("Success"); 0023 case MigratorBase::Skip: 0024 return QStringLiteral("Skipped"); 0025 case MigratorBase::Info: 0026 return QStringLiteral("Info "); 0027 case MigratorBase::Warning: 0028 return QStringLiteral("WARNING"); 0029 case MigratorBase::Error: 0030 return QStringLiteral("ERROR "); 0031 } 0032 Q_ASSERT(false); 0033 return {}; 0034 } 0035 0036 static QMap<QString, MigratorBase::MigrationState> fillMigrationStateMapping() 0037 { 0038 QMap<QString, MigratorBase::MigrationState> map; 0039 map.insert(QStringLiteral("Complete"), MigratorBase::Complete); 0040 map.insert(QStringLiteral("Aborted"), MigratorBase::Aborted); 0041 map.insert(QStringLiteral("InProgress"), MigratorBase::InProgress); 0042 map.insert(QStringLiteral("Failed"), MigratorBase::Failed); 0043 return map; 0044 } 0045 0046 static QMap<QString, MigratorBase::MigrationState> migrationStateMapping = fillMigrationStateMapping(); 0047 0048 static QString stateToIdentifier(MigratorBase::MigrationState state) 0049 { 0050 Q_ASSERT(migrationStateMapping.values().contains(state)); 0051 return migrationStateMapping.key(state); 0052 } 0053 0054 static MigratorBase::MigrationState identifierToState(const QString &identifier) 0055 { 0056 Q_ASSERT(migrationStateMapping.contains(identifier)); 0057 return migrationStateMapping.value(identifier); 0058 } 0059 0060 MigratorBase::MigratorBase(const QString &identifier, QObject *parent) 0061 : QObject(parent) 0062 , mIdentifier(identifier) 0063 , mConfig(new KConfig(Akonadi::ServerManager::addNamespace(QStringLiteral("akonadi-migrationrc")))) 0064 { 0065 const QString logFileName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + QCoreApplication::applicationName() 0066 + QLatin1Char('/') + identifier + QStringLiteral("migration.log"); 0067 QFileInfo fileInfo(logFileName); 0068 QDir().mkpath(fileInfo.absolutePath()); 0069 setLogfile(logFileName); 0070 connect(this, &MigratorBase::message, this, &MigratorBase::logMessage); 0071 loadState(); 0072 } 0073 0074 MigratorBase::MigratorBase(const QString &identifier, const QString &configFile, const QString &logFile, QObject *parent) 0075 : QObject(parent) 0076 , mIdentifier(identifier) 0077 , mMigrationState(None) 0078 { 0079 if (!configFile.isEmpty()) { 0080 mConfig.reset(new KConfig(configFile)); 0081 } 0082 setLogfile(logFile); 0083 connect(this, &MigratorBase::message, this, &MigratorBase::logMessage); 0084 loadState(); 0085 } 0086 0087 MigratorBase::~MigratorBase() = default; 0088 0089 void MigratorBase::setLogfile(const QString &logfile) 0090 { 0091 if (!logfile.isEmpty()) { 0092 mLogFile.reset(new QFile(logfile)); 0093 if (!mLogFile->open(QFile::Append)) { 0094 mLogFile.reset(); 0095 qCWarning(MIGRATION_LOG) << "Unable to open log file: " << logfile; 0096 } 0097 } else { 0098 mLogFile.reset(); 0099 } 0100 } 0101 0102 QString MigratorBase::identifier() const 0103 { 0104 return mIdentifier; 0105 } 0106 0107 QString MigratorBase::displayName() const 0108 { 0109 return {}; 0110 } 0111 0112 QString MigratorBase::description() const 0113 { 0114 return {}; 0115 } 0116 0117 QString MigratorBase::logfile() const 0118 { 0119 if (mLogFile) { 0120 return mLogFile->fileName(); 0121 } 0122 return {}; 0123 } 0124 0125 bool MigratorBase::canStart() 0126 { 0127 if (mIdentifier.isEmpty()) { 0128 Q_EMIT message(Error, i18n("Missing Identifier")); 0129 return false; 0130 } 0131 return true; 0132 } 0133 0134 void MigratorBase::start() 0135 { 0136 if (mMigrationState == InProgress) { 0137 qCWarning(MIGRATION_LOG) << "already running"; 0138 return; 0139 } 0140 if (!canStart()) { 0141 Q_EMIT message(Error, i18n("Failed to start migration because migrator is not ready")); 0142 Q_EMIT stoppedProcessing(); 0143 return; 0144 } 0145 // TODO acquire dbus lock 0146 logMessage(Info, displayName()); 0147 Q_EMIT message(Info, i18n("Starting migration...")); 0148 setMigrationState(InProgress); 0149 setProgress(0); 0150 startWork(); 0151 } 0152 0153 void MigratorBase::pause() 0154 { 0155 qCWarning(MIGRATION_LOG) << "pause is not implemented"; 0156 } 0157 0158 void MigratorBase::resume() 0159 { 0160 qCWarning(MIGRATION_LOG) << "resume is not implemented"; 0161 } 0162 0163 void MigratorBase::abort() 0164 { 0165 qCWarning(MIGRATION_LOG) << "abort is not implemented"; 0166 } 0167 0168 void MigratorBase::logMessage(MigratorBase::MessageType type, const QString &msg) 0169 { 0170 if (mLogFile) { 0171 mLogFile->write(QString(QLatin1Char('[') + QDateTime::currentDateTime().toString() + QStringLiteral("] ") + messageTypeToString(type) 0172 + QStringLiteral(": ") + msg + QLatin1Char('\n')) 0173 .toUtf8()); 0174 mLogFile->flush(); 0175 } 0176 } 0177 0178 bool MigratorBase::shouldAutostart() const 0179 { 0180 return false; 0181 } 0182 0183 void MigratorBase::setMigrationState(MigratorBase::MigrationState state) 0184 { 0185 mMigrationState = state; 0186 switch (state) { 0187 case Complete: 0188 setProgress(100); 0189 Q_EMIT message(Success, i18n("Migration complete")); 0190 Q_EMIT stoppedProcessing(); 0191 break; 0192 case Aborted: 0193 Q_EMIT message(Skip, i18n("Migration aborted")); 0194 Q_EMIT stoppedProcessing(); 0195 break; 0196 case InProgress: 0197 break; 0198 case Failed: 0199 Q_EMIT message(Error, i18n("Migration failed")); 0200 Q_EMIT stoppedProcessing(); 0201 break; 0202 case Paused: 0203 Q_EMIT message(Info, i18n("Migration paused")); 0204 Q_EMIT stateChanged(mMigrationState); 0205 return; 0206 default: 0207 qCWarning(MIGRATION_LOG) << "invalid state " << state; 0208 Q_ASSERT(false); 0209 return; 0210 } 0211 saveState(); 0212 Q_EMIT stateChanged(mMigrationState); 0213 } 0214 0215 MigratorBase::MigrationState MigratorBase::migrationState() const 0216 { 0217 return mMigrationState; 0218 } 0219 0220 void MigratorBase::saveState() 0221 { 0222 config().writeEntry(QStringLiteral("MigrationState"), stateToIdentifier(mMigrationState)); 0223 } 0224 0225 void MigratorBase::loadState() 0226 { 0227 const QString state = config().readEntry(QStringLiteral("MigrationState"), QString()); 0228 if (!state.isEmpty()) { 0229 mMigrationState = identifierToState(state); 0230 } 0231 0232 if (mMigrationState == InProgress) { 0233 Q_EMIT message(Warning, i18n("This migration has already been started once but was aborted")); 0234 mMigrationState = NeedsUpdate; 0235 } 0236 switch (mMigrationState) { 0237 case Complete: 0238 mProgress = 100; 0239 break; 0240 default: 0241 mProgress = 0; 0242 } 0243 } 0244 0245 NullableConfigGroup MigratorBase::config() 0246 { 0247 if (mConfig) { 0248 return NullableConfigGroup(mConfig->group(mIdentifier)); 0249 } 0250 return {}; 0251 } 0252 0253 int MigratorBase::progress() const 0254 { 0255 return mProgress; 0256 } 0257 0258 void MigratorBase::setProgress(int prog) 0259 { 0260 if (mProgress != prog) { 0261 mProgress = prog; 0262 Q_EMIT progress(prog); 0263 } 0264 } 0265 0266 QString MigratorBase::status() const 0267 { 0268 switch (mMigrationState) { 0269 case None: 0270 return i18nc("@info:status", "Not started"); 0271 case InProgress: 0272 return i18nc("@info:status", "Running..."); 0273 case Complete: 0274 return i18nc("@info:status", "Complete"); 0275 case Aborted: 0276 return i18nc("@info:status", "Aborted"); 0277 case Paused: 0278 return i18nc("@info:status", "Paused"); 0279 case NeedsUpdate: 0280 return i18nc("@info:status", "Needs Update"); 0281 case Failed: 0282 return i18nc("@info:status", "Failed"); 0283 } 0284 return {}; 0285 } 0286 0287 #include "moc_migratorbase.cpp"