#ifndef LIBREPOMGR_BUILD_ACTION_H #define LIBREPOMGR_BUILD_ACTION_H #include "./buildactionfwd.h" #include "./buildactionmeta.h" #include "./subprocessfwd.h" #include "../webapi/routes.h" #include "../../libpkg/data/config.h" #include "../../libpkg/data/lockable.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class BuildActionsTests; namespace LibRepoMgr { struct LogContext { explicit LogContext(BuildAction *buildAction = nullptr); LogContext &operator=(const LogContext &) = delete; template LogContext &operator()(CppUtilities::EscapeCodes::Phrases phrase, Args &&...args); template LogContext &operator()(Args &&...args); template LogContext &operator()(std::string &&msg); private: BuildAction *const m_buildAction; }; inline LogContext::LogContext(BuildAction *buildAction) : m_buildAction(buildAction) { } struct ServiceSetup; namespace WebAPI { struct Params; class Session; } // namespace WebAPI struct InternalBuildAction; struct LIBREPOMGR_EXPORT PackageBuildData : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { std::string existingVersion; std::vector> existingPackages; std::string sourceDirectory; std::string originalSourceDirectory; std::shared_ptr sourceInfo; std::vector> packages; std::vector warnings; std::string error; std::size_t specifiedIndex = std::numeric_limits::max(); bool hasSource = false; }; struct LIBREPOMGR_EXPORT BuildPreparation : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { std::unordered_map buildData; std::vector>> dbConfig, stagingDbConfig; std::string targetDb, targetArch, stagingDb; std::vector> batches; std::vector cyclicLeftovers; std::vector warnings; std::string error; bool manuallyOrdered = false; }; enum class PackageStagingNeeded { Undetermined, Yes, No, }; struct LIBREPOMGR_EXPORT PackageBuildProgress : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { bool hasBeenAnyProgressMade() const; void reset(); CppUtilities::DateTime started; CppUtilities::DateTime finished; std::string buildDirectory; std::string chrootDirectory; std::string chrootUser; std::vector makechrootpkgFlags; std::vector makepkgFlags; std::string packageExtension; std::vector warnings; std::string error; std::string updatedVersion; PackageStagingNeeded stagingNeeded = PackageStagingNeeded::Undetermined; bool skipChrootUpgrade = false; bool skipChrootCleanup = false; bool keepPreviousSourceTree = false; bool checksumsUpdated = false; bool hasSources = false; bool addedToRepo = false; }; struct LIBREPOMGR_EXPORT RebuildInfo : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { std::vector provides; std::vector libprovides; void add(const LibPkg::DependencySet &deps, const std::unordered_set &libs); }; using RebuildInfoByPackage = std::unordered_map; using RebuildInfoByDatabase = std::unordered_map; struct LIBREPOMGR_EXPORT BuildProgress : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { std::unordered_map progressByPackage; std::string targetDbFilePath; std::string targetRepoPath; std::string stagingDbFilePath; std::string stagingRepoPath; RebuildInfoByPackage producedProvides, removedProvides; RebuildInfoByDatabase rebuildList; }; struct LIBREPOMGR_EXPORT PackageMovementResult : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { std::vector> failedPackages; std::vector processedPackages; std::string errorMessage; }; struct LIBREPOMGR_EXPORT RepositoryProblem : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { std::variant desc; std::string pkg; bool critical = true; }; struct LIBREPOMGR_EXPORT BuildActionMessages : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { std::vector notes; std::vector warnings; std::vector errors; }; class BuildProcessSession; struct OutputBufferingForSession; struct ServiceSetup; struct LIBREPOMGR_EXPORT BuildAction : public std::enable_shared_from_this, public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { friend InternalBuildAction; friend ServiceSetup; friend BuildProcessSession; friend BuildActionsTests; friend void WebAPI::Routes::postBuildAction(const WebAPI::Params ¶ms, WebAPI::ResponseHandler &&handler); friend void WebAPI::Routes::postBuildActionsFromTask(const WebAPI::Params ¶ms, WebAPI::ResponseHandler &&handler, const std::string &taskName, const std::string &directory, const std::vector &startAfterIds, bool startImmediately); friend void WebAPI::Routes::deleteBuildActions(const WebAPI::Params ¶ms, WebAPI::ResponseHandler &&handler); friend void WebAPI::Routes::postCloneBuildActions(const WebAPI::Params ¶ms, WebAPI::ResponseHandler &&handler); public: using IdType = BuildActionIdType; static constexpr IdType invalidId = std::numeric_limits::max(); explicit BuildAction(IdType id = invalidId, ServiceSetup *setup = nullptr) noexcept; ~BuildAction(); bool isScheduled() const; bool isExecuting() const; bool isDone() const; bool hasSucceeded() const; static bool haveSucceeded(const std::vector> &buildActions); bool isAborted() const; void start(ServiceSetup &setup); void startAfterOtherBuildActions(ServiceSetup &setup, const std::vector> &startsAfterBuildActions); void abort(); void appendOutput(std::string &&output); void appendOutput(std::string_view output); template void appendOutput(Args &&...args); template void appendOutput(CppUtilities::EscapeCodes::Phrases phrase, Args &&...args); LogContext &log(); void setStopHandler(std::function &&stopHandler); void setConcludeHandler(std::function &&concludeHandler); std::shared_ptr findBuildProcess(const std::string &filePath); std::shared_ptr makeBuildProcess(std::string &&displayName, std::string &&logFilePath, ProcessHandler &&handler); void terminateOngoingBuildProcesses(); void streamFile(const WebAPI::Params ¶ms, const std::string &filePath, std::string_view fileMimeType); void streamOutput(const WebAPI::Params ¶ms, std::size_t offset = 0); protected: private: template void post(); template void post(Callback &&codeToRun); void conclude(BuildActionResult result); void continueStreamingExistingOutputToSession(std::shared_ptr session, OutputBufferingForSession &buffering, const boost::system::error_code &error, std::size_t bytesTransferred); void continueStreamingNewOutputToSession(std::shared_ptr session, OutputBufferingForSession &buffering, const boost::system::error_code &error, std::size_t bytesTransferred); template void appendOutput(OutputType &&output); public: IdType id; std::string taskName; std::string templateName; std::string directory; std::vector packageNames; std::vector sourceDbs, destinationDbs; std::vector extraParams; // deprecated; remove at some point std::unordered_map settings; BuildActionFlagType flags = noBuildActionFlags; BuildActionType type = BuildActionType::Invalid; // only the following member variables are supposed to change after the build action has been added // to the overall list of build actions BuildActionStatus status = BuildActionStatus::Created; BuildActionResult result = BuildActionResult::None; std::variant, LibPkg::LicenseResult, LibPkg::PackageUpdates, BuildPreparation, BuildProgress, PackageMovementResult, std::unordered_map>, BuildActionMessages> resultData; std::string output; std::string outputMimeType = "text/plain"; std::vector logfiles; std::vector artefacts; CppUtilities::DateTime created = CppUtilities::DateTime::gmtNow(); CppUtilities::DateTime started; CppUtilities::DateTime finished; std::vector startAfter; private: LogContext m_log; ServiceSetup *m_setup = nullptr; std::atomic_bool m_aborted = false; std::function m_stopHandler; std::function m_concludeHandler; std::mutex m_processesMutex; std::unordered_map> m_ongoingProcesses; std::mutex m_outputStreamingMutex; std::unordered_map, std::unique_ptr> m_bufferingForSession; std::unique_ptr m_internalBuildAction; std::vector> m_followUpActions; }; inline bool BuildAction::isScheduled() const { return status == BuildActionStatus::Created || status == BuildActionStatus::AwaitingConfirmation; } inline bool BuildAction::isExecuting() const { return status == BuildActionStatus::Enqueued || status == BuildActionStatus::Running; } inline bool BuildAction::isDone() const { return status == BuildActionStatus::Finished; } inline bool BuildAction::hasSucceeded() const { return isDone() && result == BuildActionResult::Success; } inline bool BuildAction::isAborted() const { return m_aborted.load(); } inline LogContext &BuildAction::log() { return m_log; } inline void BuildAction::setStopHandler(std::function &&stopHandler) { m_stopHandler = std::move(stopHandler); } inline void BuildAction::setConcludeHandler(std::function &&concludeHandler) { m_concludeHandler = std::move(concludeHandler); } inline std::shared_ptr BuildAction::findBuildProcess(const std::string &filePath) { const auto i = m_ongoingProcesses.find(filePath); return i != m_ongoingProcesses.cend() ? i->second : nullptr; } /*! * \brief Appends the specified arguments to the build action's log but *not* to the overall service log. */ template inline void BuildAction::appendOutput(Args &&...args) { appendOutput(CppUtilities::argsToString(std::forward(args)...)); } /*! * \brief Appends the specified arguments to the build action's log and to the overall service log. */ template inline void BuildAction::appendOutput(CppUtilities::EscapeCodes::Phrases phrase, Args &&...args) { auto msg = CppUtilities::argsToString(CppUtilities::EscapeCodes::formattedPhraseString(phrase), std::forward(args)...); std::cerr << msg; appendOutput(std::move(msg)); } struct LIBREPOMGR_EXPORT BuildActionBasicInfo : public ReflectiveRapidJSON::JsonSerializable { explicit BuildActionBasicInfo(const BuildAction &buildAction) : id(buildAction.id) , taskName(buildAction.taskName) , directory(buildAction.directory) , packageNames(buildAction.packageNames) , sourceDbs(buildAction.sourceDbs) , destinationDbs(buildAction.destinationDbs) , startAfter(buildAction.startAfter) , settings(buildAction.settings) , flags(buildAction.flags) , type(buildAction.type) , status(buildAction.status) , result(buildAction.result) , created(buildAction.created) , started(buildAction.started) , finished(buildAction.finished) { } const BuildAction::IdType id; const std::string &taskName; const std::string &directory; const std::vector &packageNames; const std::vector &sourceDbs, &destinationDbs; const std::vector &startAfter; const std::unordered_map settings; const BuildActionFlagType flags = noBuildActionFlags; const BuildActionType type; const BuildActionStatus status; const BuildActionResult result; const CppUtilities::DateTime created; const CppUtilities::DateTime started; const CppUtilities::DateTime finished; }; } // namespace LibRepoMgr #endif // LIBREPOMGR_BUILD_ACTION_H