libraries directory

This commit is contained in:
Blue 2023-09-29 18:09:09 -03:00
parent 2b913d1d42
commit 0fa8ba6918
Signed by: blue
GPG Key ID: 9B203B252A63EE38
7 changed files with 268 additions and 75 deletions

View File

@ -5,6 +5,7 @@ constexpr std::string_view downloads("downloads");
static const std::regex remote("(^https?):\\/\\/"); static const std::regex remote("(^https?):\\/\\/");
Collection::Collection( Collection::Collection(
const std::filesystem::path& location,
const std::filesystem::path& destination, const std::filesystem::path& destination,
const std::string& target, const std::string& target,
const std::shared_ptr<Logger>& logger, const std::shared_ptr<Logger>& logger,
@ -16,8 +17,11 @@ Collection::Collection(
destination(destination), destination(destination),
target(target), target(target),
taskManager(taskManager), taskManager(taskManager),
root(std::make_unique<Component>(location, shared_from_this(), logger)),
librariesPath(),
knownSources(), knownSources(),
successSources(), successSources(),
pendingSources(),
downloadingSources(), downloadingSources(),
readingSources(), readingSources(),
buildingSources() buildingSources()
@ -29,16 +33,52 @@ Collection::Collection(
throw e; throw e;
} }
root->read();
if (root->successfullyRead())
throw std::runtime_error("Error reading project in " + location.string());
if (root->getType() != Component::mason)
throw std::runtime_error("Project in " + location.string() + " doesn't seem to be a valid mason project");
librariesPath = root->getLibrariesPath();
std::lock_guard lock(mutex);
while (pendingSources.size() > 0) {
std::string source = pendingSources.front();
pendingSources.pop();
processSource(source);
}
taskManager->queue(
std::bind(&Component::build, root.get(), destination, target),
std::bind(&Collection::rootBuilt, this, std::placeholders::_1)
);
} }
void Collection::addSource(const std::string& source) { void Collection::addSource(const std::string& source) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if (_hasSource(source)) { std::pair<Sources::const_iterator, bool> result = knownSources.emplace(source);
if (!result.second) {
major("Source " + source + " is already present, skipping as duplicate"); major("Source " + source + " is already present, skipping as duplicate");
return; return;
} }
debug("Adding source " + source); debug("Adding source " + source);
switch (root->getState()) {
case Component::initial:
case Component::reading:
pendingSources.emplace(source);
break;
case Component::ready:
case Component::building:
case Component::done:
processSource(source);
case Component::error:
throw std::runtime_error("Project in " + root->getLocation().string() + " doesn't seem to be a valid mason project");
}
}
void Collection::processSource(const std::string& source) {
if (isRemote(source)) if (isRemote(source))
queueDownload(source); queueDownload(source);
else else
@ -62,7 +102,6 @@ void Collection::sourceDownaloded(const std::string& source, TaskManager::Error
void Collection::sourceRead(const std::string& source, TaskManager::Error err) { void Collection::sourceRead(const std::string& source, TaskManager::Error err) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
debug("Source " + source + " has been read");
Components::iterator itr = readingSources.find(source); Components::iterator itr = readingSources.find(source);
if (err.has_value()) { if (err.has_value()) {
error("Coundn't read " + source + ": " + err.value()->what()); error("Coundn't read " + source + ": " + err.value()->what());
@ -70,12 +109,18 @@ void Collection::sourceRead(const std::string& source, TaskManager::Error err) {
return; return;
} }
debug("Queuing build of " + source); if (itr->second->successfullyRead()) {
error("Source " + source + " had an error during read process, canceling build of this component");
readingSources.erase(itr);
return;
}
debug("Source " + source + " has been read, scheduling build");
std::pair<Components::iterator, bool> res = buildingSources.emplace(source, std::move(itr->second)); std::pair<Components::iterator, bool> res = buildingSources.emplace(source, std::move(itr->second));
readingSources.erase(itr); readingSources.erase(itr);
taskManager->queue( taskManager->queue(
std::bind(&Component::build, res.first->second.get(), destination, target), std::bind(&Component::build, res.first->second.get(), destination/librariesPath, target),
std::bind(&Collection::sourceBuilt, this, source, std::placeholders::_1) std::bind(&Collection::sourceBuilt, this, source, std::placeholders::_1)
); );
} }
@ -93,12 +138,16 @@ void Collection::sourceBuilt(const std::string& source, TaskManager::Error err)
successSources.emplace(source); successSources.emplace(source);
} }
void Collection::rootBuilt(TaskManager::Error err) {
}
bool Collection::isRemote(const std::string& source) { bool Collection::isRemote(const std::string& source) {
return std::regex_search(source, remote); return std::regex_search(source, remote);
} }
void Collection::queueDownload(const std::string& source) { void Collection::queueDownload(const std::string& source) {
debug("Queuing download of " + source); debug("Scheduling download of " + source);
std::pair<Downloads::iterator, bool> res = downloadingSources.emplace(std::piecewise_construct, std::pair<Downloads::iterator, bool> res = downloadingSources.emplace(std::piecewise_construct,
std::forward_as_tuple(source), std::forward_as_tuple(source),
std::forward_as_tuple( std::forward_as_tuple(
@ -113,7 +162,7 @@ void Collection::queueDownload(const std::string& source) {
} }
void Collection::queueRead(const std::string& source, const std::filesystem::path& location) { void Collection::queueRead(const std::string& source, const std::filesystem::path& location) {
debug("Queuing read of " + source); debug("Scheduling read of " + source);
std::pair<Components::iterator, bool> res = readingSources.emplace(std::piecewise_construct, std::pair<Components::iterator, bool> res = readingSources.emplace(std::piecewise_construct,
std::forward_as_tuple(source), std::forward_as_tuple(source),
std::forward_as_tuple( std::forward_as_tuple(
@ -132,6 +181,42 @@ bool Collection::hasSource(const std::string& source) const {
return _hasSource(source); return _hasSource(source);
} }
unsigned int Collection::sourcesTotal() const {
std::lock_guard lock(mutex);
return _sourcesTotal();
}
unsigned int Collection::sourcesSuccess() const {
std::lock_guard lock(mutex);
return _sourcesSuccess();
}
unsigned int Collection::sourcesPending() const {
std::lock_guard lock(mutex);
return _sourcesPending();
}
unsigned int Collection::sourcesError() const {
std::lock_guard lock(mutex);
return _sourcesError();
}
bool Collection::_hasSource(const std::string& source) const { bool Collection::_hasSource(const std::string& source) const {
return knownSources.count(source) > 0; return knownSources.count(source) > 0;
} }
unsigned int Collection::_sourcesTotal() const {
return knownSources.size();
}
unsigned int Collection::_sourcesSuccess() const {
return successSources.size();
}
unsigned int Collection::_sourcesPending() const {
return downloadingSources.size() + readingSources.size() + buildingSources.size() + pendingSources.size();
}
unsigned int Collection::_sourcesError() const {
return _sourcesTotal() - _sourcesPending() - _sourcesSuccess();
}

View File

@ -8,6 +8,7 @@
#include <string_view> #include <string_view>
#include <regex> #include <regex>
#include <mutex> #include <mutex>
#include <queue>
#include "loggable.h" #include "loggable.h"
#include "component.h" #include "component.h"
@ -16,11 +17,13 @@
class Collection : protected Loggable, public std::enable_shared_from_this<Collection> { class Collection : protected Loggable, public std::enable_shared_from_this<Collection> {
using Sources = std::set<std::string>; using Sources = std::set<std::string>;
using SourcesQueue = std::queue<std::string>;
using Downloads = std::map<std::string, std::unique_ptr<Download>>; using Downloads = std::map<std::string, std::unique_ptr<Download>>;
using Components = std::map<std::string, std::unique_ptr<Component>>; using Components = std::map<std::string, std::unique_ptr<Component>>;
public: public:
Collection( Collection(
const std::filesystem::path& location,
const std::filesystem::path& destination, const std::filesystem::path& destination,
const std::string& target, const std::string& target,
const std::shared_ptr<Logger>& logger, const std::shared_ptr<Logger>& logger,
@ -39,21 +42,30 @@ private:
void sourceDownaloded(const std::string& source, TaskManager::Error err); void sourceDownaloded(const std::string& source, TaskManager::Error err);
void sourceRead(const std::string& source, TaskManager::Error err); void sourceRead(const std::string& source, TaskManager::Error err);
void sourceBuilt(const std::string& source, TaskManager::Error err); void sourceBuilt(const std::string& source, TaskManager::Error err);
void rootBuilt(TaskManager::Error err);
static bool isRemote(const std::string& source); static bool isRemote(const std::string& source);
void processSource(const std::string& source);
void queueDownload(const std::string& source); void queueDownload(const std::string& source);
void queueRead(const std::string& source, const std::filesystem::path& location); void queueRead(const std::string& source, const std::filesystem::path& location);
bool _hasSource(const std::string& source) const; bool _hasSource(const std::string& source) const;
unsigned int _sourcesTotal() const;
unsigned int _sourcesPending() const;
unsigned int _sourcesError() const;
unsigned int _sourcesSuccess() const;
private: private:
mutable std::mutex mutex; mutable std::mutex mutex;
std::filesystem::path destination; std::filesystem::path destination;
std::string target; std::string target;
std::shared_ptr<TaskManager> taskManager; std::shared_ptr<TaskManager> taskManager;
std::unique_ptr<Component> root;
std::string librariesPath;
Sources knownSources; Sources knownSources;
Sources successSources; Sources successSources;
SourcesQueue pendingSources;
Downloads downloadingSources; Downloads downloadingSources;
Components readingSources; Components readingSources;
Components buildingSources; Components buildingSources;

View File

@ -13,6 +13,13 @@ constexpr std::array<std::string_view, Component::done + 1> stringStates {
"done" "done"
}; };
constexpr std::array<std::string_view, Component::unknown + 1> stringTypes {
"file",
"directory",
"mason",
"unknown"
};
Component::Component( Component::Component(
const std::filesystem::path& path, const std::filesystem::path& path,
const std::weak_ptr<Collection>& collection, const std::weak_ptr<Collection>& collection,
@ -23,7 +30,7 @@ Component::Component(
type(unknown), type(unknown),
collection(collection), collection(collection),
location(path), location(path),
scenario(std::nullopt) manifest(std::nullopt)
{} {}
void Component::read() { void Component::read() {
@ -56,29 +63,42 @@ void Component::tryReadingBuildScenarios() {
} }
bool Component::readAsMason() { bool Component::readAsMason() {
std::filesystem::path masonScenarion = location/masonJSON; std::filesystem::path masonManifest = location/masonJSON;
try { try {
std::ifstream file(masonScenarion); std::ifstream file(masonManifest);
if (file.is_open()) if (file.is_open())
scenario = nlohmann::json::parse(file); manifest = nlohmann::json::parse(file);
else else
minor("Couldn't open " + masonScenarion.string()); minor("Couldn't open " + masonManifest.string());
} catch (const nlohmann::json::exception& e) { } catch (const nlohmann::json::exception& e) {
major("Couldn't parse " + masonScenarion.string()); major("Couldn't parse " + masonManifest.string());
} }
if (scenario.has_value()) { if (manifest.has_value()) {
const nlohmann::json& sc = scenario.value(); const nlohmann::json& mnfst = manifest.value();
if (!sc.is_object()) if (!mnfst.is_object())
return errorScenario(masonScenarion.string() + " is unexpected root type"); return errorScenario(masonManifest.string() + " is unexpected root type");
nlohmann::json::const_iterator itr = sc.find(dependencies); nlohmann::json::const_iterator itr = mnfst.find(dependencies);
if (itr == sc.end()) { if (itr == mnfst.end()) {
info(masonScenarion.string() + " doesn't have dependencies"); info(masonManifest.string() + " doesn't have dependencies");
} else { } else {
const nlohmann::json& deps = *itr; const nlohmann::json& deps = *itr;
if (!readMasonDependencies(deps, masonManifest))
return false;
}
type = mason;
info(location.string() + " seems to be a valid mason project");
return true;
}
return false;
}
bool Component::readMasonDependencies(const nlohmann::json& deps, const std::string& manifestPath) {
if (!deps.is_array()) if (!deps.is_array())
return errorScenario(masonScenarion.string() + " dependencies are not organized as an array"); return errorScenario(manifestPath + " dependencies are not organized as an array");
for (const nlohmann::json& dep : deps) { for (const nlohmann::json& dep : deps) {
std::shared_ptr<Collection> col = collection.lock(); std::shared_ptr<Collection> col = collection.lock();
@ -89,32 +109,27 @@ bool Component::readAsMason() {
case nlohmann::json::value_t::object: { case nlohmann::json::value_t::object: {
nlohmann::json::const_iterator ditr = dep.find("path"); nlohmann::json::const_iterator ditr = dep.find("path");
if (ditr == dep.end()) if (ditr == dep.end())
return errorScenario(masonScenarion.string() + " object of unexpected format in dependecies"); return errorScenario(manifestPath + " object of unexpected format in dependecies");
nlohmann::json path = *ditr; nlohmann::json path = *ditr;
if (!path.is_string()) if (!path.is_string())
return errorScenario(masonScenarion.string() + " object of unexpected format in dependecies"); return errorScenario(manifestPath + " object of unexpected format in dependecies");
col->addSource(path); col->addSource(path);
} }
break; break;
default: default:
return errorScenario(masonScenarion.string() + " has unexpected entries in dependecies"); return errorScenario(manifestPath + " has unexpected entries in dependecies");
}
} }
} }
type = mason;
info(location.string() + " seems to be a mason project");
return true; return true;
}
return false;
} }
bool Component::errorScenario(const std::string& message) { bool Component::errorScenario(const std::string& message) {
major(message); major(message);
scenario = std::nullopt; manifest = std::nullopt;
return false; return false;
return false; return false;
} }
@ -124,11 +139,67 @@ void Component::build(const std::filesystem::path& destination, const std::strin
throw WrongState(state, "build"); throw WrongState(state, "build");
state = building; state = building;
info("Building " + location.string() + " to " + destination.string()); info("Building " + location.string() + " to " + destination.string());
switch (type) {
case file:
buildAsFile(destination);
break;
case directory:
buildAsDiractory(destination);
break;
case mason:
buildAsMason(destination, target);
break;
default:
break;
}
state = done; state = done;
} }
void Component::buildAsFile(const std::filesystem::path& destination) {
std::filesystem::copy(location, destination/location.filename());
}
void Component::buildAsDiractory(const std::filesystem::path& destination) {
std::filesystem::copy(location, destination/location.filename(),
std::filesystem::copy_options::recursive |
std::filesystem::copy_options::overwrite_existing
);
}
std::string Component::getLibrariesPath() const {
//TODO may be it makes sence to cache
if (type != mason)
throw WrongType(type, "getLibrariesPath");
const nlohmann::json& mnfst = manifest.value();
nlohmann::json::const_iterator itr = mnfst.find("libraries");
if (itr == mnfst.end())
return "";
const nlohmann::json& libs = *itr;
if (libs.is_string())
return libs;
warn("Mason manifest " + (location/masonJSON).string()
+ " has field \"libraries\" which is not string, ignoring it");
return "";
}
std::filesystem::path Component::getLocation() const {
return location;
}
bool Component::successfullyRead() const {
return state > reading && state != error;
}
void Component::buildAsMason(const std::filesystem::path& destination, const std::string& target) {
warn("mason build is not implemented yet");
}
Component::State Component::getState() const { Component::State Component::getState() const {
return state; return state;
} }
@ -139,5 +210,10 @@ Component::Type Component::getType() const {
Component::WrongState::WrongState(State state, const std::string& action): Component::WrongState::WrongState(State state, const std::string& action):
std::runtime_error("An attempt to perform action \"" + action std::runtime_error("An attempt to perform action \"" + action
+ "\" on a wrong state \"" + stringStates[state].data() + '\"') + "\" on a wrong component state \"" + stringStates[state].data() + '\"')
{}
Component::WrongType::WrongType(Type type, const std::string& action):
std::runtime_error("An attempt to perform an action \"" + action
+ "\" on a wrong component type \"" + stringTypes[type].data() + '\"')
{} {}

View File

@ -19,6 +19,7 @@ class Collection;
class Component : protected Loggable { class Component : protected Loggable {
public: public:
class WrongState; class WrongState;
class WrongType;
enum State { enum State {
initial, initial,
reading, reading,
@ -29,10 +30,10 @@ public:
}; };
enum Type { enum Type {
unknown,
file, file,
directory, directory,
mason mason,
unknown
}; };
Component( Component(
@ -43,6 +44,9 @@ public:
Type getType() const; Type getType() const;
State getState() const; State getState() const;
std::filesystem::path getLocation() const;
std::string getLibrariesPath() const;
bool successfullyRead() const;
void read(); void read();
void build(const std::filesystem::path& destination, const std::string& target); void build(const std::filesystem::path& destination, const std::string& target);
@ -52,15 +56,26 @@ private:
bool readAsMason(); bool readAsMason();
bool errorScenario(const std::string& message); bool errorScenario(const std::string& message);
void buildAsFile(const std::filesystem::path& destination);
void buildAsDiractory(const std::filesystem::path& destination);
void buildAsMason(const std::filesystem::path& destination, const std::string& target);
bool readMasonDependencies(const nlohmann::json& deps, const std::string& manifestPath);
private: private:
State state; State state;
Type type; Type type;
std::weak_ptr<Collection> collection; std::weak_ptr<Collection> collection;
std::filesystem::path location; std::filesystem::path location;
std::optional<nlohmann::json> scenario; std::optional<nlohmann::json> manifest;
}; };
class Component::WrongState : public std::runtime_error { class Component::WrongState : public std::runtime_error {
public: public:
explicit WrongState(State state, const std::string& action); explicit WrongState(State state, const std::string& action);
}; };
class Component::WrongType : public std::runtime_error {
public:
explicit WrongType(Type type, const std::string& action);
};

View File

@ -71,18 +71,16 @@ void Download::proceed() {
const FileInfo& fl = file.value(); const FileInfo& fl = file.value();
std::optional<std::filesystem::path> path = downloadAsFile(fl); std::optional<std::filesystem::path> path = downloadAsFile(fl);
if (path.has_value()) { if (path.has_value()) {
bool success = true;
info("Successfully downloaded " + url); info("Successfully downloaded " + url);
if (fl.archive) { if (fl.archive) {
info(url + " appears to be an archive, extracting"); info(url + " appears to be an archive, extracting");
success = extract(path.value(), destination/fl.name); bool success = extract(path.value(), destination/fl.name);
if (success)
info("Successfully extracted " + url);
}
if (success) { if (success) {
info("Successfully extracted " + url);
location = destination/fl.name; location = destination/fl.name;
return; }
} else {
location = path;
} }
} }

View File

@ -20,25 +20,31 @@ int main(int argc, char *argv[]) {
std::shared_ptr<Logger> logger = std::make_shared<Logger>(Logger::Severity::debug); std::shared_ptr<Logger> logger = std::make_shared<Logger>(Logger::Severity::debug);
std::shared_ptr<TaskManager> taskManager = std::make_shared<TaskManager>(logger); std::shared_ptr<TaskManager> taskManager = std::make_shared<TaskManager>(logger);
std::shared_ptr<Collection> collection = std::make_shared<Collection>(secondArg, "", logger, taskManager); std::shared_ptr<Collection> collection = std::make_shared<Collection>(
firstArg,
secondArg,
"",
logger,
taskManager
);
taskManager->start(); taskManager->start();
collection->addSource(firstArg);
taskManager->wait(); taskManager->wait();
taskManager->stop(); taskManager->stop();
// int result = -1; unsigned int success = collection->sourcesSuccess();
// if (success) { unsigned int total = collection->sourcesTotal();
// root.info("successfully parsed project " + root.getName()); if (total == success) {
// root.info("dependencies count is " + std::to_string(root.dependenciesCount())); logger->log(Logger::Severity::info, "Successfully built " + firstArg);
//
// root.discover();
// result = 0;
// }
//
// root.printLog();
return 0; return 0;
} else {
logger->log(Logger::Severity::error, "Failed to build " + firstArg);
logger->log(Logger::Severity::info, "Success: " + std::to_string(success));
logger->log(Logger::Severity::info, "Failed: " + std::to_string(collection->sourcesError()));
logger->log(Logger::Severity::info, "Unfinished: " + std::to_string(collection->sourcesPending()));
logger->log(Logger::Severity::info, "Total: " + std::to_string(total));
return -1;
}
return -2;
} }

View File

@ -10,5 +10,6 @@
}, },
"https://git.macaw.me/blue/mason/archive/main.tar.gz", "https://git.macaw.me/blue/mason/archive/main.tar.gz",
"https://git.macaw.me/blue/mason/raw/branch/main/src2/atomicmutex.h" "https://git.macaw.me/blue/mason/raw/branch/main/src2/atomicmutex.h"
] ],
"libraries": "lib"
} }