#include "Project.hpp" #include "Model/Workflow/Workflow.hpp" #include "Utils/Macros.hpp" #include #include #include #include #include #include #include namespace fs = std::filesystem; template void ReadItemList(ItemList& list, const fs::path& filePath) { std::ifstream ifs(filePath); if (ifs) { Json::Value root; ifs >> root; list = ItemList(root); } } Project::Project(const fs::path& rootPath) : mRootPath{ rootPath } , mRootPathString{ mRootPath.string() } , Database(*this) { // TODO better diagnostic const char* kInvalidFormatErr = "Failed to load project: invalid format."; std::ifstream ifs(rootPath / "cplt_project.json"); if (!ifs) { std::string message; message += "Failed to load project file at '"; message += rootPath.string(); message += "'."; throw std::runtime_error(message); } { Json::Value root; ifs >> root; const auto& croot = root; // Use const reference so that accessors default to returning a null if not found, instead of silently creating new elements if (!croot.isObject()) { throw std::runtime_error(kInvalidFormatErr); } if (auto& name = croot["Name"]; name.isString()) { mName = name.asString(); } else { throw std::runtime_error(kInvalidFormatErr); } } auto itemsDir = mRootPath / "items"; ReadItemList(Products, itemsDir / "products.json"); ReadItemList(Factories, itemsDir / "factories.json"); ReadItemList(Customers, itemsDir / "customers.json"); auto workflowsDir = mRootPath / "workflows"; fs::create_directories(workflowsDir); for (auto& entry : fs::directory_iterator(workflowsDir)) { if (!entry.is_regular_file()) continue; auto& path = entry.path(); if (path.extension() != ".cplt-workflow") continue; auto name = path.stem().string(); auto [it, DISCARD] = mWorkflows.insert(name, WorkflowInfo{}); auto& info = it.value(); info.Name = std::move(name); info.PathStringCache = path.string(); info.Path = path; } } Project::Project(std::filesystem::path rootPath, std::string name) : mRootPath{ std::move(rootPath) } , mRootPathString{ mRootPath.string() } , mName{ std::move(name) } , Database(*this) { } const fs::path& Project::GetPath() const { return mRootPath; } const std::string& Project::GetPathString() const { return mRootPathString; } const std::string& Project::GetName() const { return mName; } void Project::SetName(std::string name) { mName = std::move(name); } const decltype(Project::mWorkflows)& Project::GetWorkflows() const { return mWorkflows; } std::unique_ptr Project::LoadWorkflow(std::string_view name) { auto iter = mWorkflows.find(name); if (iter == mWorkflows.end()) { return iter.value().LoadFromDisk(); } else { return nullptr; } } std::unique_ptr Project::CreateWorkflow(std::string_view name) { if (mWorkflows.find(name) != mWorkflows.end()) { // Workflow with name already exists return nullptr; } auto workflow = std::make_unique(); auto [it, DISCARD] = mWorkflows.insert(name, WorkflowInfo{}); auto& info = it.value(); info.Name = name; info.Path = GetWorkflowPath(name); return workflow; } bool Project::RemoveWorkflow(std::string_view name) { auto iter = mWorkflows.find(name); if (iter == mWorkflows.end()) { return false; } auto& info = iter.value(); fs::remove(info.Path); mWorkflows.erase(iter); return true; } bool Project::RenameWorkflow(std::string_view name, std::string_view newName) { auto iter = mWorkflows.find(name); if (iter == mWorkflows.end()) return false; auto info = std::move(iter.value()); auto& oldPath = info.Path; auto newPath = GetWorkflowPath(newName); fs::rename(oldPath, newPath); info.Path = std::move(newPath); mWorkflows.insert(newName, std::move(info)); mWorkflows.erase(iter); return true; } Json::Value Project::Serialize() { Json::Value root(Json::objectValue); root["Name"] = mName; return root; } template static void WriteItemList(ItemList& list, const fs::path& filePath) { std::ofstream ofs(filePath); ofs << list.Serialize(); } void Project::WriteToDisk() { std::ofstream ofs(mRootPath / "cplt_project.json"); ofs << this->Serialize(); auto itemsDir = mRootPath / "items"; fs::create_directories(itemsDir); WriteItemList(Products, itemsDir / "products.json"); WriteItemList(Factories, itemsDir / "factories.json"); WriteItemList(Customers, itemsDir / "customers.json"); } std::filesystem::path Project::GetDatabasesDirectory() const { return mRootPath / "databases"; } std::filesystem::path Project::GetItemsDirectory() const { return mRootPath / "items"; } std::filesystem::path Project::GetWorkflowsDirectory() const { return mRootPath / "workflows"; } std::filesystem::path Project::GetWorkflowPath(std::string_view name) const { return (mRootPath / "workflows" / name).concat(".cplt-workflow"); }