Ref T103, verify important files/directories

* utility function in CDirectoryUtils
* deployed in main/application
This commit is contained in:
Klaus Basan
2017-07-07 19:31:15 +02:00
committed by Mathew Sutcliffe
parent d25be35868
commit 07b096b398
9 changed files with 68 additions and 16 deletions

View File

@@ -102,7 +102,7 @@ namespace BlackCore
Q_ASSERT_X(!sApp, Q_FUNC_INFO, "already initialized"); Q_ASSERT_X(!sApp, Q_FUNC_INFO, "already initialized");
Q_ASSERT_X(QCoreApplication::instance(), Q_FUNC_INFO, "no application object"); Q_ASSERT_X(QCoreApplication::instance(), Q_FUNC_INFO, "no application object");
// init skiped when called from CGuiApplication // init skipped when called from CGuiApplication
if (init) if (init)
{ {
this->init(true); this->init(true);
@@ -133,8 +133,6 @@ namespace BlackCore
// //
// Translations // Translations
const QFile file(":blackmisc/translations/blackmisc_i18n_de.qm");
CLogMessage(this).debug() << (file.exists() ? "Found translations in resources" : "No translations in resources");
QTranslator translator; QTranslator translator;
if (translator.load("blackmisc_i18n_de", ":blackmisc/translations/")) { CLogMessage(this).debug() << "Translator loaded"; } if (translator.load("blackmisc_i18n_de", ":blackmisc/translations/")) { CLogMessage(this).debug() << "Translator loaded"; }
QCoreApplication::instance()->installTranslator(&translator); QCoreApplication::instance()->installTranslator(&translator);
@@ -315,7 +313,7 @@ namespace BlackCore
// parse if needed, parsing contains its own error handling // parse if needed, parsing contains its own error handling
if (!this->m_parsed) if (!this->m_parsed)
{ {
const bool s = this->parse(); const bool s = this->parseAndStartupCheck();
if (!s) { return false; } if (!s) { return false; }
} }
@@ -985,15 +983,24 @@ namespace BlackCore
return this->m_parser.value(option).trimmed(); return this->m_parser.value(option).trimmed();
} }
bool CApplication::parse() bool CApplication::parseAndStartupCheck()
{ {
if (this->m_parsed) { return m_parsed; } if (this->m_parsed) { return m_parsed; } // already done
// checks
if (CBuildConfig::isLifetimeExpired()) if (CBuildConfig::isLifetimeExpired())
{ {
this->cmdLineErrorMessage("Program exired " + CBuildConfig::getEol().toString()); this->cmdLineErrorMessage("Program exired " + CBuildConfig::getEol().toString());
return false; return false;
} }
const QStringList verifyErrors = CDirectoryUtils::verifyRuntimeDirectoriesAndFiles();
if (!verifyErrors.isEmpty())
{
this->cmdLineErrorMessage("Missing runtime directories/files: " + verifyErrors.join(", "));
return false;
}
if (this->m_singleApplication && this->m_alreadyRunning) if (this->m_singleApplication && this->m_alreadyRunning)
{ {
this->cmdLineErrorMessage("Program must only run once"); this->cmdLineErrorMessage("Program must only run once");
@@ -1036,7 +1043,7 @@ namespace BlackCore
bool CApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const bool CApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const
{ {
Q_UNUSED(retry); // onyl works with UI version Q_UNUSED(retry); // only works with UI version
fputs(qPrintable(errorMessage), stderr); fputs(qPrintable(errorMessage), stderr);
fputs("\n\n", stderr); fputs("\n\n", stderr);
fputs(qPrintable(this->m_parser.helpText()), stderr); fputs(qPrintable(this->m_parser.helpText()), stderr);
@@ -1045,7 +1052,7 @@ namespace BlackCore
bool CApplication::cmdLineErrorMessage(const CStatusMessageList &msgs, bool retry) const bool CApplication::cmdLineErrorMessage(const CStatusMessageList &msgs, bool retry) const
{ {
Q_UNUSED(retry); // onyl works with UI version Q_UNUSED(retry); // only works with UI version
if (msgs.isEmpty()) { return false; } if (msgs.isEmpty()) { return false; }
if (!msgs.hasErrorMessages()) { return false; } if (!msgs.hasErrorMessages()) { return false; }
CApplication::cmdLineErrorMessage( CApplication::cmdLineErrorMessage(

View File

@@ -290,7 +290,7 @@ namespace BlackCore
//! \note in some cases (error, version, help) application is terminated during this step //! \note in some cases (error, version, help) application is terminated during this step
//! \sa parsingHookIn //! \sa parsingHookIn
//! \return true means to continue, false to stop //! \return true means to continue, false to stop
bool parse(); bool parseAndStartupCheck();
//! @} //! @}
//! Display error message //! Display error message

View File

@@ -263,9 +263,23 @@ namespace BlackGui
bool CGuiApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const bool CGuiApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const
{ {
const QString helpText(beautifyHelpMessage(this->m_parser.helpText())); const QString helpText(beautifyHelpMessage(this->m_parser.helpText()));
constexpr int MaxLength = 60;
QString htmlMsg;
if (errorMessage.length() > MaxLength)
{
htmlMsg = "<html><head/><body><h4>" + errorMessage.left(MaxLength) + "..." + "</h4>" +
"Details: " + errorMessage + "<br><br>";
}
else
{
htmlMsg = "<html><head/><body><h4>" + errorMessage + "</h4>";
}
htmlMsg += helpText + "</body></html>";
const int r = QMessageBox::warning(nullptr, const int r = QMessageBox::warning(nullptr,
QGuiApplication::applicationDisplayName(), QGuiApplication::applicationDisplayName(),
"<html><head/><body><h2>" + errorMessage + "</h2><br>" + helpText + "</body></html>", QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton); htmlMsg, QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton);
return (r == QMessageBox::Retry); return (r == QMessageBox::Retry);
} }
@@ -279,7 +293,7 @@ namespace BlackGui
const QString msgsHtml = msgs.toHtml(msgs.size() > 1 ? propertiesMulti : propertiesSingle); const QString msgsHtml = msgs.toHtml(msgs.size() > 1 ? propertiesMulti : propertiesSingle);
const int r = QMessageBox::critical(nullptr, const int r = QMessageBox::critical(nullptr,
QGuiApplication::applicationDisplayName(), QGuiApplication::applicationDisplayName(),
"<html><head/><body>" + msgsHtml + "<br><br>" + helpText + "</body></html>", QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton); "<html><head><body>" + msgsHtml + "<br><br>" + helpText + "</body></html>", QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton);
return (r == QMessageBox::Retry); return (r == QMessageBox::Retry);
} }

View File

@@ -327,6 +327,34 @@ namespace BlackMisc
return dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks); return dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
} }
QStringList CDirectoryUtils::verifyRuntimeDirectoriesAndFiles()
{
QStringList failed;
QDir d(CDirectoryUtils::binDirectory());
if (!d.isReadable()) { failed.append(d.absolutePath()); }
d = QDir(CDirectoryUtils::imagesDirectory());
if (!d.isReadable()) { failed.append(d.absolutePath()); }
d = QDir(CDirectoryUtils::stylesheetsDirectory());
if (!d.isReadable()) { failed.append(d.absolutePath()); }
d = QDir(CDirectoryUtils::applicationDataDirectory());
if (!d.isReadable()) { failed.append(d.absolutePath()); }
// check if the executables are avialable
QString fn = CDirectoryUtils::executableFilePath(CBuildConfig::swiftCoreExecutableName());
if (!QFile::exists(fn)) { failed.append(fn); }
fn = CDirectoryUtils::executableFilePath(CBuildConfig::swiftDataExecutableName());
if (!QFile::exists(fn)) { failed.append(fn); }
fn = CDirectoryUtils::executableFilePath(CBuildConfig::swiftGuiExecutableName());
if (!QFile::exists(fn)) { failed.append(fn); }
return failed;
}
QSet<QString> CDirectoryUtils::fileNamesToQSet(const QFileInfoList &fileInfoList) QSet<QString> CDirectoryUtils::fileNamesToQSet(const QFileInfoList &fileInfoList)
{ {
QSet<QString> sl; QSet<QString> sl;

View File

@@ -100,7 +100,7 @@ namespace BlackMisc
//! \remark In BlackMisc so it can also be used from BlackMisc classes //! \remark In BlackMisc so it can also be used from BlackMisc classes
static const QString &logDirectory(); static const QString &logDirectory();
//! Directory for log files //! Directory for crashpad files
static const QString &crashpadDirectory(); static const QString &crashpadDirectory();
//! Virtually the inverse operation of CDirectoryUtils::normalizedApplicationDirectory //! Virtually the inverse operation of CDirectoryUtils::normalizedApplicationDirectory
@@ -109,6 +109,9 @@ namespace BlackMisc
//! All sub directories of given dir //! All sub directories of given dir
static QStringList getSubDirectories(const QString &rootDir); static QStringList getSubDirectories(const QString &rootDir);
//! Check if the (most important) runtime directories are available
static QStringList verifyRuntimeDirectoriesAndFiles();
//! Result of directory comparison //! Result of directory comparison
struct DirComparison struct DirComparison
{ {

View File

@@ -35,7 +35,7 @@ int main(int argc, char *argv[])
a.addVatlibOptions(); a.addVatlibOptions();
a.addParserOption({{"r", "start"}, QCoreApplication::translate("main", "Start the server.")}); a.addParserOption({{"r", "start"}, QCoreApplication::translate("main", "Start the server.")});
a.addParserOption({{"c", "coreaudio"}, QCoreApplication::translate("main", "Audio in core.")}); a.addParserOption({{"c", "coreaudio"}, QCoreApplication::translate("main", "Audio in core.")});
if (!a.parse()) { return EXIT_FAILURE; } if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; }
const QString dBusAdress(a.getCmdDBusAddressValue()); const QString dBusAdress(a.getCmdDBusAddressValue());
a.useContexts(a.isParserOptionSet("coreaudio") ? a.useContexts(a.isParserOptionSet("coreaudio") ?

View File

@@ -30,7 +30,7 @@ int main(int argc, char *argv[])
CGuiApplication a(CApplicationInfo::swiftMappingTool(), CApplicationInfo::MappingTool, CIcons::swiftDatabase48()); CGuiApplication a(CApplicationInfo::swiftMappingTool(), CApplicationInfo::MappingTool, CIcons::swiftDatabase48());
a.setSignalStartupAutomatically(false); // application will signal startup on its own a.setSignalStartupAutomatically(false); // application will signal startup on its own
a.splashScreen(CIcons::swiftDatabase256()); a.splashScreen(CIcons::swiftDatabase256());
if (!a.parse()) { return EXIT_FAILURE; } if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; }
a.useWebDataServices(BlackCore::CWebReaderFlags::AllSwiftDbReaders, CDatabaseReaderConfigList::forMappingTool()); a.useWebDataServices(BlackCore::CWebReaderFlags::AllSwiftDbReaders, CDatabaseReaderConfigList::forMappingTool());
if (!a.start()) if (!a.start())
{ {

View File

@@ -29,7 +29,7 @@ int main(int argc, char *argv[])
CSwiftGuiStdApplication a; CSwiftGuiStdApplication a;
a.setSignalStartupAutomatically(false); // application will signal startup on its own a.setSignalStartupAutomatically(false); // application will signal startup on its own
a.splashScreen(CIcons::swift256()); a.splashScreen(CIcons::swift256());
if (!a.parse()) { return EXIT_FAILURE; } if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; }
if (!a.hasSetupReader() || !a.start()) if (!a.hasSetupReader() || !a.start())
{ {
a.gracefulShutdown(); a.gracefulShutdown();

View File

@@ -35,7 +35,7 @@ int main(int argc, char *argv[])
Q_UNUSED(qa); Q_UNUSED(qa);
CGuiApplication a(CApplicationInfo::swiftLauncher(), CApplicationInfo::Laucher, CIcons::swiftLauncher1024()); CGuiApplication a(CApplicationInfo::swiftLauncher(), CApplicationInfo::Laucher, CIcons::swiftLauncher1024());
a.addParserOption({{"i", "installer"}, QCoreApplication::translate("main", "Installer setup.") }); a.addParserOption({{"i", "installer"}, QCoreApplication::translate("main", "Installer setup.") });
if (!a.parse()) { return EXIT_FAILURE; } if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; }
a.useWebDataServices(BlackCore::CWebReaderFlags::AllSwiftDbReaders, CDatabaseReaderConfigList::forLauncher()); a.useWebDataServices(BlackCore::CWebReaderFlags::AllSwiftDbReaders, CDatabaseReaderConfigList::forLauncher());
if (!a.start()) if (!a.start())
{ {