/* * executepage.cc - Implementation of the UI.Perform page * horizon-run-qt5, the Qt 5 executor user interface for * Project Horizon * * Copyright (c) 2019 Adélie Linux and contributors. All rights reserved. * This code is licensed under the AGPL 3.0 license, as noted in the * LICENSE-code file in the root directory of this repository. * * SPDX-License-Identifier: AGPL-3.0-only */ #include "executepage.hh" #include "executorwizard.hh" #include #include #include #include #include ExecutePage::ExecutePage(QWidget *parent) : HorizonWizardPage(parent) { setTitle(tr("Installing Adélie Linux…")); loadWatermark("intro"); failed = false; progress = new StepProgressWidget; progress->addStep(tr("Prepare installation")); progress->addStep(tr("Validate installation")); progress->addStep(tr("Configure hard disk(s)")); progress->addStep(tr("Initial configuration")); progress->addStep(tr("Networking configuration")); progress->addStep(tr("Install software")); progress->addStep(tr("Final configuration")); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(progress); mainLayout->addStretch(); setLayout(mainLayout); finishTimer = new QTimer(this); finishTimer->setInterval(5000); finishTimer->setSingleShot(true); connect(finishTimer, &QTimer::timeout, [=]{ wizard()->next(); }); log.setFileName("/var/log/horizon/executor.log"); Q_ASSERT(log.open(QFile::Append)); this->current = Prepare; markRunning(this->current); executor = new QProcess(this); executor->setProgram("../../tools/hscript-simulate/hscript-simulate"); executor->setArguments({"/etc/horizon/installfile"}); connect(executor, &QProcess::readyReadStandardError, this, &ExecutePage::executorReady); connect(executor, &QProcess::readyReadStandardOutput, this, &ExecutePage::executorOutReady); connect(executor, QOverload::of(&QProcess::finished), this, &ExecutePage::executorFinished); executor->start(); } ExecutePage::Phase ExecutePage::stepToPhase(QString step) { if(step == "validate") return Validate; if(step == "disk") return Disk; if(step == "pre-metadata") return PreMeta; if(step == "net") return Net; if(step == "pkgdb") return Pkg; if(step == "post-metadata") return PostMeta; Q_ASSERT(false); return Prepare; } void ExecutePage::markRunning(Phase phase) { progress->setStepStatus(phase, StepProgressWidget::InProgress); } void ExecutePage::markFinished(Phase phase) { progress->setStepStatus(phase, StepProgressWidget::Finished); } void ExecutePage::markFailed(Phase phase) { progress->setStepStatus(phase, StepProgressWidget::Failed); failed = true; } void ExecutePage::executorReady() { QByteArray msgs = executor->readAllStandardError(); log.write(msgs); QStringList msgList = QString::fromUtf8(msgs).split("\n"); for(auto &msg : msgList) { QString msgType = msg.section('\t', 1, 1); if(msgType == "step-start") { this->current = stepToPhase(msg.section('\t', 2)); /* validate means prepare is done */ if(this->current == Validate) markFinished(Prepare); markRunning(this->current); } else if(msgType == "step-end") { Q_ASSERT(stepToPhase(msg.section('\t', 2)) == this->current); markFinished(this->current); } else if(msgType == "log") { QString severity = msg.section(": ", 1, 1); if(severity == "error") { markFailed(this->current); } } else { /* !? */ } } } void ExecutePage::executorOutReady() { log.write(executor->readAllStandardOutput()); } void ExecutePage::executorFinished(int code, QProcess::ExitStatus status) { if(status != QProcess::NormalExit || code != 0) { markFailed(this->current); } wizard()->button(QWizard::CancelButton)->setEnabled(false); finishTimer->start(); } int ExecutePage::nextId() const { if(failed) { return ExecutorWizard::Page_Error; } return ExecutorWizard::Page_Finished; }