From cacd6372e10eeac0f966d9f4fb898497b8447e2b Mon Sep 17 00:00:00 2001 From: Matt Young Date: Sat, 5 Nov 2022 09:12:23 +0100 Subject: [PATCH] Slightly improved logging of system/build info --- CMakeLists.txt | 43 ++++++++++++++------------ src/AboutDialog.cpp | 3 +- src/Application.cpp | 9 +++--- src/MainWindow.cpp | 2 +- src/config.in | 27 ++++++++++++----- src/main.cpp | 30 ++++++++++-------- src/xml/BeerXml.cpp | 74 +++++++++++++++++++++++---------------------- src/xml/BeerXml.h | 3 +- ui/mainWindow.ui | 2 +- 9 files changed, 109 insertions(+), 84 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d85b0fc4..803cc2a9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,8 +149,13 @@ if(UNIX AND NOT APPLE) # - /usr/local on Linux (& Mac) # - c:/Program Files/${PROJECT_NAME} on Windows # - # On Debian and derived systems (such as Ubuntu), it's more normal for apps to go in /usr/bin than /usr/local/bin, so - # CMAKE_INSTALL_PREFIX can be overridden on the command line via "--prefix usr" + # On a lot of Linux distros, including Debian and derived systems (such as Ubuntu), it's more normal for pretty much + # all user-installed apps to go in /usr/bin rather than /usr/local/bin, so CMAKE_INSTALL_PREFIX can be overridden on + # the command line via "--prefix usr" + # + # (See http://lists.busybox.net/pipermail/busybox/2010-December/074114.html for a great, albeit slightly depressing, + # explanation of why there are so many places for binaries to live on Unix/Linux systems. FWIW, the current + # "standards" for Linux are at https://refspecs.linuxfoundation.org/fhs.shtml but these are open to interpretation.) # # .:TBD: We also allow -DEXEC_PREFIX=/usr (used in .github/workflows/linux-ubuntu.yml) but I'm not sure if this is # needed or could be replaced by "--prefix usr" @@ -664,7 +669,7 @@ if(WIN32) if(WIN32) execute_process(COMMAND uname OUTPUT_VARIABLE uname) message(STATUS "Uname is " ${uname}) - if (uname MATCHES "^MSYS" OR uname MATCHES "^MINGW") + if(uname MATCHES "^MSYS" OR uname MATCHES "^MINGW") message(STATUS "Running on MSYS/MinGW") set(MINGW true) endif() @@ -677,8 +682,8 @@ if(WIN32) FIND_PATH(MINGW_BIN_DIR "mingw32-make.exe") endif() if(NOT EXISTS ${MINGW_BIN_DIR}) - MESSAGE(FATAL_ERROR "MinGW bin dir not found. Run cmake again with the option -DMINGW_BIN_DIR=c:/path/to/mingw/bin") - ELSE() + message(FATAL_ERROR "MinGW bin dir not found. Run cmake again with the option -DMINGW_BIN_DIR=c:/path/to/mingw/bin") + else() get_filename_component(Mingw_Path ${CMAKE_CXX_COMPILER} PATH) endif() message(STATUS "MINGW_BIN_DIR " ${MINGW_BIN_DIR}) @@ -698,11 +703,11 @@ include(InstallRequiredSystemLibraries) # variables into the code. # # All variables written as "${VAR}" in config.in will be replaced by the value of VAR in config.h. -# Eg "#define CONFIGDATADIR ${CONFIGDATADIR}" in config.in will be replaced by the below corresponding value in -# ${CONFIGDATADIR} below when configure_file() is called. +# Eg "#define CONFIG_DATA_DIR ${CONFIG_DATA_DIR}" in config.in will be replaced by the below corresponding value in +# ${CONFIG_DATA_DIR} below when configure_file() is called. # -set(CONFIGDATADIR "${CMAKE_INSTALL_PREFIX}/${installSubDir_data}/") -set(CONFIGDOCDIR "${CMAKE_INSTALL_PREFIX}/${installSubDir_doc}/") +set(CONFIG_DATA_DIR "${CMAKE_INSTALL_PREFIX}/${installSubDir_data}/") +string(TIMESTAMP BUILD_TIMESTAMP "%Y-%m-%d %H:%M:%S (UTC)" UTC) configure_file(src/config.in src/config.h) #======================================================================================================================= @@ -889,20 +894,20 @@ add_library(btobjlib ${filesToCompile_qrc}) set_source_files_properties(${filesToInstall_macIcons} - PROPERTIES - MACOSX_PACKAGE_LOCATION "Resources") + PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources") set_source_files_properties(${filesToInstall_data} - PROPERTIES - MACOSX_PACKAGE_LOCATION "Resources") + PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources") set_source_files_properties(${filesToInstall_docs} - PROPERTIES - MACOSX_PACKAGE_LOCATION "Resources/en.lproj") + PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources/en.lproj") set_source_files_properties(${filesToInstall_sounds} - PROPERTIES - MACOSX_PACKAGE_LOCATION "Resources/sounds") + PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources/sounds") set_source_files_properties(${QM_FILES} - PROPERTIES - MACOSX_PACKAGE_LOCATION "Resources/translations_qm") + PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources/translations_qm") if(APPLE) add_executable(${fileName_executable} diff --git a/src/AboutDialog.cpp b/src/AboutDialog.cpp index c28d91ecd..16ce41bf4 100755 --- a/src/AboutDialog.cpp +++ b/src/AboutDialog.cpp @@ -107,13 +107,12 @@ AboutDialog::AboutDialog(QWidget * parent) : "

" "" ) - .arg(VERSIONSTRING) + .arg(CONFIG_VERSION_STRING) ); return; } - void AboutDialog::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { retranslateUi(); diff --git a/src/Application.cpp b/src/Application.cpp index fa0d072ec..76ab26127 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -207,7 +207,7 @@ namespace { QJsonObject jsonObject = jsonDocument.object(); QString remoteVersion = jsonObject.value("name").toString(); - qDebug() << Q_FUNC_INFO << "Latest release is" << remoteVersion << "; this release is" << VERSIONSTRING; + qDebug() << Q_FUNC_INFO << "Latest release is" << remoteVersion << "; this release is" << CONFIG_VERSION_STRING; // Version names are usually "v3.0.2" etc, so we want to strip the 'v' off the front if (remoteVersion.startsWith("v", Qt::CaseInsensitive)) { @@ -215,7 +215,7 @@ namespace { } // If the remote version is newer... - if (!remoteVersion.startsWith(VERSIONSTRING)) { + if (!remoteVersion.startsWith(CONFIG_VERSION_STRING)) { // ...and the user wants to download the new version... if( QMessageBox::information(&MainWindow::instance(), QObject::tr("New Version"), @@ -318,8 +318,8 @@ namespace { } else { qWarning() << Q_FUNC_INFO << "Cannot determine application binary location (got" << path << ") so using compile-time " - "constant for resource dir:" << CONFIGDATADIR; - path = QString(CONFIGDATADIR); + "constant for resource dir:" << CONFIG_DATA_DIR; + path = QString(CONFIG_DATA_DIR); } #elif defined(Q_OS_MAC) // === Mac === @@ -482,7 +482,6 @@ int Application::run() { cleanup(); return 1; } - qInfo() << QString("Starting Brewtarget v%1 on %2.").arg(VERSIONSTRING).arg(QSysInfo::prettyProductName()); Database::instance().checkForNewDefaultData(); // .:TBD:. Could maybe move the calls to init and setVisible inside createMainWindowInstance() in MainWindow.cpp diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index eaba12f46..e08ec1e74 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -330,7 +330,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), pimpl{std::make_u exit(1); // Set the window title. - setWindowTitle( QString("Brewtarget - %1").arg(VERSIONSTRING) ); + setWindowTitle( QString("Brewtarget - %1").arg(CONFIG_VERSION_STRING) ); // Null out the recipe recipeObs = nullptr; diff --git a/src/config.in b/src/config.in index a068e4a12..8d4174d38 100644 --- a/src/config.in +++ b/src/config.in @@ -19,18 +19,31 @@ */ #ifndef CONFIG_IN #define CONFIG_IN +#pragma once /** - * This file gets converted to build/src/config.h by CMake (see CMakeLists.txt in top-level directory) + * This file gets converted to build/src/config.h by CMake (see configure_file command in CMakeLists.txt in top-level + * directory) * - * I _think_ this is a way to pass things back into the code that CMake has figured out + * This is a way to pass CMake variables into the code */ -//===Things that will get configured by cmake=== -// These two only get used by Linux OS version. -#define CONFIGDATADIR "${CONFIGDATADIR}" -#define CONFIGDOCDIR "${CONFIGDOCDIR}" +//! Used on Linux as a fallback way of determining where to look for resources - see Application.cpp +constexpr char const * CONFIG_DATA_DIR = "${CONFIG_DATA_DIR}"; -#define VERSIONSTRING "${brewtarget_VERSION_MAJOR}.${brewtarget_VERSION_MINOR}.${brewtarget_VERSION_PATCH}" +//! This constant makes sharing code between Brewtarget and Brewken slightly easier +// (Here, UC means upper case first letter, LC means lower case first letter) +constexpr char const * CONFIG_APPLICATION_NAME_UC = "${capitalisedProjectName}"; +constexpr char const * CONFIG_APPLICATION_NAME_LC = "${CMAKE_PROJECT_NAME}"; + +// This one has to be a #define rather than a constexpr because it's used in ui/mainWindow.ui which is processed into +// C++ code by the Qt Meta Object Compiler (MOC) and the MOC can't handle use of a constexpr const in a ui file. +#define CONFIG_VERSION_STRING "${PROJECT_VERSION}" + +// Build info +constexpr char const * CMAKE_HOST_SYSTEM = "${CMAKE_HOST_SYSTEM}"; +constexpr char const * CMAKE_SYSTEM = "${CMAKE_SYSTEM}"; +constexpr char const * CMAKE_CXX_COMPILER_ID = "${CMAKE_CXX_COMPILER_ID}"; +constexpr char const * BUILD_TIMESTAMP = "${BUILD_TIMESTAMP}"; #endif diff --git a/src/main.cpp b/src/main.cpp index a30a52b04..227d5305f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,8 +30,6 @@ #include #include -#include // DELETE - #include "Application.h" #include "config.h" #include "database/Database.h" @@ -41,10 +39,10 @@ namespace { /*! - * \brief Imports the content of an xml file to the database. - * - * Use at your own risk. - */ + * \brief Imports the content of an xml file to the database. + * + * Use at your own risk. + */ void importFromXml(const QString & filename) { QString errorMessage; @@ -92,8 +90,8 @@ int main(int argc, char **argv) { app.setOrganizationDomain("brewtarget.com"); // We used to vary the application name (and therefore location of config files etc) depending on whether we're // building with debug or release version of Qt, but on the whole I don't think this is helpful - app.setApplicationName("brewtarget"); - app.setApplicationVersion(VERSIONSTRING); + app.setApplicationName(CONFIG_APPLICATION_NAME_LC); + app.setApplicationVersion(CONFIG_VERSION_STRING); // Process command-line options relatively early as some may override other settings QCommandLineParser parser; @@ -109,7 +107,12 @@ int main(int argc, char **argv) { * This is mostly useful for developers who want to have an easy way of running an instance of the app against a * test database without messing anything up with their real database. */ - QCommandLineOption const userDirectoryOption("user-dir", "Override the user data directory used by the application with ", "directory", QString()); + QCommandLineOption const userDirectoryOption{ + "user-dir", + "Override the user data directory used by the application with ", + "directory", + QString() + }; parser.addOption(userDirectoryOption); parser.addHelpOption(); parser.addVersionOption(); @@ -156,7 +159,7 @@ int main(int argc, char **argv) { // get cleaned up. We do attempt to detect and rectify such cases, with the double-check below, but it still seems // wise to allow the user to override the warning if for any reason it is triggered incorrectly. // - QSharedMemory sharedMemory("Brewtarget"); + QSharedMemory sharedMemory(CONFIG_APPLICATION_NAME_UC); if (!sharedMemory.create(1)) { // // According to @@ -189,8 +192,11 @@ int main(int argc, char **argv) { try { qInfo() << - "Starting Brewtarget v" << VERSIONSTRING << " (app name" << app.applicationName() << ") on " << - QSysInfo::prettyProductName(); + "Starting" << CONFIG_APPLICATION_NAME_UC << "v" << CONFIG_VERSION_STRING << " (app name" << + app.applicationName() << ") on " << QSysInfo::prettyProductName(); + qInfo() << + "Built at" << BUILD_TIMESTAMP << "on" << CMAKE_HOST_SYSTEM << "for" << CMAKE_SYSTEM << "with" << + CMAKE_CXX_COMPILER_ID << "compiler"; qInfo() << "Log directory:" << Logging::getDirectory().absolutePath(); qInfo() << "Using Qt runtime v" << qVersion() << " (compiled against Qt v" << QT_VERSION_STR << ")"; qInfo() << "Configuration directory:" << PersistentSettings::getConfigDir().absolutePath(); diff --git a/src/xml/BeerXml.cpp b/src/xml/BeerXml.cpp index d120845af..472aa9bd7 100644 --- a/src/xml/BeerXml.cpp +++ b/src/xml/BeerXml.cpp @@ -30,7 +30,7 @@ #include #include -#include "config.h" // For VERSIONSTRING +#include "config.h" // For CONFIG_VERSION_STRING #include "model/BrewNote.h" #include "model/Equipment.h" #include "model/Fermentable.h" @@ -92,8 +92,8 @@ namespace { {"Aroma", Hop::Use::UseAroma} }; EnumStringMapping const BEER_XML_HOP_TYPE_MAPPER { - {"Bittering", Hop::Type::Bittering}, - {"Aroma", Hop::Type::Aroma}, + {"Bittering", Hop::Type::Bittering}, + {"Aroma", Hop::Type::Aroma}, {"Both", Hop::Type::Both} }; EnumStringMapping const BEER_XML_HOP_FORM_MAPPER { @@ -102,26 +102,26 @@ namespace { {"Leaf", Hop::Form::Leaf} }; template<> XmlRecord::FieldDefinitions const BEER_XML_RECORD_FIELDS { - // Type XPath Q_PROPERTY Enum Mapper - {XmlRecord::FieldType::String, "NAME", PropertyNames::NamedEntity::name, nullptr}, - {XmlRecord::FieldType::RequiredConstant, "VERSION", VERSION1, nullptr}, - {XmlRecord::FieldType::Double, "ALPHA", PropertyNames::Hop::alpha_pct, nullptr}, - {XmlRecord::FieldType::Double, "AMOUNT", PropertyNames::Hop::amount_kg, nullptr}, + // Type XPath Q_PROPERTY Enum Mapper + {XmlRecord::FieldType::String, "NAME", PropertyNames::NamedEntity::name, nullptr}, + {XmlRecord::FieldType::RequiredConstant, "VERSION", VERSION1, nullptr}, + {XmlRecord::FieldType::Double, "ALPHA", PropertyNames::Hop::alpha_pct, nullptr}, + {XmlRecord::FieldType::Double, "AMOUNT", PropertyNames::Hop::amount_kg, nullptr}, {XmlRecord::FieldType::Enum, "USE", PropertyNames::Hop::use, &BEER_XML_HOP_USE_MAPPER}, - {XmlRecord::FieldType::Double, "TIME", PropertyNames::Hop::time_min, nullptr}, - {XmlRecord::FieldType::String, "NOTES", PropertyNames::Hop::notes, nullptr}, - {XmlRecord::FieldType::Enum, "TYPE", PropertyNames::Hop::type, &BEER_XML_HOP_TYPE_MAPPER}, - {XmlRecord::FieldType::Enum, "FORM", PropertyNames::Hop::form, &BEER_XML_HOP_FORM_MAPPER}, - {XmlRecord::FieldType::Double, "BETA", PropertyNames::Hop::beta_pct, nullptr}, - {XmlRecord::FieldType::Double, "HSI", PropertyNames::Hop::hsi_pct, nullptr}, - {XmlRecord::FieldType::String, "ORIGIN", PropertyNames::Hop::origin, nullptr}, - {XmlRecord::FieldType::String, "SUBSTITUTES", PropertyNames::Hop::substitutes, nullptr}, - {XmlRecord::FieldType::Double, "HUMULENE", PropertyNames::Hop::humulene_pct, nullptr}, - {XmlRecord::FieldType::Double, "CARYOPHYLLENE", PropertyNames::Hop::caryophyllene_pct, nullptr}, - {XmlRecord::FieldType::Double, "COHUMULONE", PropertyNames::Hop::cohumulone_pct, nullptr}, - {XmlRecord::FieldType::Double, "MYRCENE", PropertyNames::Hop::myrcene_pct, nullptr}, - {XmlRecord::FieldType::String, "DISPLAY_AMOUNT", BtString::NULL_STR, nullptr}, // Extension tag - {XmlRecord::FieldType::String, "INVENTORY", BtString::NULL_STR, nullptr}, // Extension tag + {XmlRecord::FieldType::Double, "TIME", PropertyNames::Hop::time_min, nullptr}, + {XmlRecord::FieldType::String, "NOTES", PropertyNames::Hop::notes, nullptr}, + {XmlRecord::FieldType::Enum, "TYPE", PropertyNames::Hop::type, &BEER_XML_HOP_TYPE_MAPPER}, + {XmlRecord::FieldType::Enum, "FORM", PropertyNames::Hop::form, &BEER_XML_HOP_FORM_MAPPER}, + {XmlRecord::FieldType::Double, "BETA", PropertyNames::Hop::beta_pct, nullptr}, + {XmlRecord::FieldType::Double, "HSI", PropertyNames::Hop::hsi_pct, nullptr}, + {XmlRecord::FieldType::String, "ORIGIN", PropertyNames::Hop::origin, nullptr}, + {XmlRecord::FieldType::String, "SUBSTITUTES", PropertyNames::Hop::substitutes, nullptr}, + {XmlRecord::FieldType::Double, "HUMULENE", PropertyNames::Hop::humulene_pct, nullptr}, + {XmlRecord::FieldType::Double, "CARYOPHYLLENE", PropertyNames::Hop::caryophyllene_pct, nullptr}, + {XmlRecord::FieldType::Double, "COHUMULONE", PropertyNames::Hop::cohumulone_pct, nullptr}, + {XmlRecord::FieldType::Double, "MYRCENE", PropertyNames::Hop::myrcene_pct, nullptr}, + {XmlRecord::FieldType::String, "DISPLAY_AMOUNT", BtString::NULL_STR, nullptr}, // Extension tag + {XmlRecord::FieldType::String, "INVENTORY", BtString::NULL_STR, nullptr}, // Extension tag {XmlRecord::FieldType::String, "DISPLAY_TIME", BtString::NULL_STR, nullptr} // Extension tag }; @@ -742,13 +742,13 @@ void BeerXML::createXmlFile(QFile & outFile) const { out << "\n" - "\n"; return; } -template void BeerXML::toXml(QList & nes, QFile & outFile) const { +template void BeerXML::toXml(QList const & nes, QFile & outFile) const { // We don't want to output empty container records if (nes.empty()) { return; @@ -760,6 +760,8 @@ template void BeerXML::toXml(QList & nes, QFile & outFile) const // ... tags and so on. QTextStream out(&outFile); // BeerXML specifies the ISO-8859-1 encoding + // .:TODO:. In Qt6, QTextCodec and QTextStream::setCodec have been removed and are replaced by QStringConverter + // (which is new in Qt6). out.setCodec(QTextCodec::codecForMib(CharacterSets::ISO_8859_1_1987)); out << "<" << BEER_XML_RECORD_NAME << "S>\n"; for (auto ne : nes) { @@ -773,18 +775,18 @@ template void BeerXML::toXml(QList & nes, QFile & outFile) const // (This is all just a trick to allow the template definition to be here in the .cpp file and not in the header, which // means, amongst other things, that we can reference the pimpl.) // -template void BeerXML::toXml(QList & nes, QFile & outFile) const; -template void BeerXML::toXml(QList &nes, QFile & outFile) const; -template void BeerXML::toXml(QList & nes, QFile & outFile) const; -template void BeerXML::toXml(QList & nes, QFile & outFile) const; -template void BeerXML::toXml(QList & nes, QFile & outFile) const; -template void BeerXML::toXml(QList