#include "worker.h" #include "update.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "message_handler.h" #include #include "ismas/ismas_client.h" #include "progress_event.h" #include "mainwindow.h" #include "utils.h" #include "process/command.h" QString const Worker::UPDATE_STEP_OK ( " [ ok]"); QString const Worker::UPDATE_STEP_DONE ( " [done]"); QString const Worker::UPDATE_STEP_WRONG ( "[WRONG]"); QString const Worker::UPDATE_STEP_FAIL ( " [FAIL]"); QString const Worker::UPDATE_STEP_SUCCESS(" [SUCCESS]"); bool Worker::sendLastVersionOnce = false; using UPDATE_STEP = Worker::UPDATE_STEP; const QMap Worker::smap ( std::initializer_list>{ #define INSERT_ELEMENT(p) std::pair(p, #p) INSERT_ELEMENT(UPDATE_STEP::STARTED), INSERT_ELEMENT(UPDATE_STEP::CHECK_REPOSITORY), INSERT_ELEMENT(UPDATE_STEP::CHECK_REPOSITORY_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::CHECK_REPOSITORY_FAILURE), INSERT_ELEMENT(UPDATE_STEP::CHECK_SANITY), INSERT_ELEMENT(UPDATE_STEP::CHECK_SANITY_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::CHECK_SANITY_FAILURE), INSERT_ELEMENT(UPDATE_STEP::REPOSITORY_RECOVERED_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::REPOSITORY_RECOVERED_FAILURE), INSERT_ELEMENT(UPDATE_STEP::CLONE_REPOSITORY), INSERT_ELEMENT(UPDATE_STEP::CLONE_REPOSITORY_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::CLONE_REPOSITORY_FAILURE), INSERT_ELEMENT(UPDATE_STEP::CHECKOUT_REPOSITORY), INSERT_ELEMENT(UPDATE_STEP::CHECKOUT_REPOSITORY_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::CHECKOUT_REPOSITORY_FAILURE), INSERT_ELEMENT(UPDATE_STEP::CHECK_ISMAS_TRIGGER), INSERT_ELEMENT(UPDATE_STEP::CHECK_ISMAS_TRIGGER_WRONG_VALUE), INSERT_ELEMENT(UPDATE_STEP::CHECK_ISMAS_TRIGGER_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE), INSERT_ELEMENT(UPDATE_STEP::INITIAL_CLONE_WITHOUT_ACTIVE_ISMAS_TRIGGER), INSERT_ELEMENT(UPDATE_STEP::INITIAL_CLONE_WITH_ACTIVE_ISMAS_TRIGGER), INSERT_ELEMENT(UPDATE_STEP::PULL_NEW_BRANCH), INSERT_ELEMENT(UPDATE_STEP::PULL_NEW_BRANCH_FAILURE), INSERT_ELEMENT(UPDATE_STEP::PULL_NEW_BRANCH_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::CHECKOUT_BRANCH), INSERT_ELEMENT(UPDATE_STEP::CHECKOUT_BRANCH_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::CHECKOUT_BRANCH_FAILURE), INSERT_ELEMENT(UPDATE_STEP::UPDATE_REPOSITORY), INSERT_ELEMENT(UPDATE_STEP::UPDATE_REPOSITORY_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::UPDATE_REPOSITORY_FAILURE), INSERT_ELEMENT(UPDATE_STEP::CHECK_FOR_REPOSITORY_CHANGES), INSERT_ELEMENT(UPDATE_STEP::CHECK_FOR_REPOSITORY_CHANGES_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::CHECK_FOR_REPOSITORY_CHANGES_FAILURE), INSERT_ELEMENT(UPDATE_STEP::FILES_TO_UPDATE), INSERT_ELEMENT(UPDATE_STEP::FILES_TO_DOWNLOAD), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMANDS), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_1), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_2), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_3), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_4), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_5), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_6), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_7), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_8), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_9), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_LAST), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::EXEC_OPKG_COMMAND_FAILURE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_CONFIG_FILE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_CONFIG_FILE_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_CONFIG_FILE_FAILURE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_CASH_FILE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_CASH_FILE_FAILURE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_CASH_FILE_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_DEVICE_FILE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_DEVICE_FILE_FAILURE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_DEVICE_FILE_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_JSON_FILE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_JSON_FILE_FAILURE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_JSON_FILE_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_DEVICE_CONTROLLER), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_DEVICE_CONTROLLER_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_DEVICE_CONTROLLER_FAILURE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_FILES_TO_PSA_HARDWARE), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_FILES_TO_PSA_HARDWARE_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::DOWNLOAD_FILES_TO_PSA_HARDWARE_FAILURE), INSERT_ELEMENT(UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY), INSERT_ELEMENT(UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY_FAILURE), INSERT_ELEMENT(UPDATE_STEP::SAVE_LOGS), INSERT_ELEMENT(UPDATE_STEP::SAVE_LOGS_SUCCESS), INSERT_ELEMENT(UPDATE_STEP::SAVE_LOGS_FAILURE), INSERT_ELEMENT(UPDATE_STEP::SEND_LAST_VERSION), INSERT_ELEMENT(UPDATE_STEP::UPDATE_FINALIZE), INSERT_ELEMENT(UPDATE_STEP::UPDATE_SUCCEEDED), INSERT_ELEMENT(UPDATE_STEP::UPDATE_NOT_NECESSARY), INSERT_ELEMENT(UPDATE_STEP::UPDATE_FAILED), INSERT_ELEMENT(UPDATE_STEP::UPDATE_ACTIVATED), INSERT_ELEMENT(UPDATE_STEP::FINISHED), INSERT_ELEMENT(UPDATE_STEP::DEBUG), INSERT_ELEMENT(UPDATE_STEP::ERROR), INSERT_ELEMENT(UPDATE_STEP::NONE) #undef INSERT_ELEMENT }); Worker *Worker::instance = nullptr; Worker::Worker(int customerNr, int machineNr, int zoneNr, QString repositoryUrl, QString branchName, QString pluginDir, QString pluginName, QString workingDirectory, bool noUpdatePsaHardware, bool alwaysDownloadConfig, bool alwaysDownloadDC, bool dryRun, QObject *parent, char const *serialInterface, char const *baudrate) : m_customerNr(customerNr) , m_customerNrStr(QString("customer_") + QString::number(m_customerNr)) , m_machineNr(machineNr) , m_zoneNr(zoneNr) , m_pluginDir(pluginDir) , m_pluginName(pluginName) , m_workingDirectory(workingDirectory) , m_branchName(branchName) , m_customerRepositoryPath(QString("%1/%2.git").arg(repositoryUrl).arg(m_customerNrStr)) , m_customerRepository(QDir::cleanPath(m_workingDirectory + QDir::separator() + m_customerNrStr)) , m_noUpdatePsaHardware(noUpdatePsaHardware) , m_alwaysDownloadConfig(alwaysDownloadConfig) , m_alwaysDownloadDC(alwaysDownloadDC) , m_dryRun(dryRun) , m_parent(parent) , m_serialInterface(serialInterface) , m_baudrate(baudrate) , m_gc(m_customerRepositoryPath, m_customerNrStr, m_customerRepository, m_workingDirectory, m_branchName, this) , m_versionInfo(QStringList()) , m_osVersion(getOsVersion()) , m_atbqtVersion(getATBQTVersion()) , m_atbUpdateToolVersion(getATBUpdateToolVersion()) , m_cpuSerial(getCPUSerial()) , m_pluginVersionATBDeciceController(getPluginVersion("/opt/app/ATBAPP/plugins/libATBDeviceControllerPlugin.so")) , m_pluginVersionIngenicoISelf(getPluginVersion("/opt/app/ATBAPP/plugins/libIngenicoISelf_CCPlugin.so")) , m_pluginVersionMobilisisCalc(getPluginVersion("/opt/app/ATBAPP/plugins/libMOBILISIS_CalculatePricePlugin.so")) , m_pluginVersionMobilisisCalcConfig(getPluginVersion("/opt/app/ATBAPP/plugins/libMOBILISIS_CalculatePricePlugin_ConfigUi.so")) , m_pluginVersionPrmCalc(getPluginVersion("/opt/app/ATBAPP/plugins/libPRM_CalculatePricePlugin.so")) , m_pluginVersionPrmCalcConfig(getPluginVersion("/opt/app/ATBAPP/plugins/libPRM_CalculatePricePlugin_ConfigUi.so")) , m_pluginVersionTcpZvt(getPluginVersion("/opt/app/ATBAPP/plugins/libTCP_ZVT_CCPlugin.so")) , m_ismasUpdateRequests(ISMAS_UPDATE_REQUESTS) , m_waitForNewUpdates(this) , m_filesToUpdate() , m_updateProcessRunning(true) , m_mainWindow(nullptr) /* contains plugin */ , m_dcDownloadFirmware(new Command("/opt/app/tools/atbupdate/ATBDownloadDCFirmware --read-dc-version true")) //, m_withoutIsmasDirectPort(true) /* useful for testing */ { , m_withoutIsmasDirectPort(false) /* useful for testing */ { m_start = QDateTime::currentDateTime(); m_dcDownloadFirmware->setWorker(this); // TODO: turn object into singleton instance = this; m_lastFailedUpdateStep = UPDATE_STEP::NONE; if (m_noUpdatePsaHardware == false) { m_update = new Update(this, QDir::cleanPath(m_workingDirectory + QDir::separator() + m_customerNrStr), m_customerNrStr, m_branchName, m_pluginDir, m_pluginName, m_workingDirectory); } this->setObjectName("worker-object"); QDir::setCurrent(m_workingDirectory); m_apismVersion = getAPISMYoctoVersion(); } Worker::~Worker() { if (m_update != nullptr) { delete m_update; m_update = nullptr; } } void Worker::displayProgressInMainWindow(int progress) { if (m_mainWindow) { QApplication::postEvent(m_mainWindow, new ProgressEvent(this, progress)); } } void Worker::setProgress(int progress) { m_ismasClient.setProgressInPercent(progress); displayProgressInMainWindow(progress); } void Worker::startProgressLoop() { displayProgressInMainWindow(MainWindow::START_PROGRESS_LOOP); } void Worker::stopProgressLoop() { displayProgressInMainWindow(MainWindow::STOP_PROGRESS_LOOP); } static std::once_flag once; void Worker::run() { // user should not start the update process several times std::call_once(once, &Worker::privateUpdate, this); } bool Worker::isRepositoryCorrupted() { QDir customerRepository(m_customerRepository); if (customerRepository.exists()) { QDir customerRepositoryGit(QDir::cleanPath(m_customerRepository + QDir::separator() + ".git/")); if (!m_gc.gitFsck()) { // should never happen Utils::printCriticalErrorMsg("CORRUPTED CUSTOMER REPOSITORY: GIT_FSCK FAILED"); return true; } // .git-directory inside git-repository does not exist, which means the // git-repository is corrupted -> remove it and start from scratch if (!customerRepositoryGit.exists()) { // should never happen Utils::printCriticalErrorMsg("CORRUPTED CUSTOMER REPOSITORY .GIT DOES NOT EXIST"); return true; } QDir customerRepositoryEtc(QDir::cleanPath(m_customerRepository + QDir::separator() + "etc/")); if (!customerRepositoryEtc.exists()) { // should never happen Utils::printCriticalErrorMsg(QString("CORRUPTED CUSTOMER REPOSITORY %1/etc DOES NOT EXIST").arg(m_customerRepository)); return true; } } return false; } bool Worker::repairCorruptedRepository() { QDir customerRepository(m_customerRepository); if (!customerRepository.removeRecursively()) { Utils::printCriticalErrorMsg("ERROR REMOVING CORR. CUST-REPOSITORY"); //m_updateStatus = UpdateStatus(UPDATE_STATUS::REMOVE_GIT_REPOSITORY_FAILED, // QString("REMOVAL OF GIT-REPOSITORY %1 FAILED").arg(m_customerRepository)); //IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, // QString("#M=APISM#C=CMD_EVENT#J=") + // m_ismasClient.sanityCheckFailed(IsmasClient::RESULT_CODE::INSTALL_ERROR, // m_updateStatus.m_statusDescription)); //emit showErrorMessage("apism sanity check", m_updateStatus.m_statusDescription); return false; } return true; } void Worker::privateUpdate() { if (!m_mainWindow) { Utils::printCriticalErrorMsg("m_mainWindow NOT SET"); return; } return; QString func(__PRETTY_FUNCTION__); GUI() << (ISMAS() << (CONSOLE() << UPDATE_STEP::STARTED)); QScopedPointer upr(new UpdateProcessRunning(this)); QStringList lst; //////////////////////////////////////////////////////////////////////////// // // CHECK UPDATE TRIGGER // //////////////////////////////////////////////////////////////////////////// // NOTE: make sure that nothing is sent to ISMAS during updateTriggerSet ISMAS() << UPDATE_STEP::CHECK_ISMAS_TRIGGER; m_ismasTriggerActive = false; m_updateNotNecessary = false; if (QDir(m_customerRepository).exists()) { // ignore a possibly corrupted repository m_ismasTriggerActive = updateTriggerSet(); if (m_ismasTriggerActive == false) { QDateTime const ¤t = QDateTime::currentDateTime(); m_automaticUpdate = (current.time().hour() < 4); m_versionInfo = m_gc.gitShowReason(m_branchName); qCritical() << "***"; qCritical() << "privateUpdate ............. m_versionInfo:" << m_versionInfo; qCritical() << "privateUpdate ......... m_automaticUpdate:" << m_automaticUpdate; if (m_automaticUpdate) { // update has been triggered within [00:00:00, 00:03:59] m_updateNotNecessary = true; m_ismasTriggerStatusMessage = QStringList(QString("NO UPDATE NECESSARY (%1)").arg(current.toString(Qt::ISODate))); qCritical() << "privateUpdate m_ismasTriggerStatusMessage:" << QStringList(m_ismasTriggerStatusMessage); qCritical() << "***"; // the customer-repository does exist, and the ISMAS-trigger is // *NOT* "WAIT", but from 00:00:00 - 00:03:59 this counts as an // automatic update QStringList lst = m_ismasTriggerStatusMessage; // trigger message to ISMAS and CONSOLE CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_SUCCESS); // overwrite m_lastFailedUpdateStep m_lastFailedUpdateStep = UPDATE_STEP::NONE; return; } qCritical() << "***"; // the customer-repository does exist, but the ISMAS-trigger is // *NOT* "WAIT", so STOP the update procedure return; } // the customer-repository does exist, and the ISMAS-trigger is "WAIT", // so continue the update procedure } else { // the customer-repository does not exist, so PROCEED with the // update procedure, even if ISMAS-trigger is not correctly set ("WAIT") } emit this->disableExit(); QDir customerRepository(m_customerRepository); CONSOLE() << (ISMAS() << UPDATE_STEP::CHECK_SANITY); m_clone = false; m_repairClone = false; m_initialClone = false; m_pulledNewBranch = false; // the customer repository is cloned or // repaired/re-cloned without checking the // ISMAS-trigger (WAIT-)button. // Case 1: no existing repository: // if there was a sane repository // available, then the trigger-button is // checked: // 1: trigger == WAIT: then // have been activated in ISMAS. bool continueUpdate = true; // check if git-clone command has timed-out, // resulting in a corrupted git-repository, which // does not contain an ./etc-directory if (isRepositoryCorrupted()) { // a not-existing repository is not meant // to be corrupted CONSOLE() << (ISMAS() << UPDATE_STEP::CHECK_SANITY_FAILURE); if ((continueUpdate = repairCorruptedRepository()) == true) { m_repairClone = true; CONSOLE() << (ISMAS() << UPDATE_STEP::REPOSITORY_RECOVERED_SUCCESS); } else { ISMAS() << (GUI() << (CONSOLE() << UPDATE_STEP::REPOSITORY_RECOVERED_FAILURE)); return; } } CONSOLE() << (ISMAS() << UPDATE_STEP::CHECK_SANITY_SUCCESS); if (continueUpdate) { if ((continueUpdate = customerRepository.exists()) == false) { m_initialClone = (m_repairClone == false); ISMAS() << (GUI() << (CONSOLE() << UPDATE_STEP::CLONE_REPOSITORY)); for (int i = 0; i < 5; ++i) { // try to checkout git repository setProgress(i); // and switch to branch if (m_gc.gitCloneAndCheckoutBranch()) { if (!isRepositoryCorrupted()) { m_versionInfo = m_gc.gitShowReason(m_branchName); GUI() << (ISMAS() << (CONSOLE() << UPDATE_STEP::CLONE_REPOSITORY_SUCCESS)); continueUpdate = true; m_clone = true; break; } } QThread::sleep(1); // maybe git needs more time } if (continueUpdate == false) { GUI() << (ISMAS() << (CONSOLE() << (m_lastFailedUpdateStep = UPDATE_STEP::CLONE_REPOSITORY_FAILURE))); return; } Q_ASSERT_X(m_clone, (func + QString(":%1").arg(__LINE__)).toStdString().c_str(), "clone failed"); } else { Q_ASSERT_X(!m_clone, (func + QString(":%1").arg(__LINE__)).toStdString().c_str(), "m_clone not false"); Q_ASSERT_X(!m_initialClone, (func + QString(":%1").arg(__LINE__)).toStdString().c_str(), "m_initialClone not false"); Q_ASSERT_X(!m_repairClone, (func + QString(":%1").arg(__LINE__)).toStdString().c_str(), "m_repairClone not false"); CONSOLE() << UPDATE_STEP::CHECK_REPOSITORY; if (isRepositoryCorrupted()) { ISMAS() << (GUI() << (CONSOLE() << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_REPOSITORY_FAILURE))); return; } } } m_versionInfo = m_gc.gitShowReason(m_branchName); CONSOLE() << UPDATE_STEP::CHECK_REPOSITORY_SUCCESS; setProgress(_CHECKOUT_REPOSITORY_SUCCESS); if (m_clone == false) { if (m_ismasTriggerActive == false) { return; } else { GUI() << (ISMAS() << (CONSOLE() << UPDATE_STEP::CHECK_ISMAS_TRIGGER_SUCCESS)); setProgress(_CHECK_ISMAS_TRIGGER_SUCCESS); } } else { if (m_initialClone) { GUI() << (ISMAS() << (CONSOLE() << UPDATE_STEP::INITIAL_CLONE_WITHOUT_ACTIVE_ISMAS_TRIGGER)); } } if (m_ismasTriggerActive == false) {// make it explicit again: only if the // ismas trigger is active ('WAIT'), // then proceed if (m_clone == false) { // if it is an (initial) clone, then return; // run the whole update process: } // sync tariff-files, download jsons, } // download device controller //////////////////////////////////////////////////////////////////////////// // // CHECK-OUT BRANCH // //////////////////////////////////////////////////////////////////////////// if ((continueUpdate = customerEnvironment()) == false) { // even if something goes wrong creating the environment, try to execute // opkg_commands if (QDir(m_customerRepository).exists()) { // always execute contents of opkg_commands-file m_filesToUpdate.clear(); m_filesToUpdate << "etc/psa_update/opkg_commands"; execOpkgCommands(); } return; } m_versionInfo = m_gc.gitShowReason(m_branchName); lst = QStringList(QString(smap[UPDATE_STEP::CHECKOUT_BRANCH_SUCCESS])); ISMAS(lst) << (CONSOLE(lst) << UPDATE_STEP::CHECKOUT_BRANCH); setProgress(_CHECKOUT_BRANCH_SUCCESS); //////////////////////////////////////////////////////////////////////////// // // COMPUTE CHANGED FILES OF CUSTOMER REPOSITORY // //////////////////////////////////////////////////////////////////////////// if ((continueUpdate = filesToUpdate()) == false) { // even if something goes wrong in filesToUpdate, try to execute // opkg_commands if (QDir(m_customerRepository).exists()) { // always execute contents of opkg_commands-file m_filesToUpdate.clear(); m_filesToUpdate << "etc/psa_update/opkg_commands"; execOpkgCommands(); } return; } m_versionInfo = m_gc.gitShowReason(m_branchName); lst = QStringList(QString(smap[UPDATE_STEP::UPDATE_REPOSITORY_SUCCESS])); ISMAS() << (GUI() << (CONSOLE() << UPDATE_STEP::UPDATE_REPOSITORY)); setProgress(_UPDATE_REPOSITORY_SUCCESS); //////////////////////////////////////////////////////////////////////////// // // (R)SYNC THE REPOSITORY WITH THE LOCAL FILEYSTEM // //////////////////////////////////////////////////////////////////////////// if ((continueUpdate = syncCustomerRepositoryAndFS()) == false) { // even if something goes wrong with rsync, try to execute // opkg_commands if (QDir(m_customerRepository).exists()) { // always execute contents of opkg_commands-file m_filesToUpdate.clear(); m_filesToUpdate << "etc/psa_update/opkg_commands"; execOpkgCommands(); } return; } lst = QStringList(QString(smap[UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY_SUCCESS])); ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY_SUCCESS)); setProgress(_SYNC_CUSTOMER_REPOSITORY_SUCCESS); //////////////////////////////////////////////////////////////////////////// // // EXECUTE OPKG COMMANDS // //////////////////////////////////////////////////////////////////////////// if ((continueUpdate = execOpkgCommands()) == false) { return; } lst = QStringList(QString(smap[UPDATE_STEP::EXEC_OPKG_COMMAND_SUCCESS])); GUI(lst) << (CONSOLE(lst) << UPDATE_STEP::EXEC_OPKG_COMMANDS); setProgress(_EXEC_OPKG_COMMAND_SUCCESS); //////////////////////////////////////////////////////////////////////////// // // UPDATE THE PSA USING THE CHANGED FILES // //////////////////////////////////////////////////////////////////////////// if ((continueUpdate = downloadFilesToPSAHardware()) == false) { return; } lst = QStringList(QString("DONE")); ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << UPDATE_STEP::DOWNLOAD_FILES_TO_PSA_HARDWARE_SUCCESS)); //////////////////////////////////////////////////////////////////////////// // // FUTURE: SAVE LOG FILES // //////////////////////////////////////////////////////////////////////////// if ((continueUpdate = saveLogFile()) == false) { return; } // ISMAS() << (GUI() << (CONSOLE() << UPDATE_STEP::SAVE_LOGS_SUCCESS)); setProgress(_SAVE_LOGS_SUCCESS); // final messages: see destructor of UpdateProcessRunning subclass m_lastFailedUpdateStep = UPDATE_STEP::NONE; } bool Worker::updateTriggerSet() { // repository is existent and not corrupted. check now if the ISMAS-trigger // (WAIT-button) is activated even in case of initial checkout static const QString func = "UPDATE-TRIGGER-SET"; // if (m_withoutIsmasDirectPort) { // useful for testing // return true; //} m_ismasTriggerStatusMessage.clear(); GUI() << (CONSOLE() << UPDATE_STEP::CHECK_ISMAS_TRIGGER); bool const automaticUpdate = (QDateTime::currentDateTime().time().hour() < 4); QString triggerValue("NOT CHECKED YET"); static constexpr int const repeats = 15; for (int repeat = 1; repeat <= repeats; ++repeat) { if (repeat > 1) { int const startMs = QTime::currentTime().msecsSinceStartOfDay(); int const durationMs = QTime::currentTime().msecsSinceStartOfDay() - startMs; QString const &s = QString("elapsed: %1.%2s").arg(durationMs / 1000).arg(durationMs % 1000); QStringList lst = (m_ismasTriggerStatusMessage = (QStringList(func) << s)); CONSOLE(lst) << UPDATE_STEP::DEBUG; } else { QStringList lst = (m_ismasTriggerStatusMessage = (QStringList(func) << QString("-> REPEAT=%1 (%2)").arg(repeat).arg(repeats-repeat))); CONSOLE(lst) << UPDATE_STEP::DEBUG; } if ((repeat % 8) == 0) { CONSOLE(QStringList(func) << "RESTART APISM") << UPDATE_STEP::DEBUG; Command c("systemctl restart apism"); if (c.execute("/tmp")) { QThread::sleep(20); // give APISM some time to reconnect QStringList lst = (m_ismasTriggerStatusMessage = (QStringList(func) << "RESTART APISM DONE")); CONSOLE(lst) << UPDATE_STEP::DEBUG; } } if (std::optional result = IsmasClient::sendRequestReceiveResponse( IsmasClient::APISM::DIRECT_PORT, "#M=APISM#C=REQ_ISMASPARAMETER#J={}")) { QString const &msg = QString("APISM RESPONSE(%1)=(").arg(repeat) + result.value() + ")"; QStringList lst = (m_ismasTriggerStatusMessage = (QStringList(func) << msg)); CONSOLE(lst) << UPDATE_STEP::DEBUG; QJsonParseError parseError; QJsonDocument document(QJsonDocument::fromJson(result.value().toUtf8(), &parseError)); if (parseError.error != QJsonParseError::NoError) { m_ismasTriggerStatusMessage = QStringList(QString("INVALID JSON MSG: PARSING FAILED (json=%1 error=[%2] str=[%3] offset=[%4])") .arg(msg) .arg(parseError.error) .arg(parseError.errorString()) .arg(parseError.offset)); QStringList lst = m_ismasTriggerStatusMessage; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } if (!document.isObject()) { m_ismasTriggerStatusMessage = QStringList(QString("not a json-object %1").arg(result.value())); QStringList lst = m_ismasTriggerStatusMessage; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } QJsonObject obj = document.object(); // always look for an 'error' first if (obj.contains("error")) { m_ismasTriggerStatusMessage = QStringList(obj.value("error").toString()); QStringList lst = m_ismasTriggerStatusMessage; CONSOLE(QStringList(lst)) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE); QThread::sleep(6); continue; } // sanity check: cust_nr and machine_nr of PSA correct ? // note: this check has to be done here, as the cust_nr and the machine_nr // of the PSA are sent by ISMAS. if (obj.contains("Dev_ID")) { QJsonValue v = obj.value("Dev_ID"); if (v.isObject()) { QJsonObject obj = v.toObject(); if (obj.contains("Custom_ID") && obj.contains("Device_ID")) { int const customerNr = obj.value("Custom_ID").toInt(-1); int const machineNr = obj.value("Device_ID").toInt(-1); if (customerNr != m_customerNr) { m_ismasTriggerStatusMessage = QStringList(QString("CUSTOMER-NR (%1) != LOCAL CUSTOMER-NR (%2)") .arg(customerNr).arg(m_customerNr)); QStringList lst = m_ismasTriggerStatusMessage; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } if (machineNr != m_machineNr) { m_ismasTriggerStatusMessage = QStringList(QString("MACHINE-NR (%1) != LOCAL MACHINE-NR (%2)") .arg(machineNr).arg(m_machineNr)); QStringList lst = m_ismasTriggerStatusMessage; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } } else { QStringList lst(QString("Dev_ID DOES NOT CONTAIN Custom_ID AND/OR Device_ID (LINE=%1)").arg(__LINE__)); ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } } else { m_ismasTriggerStatusMessage = QStringList(QString("Dev_ID KEY NOT A JSON-OBJECT (LINE=%1)").arg(__LINE__)); QStringList lst = m_ismasTriggerStatusMessage; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } } else { m_ismasTriggerStatusMessage = QStringList(QString("Dev_ID KEY NOT AVAILABLE (LINE=%1)").arg(__LINE__)); QStringList lst = m_ismasTriggerStatusMessage; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } if (obj.contains("Fileupload")) { QJsonValue v = obj.value("Fileupload"); if (v.isObject()) { obj = v.toObject(); if (obj.contains("TRG")) { if ((triggerValue = obj.value("TRG").toString()) == "WAIT") { m_ismasTriggerStatusMessage = QStringList("ISMAS_UPDATE-TRIGGER SET TO WAIT"); m_ismasTriggerActive = true; return m_ismasTriggerActive; } else if (QRegExp("\\s*").exactMatch(triggerValue)) { // check for whitespace m_ismasTriggerStatusMessage = QStringList(QString("%1 EMPTY UPDATE TRIGGER (%2)").arg(repeat).arg(repeats-repeat)); QStringList lst = m_ismasTriggerStatusMessage; if (m_clone) { ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_WRONG_VALUE))); // if the customer repository has just been cloned return false; // it is OK the ISMAS trigger might not be 'WAIT' } // not a clone and empty update-trigger if (automaticUpdate) { // do not inform ISMAS in case of automatic update, because the // update is not necessary as the trigger-button is not set to WAIT. GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_WRONG_VALUE)); return false; } CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE); QThread::sleep(6); continue; } else { // if the download-button once has a wrong value, it will never recover if (m_clone) { m_ismasTriggerStatusMessage = QStringList(QString("TRIGGER-VALUE='%1' != 'WAIT'").arg(triggerValue)); QStringList lst = m_ismasTriggerStatusMessage; if (automaticUpdate) { // do not inform ISMAS in case of automatic update GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_WRONG_VALUE)); } else { ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_WRONG_VALUE))); } } else { m_ismasTriggerStatusMessage = QStringList(QString("TRIGGER-VALUE='%1' != 'WAIT'").arg(triggerValue)); QStringList lst = m_ismasTriggerStatusMessage; if (automaticUpdate) { // do not inform ISMAS in case of automatic update GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_WRONG_VALUE)); } else { ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); } } return false; } } else { m_ismasTriggerStatusMessage = QStringList(QString("TRG key not available (LINE=%1)").arg(__LINE__)); QStringList lst = m_ismasTriggerStatusMessage; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } } else { m_ismasTriggerStatusMessage = QStringList(QString("Fileupload not a json-object (LINE=%1)").arg(__LINE__)); QStringList lst = m_ismasTriggerStatusMessage; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } } else { m_ismasTriggerStatusMessage = QStringList(QString("Fileupload not available (LINE=%1)").arg(__LINE__)); QStringList lst = m_ismasTriggerStatusMessage; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } } else { m_ismasTriggerStatusMessage = QStringList(QString("no ISMAS response (LINE=%1)").arg(__LINE__)); QStringList lst = m_ismasTriggerStatusMessage; CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE); QThread::sleep(6); continue; } } if (m_initialClone == false) { if (!triggerValue.contains("WAIT", Qt::CaseInsensitive)) { m_ismasTriggerStatusMessage = QStringList(QString("ISMAS_UPDATE-TRIGGER-NOT-SET-OR-WRONG: VALUE=(") + triggerValue + ")"); QStringList lst = m_ismasTriggerStatusMessage; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECK_ISMAS_TRIGGER_FAILURE))); return false; } } return false; } bool Worker::customerEnvironment() { // configure customer environment -> checkout branch in case someone has // changed the zone_nr ISMAS() << (GUI() << (CONSOLE() << UPDATE_STEP::CHECKOUT_BRANCH)); if (QDir(m_customerRepository).exists()) { if (m_clone == false) { if (m_gc.branchExistsRemotely()) { QString msg; QStringList lst; if (!m_gc.branchExistsLocally()) { lst.clear(); msg = QString("PULLING OF NEW BRANCH " + m_branchName + " DOES NOT EXIST LOCALLY"); lst << msg; CONSOLE(lst) << UPDATE_STEP::PULL_NEW_BRANCH; if (!m_gc.gitPullNewBranches()) { lst.clear(); msg = QString("PULLING OF NEW BRANCH " + m_branchName + " FAILED"); lst << msg; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::PULL_NEW_BRANCH_FAILURE))); return false; } else { lst.clear(); msg = QString("PULLING OF NEW BRANCH " + m_branchName + " SUCCESS"); lst << msg; ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::PULL_NEW_BRANCH_SUCCESS))); m_pulledNewBranch = true; } } else { m_pulledNewBranch = false; } } } if (m_gc.gitCheckoutBranch()) { return true; } else { QStringList lst(QString("CHECKOUT OF " + m_customerRepository + "FAILED")); ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECKOUT_BRANCH_FAILURE))); } } else {// cannot happen QStringList lst(QString(m_customerRepository + " DOES NOT EXIST")); ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::CHECKOUT_BRANCH_FAILURE))); } return false; } bool Worker::filesToUpdate() { // determine which files has to be updated: either sent to the hardware or // rsynced with the filesystem in case of tariff-files ISMAS() << (GUI() << (CONSOLE() << UPDATE_STEP::UPDATE_REPOSITORY)); // always execute contents of opkg_commands-file m_filesToUpdate << "etc/psa_update/opkg_commands"; if ((m_clone || m_pulledNewBranch) && m_alwaysDownloadConfig) { // always download all json-config files, even if none of them have been // changed in the git repository. useful for first installation. QDir dir(QDir::cleanPath(m_customerRepository + QDir::separator() + "etc/psa_config")); if (dir.exists()) { QStringList jsons = dir.entryList(QStringList() << "DC2C*.json", QDir::Files); if (!jsons.isEmpty()) { for (QStringList::size_type i=0; i changes = m_gc.gitPull()) { if (!changes.value().contains("Already up to date")) { if (std::optional changedFileNames = m_gc.gitDiff(changes.value())) { m_filesToUpdate << changedFileNames.value(); } } m_filesToUpdate.removeDuplicates(); qCritical() << "(" << __func__ << ":" << __LINE__ << ") FILES-TO-UPDATE" << m_filesToUpdate; GUI(m_filesToUpdate) << (CONSOLE(m_filesToUpdate) << UPDATE_STEP::FILES_TO_UPDATE); setProgress(_FILES_TO_UPDATE); } else { ISMAS() << (GUI() << (CONSOLE() << (m_lastFailedUpdateStep = UPDATE_STEP::UPDATE_REPOSITORY_FAILURE))); return false; } return true; } bool Worker::computeFilesToDownload() { m_filesToDownload.clear(); for (int i = 0; i < m_filesToUpdate.size(); ++i) { QString const fName = m_filesToUpdate.at(i); if (fName.contains("DC2C_print", Qt::CaseInsensitive) || fName.contains("DC2C_device", Qt::CaseInsensitive) || fName.contains("DC2C_conf", Qt::CaseInsensitive) || fName.contains("DC2C_cash", Qt::CaseInsensitive)) { m_filesToDownload << fName; // download printer-config-files } else { if (fName.contains("dc2c.bin")) { m_filesToDownload << fName; // download device controller } } } return (m_filesToDownload.size() > 0); } bool Worker::cleanUpOpkgCache() { bool removedFiles = true; QDir dir("/var/cache/opkg"); if (dir.exists()) { dir.setNameFilters(QStringList() << ".gz" << ".ipk"); dir.setFilter(QDir::Files); foreach(QString dirFile, dir.entryList()) { removedFiles &= dir.remove(dirFile); } } return removedFiles; } bool Worker::execOpkgCommands() { if (!cleanUpOpkgCache()) { CONSOLE() << "INFO: some cached opkg files not removed"; } for (int i = 0; i < m_filesToUpdate.size(); ++i) { QString const fName = m_filesToUpdate.at(i); if (fName.contains("opkg_commands", Qt::CaseInsensitive)) { GUI() << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMANDS); // execute opkg commands if (QDir::setCurrent(m_customerRepository)) { QFile f(fName); if (f.exists()) { if (f.open(QIODevice::ReadOnly)) { QTextStream in(&f); m_opkgCommands.clear(); QStringList opkgErrorLst; while (!in.atEnd()) { QString line = in.readLine(); // TODO: "^\\s*[#]{0,}$" : empty line or comment line starting with # static const QRegularExpression comment("^\\s*[#].*$"); static const QRegularExpression emptyLine("^\\s*$"); if (line.indexOf(emptyLine, 0) == -1 && line.indexOf(comment, 0) == -1) { QString opkgCommand = line.trimmed(); qCritical() << "Found opkg-command" << opkgCommand; if (!executeOpkgCommand(opkgCommand)) { opkgErrorLst << opkgCommand; } else { QString cmd = "\n " + opkgCommand; emit appendText(cmd); m_opkgCommands << cmd; QStringList const opkgLst(opkgCommand); QStringList const cmdLst(cmd); switch(m_opkgCommands.size()) { case 1: ISMAS(opkgLst) << (GUI(cmdLst) << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_1)); setProgress(_EXEC_OPKG_COMMAND_1); break; case 2: ISMAS(opkgLst) << (GUI(cmdLst) << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_2)); setProgress(_EXEC_OPKG_COMMAND_2); break; case 3: ISMAS(opkgLst) << (GUI(cmdLst) << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_3)); setProgress(_EXEC_OPKG_COMMAND_3); break; case 4: ISMAS(opkgLst) << (GUI(cmdLst) << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_4)); setProgress(_EXEC_OPKG_COMMAND_4); break; case 5: ISMAS(opkgLst) << (GUI(cmdLst) << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_5)); setProgress(_EXEC_OPKG_COMMAND_5); break; case 6: ISMAS(opkgLst) << (GUI(cmdLst) << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_6)); setProgress(_EXEC_OPKG_COMMAND_6); break; case 7: ISMAS(opkgLst) << (GUI(cmdLst) << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_7)); setProgress(_EXEC_OPKG_COMMAND_7); break; case 8: ISMAS(opkgLst) << (GUI(cmdLst) << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_8)); setProgress(_EXEC_OPKG_COMMAND_8); break; case 9: ISMAS(opkgLst) << (GUI(cmdLst) << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_9)); setProgress(_EXEC_OPKG_COMMAND_9); break; default: ISMAS(opkgLst) << (GUI(cmdLst) << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_LAST)); setProgress(_EXEC_OPKG_COMMAND_LAST); } } } } f.close(); if (opkgErrorLst.size() == 0) { if (m_opkgCommands.size() > 0) { m_displayIndex = 1; ISMAS() << (GUI() << (CONSOLE() << UPDATE_STEP::EXEC_OPKG_COMMAND_SUCCESS)); setProgress(_EXEC_OPKG_COMMAND_SUCCESS); } } else { m_displayIndex = 1; ISMAS(opkgErrorLst) << (GUI(opkgErrorLst) << (CONSOLE() << (m_lastFailedUpdateStep = UPDATE_STEP::EXEC_OPKG_COMMAND_FAILURE))); GUI() << UPDATE_STEP::EXEC_OPKG_COMMAND_FAILURE; setProgress(_EXEC_OPKG_COMMAND_FAILURE); return false; } } } } } } return true; } bool Worker::downloadFilesToPSAHardware() { m_displayIndex = 0; QStringList lst(QString("START")); ISMAS(lst) << (GUI(m_filesToDownload) << (CONSOLE(m_filesToDownload) << UPDATE_STEP::DOWNLOAD_FILES_TO_PSA_HARDWARE)); if (m_noUpdatePsaHardware == false) { if (computeFilesToDownload() > 0) { lst.clear(); for (int i = 0; i < m_filesToDownload.size(); ++i) { lst << QFileInfo(m_filesToDownload.at(i)).fileName(); } ISMAS(lst) << (CONSOLE(lst) << UPDATE_STEP::FILES_TO_DOWNLOAD); if (m_update && m_update->doUpdate(m_displayIndex, m_filesToDownload)) { // prepared for use: at the moment, the dc-library does not work // as expected. // static const QRegularExpression re("^.*\\.json$"); // return update.checkDownloadedJsonVersions(m_filesToDownload.filter(re)); return true; } ISMAS(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::DOWNLOAD_FILES_TO_PSA_HARDWARE_FAILURE)); setProgress(_DOWNLOAD_FILES_TO_PSA_HARDWARE_FAILURE); return false; } } return true; } bool Worker::syncCustomerRepositoryAndFS() { QString msg("START"); QStringList lst(msg); ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY)); lst.clear(); if (QDir(m_customerRepository).exists()) { if (QDir::setCurrent(m_customerRepository)) { Command md("bash"); if (!md.execute(m_customerRepository, QStringList() << "-c" << "mkdir -p /etc/psa_config /etc/dc /etc/psa_tariff")) { msg = QString("COULD NOT EXECUTE '%1', exitCode=%2").arg(md.command()).arg(md.exitCode()); qCritical() << msg; QStringList lst2(msg); ISMAS(lst2) << (CONSOLE(lst2) << UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY); } QString const params("-v " "--recursive " "--progress " "--checksum " "--exclude=.* " "--include=*.bin " "--include=*.json " "--include=*.ini"); QStringList cmds; if (QDir(QDir::cleanPath(m_customerRepository + QDir::separator() + "etc/")).exists()) { cmds << QString("rsync ") + params.simplified() + " etc/ /etc"; Utils::printInfoMsg(QString("CONFIGURED SYNCING TO /ETC")); } if (QDir(QDir::cleanPath(m_customerRepository + QDir::separator() + "opt/")).exists()) { cmds << QString("rsync ") + params.simplified() + " opt/ /opt"; Utils::printInfoMsg(QString("CONFIGURED SYNCING TO /OPT")); } QString cmd; bool error = false; foreach (cmd, cmds) { if (!error) { Command c("bash"); qInfo() << "EXECUTING CMD..." << cmd; Utils::printInfoMsg(QString("EXECUTING CMD %1...").arg(cmd)); if (c.execute(m_customerRepository, QStringList() << "-c" << cmd)) { QStringList result = c.getCommandResult().split('\n'); QString const &p1 = "send_files mapped "; QString const &p2 = "of size"; for (int i = 0; i < result.size(); ++i) { QString line = result.at(i); qInfo() << line; // "send_files mapped etc/psa_tariff/tariff01.json of size 19339" int sendFilesAtPos = line.indexOf(p1); int ofSizeAtPos = line.indexOf(p2); if (sendFilesAtPos != -1 && ofSizeAtPos != -1) { sendFilesAtPos += p1.length(); QString const &s = line.mid(sendFilesAtPos, ofSizeAtPos - sendFilesAtPos).trimmed(); //m_updateStatus = UpdateStatus(UPDATE_STATUS::RSYNC_FILE_SUCCESS, // QString("RSYNC FILE ") + s.split("/").last() + // " LAST-COMMIT: " + m_gc.gitLastCommit(s)); //IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, // QString("#M=APISM#C=CMD_EVENT#J=") + // m_ismasClient.rsyncFile(m_updateStatus.m_statusDescription, "")); } } } else { Utils::printCriticalErrorMsg(QString("CMD ") + cmd + " FAILED: " + c.getCommandResult() + QString(" EXIT_CODE=(%1)").arg(c.exitCode())); error = true; } } if (!error) { lst.clear(); lst << QString("SUCCESS %1").arg(cmd); ISMAS(lst) << (CONSOLE(lst) << UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY); } else { msg = QString("FAILURE %1").arg(cmd); lst << msg; QStringList lst2(msg); ISMAS(lst2) << (CONSOLE(lst2) << UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY); } } if (!error) { // now check tariff-files in etc and /etc/psa_tariff QDir dir1(QDir::cleanPath(m_customerRepository + QDir::separator() + "etc/psa_tariff")); QDir dir2("/etc/psa_tariff"); if (Utils::sameFilesInDirs(dir1, dir2) == false) { CONSOLE() << QDir::cleanPath(m_customerRepository + QDir::separator() + "etc/psa_tariff") << "AND /etc/psa_tariff ARE DIFFERENT: CHANGED CUSTOMER-NUMBER?"; } CONSOLE() << UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY_SUCCESS; setProgress(_SYNC_CUSTOMER_REPOSITORY_SUCCESS); return true; } } else { lst << QString("CAN NOT CD TO CUST-REPO %1").arg(m_customerRepository); } } else { lst << QString("CUST-REPO %1 DOES NOT EXIST").arg(m_customerRepository); } ISMAS(lst) << (GUI(lst) << (CONSOLE(lst) << (m_lastFailedUpdateStep = UPDATE_STEP::SYNC_CUSTOMER_REPOSITORY_FAILURE))); setProgress(_SYNC_CUSTOMER_REPOSITORY_FAILURE); return false; } bool Worker::saveLogFile() { // ISMAS() << (GUI() << (CONSOLE() << UPDATE_STEP::SAVE_LOGS)); // ISMAS() << (GUI() << (CONSOLE() << UPDATE_STEP::SAVE_LOGS_FAILURE)); return true; } QString Worker::getOsVersion() const { QString const cmd = QString("echo -n $(cat /etc/os-release | head -n 1 | cut -d'\"' -f2 | tr -d '\"')"); Command c("bash"); if (c.execute(m_workingDirectory, QStringList() << "-c" << cmd)) { return c.getCommandResult(); } return "N/A"; } QString Worker::getATBUpdateToolYoctoVersion() { if (QFile::exists("/var/lib/opkg/status")) { QString const cmd = QString("echo -n $(cat /var/lib/opkg/status | grep -A1 atbupdatetool | tail -n 1 | cut -d':' -f2 | cut -d' ' -f2)"); Command c("bash"); if (c.execute("/tmp", QStringList() << "-c" << cmd)) { return c.getCommandResult(); // 1.3.9+git0+226553a8ab-r0 } } return "N/A"; } QString Worker::getAPISMYoctoVersion() { if (QFile::exists("/var/lib/opkg/status")) { QString const cmd = QString("echo -n $(cat /var/lib/opkg/status | grep -A1 -e apism[[:space:]]*$ | tail -n 1 | cut -d':' -f2 | cut -d' ' -f2)"); Command c("bash"); if (c.execute("/tmp", QStringList() << "-c" << cmd)) { return c.getCommandResult(); // 1.4.1.0-r4 } } return "N/A"; } QString Worker::getATBUpdateToolYoctoInstallationStatus() { if (QFile::exists("/var/lib/opkg/status")) { QString const cmd = QString("echo -n $(cat /var/lib/opkg/status | grep -A3 atbupdatetool | tail -n 1 | cut -d':' -f2 | cut -d' ' -f2,3,4)"); Command c("bash"); if (c.execute("/tmp", QStringList() << "-c" << cmd)) { return c.getCommandResult(); // 1.3.9+git0+226553a8ab-r0 } } return "N/A"; } QString Worker::getAPISMYoctoInstallationStatus() { if (QFile::exists("/var/lib/opkg/status")) { QString const cmd = QString("echo -n $(cat /var/lib/opkg/status | grep -A3 apism | tail -n 1 | cut -d':' -f2 | cut -d' ' -f2,3,4)"); Command c("bash"); if (c.execute("/tmp", QStringList() << "-c" << cmd)) { return c.getCommandResult(); // 1.3.9+git0+226553a8ab-r0 } } return "N/A"; } QString Worker::getDCVersionPreparedForDownload(QString const &filename) { if (QFile::exists(filename)) { // QString const cmd = QString("strings %1 | grep -e DC2[Cc]\\. | head -n1").arg(filename); Command c("bash"); if (c.execute("/tmp", QStringList() << "-c" << cmd)) { return c.getCommandResult(); // DC2c.04.42 14.09.2023 } } return "N/A"; } QString Worker::getATBQTVersion() const { QString const cmd = QString("echo -n $(/opt/app/ATBAPP/ATBQT -v | head -n 2 | cut -d':' -f2)"); Command c("bash"); if (c.execute(m_workingDirectory, QStringList() << "-c" << cmd)) { return c.getCommandResult(); } return "N/A"; } QString Worker::getATBUpdateToolVersion() const { return APP_EXTENDED_VERSION; } QString Worker::getCPUSerial() const { QString const cmd = QString("echo -n $(cat /proc/cpuinfo | grep -i Serial | cut -d':' -f2)"); Command c("bash"); if (c.execute(m_workingDirectory, QStringList() << "-c" << cmd)) { return c.getCommandResult(); } return "N/A"; } QString Worker::getRaucVersion() const { QString const cmd = QString("echo -n $(rauc --version)"); Command c("bash"); if (c.execute(m_workingDirectory, QStringList() << "-c" << cmd)) { return c.getCommandResult(); } return "N/A"; } QString Worker::getOpkgVersion() const { QString const cmd = QString("echo -n $(opkg --version)"); Command c("bash"); if (c.execute(m_workingDirectory, QStringList() << "-c" << cmd)) { return c.getCommandResult(); } return "N/A"; } QString Worker::getPluginVersion(QString const &pluginFileName) const { QString const cmd = QString("echo -n $(strings %1 | grep \\\"Version\\\" | cut -d':' -f2 | tr -d '\"' | tr -d ',')").arg(pluginFileName); Command c("bash"); if (c.execute(m_workingDirectory, QStringList() << "-c" << cmd)) { return c.getCommandResult(); } return "N/A"; } QStringList Worker::getDCVersion() const { QStringList lst = (QStringList() << "N/A" << "N/A"); #if 0 Update const *up = update(); if (up) { hwinf const *caPlugin = up->hw(); if (caPlugin) { caPlugin->dc_autoRequest(true); // turn auto-request setting on QByteArray const cmp(8, char(0)); QByteArray hw(""), sw(""); for (int i=0; i<5; ++i) { hw = caPlugin->dc_getHWversion().toUtf8(); sw = caPlugin->dc_getSWversion().toUtf8(); if (!hw.startsWith(cmp)) { lst.clear(); qInfo() << hw << sw; lst << hw << sw; break; } QThread::sleep(1); } } } #endif return lst; } qint64 Worker::getFileSize(QString const &fileName) const { // fileName has to be an absolute path QFileInfo fInfo(fileName); return fInfo.exists() ? fInfo.size() : -1; } bool Worker::executeOpkgCommand(QString opkgCommand) { Command c(opkgCommand); if (c.execute(m_workingDirectory)) { QString const r = c.getCommandResult(); Utils::printInfoMsg(QString("EXECUTE OPKG COMMAND %1 OK: %2") .arg(opkgCommand) .arg(c.getCommandResult())); return true; } else { Utils::printCriticalErrorMsg(QString("EXECUTE OPKG COMMAND %1 FAILED") .arg(opkgCommand)); } return false; } PSAInstalled Worker::getPSAInstalled() { QStringList const dcVersion = getDCVersion(); QString const deviceControllerVersionHW = dcVersion.first(); QString const deviceControllerVersionSW = dcVersion.last(); qInfo() << "CURRENT DC-HW-VERSION: " << deviceControllerVersionHW; qInfo() << "CURRENT DC-SW-VERSION: " << deviceControllerVersionSW; QString const deviceControllerGitBlob = "N/A"; QString const deviceControllerGitLastCommit = "N/A"; PSAInstalled psaInstalled; QString printSysDir("/etc/psa_config"); QString tariffSysDir("/etc/psa_tariff"); QString tariffRepoDir("etc/psa_tariff"); QString opkgRepoDir("etc/psa_update"); QString const &absPathNameRepositoryOpkg = QDir::cleanPath(opkgRepoDir + QDir::separator() + "opkg_commands"); QString absPathName; QString absPathNameRepository; psaInstalled.versionInfo.lastCommit = "N/A"; psaInstalled.versionInfo.reason = "N/A"; psaInstalled.versionInfo.created = "N/A"; if (m_versionInfo.size() == 3) { QString const &lastCommit = m_versionInfo.at(0); QString reason = m_versionInfo.at(1); QDateTime const dt = QDateTime::fromString(m_versionInfo.at(2), Qt::ISODate); QString version{""}; QString date{""}; if (dt.isValid()) { date += " "; date += dt.date().toString(Qt::ISODate); } static const QRegularExpression re("^\\s*(\\d+)\\.(\\d+)\\.(\\d+)(.*$)"); QRegularExpressionMatch match = re.match(reason); if (match.hasMatch()) { int const lastCapturedIndex = match.lastCapturedIndex(); if (lastCapturedIndex >= 1) { version += " v"; version += match.captured(1); // major } if (lastCapturedIndex >= 2) { version += "."; version += match.captured(2); // minor } if (lastCapturedIndex >= 3) { version += "."; version += match.captured(3); // patch } if (lastCapturedIndex >= 4) { // rest after version reason = match.captured(4); } } psaInstalled.versionInfo.lastCommit = QString("%1%2").arg(lastCommit).arg(version); psaInstalled.versionInfo.reason = reason; psaInstalled.versionInfo.created = m_versionInfo.at(2); } //qCritical() << ""; //qCritical() << "VERSION-INFO"; //qCritical() << "LAST-COMMIT" << psaInstalled.versionInfo.lastCommit; //qCritical() << "REASON" << psaInstalled.versionInfo.reason; //qCritical() << "CREATED" << psaInstalled.versionInfo.created; //qCritical() << ""; if (m_zoneNr != 0) { QString const &n = QString("%1").arg(m_zoneNr).rightJustified(2, '0'); psaInstalled.tariff.name = QString("tariff%1.json").arg(n); absPathName = QDir::cleanPath(tariffSysDir + QDir::separator() + psaInstalled.tariff.name); psaInstalled.tariff.blob = m_gc.gitBlob(absPathName); absPathNameRepository = QDir::cleanPath(tariffRepoDir + QDir::separator() + psaInstalled.tariff.name); psaInstalled.tariff.lastCommit = m_gc.gitLastCommit(absPathNameRepository); psaInstalled.tariff.size = getFileSize(absPathName); psaInstalled.tariff.zone = m_zoneNr; psaInstalled.tariff.loadTime = Utils::getTariffLoadTime(absPathName); psaInstalled.tariff.project = Utils::getLocation(absPathName); psaInstalled.tariff.version = Utils::getTariffVersion(absPathName); psaInstalled.tariff.info = Utils::getTariffInfo(absPathName); } psaInstalled.hw.linuxVersion = getOsVersion(); psaInstalled.hw.cpuSerial = m_cpuSerial; psaInstalled.opkg.blob = m_gc.gitBlob(absPathNameRepositoryOpkg); // psaInstalled.opkg.size = getFileSize(absPathNameRepositoryOpkg); // psaInstalled.opkg.loadTime = Utils::getTariffLoadTime(absPathNameRepositoryOpkg); psaInstalled.opkg.lastCommit = m_gc.gitLastCommit(absPathNameRepositoryOpkg); psaInstalled.dc.versionHW = deviceControllerVersionHW; psaInstalled.dc.versionSW = deviceControllerVersionSW; psaInstalled.dc.gitBlob = "N/A"; psaInstalled.dc.gitLastCommit = "N/A"; psaInstalled.dc.size = -1; psaInstalled.sw.apismVersion = getAPISMYoctoVersion(); psaInstalled.sw.atbQTVersion = getATBQTVersion(); psaInstalled.sw.atbUpdateToolVersion = m_atbUpdateToolVersion; psaInstalled.pluginVersion.deviceController = m_pluginVersionATBDeciceController; psaInstalled.pluginVersion.ingenicoISelfCC = m_pluginVersionIngenicoISelf; psaInstalled.pluginVersion.mobilisisCalculatePrice = m_pluginVersionMobilisisCalc; psaInstalled.pluginVersion.mobilisisCalculatePriceConfigUi = m_pluginVersionMobilisisCalcConfig; psaInstalled.pluginVersion.prmCalculatePrice = m_pluginVersionPrmCalc; psaInstalled.pluginVersion.prmCalculatePriceConfigUi = m_pluginVersionPrmCalcConfig; psaInstalled.pluginVersion.tcpZVT = m_pluginVersionTcpZvt; // key: conf-json-filename; value: installed version on DC QMap map; if (m_update) { map = m_update->getInstalledJsonVersions(); } psaInstalled.cash.name = "DC2C_cash.json"; absPathName = QDir::cleanPath(printSysDir + QDir::separator() + psaInstalled.cash.name); psaInstalled.cash.blob = m_gc.gitBlob(absPathName); psaInstalled.cash.size = getFileSize(absPathName); if (map.contains("DC2C_cash.json")) { psaInstalled.cash.blob = map.value("DC2C_cash.json", "inst.vers.not.avail"); } psaInstalled.conf.name = "DC2C_conf.json"; absPathName = QDir::cleanPath(printSysDir + QDir::separator() + psaInstalled.conf.name); psaInstalled.conf.blob = m_gc.gitBlob(absPathName); psaInstalled.conf.size = getFileSize(absPathName); if (map.contains("DC2C_conf.json")) { psaInstalled.conf.blob = map.value("DC2C_conf.json", "inst.vers.not.avail"); } psaInstalled.device.name = "DC2C_device.json"; absPathName = QDir::cleanPath(printSysDir + QDir::separator() + psaInstalled.device.name); psaInstalled.device.blob = m_gc.gitBlob(absPathName); psaInstalled.device.size = getFileSize(absPathName); if (map.contains("DC2C_device.json")) { psaInstalled.device.blob = map.value("DC2C_device.json", "inst.vers.not.avail"); } for (int i=0; i < 32; ++i) { QString const &n = QString("%1").arg(i+1).rightJustified(2, '0'); psaInstalled.print[i].name = QString("DC2C_print%1.json").arg(n); absPathName = QDir::cleanPath(printSysDir + QDir::separator() + psaInstalled.print[i].name); psaInstalled.print[i].blob = m_gc.gitBlob(absPathName); psaInstalled.print[i].size = getFileSize(absPathName); if (map.contains(psaInstalled.print[i].name)) { psaInstalled.print[i].blob = map.value(psaInstalled.print[i].name, "inst.vers.not.avail"); } } psaInstalled.ptuPackageVersion = "{}"; if (QFile::exists("/usr/bin/ptuPackageVersions")) { Command c("/usr/bin/ptuPackageVersions -i -o json"); if (c.execute(m_workingDirectory)) { QString r = c.getCommandResult(); // ptuPackageVersions returns a json-array QJsonArray const &ja = QJsonDocument::fromJson(r.remove(QRegExp("\\n")).toUtf8()).array(); if (!ja.empty()) { // transform the array into an object, containing the objects // of the array (christian needs it this way) QJsonObject o; foreach (QJsonValue const &value, ja) { if (value.isObject()) { QJsonObject obj = value.toObject(); QStringList keys = obj.keys(); if (!keys.isEmpty()) { QString const &k = obj.keys().first(); QJsonValue const &v = obj.value(k); o.insert(k, v); } } } psaInstalled.ptuPackageVersion = QJsonDocument(o).toJson(QJsonDocument::Compact); } else { qCritical() << __func__ << ":" << __LINE__ << "ERROR array return by ptuPackageVersions empty"; } } else { qCritical() << __func__ << ":" << __LINE__ << "ERROR executing ptuPackageVersions"; } } return psaInstalled; } bool Worker::dcUpdate() { return m_dcDownloadFirmware->start("/opt/app/tools/atbupdate"); } void Worker::summary() { QString summary, first, second, line, tmp; QVector> vec = Utils::installedPackages(); int max_first = 0, max_second = 0; for (int i = 0; i < vec.size(); ++i) { max_first = std::max(max_first, vec[i].first.length()); max_second = std::max(max_second, vec[i].second.length()); } max_first += 5; summary = "UPDATE SUMMARY\n\n"; first = QString("%1").arg("start", max_first, QChar(' ')); tmp = QString("%1").arg(start().toString(Qt::ISODate)); second = QString("%1").arg(tmp, -max_second, QChar(' ')); line = first + ": " + second; summary += line + "\n"; first = QString("%1").arg("update tool version", max_first, QChar(' ')); tmp = QString("%1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME); second = QString("%1").arg(tmp, -max_second, QChar(' ')); line = first + ": " + second; summary += line + "\n"; first = QString("%1").arg("machine number", max_first, QChar(' ')); tmp = QString("%1").arg(machineNr()); second = QString("%1").arg(tmp, -max_second, QChar(' ')); line = first + ": " + second; summary += line + "\n"; first = QString("%1").arg("customer number", max_first, QChar(' ')); tmp = QString("%1").arg(customerNr()); second = QString("%1").arg(tmp, -max_second, QChar(' ')); line = first + ": " + second; summary += line + "\n"; first = QString("%1").arg("zone number", max_first, QChar(' ')); tmp = QString("%1").arg(zoneNr()); second = QString("%1").arg(tmp, -max_second, QChar(' ')); line = first + ": " + second; summary += line + "\n"; if (m_mainWindow) { tmp = m_mainWindow->targetDcVersion(); if (!tmp.isEmpty()) { first = QString("%1").arg("target device controller", max_first, QChar(' ')); second = QString("%1").arg(tmp, -max_second, QChar(' ')); line = first + ": " + second; summary += line + "\n"; } } first = QString("%1").arg("apism", max_first, QChar(' ')); tmp = QString("%1").arg(apismVersion()); second = QString("%1").arg(tmp, -max_second, QChar(' ')); line = first + ": " + second; summary += line + "\n"; for (int i = 0; i < vec.size(); ++i) { first = QString("%1").arg(vec[i].first, max_first, QChar(' ')); second = QString("%1").arg(vec[i].second, -max_second, QChar(' ')); line = first + ": " + second; summary += line + "\n"; } emit showSummary(summary); }