Allow specifying build tasks with more complicated build actions
The new data structures (e.g. concurrent flag) aren't actually used yet.
This commit is contained in:
parent
fdf40aa917
commit
7f0ec081c6
|
@ -10,3 +10,61 @@ using namespace CppUtilities;
|
|||
namespace LibRepoMgr {
|
||||
|
||||
} // namespace LibRepoMgr
|
||||
|
||||
namespace ReflectiveRapidJSON {
|
||||
namespace JsonReflector {
|
||||
|
||||
template <>
|
||||
LIBREPOMGR_EXPORT void push<LibRepoMgr::BuildActionSequence>(
|
||||
const LibRepoMgr::BuildActionSequence &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
||||
{
|
||||
if (reflectable.name.empty() && !reflectable.concurrent) {
|
||||
push(reflectable.actions, value, allocator);
|
||||
} else {
|
||||
push(static_cast<const LibRepoMgr::BuildActionSequenceData &>(reflectable), value, allocator);
|
||||
push(static_cast<const LibRepoMgr::BuildActionSequenceNodes &>(reflectable), value, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
LIBREPOMGR_EXPORT void pull<LibRepoMgr::BuildActionSequence>(LibRepoMgr::BuildActionSequence &reflectable,
|
||||
const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
|
||||
{
|
||||
if (value.IsArray()) {
|
||||
reflectable.name.clear();
|
||||
reflectable.concurrent = false;
|
||||
pull(reflectable.actions, value, errors);
|
||||
} else if (value.IsObject()) {
|
||||
pull(static_cast<LibRepoMgr::BuildActionSequenceData &>(reflectable), value, errors);
|
||||
pull(static_cast<LibRepoMgr::BuildActionSequenceNodes &>(reflectable), value, errors);
|
||||
} else if (errors) {
|
||||
errors->reportTypeMismatch<LibRepoMgr::BuildActionSequence>(value.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
LIBREPOMGR_EXPORT void push<LibRepoMgr::BuildActionSequenceNode>(const LibRepoMgr::BuildActionSequenceNode &reflectable,
|
||||
RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
||||
{
|
||||
if (const auto *const name = std::get_if<std::string>(&reflectable)) {
|
||||
push(*name, value, allocator);
|
||||
} else if (const auto *const sequence = std::get_if<LibRepoMgr::BuildActionSequence>(&reflectable)) {
|
||||
push(*sequence, value, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
LIBREPOMGR_EXPORT void pull<LibRepoMgr::BuildActionSequenceNode>(LibRepoMgr::BuildActionSequenceNode &reflectable,
|
||||
const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
|
||||
{
|
||||
if (value.IsString()) {
|
||||
auto &name = reflectable.emplace<std::string>();
|
||||
pull(name, value, errors);
|
||||
} else {
|
||||
auto &sequence = reflectable.emplace<LibRepoMgr::BuildActionSequence>();
|
||||
pull(sequence, value, errors);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace JsonReflector
|
||||
} // namespace ReflectiveRapidJSON
|
||||
|
|
|
@ -21,11 +21,22 @@ struct LIBREPOMGR_EXPORT BuildActionTemplate : public ReflectiveRapidJSON::JsonS
|
|||
CppUtilities::TimeSpan maxFrequency = CppUtilities::TimeSpan::infinity();
|
||||
};
|
||||
|
||||
struct LIBREPOMGR_EXPORT BuildTask : public ReflectiveRapidJSON::JsonSerializable<BuildTask> {
|
||||
struct BuildActionSequenceNode;
|
||||
struct LIBREPOMGR_EXPORT BuildActionSequenceData : public ReflectiveRapidJSON::JsonSerializable<BuildActionSequenceData> {
|
||||
std::string name;
|
||||
bool concurrent = false;
|
||||
};
|
||||
struct LIBREPOMGR_EXPORT BuildActionSequenceNodes : public ReflectiveRapidJSON::JsonSerializable<BuildActionSequenceData> {
|
||||
std::vector<BuildActionSequenceNode> actions;
|
||||
};
|
||||
struct LIBREPOMGR_EXPORT BuildActionSequence : public BuildActionSequenceData, public BuildActionSequenceNodes {
|
||||
};
|
||||
struct LIBREPOMGR_EXPORT BuildActionSequenceNode : public std::variant<std::string, BuildActionSequence> {
|
||||
};
|
||||
|
||||
struct LIBREPOMGR_EXPORT BuildTask : public BuildActionSequence, public ReflectiveRapidJSON::JsonSerializable<BuildTask> {
|
||||
std::string desc;
|
||||
std::string category;
|
||||
std::vector<std::string> actions;
|
||||
CppUtilities::TimeSpan frequency = CppUtilities::TimeSpan::infinity();
|
||||
};
|
||||
|
||||
|
@ -36,4 +47,26 @@ struct LIBREPOMGR_EXPORT BuildPresets : public ReflectiveRapidJSON::JsonSerializ
|
|||
|
||||
} // namespace LibRepoMgr
|
||||
|
||||
namespace ReflectiveRapidJSON {
|
||||
namespace JsonReflector {
|
||||
|
||||
// declare custom (de)serialization for BuildActionSequence
|
||||
template <>
|
||||
LIBREPOMGR_EXPORT void push<LibRepoMgr::BuildActionSequence>(
|
||||
const LibRepoMgr::BuildActionSequence &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
|
||||
template <>
|
||||
LIBREPOMGR_EXPORT void pull<LibRepoMgr::BuildActionSequence>(LibRepoMgr::BuildActionSequence &reflectable,
|
||||
const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
|
||||
|
||||
// declare custom (de)serialization for BuildActionSequenceNode
|
||||
template <>
|
||||
LIBREPOMGR_EXPORT void push<LibRepoMgr::BuildActionSequenceNode>(const LibRepoMgr::BuildActionSequenceNode &reflectable,
|
||||
RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
|
||||
template <>
|
||||
LIBREPOMGR_EXPORT void pull<LibRepoMgr::BuildActionSequenceNode>(LibRepoMgr::BuildActionSequenceNode &reflectable,
|
||||
const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
|
||||
|
||||
} // namespace JsonReflector
|
||||
} // namespace ReflectiveRapidJSON
|
||||
|
||||
#endif // LIBREPOMGR_BUILD_ACTION_TEMPLATE_H
|
||||
|
|
|
@ -136,13 +136,13 @@ void ServiceSetup::BuildSetup::readPresets(const std::string &configFilePath, co
|
|||
errors.throwOn = ReflectiveRapidJSON::JsonDeserializationErrors::ThrowOn::All;
|
||||
presets = BuildPresets::fromJson(readFile(presetsFilePath), &errors);
|
||||
} catch (const ReflectiveRapidJSON::JsonDeserializationError &e) {
|
||||
cerr << Phrases::ErrorMessage << "Unable to deserialize presets file " << presetsFilePath << Phrases::SubMessage
|
||||
<< ReflectiveRapidJSON::formatJsonDeserializationError(e) << Phrases::End;
|
||||
cerr << Phrases::ErrorMessage << "Unable to deserialize presets file " << presetsFilePath << '\n'
|
||||
<< Phrases::SubMessage << ReflectiveRapidJSON::formatJsonDeserializationError(e) << Phrases::End;
|
||||
} catch (const RAPIDJSON_NAMESPACE::ParseResult &e) {
|
||||
cerr << Phrases::ErrorMessage << "Unable to parse presets file " << presetsFilePath << Phrases::SubMessage << "parse error at " << e.Offset()
|
||||
<< ": " << RAPIDJSON_NAMESPACE::GetParseError_En(e.Code()) << Phrases::End;
|
||||
cerr << Phrases::ErrorMessage << "Unable to parse presets file " << presetsFilePath << '\n'
|
||||
<< Phrases::SubMessage << "parse error at " << e.Offset() << ": " << RAPIDJSON_NAMESPACE::GetParseError_En(e.Code()) << Phrases::End;
|
||||
} catch (const std::runtime_error &e) {
|
||||
cerr << Phrases::ErrorMessage << "Unable to read presets file " << presetsFilePath << Phrases::SubMessage << e.what() << Phrases::End;
|
||||
cerr << Phrases::ErrorMessage << "Unable to read presets file " << presetsFilePath << '\n' << Phrases::SubMessage << e.what() << Phrases::End;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -653,6 +653,53 @@ void postBuildAction(const Params ¶ms, ResponseHandler &&handler)
|
|||
handler(makeJson(params.request(), response));
|
||||
}
|
||||
|
||||
static std::string allocateNewBuildAction(const BuildActionMetaInfo &metaInfo, const std::string &taskName,
|
||||
const std::vector<std::string> &packageNames, const std::string &directory,
|
||||
const std::unordered_map<std::string, BuildActionTemplate> &actionTemplates, std::vector<std::shared_ptr<BuildAction>> &newBuildActions,
|
||||
const std::string &actionName)
|
||||
{
|
||||
const auto actionTemplateIterator = actionTemplates.find(actionName);
|
||||
if (actionTemplateIterator == actionTemplates.end()) {
|
||||
return "the action \"" % actionName + "\" of the specified task is not configured";
|
||||
}
|
||||
const auto &actionTemplate = actionTemplateIterator->second;
|
||||
const auto buildActionType = actionTemplate.type;
|
||||
if (!metaInfo.isTypeIdValid(buildActionType)) {
|
||||
return argsToString(
|
||||
"the type \"", static_cast<std::size_t>(buildActionType), "\" of action \"", actionName, "\" of the specified task is invalid");
|
||||
}
|
||||
const auto &typeInfo = metaInfo.typeInfoForId(actionTemplate.type);
|
||||
auto &buildAction = newBuildActions.emplace_back(std::make_shared<BuildAction>()); // a real ID is set later
|
||||
buildAction->taskName = taskName;
|
||||
buildAction->directory = !typeInfo.directory || directory.empty() ? actionTemplate.directory : directory;
|
||||
buildAction->type = buildActionType;
|
||||
buildAction->sourceDbs = actionTemplate.sourceDbs;
|
||||
buildAction->destinationDbs = actionTemplate.destinationDbs;
|
||||
buildAction->packageNames = !typeInfo.packageNames || packageNames.empty() ? actionTemplate.packageNames : packageNames;
|
||||
buildAction->flags = actionTemplate.flags;
|
||||
buildAction->settings = actionTemplate.settings;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
static std::string allocateNewBuildActionSequence(const BuildActionMetaInfo &metaInfo, const std::string &taskName,
|
||||
const std::vector<std::string> &packageNames, const std::string &directory,
|
||||
const std::unordered_map<std::string, BuildActionTemplate> &actionTemplates, std::vector<std::shared_ptr<BuildAction>> &newBuildActions,
|
||||
const BuildActionSequence &actionSequence)
|
||||
{
|
||||
auto error = std::string();
|
||||
for (const auto &actionNode : actionSequence.actions) {
|
||||
if (const auto *const actionName = std::get_if<std::string>(&actionNode)) {
|
||||
error = allocateNewBuildAction(metaInfo, taskName, packageNames, directory, actionTemplates, newBuildActions, *actionName);
|
||||
} else if (const auto *const actionSequence = std::get_if<BuildActionSequence>(&actionNode)) {
|
||||
error = allocateNewBuildActionSequence(metaInfo, taskName, packageNames, directory, actionTemplates, newBuildActions, *actionSequence);
|
||||
}
|
||||
if (!error.empty()) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
void postBuildActionsFromTask(const Params ¶ms, ResponseHandler &&handler, const std::string &taskName, const std::string &directory,
|
||||
const std::vector<BuildActionIdType> &startAfterIds, bool startImmediately)
|
||||
{
|
||||
|
@ -681,7 +728,6 @@ void postBuildActionsFromTask(const Params ¶ms, ResponseHandler &&handler, c
|
|||
return;
|
||||
}
|
||||
const auto &task = taskIterator->second;
|
||||
const auto &actionsToCreate = task.actions;
|
||||
const auto &actionTemplates = presets.templates;
|
||||
if (task.actions.empty()) {
|
||||
setupLock.unlock();
|
||||
|
@ -691,43 +737,18 @@ void postBuildActionsFromTask(const Params ¶ms, ResponseHandler &&handler, c
|
|||
|
||||
// allocate a vector to store build actions (temporarily) in
|
||||
auto newBuildActions = std::vector<std::shared_ptr<BuildAction>>();
|
||||
newBuildActions.reserve(actionsToCreate.size());
|
||||
newBuildActions.reserve(task.actions.size());
|
||||
|
||||
// copy data from templates into new build actions
|
||||
auto &metaInfo = params.setup.building.metaInfo;
|
||||
auto metaInfoLock = metaInfo.lockToRead();
|
||||
for (const auto &actionName : actionsToCreate) {
|
||||
const auto actionTemplateIterator = actionTemplates.find(actionName);
|
||||
if (actionTemplateIterator == actionTemplates.end()) {
|
||||
metaInfoLock.unlock();
|
||||
auto errorMessage = "the action \"" % actionName + "\" of the specified task is not configured";
|
||||
setupLock.unlock();
|
||||
handler(makeBadRequest(params.request(), std::move(errorMessage)));
|
||||
return;
|
||||
}
|
||||
const auto &actionTemplate = actionTemplateIterator->second;
|
||||
const auto buildActionType = actionTemplate.type;
|
||||
if (!metaInfo.isTypeIdValid(buildActionType)) {
|
||||
metaInfoLock.unlock();
|
||||
auto errorMessage = argsToString(
|
||||
"the type \"", static_cast<std::size_t>(buildActionType), "\" of action \"", actionName, "\" of the specified task is invalid");
|
||||
setupLock.unlock();
|
||||
handler(makeBadRequest(params.request(), std::move(errorMessage)));
|
||||
return;
|
||||
}
|
||||
const auto &typeInfo = metaInfo.typeInfoForId(actionTemplate.type);
|
||||
auto &buildAction = newBuildActions.emplace_back(std::make_shared<BuildAction>()); // a real ID is set later
|
||||
buildAction->taskName = taskName;
|
||||
buildAction->directory = !typeInfo.directory || directory.empty() ? actionTemplate.directory : directory;
|
||||
buildAction->type = buildActionType;
|
||||
buildAction->sourceDbs = actionTemplate.sourceDbs;
|
||||
buildAction->destinationDbs = actionTemplate.destinationDbs;
|
||||
buildAction->packageNames = !typeInfo.packageNames || packageNames.empty() ? actionTemplate.packageNames : packageNames;
|
||||
buildAction->flags = actionTemplate.flags;
|
||||
buildAction->settings = actionTemplate.settings;
|
||||
}
|
||||
auto error = allocateNewBuildActionSequence(metaInfo, taskName, packageNames, directory, actionTemplates, newBuildActions, task);
|
||||
metaInfoLock.unlock();
|
||||
setupLock.unlock();
|
||||
if (!error.empty()) {
|
||||
handler(makeBadRequest(params.request(), std::move(error)));
|
||||
return;
|
||||
}
|
||||
|
||||
// allocate build action IDs and populate "start after ID"
|
||||
BuildAction *lastBuildAction = nullptr;
|
||||
|
|
Loading…
Reference in New Issue