sources as different names, explicit targets
This commit is contained in:
parent
cc4d8d1fc3
commit
1d9a6ec3f8
@ -7,6 +7,7 @@ set(SOURCES
|
||||
taskmanager.cpp
|
||||
download.cpp
|
||||
atomicmutex.cpp
|
||||
source.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
@ -17,6 +18,7 @@ set(HEADERS
|
||||
taskmanager.h
|
||||
download.h
|
||||
atomicmutex.h
|
||||
source.h
|
||||
)
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
|
||||
|
@ -43,7 +43,7 @@ Collection::Collection(
|
||||
librariesPath = root->getLibrariesPath();
|
||||
std::lock_guard lock(mutex);
|
||||
while (pendingSources.size() > 0) {
|
||||
std::string source = pendingSources.front();
|
||||
Source source = pendingSources.front();
|
||||
pendingSources.pop();
|
||||
processSource(source);
|
||||
}
|
||||
@ -54,15 +54,15 @@ Collection::Collection(
|
||||
);
|
||||
}
|
||||
|
||||
void Collection::addSource(const std::string& source) {
|
||||
void Collection::addSource(const Source& source) {
|
||||
std::lock_guard lock(mutex);
|
||||
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.print() + " is already present, skipping as duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Adding source " + source);
|
||||
debug("Adding source " + source.print());
|
||||
switch (root->getState()) {
|
||||
case Component::initial:
|
||||
case Component::reading:
|
||||
@ -78,69 +78,74 @@ void Collection::addSource(const std::string& source) {
|
||||
}
|
||||
}
|
||||
|
||||
void Collection::processSource(const std::string& source) {
|
||||
if (isRemote(source))
|
||||
void Collection::processSource(const Source& source) {
|
||||
std::string path = source.getPath();
|
||||
if (isRemote(path))
|
||||
queueDownload(source);
|
||||
else
|
||||
queueRead(source, source);
|
||||
queueRead(source, path);
|
||||
}
|
||||
|
||||
void Collection::sourceDownaloded(const std::string& source, TaskManager::Error err) {
|
||||
void Collection::sourceDownaloded(const Source& source, TaskManager::Error err) {
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
Downloads::const_iterator itr = downloadingSources.find(source);
|
||||
std::optional<std::filesystem::path> location = itr->second->getLocation();
|
||||
downloadingSources.erase(itr);
|
||||
if (err.has_value() || !location.has_value()) {
|
||||
error("Coundn't download " + source + ": " + err.value()->what());
|
||||
error("Coundn't download " + source.print() + ": " + err.value()->what());
|
||||
return;
|
||||
}
|
||||
|
||||
queueRead(source, location.value());
|
||||
}
|
||||
|
||||
void Collection::sourceRead(const std::string& source, TaskManager::Error err) {
|
||||
void Collection::sourceRead(const Source& source, TaskManager::Error err) {
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
Components::iterator itr = readingSources.find(source);
|
||||
if (err.has_value()) {
|
||||
error("Coundn't read " + source + ": " + err.value()->what());
|
||||
error("Coundn't read " + source.print() + ": " + err.value()->what());
|
||||
readingSources.erase(itr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!itr->second->successfullyRead()) {
|
||||
error("Source " + source + " had an error during read process, canceling build of this component");
|
||||
error("Source " + source.print() + " had an error during read process, canceling build of this component");
|
||||
readingSources.erase(itr);
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Source " + source + " has been read, scheduling build");
|
||||
debug("Source " + source.print() + " has been read, scheduling build");
|
||||
std::pair<Components::iterator, bool> res = buildingSources.emplace(source, std::move(itr->second));
|
||||
readingSources.erase(itr);
|
||||
|
||||
std::string tgt = target;
|
||||
if (source.hasExplicitTarget())
|
||||
tgt = source.getTarget();
|
||||
|
||||
taskManager->queue(
|
||||
std::bind(&Component::build, res.first->second.get(), destination/librariesPath, target, true),
|
||||
std::bind(&Component::build, res.first->second.get(), destination/librariesPath, tgt, true),
|
||||
std::bind(&Collection::sourceBuilt, this, source, std::placeholders::_1)
|
||||
);
|
||||
}
|
||||
|
||||
void Collection::sourceBuilt(const std::string& source, TaskManager::Error err) {
|
||||
void Collection::sourceBuilt(const Source& source, TaskManager::Error err) {
|
||||
std::lock_guard lock(mutex);
|
||||
Components::iterator itr = buildingSources.find(source);
|
||||
bool success = itr->second->successfullyBuilt();
|
||||
buildingSources.erase(itr);
|
||||
if (err.has_value()) {
|
||||
error("Coundn't read " + source + ": " + err.value()->what());
|
||||
error("Coundn't read " + source.print() + ": " + err.value()->what());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
error("Source " + source + " had an error during build process");
|
||||
error("Source " + source.print() + " had an error during build process");
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Source " + source + " has been built");
|
||||
debug("Source " + source.print() + " has been built");
|
||||
successSources.emplace(source);
|
||||
}
|
||||
|
||||
@ -161,12 +166,12 @@ bool Collection::isRemote(const std::string& source) {
|
||||
return std::regex_search(source, remote);
|
||||
}
|
||||
|
||||
void Collection::queueDownload(const std::string& source) {
|
||||
debug("Scheduling download of " + source);
|
||||
void Collection::queueDownload(const Source& source) {
|
||||
debug("Scheduling download of " + source.print());
|
||||
std::pair<Downloads::iterator, bool> res = downloadingSources.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(source),
|
||||
std::forward_as_tuple(
|
||||
std::make_unique<Download>(source, destination/downloads, logger)
|
||||
std::make_unique<Download>(source.getPath(), destination/downloads, logger)
|
||||
)
|
||||
);
|
||||
|
||||
@ -176,12 +181,12 @@ void Collection::queueDownload(const std::string& source) {
|
||||
);
|
||||
}
|
||||
|
||||
void Collection::queueRead(const std::string& source, const std::filesystem::path& location) {
|
||||
debug("Scheduling read of " + source);
|
||||
void Collection::queueRead(const Source& source, const std::filesystem::path& location) {
|
||||
debug("Scheduling read of " + source.print());
|
||||
std::pair<Components::iterator, bool> res = readingSources.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(source),
|
||||
std::forward_as_tuple(
|
||||
std::make_unique<Component>(location, this, logger)
|
||||
std::make_unique<Component>(location, this, logger, source.getOptionalName())
|
||||
)
|
||||
);
|
||||
|
||||
@ -191,7 +196,7 @@ void Collection::queueRead(const std::string& source, const std::filesystem::pat
|
||||
);
|
||||
}
|
||||
|
||||
bool Collection::hasSource(const std::string& source) const {
|
||||
bool Collection::hasSource(const Source& source) const {
|
||||
std::lock_guard lock(mutex);
|
||||
return _hasSource(source);
|
||||
}
|
||||
@ -221,7 +226,7 @@ bool Collection::success() const {
|
||||
return _sourcesTotal() == _sourcesSuccess() && root->successfullyBuilt();
|
||||
}
|
||||
|
||||
bool Collection::_hasSource(const std::string& source) const {
|
||||
bool Collection::_hasSource(const Source& source) const {
|
||||
return knownSources.count(source) > 0;
|
||||
}
|
||||
|
||||
|
@ -14,12 +14,13 @@
|
||||
#include "component.h"
|
||||
#include "download.h"
|
||||
#include "taskmanager.h"
|
||||
#include "source.h"
|
||||
|
||||
class Collection : protected Loggable {
|
||||
using Sources = std::set<std::string>;
|
||||
using SourcesQueue = std::queue<std::string>;
|
||||
using Downloads = std::map<std::string, std::unique_ptr<Download>>;
|
||||
using Components = std::map<std::string, std::unique_ptr<Component>>;
|
||||
using Sources = std::set<Source>;
|
||||
using SourcesQueue = std::queue<Source>;
|
||||
using Downloads = std::map<Source, std::unique_ptr<Download>>;
|
||||
using Components = std::map<Source, std::unique_ptr<Component>>;
|
||||
|
||||
public:
|
||||
Collection(
|
||||
@ -37,22 +38,22 @@ public:
|
||||
unsigned int sourcesError() const;
|
||||
unsigned int sourcesSuccess() const;
|
||||
|
||||
bool hasSource(const std::string& source) const;
|
||||
void addSource(const std::string& source);
|
||||
bool hasSource(const Source& source) const;
|
||||
void addSource(const Source& source);
|
||||
|
||||
private:
|
||||
void sourceDownaloded(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 sourceDownaloded(const Source& source, TaskManager::Error err);
|
||||
void sourceRead(const Source& source, TaskManager::Error err);
|
||||
void sourceBuilt(const Source& source, TaskManager::Error err);
|
||||
void rootBuilt(TaskManager::Error err);
|
||||
|
||||
static bool isRemote(const std::string& source);
|
||||
|
||||
void processSource(const std::string& source);
|
||||
void queueDownload(const std::string& source);
|
||||
void queueRead(const std::string& source, const std::filesystem::path& location);
|
||||
void processSource(const Source& source);
|
||||
void queueDownload(const Source& source);
|
||||
void queueRead(const Source& source, const std::filesystem::path& location);
|
||||
|
||||
bool _hasSource(const std::string& source) const;
|
||||
bool _hasSource(const Source& source) const;
|
||||
unsigned int _sourcesTotal() const;
|
||||
unsigned int _sourcesPending() const;
|
||||
unsigned int _sourcesError() const;
|
||||
|
@ -42,7 +42,7 @@ Component::Component(
|
||||
const std::filesystem::path& path,
|
||||
Collection* collection,
|
||||
const std::shared_ptr<Logger>& logger,
|
||||
const std::string& name
|
||||
const std::optional<std::string>& name
|
||||
):
|
||||
Loggable(logger),
|
||||
state(initial),
|
||||
@ -64,14 +64,14 @@ void Component::read() {
|
||||
case std::filesystem::file_type::directory:
|
||||
type = directory;
|
||||
state = ready;
|
||||
if (!tryReadingBuildScenarios() && name.empty())
|
||||
if (!tryReadingBuildScenarios() && !name.has_value())
|
||||
name = location.filename();
|
||||
|
||||
break;
|
||||
case std::filesystem::file_type::regular:
|
||||
type = file;
|
||||
state = ready;
|
||||
if (name.empty())
|
||||
if (!name.has_value())
|
||||
name = location.filename();
|
||||
|
||||
break;
|
||||
@ -115,12 +115,12 @@ bool Component::readAsMason() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name.empty()) {
|
||||
if (!name.has_value()) {
|
||||
std::optional<std::string> manifestName = tryStringValue(mnfst, "name");
|
||||
if (manifestName.has_value())
|
||||
name = manifestName.value();
|
||||
|
||||
if (name.empty()) {
|
||||
if (!name.has_value()) {
|
||||
major("Couldn't define name of the project at " + location.string() + ", using directory name as project name");
|
||||
name = location.filename();
|
||||
}
|
||||
@ -141,18 +141,14 @@ bool Component::readMasonDependencies(const nlohmann::json& deps, const std::str
|
||||
for (const nlohmann::json& dep : deps) {
|
||||
switch (dep.type()) {
|
||||
case nlohmann::json::value_t::string:
|
||||
collection->addSource(dep);
|
||||
collection->addSource({dep});
|
||||
break;
|
||||
case nlohmann::json::value_t::object: {
|
||||
nlohmann::json::const_iterator ditr = dep.find("path");
|
||||
if (ditr == dep.end())
|
||||
std::optional<std::string> path = tryStringValue(dep, "path");
|
||||
if (!path.has_value())
|
||||
return errorScenario(manifestPath + " object of unexpected format in dependecies");
|
||||
|
||||
nlohmann::json path = *ditr;
|
||||
if (!path.is_string())
|
||||
return errorScenario(manifestPath + " object of unexpected format in dependecies");
|
||||
|
||||
collection->addSource(path);
|
||||
collection->addSource({path.value(), tryStringValue(dep, "target"), tryStringValue(dep, "name")});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -181,20 +177,20 @@ void Component::build(const std::filesystem::path& destination, const std::strin
|
||||
switch (type) {
|
||||
case file:
|
||||
if (useName)
|
||||
buildAsFile(destination/name);
|
||||
buildAsFile(destination/name.value());
|
||||
else
|
||||
buildAsFile(destination);
|
||||
|
||||
break;
|
||||
case directory:
|
||||
if (useName)
|
||||
buildAsDirectory(destination/name);
|
||||
buildAsDirectory(destination/name.value());
|
||||
else
|
||||
buildAsDirectory(destination);
|
||||
break;
|
||||
case mason:
|
||||
if (useName)
|
||||
buildAsMason(destination/name, target);
|
||||
buildAsMason(destination/name.value(), target);
|
||||
else
|
||||
buildAsMason(destination, target);
|
||||
break;
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
const std::filesystem::path& path,
|
||||
Collection* collection,
|
||||
const std::shared_ptr<Logger>& logger,
|
||||
const std::string& name = ""
|
||||
const std::optional<std::string>& name = std::nullopt
|
||||
);
|
||||
|
||||
Type getType() const;
|
||||
@ -84,7 +84,7 @@ private:
|
||||
Collection* collection;
|
||||
std::filesystem::path location;
|
||||
std::optional<nlohmann::json> manifest;
|
||||
std::string name;
|
||||
std::optional<std::string> name;
|
||||
};
|
||||
|
||||
class Component::WrongState : public std::runtime_error {
|
||||
|
10
src/main.cpp
10
src/main.cpp
@ -7,6 +7,7 @@
|
||||
int main(int argc, char *argv[]) {
|
||||
std::string firstArg;
|
||||
std::string secondArg;
|
||||
std::string thirdArg;
|
||||
if (argc > 1)
|
||||
firstArg = argv[1];
|
||||
else
|
||||
@ -17,13 +18,18 @@ int main(int argc, char *argv[]) {
|
||||
else
|
||||
secondArg = "./";
|
||||
|
||||
if (argc > 3)
|
||||
thirdArg = argv[3];
|
||||
else
|
||||
thirdArg = "";
|
||||
|
||||
std::shared_ptr<Logger> logger = std::make_shared<Logger>(Logger::Severity::debug);
|
||||
|
||||
std::shared_ptr<Logger> logger = std::make_shared<Logger>(Logger::Severity::info);
|
||||
std::shared_ptr<TaskManager> taskManager = std::make_shared<TaskManager>(logger);
|
||||
std::shared_ptr<Collection> collection = std::make_shared<Collection>(
|
||||
firstArg,
|
||||
secondArg,
|
||||
"",
|
||||
thirdArg,
|
||||
logger,
|
||||
taskManager
|
||||
);
|
||||
|
129
src/source.cpp
Normal file
129
src/source.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
#include "source.h"
|
||||
|
||||
Source::Source(const std::string& path) :
|
||||
path(path),
|
||||
target(std::nullopt),
|
||||
name(std::nullopt)
|
||||
{}
|
||||
|
||||
Source::Source(const std::string& path, const std::string& target) :
|
||||
path(path),
|
||||
target(target),
|
||||
name(std::nullopt)
|
||||
{}
|
||||
|
||||
Source::Source(const std::string& path, const std::string& target, const std::string& name) :
|
||||
path(path),
|
||||
target(target),
|
||||
name(name)
|
||||
{}
|
||||
|
||||
Source::Source(const std::string& path, const std::optional<std::string>& target, const std::optional<std::string>& name) :
|
||||
path(path),
|
||||
target(target),
|
||||
name(name)
|
||||
{}
|
||||
|
||||
void Source::clearName() {
|
||||
name = std::nullopt;
|
||||
}
|
||||
|
||||
void Source::clearTarget() {
|
||||
target = std::nullopt;
|
||||
}
|
||||
|
||||
std::string Source::getPath() const {
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string Source::getTarget() const {
|
||||
if (target.has_value())
|
||||
return target.value();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string Source::getName() const {
|
||||
if (name.has_value())
|
||||
return name.value();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
std::optional<std::string> Source::getOptionalTarget() const {
|
||||
return target;
|
||||
}
|
||||
|
||||
std::optional<std::string> Source::getOptionalName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
bool Source::hasExplicitTarget() const {
|
||||
return target.has_value();
|
||||
}
|
||||
|
||||
bool Source::hasExplicitName() const {
|
||||
return name.has_value();
|
||||
}
|
||||
|
||||
void Source::setPath(const std::string& path) {
|
||||
Source::path = path;
|
||||
}
|
||||
|
||||
void Source::setTarget(const std::string& target) {
|
||||
Source::target = target;
|
||||
}
|
||||
|
||||
void Source::setName(const std::string& name) {
|
||||
Source::name = name;
|
||||
}
|
||||
|
||||
bool Source::operator < (const Source& other) const {
|
||||
if (path < other.path)
|
||||
return true;
|
||||
else if (path > other.path)
|
||||
return false;
|
||||
else {
|
||||
if (hasExplicitTarget()) {
|
||||
if (other.hasExplicitTarget()) {
|
||||
if (target.value() < other.target.value())
|
||||
return true;
|
||||
else if (target.value() > other.target.value()) {
|
||||
return false;
|
||||
} else {
|
||||
if (hasExplicitName()) {
|
||||
if (other.hasExplicitName()) {
|
||||
return name.value() < other.name.value();
|
||||
} else
|
||||
return false;
|
||||
} else
|
||||
return other.hasExplicitName();
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
} else {
|
||||
if (other.hasExplicitTarget())
|
||||
return true;
|
||||
else {
|
||||
if (hasExplicitName()) {
|
||||
if (other.hasExplicitName()) {
|
||||
return name.value() < other.name.value();
|
||||
} else
|
||||
return false;
|
||||
} else
|
||||
return other.hasExplicitName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Source::print() const {
|
||||
std::string result = path;
|
||||
if (hasExplicitTarget())
|
||||
result += " -> " + target.value();
|
||||
|
||||
if (hasExplicitName())
|
||||
result += " (as " + name.value() + ")";
|
||||
|
||||
return result;
|
||||
}
|
37
src/source.h
Normal file
37
src/source.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
class Source {
|
||||
public:
|
||||
Source(const std::string& path);
|
||||
Source(const std::string& path, const std::string& target);
|
||||
Source(const std::string& path, const std::string& target, const std::string& name);
|
||||
Source(const std::string& path, const std::optional<std::string>& target, const std::optional<std::string>& name);
|
||||
|
||||
std::string getPath() const;
|
||||
std::string getTarget() const;
|
||||
std::string getName() const;
|
||||
std::optional<std::string> getOptionalTarget() const;
|
||||
std::optional<std::string> getOptionalName() const;
|
||||
|
||||
void setPath(const std::string& path);
|
||||
void setTarget(const std::string& target);
|
||||
void setName(const std::string& name);
|
||||
|
||||
std::string print() const;
|
||||
|
||||
void clearTarget();
|
||||
void clearName();
|
||||
|
||||
bool hasExplicitTarget() const;
|
||||
bool hasExplicitName() const;
|
||||
|
||||
bool operator < (const Source& other) const;
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
std::optional<std::string> target;
|
||||
std::optional<std::string> name;
|
||||
};
|
@ -95,8 +95,13 @@ void TaskManager::executeTask(const Task& task) const {
|
||||
try {
|
||||
task.first();
|
||||
} catch (const std::exception& e) {
|
||||
if (task.second.has_value())
|
||||
if (task.second.has_value()) {
|
||||
try {
|
||||
task.second.value()(&e);
|
||||
} catch (const std::exception& e) {
|
||||
error(std::string("Uncaught exception: ") + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -10,7 +10,16 @@
|
||||
"path" : "https://nowhere/to/get.from"
|
||||
},
|
||||
"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",
|
||||
{
|
||||
"path" : "https://git.macaw.me/blue/mason/raw/branch/main/src2/atomicmutex.h",
|
||||
"name" : "changed.h"
|
||||
},
|
||||
{
|
||||
"path" : "https://git.macaw.me/blue/mimicry.git",
|
||||
"name" : "mimicryNode",
|
||||
"target" : "node"
|
||||
}
|
||||
],
|
||||
"build": [
|
||||
"mason.json",
|
||||
|
Loading…
Reference in New Issue
Block a user