2022-02-22 22:49:40 +01:00
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
#include "./buildactionprivate.h"
|
|
|
|
|
|
|
|
#include "../webapi/session.h"
|
|
|
|
|
|
|
|
#include <reflective_rapidjson/binary/reflector-chronoutilities.h>
|
|
|
|
#include <reflective_rapidjson/json/reflector-chronoutilities.h>
|
|
|
|
|
|
|
|
#include "reflection/buildaction.h"
|
|
|
|
|
|
|
|
#include <boost/asio/post.hpp>
|
|
|
|
|
|
|
|
#ifdef LIBREPOMGR_DUMMY_BUILD_ACTION_ENABLED
|
|
|
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
|
|
#include <c++utilities/io/misc.h>
|
|
|
|
#include <c++utilities/tests/testutils.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace CppUtilities;
|
|
|
|
using namespace CppUtilities::EscapeCodes;
|
|
|
|
|
|
|
|
namespace LibRepoMgr {
|
|
|
|
|
|
|
|
InternalBuildAction::InternalBuildAction(ServiceSetup &setup, const std::shared_ptr<BuildAction> &buildAction)
|
|
|
|
: m_setup(setup)
|
|
|
|
, m_buildAction(buildAction)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isAur(const std::string &dbName)
|
|
|
|
{
|
|
|
|
return dbName == "aur" || dbName == "AUR";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string InternalBuildAction::validateParameter(RequiredDatabases requiredDatabases, RequiredParameters requiredParameters)
|
|
|
|
{
|
|
|
|
if (requiredDatabases & RequiredDatabases::OneOrMoreSources) {
|
|
|
|
if (m_buildAction->sourceDbs.empty()) {
|
|
|
|
return "no source databases specified";
|
|
|
|
}
|
|
|
|
} else if (requiredDatabases & RequiredDatabases::OneSource) {
|
|
|
|
if (m_buildAction->sourceDbs.size() != 1) {
|
|
|
|
return "not exactly one source database specified";
|
|
|
|
}
|
|
|
|
} else if (!(requiredDatabases & RequiredDatabases::MaybeSource)) {
|
|
|
|
if (!m_buildAction->sourceDbs.empty()) {
|
|
|
|
return "no source database must be specified";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (requiredDatabases & RequiredDatabases::OneOrMoreDestinations) {
|
|
|
|
if (m_buildAction->destinationDbs.empty()) {
|
|
|
|
return "no destination databases specified";
|
|
|
|
}
|
|
|
|
} else if (requiredDatabases & RequiredDatabases::OneDestination) {
|
|
|
|
if (m_buildAction->destinationDbs.size() != 1) {
|
|
|
|
return "not exactly one destination database specified";
|
|
|
|
}
|
|
|
|
} else if (!(requiredDatabases & RequiredDatabases::MaybeDestination)) {
|
|
|
|
if (!m_buildAction->destinationDbs.empty()) {
|
|
|
|
return "no destination database must be specified";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (const auto &sourceDb : m_buildAction->sourceDbs) {
|
|
|
|
if (sourceDb.empty() || sourceDb == "none") {
|
|
|
|
return "empty/invalid source database specified";
|
|
|
|
}
|
|
|
|
if (isAur(sourceDb)) {
|
|
|
|
if (requiredDatabases & RequiredDatabases::AllowFromAur) {
|
|
|
|
m_fromAur = true;
|
|
|
|
} else {
|
|
|
|
return "source database must not be AUR";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (const auto &destinationDb : m_buildAction->destinationDbs) {
|
|
|
|
if (destinationDb.empty() || destinationDb == "none") {
|
|
|
|
return "empty/invalid destination database specified";
|
|
|
|
}
|
|
|
|
if (isAur(destinationDb)) {
|
|
|
|
if (requiredDatabases & RequiredDatabases::AllowToAur) {
|
|
|
|
m_toAur = true;
|
|
|
|
} else {
|
|
|
|
return "destination database must not be AUR";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (requiredParameters & RequiredParameters::Packages) {
|
|
|
|
if (m_buildAction->packageNames.empty()) {
|
|
|
|
return "no packages specified";
|
|
|
|
}
|
|
|
|
} else if (!(requiredParameters & RequiredParameters::MaybePackages)) {
|
|
|
|
if (!m_buildAction->packageNames.empty()) {
|
|
|
|
return "no packages must be specified";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return string();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string InternalBuildAction::findDatabases()
|
|
|
|
{
|
|
|
|
m_sourceDbs.clear();
|
|
|
|
m_destinationDbs.clear();
|
|
|
|
for (const auto &sourceDb : m_buildAction->sourceDbs) {
|
|
|
|
if (isAur(sourceDb)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (auto *const db = m_setup.config.findDatabaseFromDenotation(sourceDb)) {
|
|
|
|
m_sourceDbs.emplace(db);
|
|
|
|
} else {
|
|
|
|
return "source database " % sourceDb + " does not exist";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (const auto &destinationDb : m_buildAction->destinationDbs) {
|
|
|
|
if (isAur(destinationDb)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (auto *const db = m_setup.config.findDatabaseFromDenotation(destinationDb)) {
|
|
|
|
m_destinationDbs.emplace(db);
|
|
|
|
} else {
|
|
|
|
return "destination database " % destinationDb + " does not exist";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return string();
|
|
|
|
}
|
|
|
|
|
|
|
|
typename InternalBuildAction::InitReturnType InternalBuildAction::init(
|
|
|
|
BuildActionAccess access, RequiredDatabases requiredDatabases, RequiredParameters requiredParameters)
|
|
|
|
{
|
|
|
|
InitReturnType configLock;
|
|
|
|
if (auto error = validateParameter(requiredDatabases, requiredParameters); !error.empty()) {
|
|
|
|
reportError(move(error));
|
|
|
|
return configLock;
|
|
|
|
}
|
|
|
|
switch (access) {
|
|
|
|
case BuildActionAccess::ReadConfig:
|
|
|
|
configLock = m_setup.config.lockToRead();
|
|
|
|
break;
|
|
|
|
case BuildActionAccess::WriteConfig:
|
|
|
|
configLock = m_setup.config.lockToWrite();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (auto error = findDatabases(); !error.empty()) {
|
|
|
|
configLock = monostate();
|
|
|
|
reportError(move(error));
|
|
|
|
return configLock;
|
|
|
|
}
|
|
|
|
return configLock;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string InternalBuildAction::determineWorkingDirectory(std::string_view name)
|
|
|
|
{
|
|
|
|
const auto workingDirectory = m_setup.building.workingDirectory % '/' % name % '/' + m_buildAction->directory;
|
|
|
|
m_buildAction->appendOutput(Phrases::InfoMessage, "Working directory: " % workingDirectory + '\n');
|
|
|
|
return workingDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string &InternalBuildAction::findSetting(const std::string_view &setting) const
|
|
|
|
{
|
|
|
|
if (const auto i = m_buildAction->settings.find(std::string(setting)); i != m_buildAction->settings.end()) {
|
|
|
|
return i->second;
|
|
|
|
} else {
|
|
|
|
static const auto empty = std::string();
|
|
|
|
return empty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalBuildAction::reportError(std::string &&error)
|
|
|
|
{
|
|
|
|
const auto buildActionLock = m_setup.building.lockToWrite();
|
2022-02-22 22:49:40 +01:00
|
|
|
m_buildAction->resultData = std::move(error);
|
2021-01-25 00:24:31 +01:00
|
|
|
m_buildAction->conclude(BuildActionResult::Failure);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalBuildAction::reportError()
|
|
|
|
{
|
|
|
|
m_buildAction->conclude(BuildActionResult::Failure);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalBuildAction::reportSuccess()
|
|
|
|
{
|
|
|
|
m_buildAction->conclude(BuildActionResult::Success);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalBuildAction::reportResult(BuildActionResult result)
|
|
|
|
{
|
|
|
|
m_buildAction->conclude(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InternalBuildAction::reportAbortedIfAborted()
|
|
|
|
{
|
|
|
|
if (!m_buildAction->isAborted()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto buildActionLock = m_setup.building.lockToWrite();
|
|
|
|
m_buildAction->conclude(BuildActionResult::Aborted);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
BuildAction::BuildAction(IdType id, ServiceSetup *setup) noexcept
|
|
|
|
: id(id)
|
|
|
|
, m_log(this)
|
|
|
|
, m_setup(setup)
|
|
|
|
, m_stopHandler(std::bind(&BuildAction::terminateOngoingBuildProcesses, this))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-02-05 22:09:52 +01:00
|
|
|
BuildAction &BuildAction::operator=(BuildAction &&other)
|
|
|
|
{
|
|
|
|
if (this == &other) {
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
id = other.id;
|
|
|
|
taskName = std::move(other.taskName);
|
|
|
|
templateName = std::move(other.templateName);
|
|
|
|
directory = std::move(other.directory);
|
|
|
|
packageNames = std::move(other.packageNames);
|
|
|
|
sourceDbs = std::move(other.sourceDbs);
|
|
|
|
destinationDbs = std::move(other.destinationDbs);
|
|
|
|
settings = std::move(other.settings);
|
|
|
|
flags = other.flags;
|
|
|
|
type = other.type;
|
|
|
|
status = other.status;
|
|
|
|
result = other.result;
|
|
|
|
resultData = std::move(other.resultData);
|
|
|
|
logfiles = std::move(other.logfiles);
|
|
|
|
artefacts = std::move(other.artefacts);
|
|
|
|
created = other.created;
|
|
|
|
started = other.started;
|
|
|
|
finished = other.finished;
|
|
|
|
startAfter = std::move(other.startAfter);
|
2022-02-22 22:49:40 +01:00
|
|
|
m_log = LogContext(this);
|
2022-02-05 22:09:52 +01:00
|
|
|
m_setup = other.m_setup;
|
|
|
|
m_aborted = false;
|
2022-02-22 22:49:40 +01:00
|
|
|
m_stopHandler = std::bind(&BuildAction::terminateOngoingBuildProcesses, this);
|
2022-02-05 22:09:52 +01:00
|
|
|
m_concludeHandler = std::function<void(void)>();
|
|
|
|
m_ongoingProcesses.clear();
|
2022-02-19 21:26:56 +01:00
|
|
|
m_outputSession.reset();
|
2022-02-05 22:09:52 +01:00
|
|
|
m_internalBuildAction = std::move(other.m_internalBuildAction);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
BuildAction::~BuildAction()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BuildAction::haveSucceeded(const std::vector<std::shared_ptr<BuildAction>> &buildActions)
|
|
|
|
{
|
|
|
|
for (const auto &buildAction : buildActions) {
|
|
|
|
if (!buildAction->hasSucceeded()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2021-04-04 22:20:47 +02:00
|
|
|
* \brief Starts the build action. The caller must acquire the lock to write build actions if
|
|
|
|
* the build action is setup-globally visible.
|
2021-01-25 00:24:31 +01:00
|
|
|
* \returns Returns immediately. The real work is done in a build action thread.
|
|
|
|
*/
|
2022-02-05 22:09:52 +01:00
|
|
|
LibPkg::StorageID BuildAction::start(ServiceSetup &setup)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
|
|
|
if (!isScheduled()) {
|
2022-02-05 22:09:52 +01:00
|
|
|
return 0;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
started = DateTime::gmtNow();
|
|
|
|
status = BuildActionStatus::Running;
|
|
|
|
m_setup = &setup;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case BuildActionType::Invalid:
|
|
|
|
resultData = "type is invalid";
|
2022-02-05 22:09:52 +01:00
|
|
|
return conclude(BuildActionResult::Failure);
|
2021-01-25 00:24:31 +01:00
|
|
|
case BuildActionType::RemovePackages:
|
|
|
|
post<RemovePackages>();
|
|
|
|
break;
|
|
|
|
case BuildActionType::MovePackages:
|
|
|
|
post<MovePackages>();
|
|
|
|
break;
|
|
|
|
case BuildActionType::CheckForUpdates:
|
|
|
|
post<UpdateCheck>();
|
|
|
|
break;
|
|
|
|
case BuildActionType::ReloadDatabase:
|
|
|
|
post<ReloadDatabase>();
|
|
|
|
break;
|
|
|
|
case BuildActionType::ReloadLibraryDependencies:
|
|
|
|
post<ReloadLibraryDependencies>();
|
|
|
|
break;
|
|
|
|
case BuildActionType::PrepareBuild:
|
|
|
|
post<PrepareBuild>();
|
|
|
|
break;
|
|
|
|
case BuildActionType::ConductBuild:
|
|
|
|
post<ConductBuild>();
|
|
|
|
break;
|
|
|
|
case BuildActionType::MakeLicenseInfo:
|
|
|
|
post<MakeLicenseInfo>();
|
|
|
|
break;
|
|
|
|
case BuildActionType::ReloadConfiguration:
|
|
|
|
post<ReloadConfiguration>();
|
|
|
|
break;
|
|
|
|
case BuildActionType::CheckForProblems:
|
|
|
|
post<CheckForProblems>();
|
|
|
|
break;
|
|
|
|
case BuildActionType::CleanRepository:
|
|
|
|
post<CleanRepository>();
|
|
|
|
break;
|
|
|
|
#ifdef LIBREPOMGR_DUMMY_BUILD_ACTION_ENABLED
|
|
|
|
case BuildActionType::DummyBuildAction:
|
|
|
|
post<DummyBuildAction>();
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case BuildActionType::CustomCommand:
|
|
|
|
post<CustomCommand>();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
resultData = "not implemented yet or invalid type";
|
2022-02-05 22:09:52 +01:00
|
|
|
return conclude(BuildActionResult::Failure);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
2022-02-05 22:09:52 +01:00
|
|
|
// update in persistent storage and create entry in "running cache"
|
|
|
|
return m_setup->building.storeBuildAction(shared_from_this());
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
2021-04-04 22:20:47 +02:00
|
|
|
void BuildAction::assignStartAfter(const std::vector<std::shared_ptr<BuildAction>> &startsAfterBuildActions)
|
|
|
|
{
|
|
|
|
for (auto &previousBuildAction : startsAfterBuildActions) {
|
|
|
|
startAfter.emplace_back(previousBuildAction->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
void BuildAction::abort()
|
|
|
|
{
|
|
|
|
m_aborted.store(true);
|
|
|
|
if (m_setup && m_stopHandler) {
|
|
|
|
boost::asio::post(m_setup->building.ioContext.get_executor(), m_stopHandler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename InternalBuildActionType> void BuildAction::post()
|
|
|
|
{
|
|
|
|
assert(m_setup);
|
|
|
|
m_internalBuildAction = make_unique<InternalBuildActionType>(*m_setup, shared_from_this());
|
|
|
|
post(bind(&InternalBuildActionType::run, static_cast<InternalBuildActionType *>(m_internalBuildAction.get())));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Callback> void BuildAction::post(Callback &&codeToRun)
|
|
|
|
{
|
|
|
|
assert(m_setup);
|
|
|
|
boost::asio::post(m_setup->building.ioContext.get_executor(), forward<Callback>(codeToRun));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Internally called to conclude the build action.
|
|
|
|
*/
|
2022-02-05 22:09:52 +01:00
|
|
|
LibPkg::StorageID BuildAction::conclude(BuildActionResult result)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
|
|
|
// set fields accordingly
|
|
|
|
status = BuildActionStatus::Finished;
|
|
|
|
this->result = result;
|
|
|
|
finished = DateTime::gmtNow();
|
|
|
|
|
2021-04-04 22:20:47 +02:00
|
|
|
// start globally visible follow-up actions if succeeded
|
2021-01-25 00:24:31 +01:00
|
|
|
if (result == BuildActionResult::Success && m_setup) {
|
2022-02-05 22:09:52 +01:00
|
|
|
const auto followUps = m_setup->building.followUpBuildActions(id);
|
|
|
|
for (auto &followUpAction : followUps) {
|
|
|
|
if (followUpAction->isScheduled() && BuildAction::haveSucceeded(m_setup->building.getBuildActions(followUpAction->startAfter))) {
|
2021-01-25 00:24:31 +01:00
|
|
|
followUpAction->start(*m_setup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// note: Not cleaning up the follow-up actions here because at some point I might implement recursive restarting.
|
|
|
|
}
|
|
|
|
|
2022-03-01 00:43:06 +01:00
|
|
|
// detach build process sessions
|
2022-02-22 22:49:40 +01:00
|
|
|
if (const auto lock = std::unique_lock(m_outputSessionMutex); m_outputSession) {
|
|
|
|
m_outputSession->writeEnd(); // tell clients waiting for output that it's over
|
|
|
|
m_outputSession.reset();
|
|
|
|
}
|
|
|
|
if (const auto lock = std::unique_lock(m_processesMutex)) {
|
|
|
|
m_ongoingProcesses.clear();
|
|
|
|
}
|
|
|
|
|
2022-02-05 22:09:52 +01:00
|
|
|
// write build action to persistent storage
|
|
|
|
// TODO: should this also be done in the middle of the execution to have some "save points"?
|
|
|
|
auto id = LibPkg::StorageID();
|
|
|
|
if (m_setup && m_setup->building.hasStorage()) {
|
|
|
|
id = m_setup->building.storeBuildAction(shared_from_this());
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
if (m_concludeHandler) {
|
|
|
|
m_concludeHandler();
|
|
|
|
}
|
2022-02-05 22:09:52 +01:00
|
|
|
return id;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef LIBREPOMGR_DUMMY_BUILD_ACTION_ENABLED
|
|
|
|
DummyBuildAction::DummyBuildAction(ServiceSetup &setup, const std::shared_ptr<BuildAction> &buildAction)
|
|
|
|
: InternalBuildAction(setup, buildAction)
|
|
|
|
, m_counter(0)
|
|
|
|
, m_timer(setup.building.ioContext)
|
|
|
|
{
|
|
|
|
m_buildAction->setStopHandler(std::bind(&DummyBuildAction::stop, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void DummyBuildAction::run()
|
|
|
|
{
|
|
|
|
// validate parameter
|
|
|
|
if (auto error = validateParameter(RequiredDatabases::None, RequiredParameters::None); !error.empty()) {
|
|
|
|
reportError(move(error));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (m_buildAction->directory.empty()) {
|
|
|
|
reportError("Unable to find working directory: no directory name specified");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find test files
|
|
|
|
auto testApp = TestApplication();
|
|
|
|
auto scriptPath = std::string();
|
|
|
|
try {
|
|
|
|
scriptPath = testFilePath("scripts/print_some_data.sh");
|
|
|
|
} catch (const std::exception &e) {
|
|
|
|
reportError(e.what());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create working directory
|
|
|
|
m_workingDirectory = "dummy/" + m_buildAction->directory;
|
|
|
|
try {
|
|
|
|
std::filesystem::create_directories(m_workingDirectory);
|
|
|
|
} catch (const std::filesystem::filesystem_error &e) {
|
|
|
|
reportError(argsToString("Unable to make working directory: ", e.what()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add an artefact
|
|
|
|
auto buildActionsWriteLock = m_setup.building.lockToWrite();
|
|
|
|
m_buildAction->artefacts.emplace_back(m_workingDirectory + "/some-artefact.txt");
|
|
|
|
buildActionsWriteLock.unlock();
|
|
|
|
try {
|
|
|
|
writeFile(m_buildAction->artefacts.back(), "artefact contents\n");
|
|
|
|
} catch (const std::ios_base::failure &e) {
|
|
|
|
reportError(argsToString("Unable to make artefact: ", e.what()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// launch subprocess producing a logfile
|
2021-01-25 19:02:51 +01:00
|
|
|
m_logProcess
|
|
|
|
= m_buildAction->makeBuildProcess("dummy", m_workingDirectory + "/foo.log", [this](boost::process::child &&child, ProcessResult &&result) {
|
|
|
|
CPP_UTILITIES_UNUSED(child)
|
|
|
|
m_logProcess = nullptr;
|
|
|
|
m_buildAction->appendOutput("log process exited with code: ", result.exitCode, '\n');
|
|
|
|
if (!result.error.empty()) {
|
|
|
|
m_buildAction->appendOutput("log process error: ", result.error, '\n');
|
|
|
|
}
|
|
|
|
if (!m_buildAction->isAborted()) {
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
});
|
2021-01-25 00:24:31 +01:00
|
|
|
m_logProcess->launch(scriptPath, "1");
|
|
|
|
|
|
|
|
continuePrinting();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DummyBuildAction::continuePrinting()
|
|
|
|
{
|
|
|
|
m_timer.expires_from_now(boost::posix_time::seconds(1));
|
|
|
|
m_timer.async_wait(std::bind(&DummyBuildAction::printLine, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void DummyBuildAction::printLine()
|
|
|
|
{
|
|
|
|
if (m_buildAction->isAborted()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_buildAction->appendOutput("Output: ", ++m_counter, '\n');
|
|
|
|
continuePrinting();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DummyBuildAction::stop()
|
|
|
|
{
|
|
|
|
m_buildAction->appendOutput("stopping"sv);
|
|
|
|
boost::system::error_code timerCancelError;
|
|
|
|
m_timer.cancel(timerCancelError);
|
|
|
|
if (timerCancelError.failed()) {
|
|
|
|
m_buildAction->appendOutput("failed to cancel timer: ", timerCancelError.message(), '\n');
|
|
|
|
}
|
|
|
|
std::error_code terminateError;
|
|
|
|
if (m_logProcess) {
|
|
|
|
m_logProcess->group.terminate(terminateError);
|
|
|
|
if (terminateError) {
|
|
|
|
m_buildAction->appendOutput("failed to terminate logging process: ", terminateError.message(), '\n');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
reportSuccess();
|
|
|
|
}
|
|
|
|
#endif // LIBREPOMGR_DUMMY_BUILD_ACTION_ENABLED
|
|
|
|
|
|
|
|
} // namespace LibRepoMgr
|