|
MythTV
0.26-pre
|
00001 #include <iostream> 00002 #include <unistd.h> // for isatty() on Windows 00003 00004 #include "dialogbox.h" 00005 #include "mythcorecontext.h" 00006 #include "schemawizard.h" 00007 #include "mythmiscutil.h" 00008 00009 #include "mythtimer.h" 00010 #include "mythlogging.h" 00011 #include "mythmainwindow.h" 00012 #include "mythuihelper.h" 00013 #include "mythdb.h" 00014 00015 00016 static SchemaUpgradeWizard * c_wizard = 0; 00017 00018 00019 SchemaUpgradeWizard::SchemaUpgradeWizard(const QString &DBSchemaSetting, 00020 const QString &appName, 00021 const QString &upgradeSchemaVal) 00022 : DBver(), emptyDB(false), versionsBehind(-1), 00023 backupStatus(kDB_Backup_Unknown), 00024 m_autoUpgrade(false), 00025 m_backupResult(), 00026 m_busyPopup(NULL), 00027 m_expertMode(false), 00028 m_schemaSetting(DBSchemaSetting), 00029 m_schemaName(appName), 00030 m_newSchemaVer(upgradeSchemaVal) 00031 { 00032 c_wizard = this; 00033 00034 // Users and developers can choose to live dangerously, 00035 // either to silently and automatically upgrade, 00036 // or an expert option to allow use of existing: 00037 switch (gCoreContext->GetNumSetting("DBSchemaAutoUpgrade")) 00038 { 00039 case 1: m_autoUpgrade = true; break; 00040 #if ENABLE_SCHEMA_DEVELOPER_MODE 00041 case -1: m_expertMode = true; break; 00042 #endif 00043 default: break; 00044 } 00045 } 00046 00047 SchemaUpgradeWizard::~SchemaUpgradeWizard() 00048 { 00049 c_wizard = 0; 00050 } 00051 00052 SchemaUpgradeWizard * 00053 SchemaUpgradeWizard::Get(const QString &DBSchemaSetting, 00054 const QString &appName, 00055 const QString &upgradeSchemaVal) 00056 { 00057 if (c_wizard == 0) 00058 c_wizard = new SchemaUpgradeWizard(DBSchemaSetting, appName, 00059 upgradeSchemaVal); 00060 else 00061 { 00062 c_wizard->DBver = QString(); 00063 c_wizard->versionsBehind = -1; 00064 c_wizard->m_schemaSetting = DBSchemaSetting; 00065 c_wizard->m_schemaName = appName; 00066 c_wizard->m_newSchemaVer = upgradeSchemaVal; 00067 } 00068 00069 return c_wizard; 00070 } 00071 00077 void SchemaUpgradeWizard::BusyPopup(const QString &message) 00078 { 00079 if (m_busyPopup) 00080 m_busyPopup->Close(); 00081 00082 m_busyPopup = ShowBusyPopup(message); 00083 } 00084 00085 MythDBBackupStatus SchemaUpgradeWizard::BackupDB(void) 00086 { 00087 if (emptyDB) 00088 { 00089 LOG(VB_GENERAL, LOG_INFO, 00090 "The database seems to be empty - not attempting a backup"); 00091 return kDB_Backup_Empty_DB; 00092 } 00093 00094 backupStatus = DBUtil::BackupDB(m_backupResult, true); 00095 00096 return backupStatus; 00097 } 00098 00099 int SchemaUpgradeWizard::Compare(void) 00100 { 00101 DBver = gCoreContext->GetSetting(m_schemaSetting); 00102 00103 // No current schema? Investigate further: 00104 if (DBver.isEmpty() || DBver == "0") 00105 { 00106 LOG(VB_GENERAL, LOG_INFO, "No current database version?"); 00107 00108 if (DBUtil::IsNewDatabase()) 00109 { 00110 LOG(VB_GENERAL, LOG_INFO, "Database appears to be empty/new!"); 00111 emptyDB = true; 00112 } 00113 } 00114 else 00115 LOG(VB_GENERAL, LOG_INFO, 00116 QString("Current %1 Schema Version (%2): %3") 00117 .arg(m_schemaName).arg(m_schemaSetting).arg(DBver)); 00118 00119 #if TESTING 00120 //DBver = "9" + DBver + "-testing"; 00121 DBver += "-testing"; 00122 return 0; 00123 #endif 00124 00125 if (m_newSchemaVer == DBver) 00126 { 00127 versionsBehind = 0; 00128 } 00129 else 00130 { 00131 // Branch DB versions may not be integer version numbers. 00132 bool new_ok, old_ok; 00133 int new_version = m_newSchemaVer.toInt(&new_ok); 00134 int old_version = DBver.toInt(&old_ok); 00135 if (new_ok && old_ok) 00136 versionsBehind = new_version - old_version; 00137 else 00138 versionsBehind = 5000; 00139 } 00140 return versionsBehind; 00141 } 00142 00143 MythSchemaUpgrade SchemaUpgradeWizard::GuiPrompt(const QString &message, 00144 bool upgradable, bool expert) 00145 { 00146 DialogBox * dlg; 00147 MythMainWindow * win = GetMythMainWindow(); 00148 00149 if (!win) 00150 return MYTH_SCHEMA_ERROR; 00151 00152 dlg = new DialogBox(win, message); 00153 dlg->AddButton(tr("Exit")); 00154 if (upgradable) 00155 dlg->AddButton(tr("Upgrade")); 00156 if (expert) 00157 // Not translated. This string can't appear in released builds. 00158 dlg->AddButton("Use current schema"); 00159 00160 DialogCode selected = dlg->exec(); 00161 dlg->deleteLater(); 00162 00163 switch (selected) 00164 { 00165 case kDialogCodeRejected: 00166 case kDialogCodeButton0: 00167 return MYTH_SCHEMA_EXIT; 00168 case kDialogCodeButton1: 00169 return upgradable ? MYTH_SCHEMA_UPGRADE: MYTH_SCHEMA_USE_EXISTING; 00170 case kDialogCodeButton2: 00171 return MYTH_SCHEMA_USE_EXISTING; 00172 default: 00173 return MYTH_SCHEMA_ERROR; 00174 } 00175 } 00176 00196 enum MythSchemaUpgrade 00197 SchemaUpgradeWizard::PromptForUpgrade(const char *name, 00198 const bool upgradeAllowed, 00199 const bool upgradeIfNoUI, 00200 const int minDBMSmajor, 00201 const int minDBMSminor, 00202 const int minDBMSpoint) 00203 { 00204 bool connections; // Are (other) FE/BEs connected? 00205 bool gui; // Was gContext Init'ed gui=true? 00206 bool upgradable; // Can/should we upgrade? 00207 bool validDBMS; // Do we measure up to minDBMS* ? 00208 QString warnOldDBMS; 00209 QString warnOtherCl; 00210 00211 00212 00213 if (versionsBehind == -1) 00214 Compare(); 00215 00216 #if minDBMS_is_only_for_schema_upgrades 00217 if (versionsBehind == 0) // Why was this method even called? 00218 return MYTH_SCHEMA_USE_EXISTING; 00219 #endif 00220 00221 // Only back up the database if we haven't already successfully made a 00222 // backup and the database is old/about to be upgraded (not if it's too 00223 // new) or if a user is doing something they probably shouldn't ("expert 00224 // mode") 00225 if (((backupStatus == kDB_Backup_Unknown) || 00226 (backupStatus == kDB_Backup_Failed)) && 00227 ((upgradeAllowed && (versionsBehind > 0)) || 00228 m_expertMode)) 00229 BackupDB(); 00230 00231 connections = CountClients() > 1; 00232 gui = GetMythUI()->IsScreenSetup() && GetMythMainWindow(); 00233 validDBMS = (minDBMSmajor == 0) // If the caller provided no version, 00234 ? true // the upgrade code can't be fussy! 00235 : CompareDBMSVersion(minDBMSmajor, 00236 minDBMSminor, minDBMSpoint) >= 0; 00237 upgradable = validDBMS && (versionsBehind > 0) 00238 && (upgradeAllowed || m_expertMode); 00239 00240 00241 // Build up strings used both in GUI and command shell contexts: 00242 if (connections) 00243 warnOtherCl = tr("There are also other clients using this" 00244 " database. They should be shut down first."); 00245 if (!validDBMS) 00246 warnOldDBMS = tr("Error: This version of Myth%1" 00247 " requires MySQL %2.%3.%4 or later." 00248 " You seem to be running MySQL version %5.") 00249 .arg(name).arg(minDBMSmajor).arg(minDBMSminor) 00250 .arg(minDBMSpoint).arg(GetDBMSVersion()); 00251 00252 00253 00254 // 00255 // 1. Deal with the trivial cases (No user prompting required) 00256 // 00257 if (validDBMS) 00258 { 00259 // Empty database? Always upgrade, to create tables 00260 if (emptyDB) 00261 return MYTH_SCHEMA_UPGRADE; 00262 00263 if (m_autoUpgrade && !connections && upgradable) 00264 return MYTH_SCHEMA_UPGRADE; 00265 } 00266 00267 if (!gui && (!isatty(fileno(stdin)) || !isatty(fileno(stdout)))) 00268 { 00269 LOG(VB_GENERAL, LOG_INFO, 00270 "Console is non-interactive, can't prompt user..."); 00271 00272 if (m_expertMode) 00273 { 00274 LOG(VB_GENERAL, LOG_CRIT, "Using existing schema."); 00275 return MYTH_SCHEMA_USE_EXISTING; 00276 } 00277 00278 if (!validDBMS) 00279 { 00280 LOG(VB_GENERAL, LOG_CRIT, warnOldDBMS); 00281 return MYTH_SCHEMA_EXIT; 00282 } 00283 00284 if (versionsBehind < 0) 00285 { 00286 LOG(VB_GENERAL, LOG_CRIT, 00287 QString("Error: MythTV database has newer %1 schema (%2) " 00288 "than expected (%3).") 00289 .arg(name).arg(DBver).arg(m_newSchemaVer)); 00290 return MYTH_SCHEMA_ERROR; 00291 } 00292 00293 if (upgradeIfNoUI && validDBMS) 00294 { 00295 LOG(VB_GENERAL, LOG_CRIT, "Upgrading."); 00296 return MYTH_SCHEMA_UPGRADE; 00297 } 00298 00299 return MYTH_SCHEMA_EXIT; 00300 } 00301 00302 00303 00304 // 00305 // 2. Build up a compound message to show the user, wait for a response 00306 // 00307 enum MythSchemaUpgrade returnValue = MYTH_SCHEMA_UPGRADE; 00308 QString message; 00309 00310 if (upgradable) 00311 { 00312 if (m_autoUpgrade && connections) 00313 { 00314 message = tr("Error: MythTV cannot upgrade the schema of this" 00315 " datatase because other clients are using it.\n\n" 00316 "Please shut them down before upgrading."); 00317 returnValue = MYTH_SCHEMA_ERROR; 00318 } 00319 else 00320 { 00321 message = tr("Warning: MythTV wants to upgrade your database,") 00322 + "\n" + tr("for the %1 schema, from %2 to %3."); 00323 if (m_expertMode) 00324 // Not translated. This string can't appear in released builds. 00325 message += "\n\nYou can try using the old schema," 00326 " but that may cause problems."; 00327 } 00328 } 00329 else if (!validDBMS) 00330 { 00331 message = warnOldDBMS; 00332 returnValue = MYTH_SCHEMA_ERROR; 00333 } 00334 else if (versionsBehind > 0) 00335 { 00336 message = tr("This version of MythTV requires an updated database. ") 00337 + tr("(schema is %1 versions behind)").arg(versionsBehind) 00338 + "\n\n" + tr("Please run mythtv-setup or mythbackend " 00339 "to update your database."); 00340 returnValue = MYTH_SCHEMA_ERROR; 00341 } 00342 else // This client is too old 00343 { 00344 if (m_expertMode) 00345 // Not translated. This string can't appear in released builds. 00346 message = "Warning: MythTV database has newer" 00347 " %1 schema (%2) than expected (%3)."; 00348 else 00349 { 00350 message = tr("Error: MythTV database has newer" 00351 " %1 schema (%2) than expected (%3)."); 00352 returnValue = MYTH_SCHEMA_ERROR; 00353 } 00354 } 00355 00356 if (backupStatus == kDB_Backup_Failed) 00357 message += "\n" + tr("MythTV was unable to backup your database."); 00358 00359 if (message.contains("%1")) 00360 message = message.arg(name).arg(DBver).arg(m_newSchemaVer); 00361 00362 00363 DatabaseParams dbParam = MythDB::getMythDB()->GetDatabaseParams(); 00364 message += "\n\n" + tr("Database Host: %1\nDatabase Name: %2") 00365 .arg(dbParam.dbHostName).arg(dbParam.dbName); 00366 00367 if (gui) 00368 { 00369 if (returnValue == MYTH_SCHEMA_ERROR) 00370 { 00371 // Display error, return warning to caller 00372 MythPopupBox::showOkPopup(GetMythMainWindow(), "", message); 00373 return MYTH_SCHEMA_ERROR; 00374 } 00375 00376 returnValue = GuiPrompt(message, upgradable, m_expertMode); 00377 if (returnValue == MYTH_SCHEMA_EXIT) 00378 return MYTH_SCHEMA_EXIT; 00379 00380 if (m_expertMode) 00381 return returnValue; 00382 00383 // The annoying extra confirmation: 00384 if (backupStatus == kDB_Backup_Completed) 00385 { 00386 int dirPos = m_backupResult.lastIndexOf('/'); 00387 QString dirName; 00388 QString fileName; 00389 if (dirPos > 0) 00390 { 00391 fileName = m_backupResult.mid(dirPos + 1); 00392 dirName = m_backupResult.left(dirPos); 00393 } 00394 message = tr("If your system becomes unstable, a database" 00395 " backup file called\n%1\nis located in %2") 00396 .arg(fileName).arg(dirName); 00397 } 00398 else 00399 message = tr("This cannot be un-done, so having a" 00400 " database backup would be a good idea."); 00401 if (connections) 00402 message += "\n\n" + warnOtherCl; 00403 00404 return GuiPrompt(message, upgradable, m_expertMode); 00405 } 00406 00407 // We are not in a GUI environment, so try to prompt the user in the shell 00408 QString resp; 00409 00410 cout << endl << message.toLocal8Bit().constData() << endl << endl; 00411 00412 if (returnValue == MYTH_SCHEMA_ERROR) 00413 return MYTH_SCHEMA_ERROR; 00414 00415 if (backupStatus == kDB_Backup_Failed) 00416 cout << "WARNING: MythTV was unable to backup your database." 00417 << endl << endl; 00418 else if ((backupStatus == kDB_Backup_Completed) && 00419 (m_backupResult != "")) 00420 cout << "If your system becomes unstable, " 00421 "a database backup is located in " 00422 << m_backupResult.toLocal8Bit().constData() << endl << endl; 00423 00424 if (m_expertMode) 00425 { 00426 resp = getResponse("Would you like to use the existing schema?", "yes"); 00427 if (resp.isEmpty() || resp.left(1).toLower() == "y") 00428 return MYTH_SCHEMA_USE_EXISTING; 00429 } 00430 00431 resp = getResponse("\nShall I upgrade this database?", "yes"); 00432 if (!resp.isEmpty() && resp.left(1).toLower() != "y") 00433 return MYTH_SCHEMA_EXIT; 00434 00435 if (connections) 00436 cout << endl << warnOtherCl.toLocal8Bit().constData() << endl; 00437 00438 if ((backupStatus != kDB_Backup_Completed) && 00439 (backupStatus != kDB_Backup_Empty_DB)) 00440 { 00441 resp = getResponse("\nA database backup might be a good idea" 00442 "\nAre you sure you want to upgrade?", "no"); 00443 if (resp.isEmpty() || resp.left(1).toLower() == "n") 00444 return MYTH_SCHEMA_EXIT; 00445 } 00446 00447 return MYTH_SCHEMA_UPGRADE; 00448 }
1.7.6.1