first attempt to download something

This commit is contained in:
Blue 2023-09-01 18:39:24 -03:00
parent 60b2220b97
commit 7ac697f111
Signed by: blue
GPG Key ID: 9B203B252A63EE38
9 changed files with 296 additions and 42 deletions

View File

@ -23,6 +23,7 @@ elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
endif() endif()
find_package(nlohmann_json REQUIRED) find_package(nlohmann_json REQUIRED)
find_package(CURL REQUIRED)
add_executable(${PROJECT_NAME}) add_executable(${PROJECT_NAME})
@ -42,6 +43,7 @@ add_subdirectory(src)
add_subdirectory(test) add_subdirectory(test)
target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json) target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json)
target_link_libraries(${PROJECT_NAME} PRIVATE CURL::libcurl)
install(TARGETS ${PROJECT_NAME} install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets EXPORT ${PROJECT_NAME}Targets

View File

@ -1,10 +1,12 @@
set(SOURCES set(SOURCES
main.cpp main.cpp
loggger.cpp
project.cpp project.cpp
dependency.cpp dependency.cpp
) )
set(HEADERS set(HEADERS
logger.h
project.h project.h
dependency.cpp dependency.cpp
) )

View File

@ -1,5 +1,11 @@
#include "dependency.h" #include "dependency.h"
#include <regex>
#include "project.h"
const std::regex http("^https?://");
Dependency::Dependency( Dependency::Dependency(
const std::string& path, const std::string& path,
Type type, Type type,
@ -23,3 +29,69 @@ std::optional<std::string> Dependency::getName() const {
std::optional<std::string> Dependency::getVersion() const { std::optional<std::string> Dependency::getVersion() const {
return version; return version;
} }
bool Dependency::prepare(const std::filesystem::path& source, const std::filesystem::path& destination) {
if (std::regex_search(path, http)) {
Project::info("downloading project from " + path);
std::filesystem::create_directories(destination / "downloads");
return download(destination);
} else {
Project::info("checking project at path " + path);
std::filesystem::directory_entry srcDir(source / path);
if (!srcDir.exists()) {
Project::error("Project at " + path + " doesn't exist");
return false;
}
}
return true;
}
bool Dependency::download(const std::filesystem::path& destination) {
std::filesystem::path dwn = destination / "downloads";
bool result = std::filesystem::create_directories(dwn);
// if (!result) {
// Project::error("couldn't create " + dwn.string());
// return result;
// }
CURL *curl_handle;
std::filesystem::path out = dwn / ("out" + std::to_string(std::rand()));
FILE *pagefile;
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
/* set URL to get here */
curl_easy_setopt(curl_handle, CURLOPT_URL, path.c_str());
/* disable progress meter, set to 0L to enable it */
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write);
/* open the file */
pagefile = fopen(out.c_str(), "wb");
if (pagefile) {
/* write the page body to this file handle */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);
/* get it! */
curl_easy_perform(curl_handle);
/* close the header file */
fclose(pagefile);
} else {
Project::error(std::string("couldn't open output file ") + out.c_str());
}
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return true;
}
size_t Dependency::write(void* file, size_t size, size_t nmemb, void* stream) {
size_t written = fwrite(file, size, nmemb, (FILE *)stream);
return written;
}

View File

@ -2,6 +2,10 @@
#include <string> #include <string>
#include <optional> #include <optional>
#include <filesystem>
#include <curl/curl.h>
#include <stdio.h>
class Dependency { class Dependency {
public: public:
@ -22,8 +26,14 @@ public:
std::optional<std::string> getName() const; std::optional<std::string> getName() const;
std::optional<std::string> getVersion() const; std::optional<std::string> getVersion() const;
bool prepare(const std::filesystem::path& source, const std::filesystem::path& destination);
const std::string path; const std::string path;
private:
static size_t write(void *file, size_t size, size_t nmemb, void *stream);
bool download(const std::filesystem::path& destination);
private: private:
Type type; Type type;
std::optional<std::string> name; std::optional<std::string> name;

59
src/loggger.cpp Normal file
View File

@ -0,0 +1,59 @@
#include "loggger.h"
constexpr const std::array<std::string_view, static_cast<int>(Logger::Severity::fatal) + 1> logSettings({
/*debug*/ "\e[90m",
/*info*/ "\e[32m",
/*minor*/ "\e[34m",
/*major*/ "\e[94m",
/*warning*/ "\e[33m",
/*error*/ "\e[31m",
/*fatal*/ "\e[91m"
});
constexpr const std::array<std::string_view, static_cast<int>(Logger::Severity::fatal) + 1> logHeaders({
/*debug*/ "DEBUG: ",
/*info*/ "INFO: ",
/*minor*/ "MINOR: ",
/*major*/ "MAJOR: ",
/*warning*/ "WARNING: ",
/*error*/ "ERROR: ",
/*fatal*/ "FATAL: "
});
constexpr const std::string_view bold("\e[1m");
constexpr const std::string_view regular("\e[22m");
constexpr const std::string_view clearStyle("\e[0m");
Logger::Logger(Logger::Severity severity):
currentSeverity(severity),
history(),
readMutex(),
writeMutex()
{}
Logger::~Logger()
{}
void Logger::printLog(bool colored) {
std::cout << std::endl;
for (const Message& message : history) {
if (colored) {
int severity = static_cast<int>(message.first);
std::cout << logSettings[severity] << bold << logHeaders[severity] << regular;
}
std::cout << message.second << std::endl;
}
if (colored)
std::cout << clearStyle << std::flush;
}
void Logger::log(Logger::Severity severity, const std::string& comment) const {
std::scoped_lock lock(readMutex, writeMutex);
if (severity >= currentSeverity)
history.emplace_back(severity, comment);
}
std::list<std::pair<Logger::Severity, std::string>> Logger::getLog() const {
std::scoped_lock lock(readMutex);
return history;
}

36
src/loggger.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include <list>
#include <string>
#include <mutex>
#include <array>
#include <string_view>
#include <iostream>
class Logger {
public:
enum class Severity {
debug,
info,
minor,
major,
warning,
error,
fatal
};
typedef std::pair<Severity, std::string> Message;
Logger(Severity severity = Severity::info);
~Logger();
void log (Severity severity, const std::string& comment) const;
std::list<Message> getLog() const;
void printLog(bool colored = true);
private:
const Severity currentSeverity;
mutable std::list<Message> history;
mutable std::mutex readMutex;
mutable std::mutex writeMutex;
};

View File

@ -1,29 +1,34 @@
#include <iostream>
#include <string> #include <string>
#include "project.h" #include "project.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
std::string firstArg; std::string firstArg;
std::string secondArg;
if (argc > 1) if (argc > 1)
firstArg = argv[1]; firstArg = argv[1];
else else
firstArg = "./"; firstArg = "./";
Project root(firstArg); if (argc > 2)
secondArg = argv[2];
else
secondArg = "./";
Project root(firstArg, secondArg);
bool success = root.read(); bool success = root.read();
if (!success) { int result = -1;
Project::Log log(root.getLog()); if (success) {
for (const Project::LogMessage& msg : log) root.info("successfully parsed project " + root.getName());
std::cout << msg << std::endl; root.info("dependencies count is " + std::to_string(root.dependenciesCount()));
return -1; root.discover();
} else { result = 0;
std::cout << "successfully parsed project " << root.getName() << std::endl;
std::cout << "dependencies count is " << root.dependenciesCount() << std::endl;
} }
root.printLog();
return 0;
return result;
} }

View File

@ -15,31 +15,54 @@ std::map<std::string, Dependency::Type> types({
{"automatic", Dependency::Type::automatic} {"automatic", Dependency::Type::automatic}
}); });
Project::Project(const std::filesystem::path& location): Logger* Project::logger = nullptr;
Project::Project(const std::filesystem::path& location, const std::filesystem::path& destination):
location(location), location(location),
status(Status::unknown), destination(destination),
state(State::unknown),
name(), name(),
logStorage(), dependencies(),
dependencies() root(logger == nullptr)
{} {
if (root)
logger = new Logger();
}
Project::~Project() {
if (root) {
delete logger;
logger = nullptr;
}
}
bool Project::read() { bool Project::read() {
if (status == Status::read) if (state == State::read)
return true; return true;
std::filesystem::path entryPointPath; std::filesystem::path entryPointPath;
try { try {
entryPointPath = std::filesystem::canonical(location) / entry; location = std::filesystem::canonical(location);
entryPointPath = location / entry;
} catch (const std::exception& e) { } catch (const std::exception& e) {
log(e.what()); fatal(e.what());
status = Status::error; state = State::error;
return false;
}
try {
std::filesystem::create_directories(destination);
destination = std::filesystem::canonical(destination);
} catch (const std::exception& e) {
fatal(e.what());
state = State::error;
return false; return false;
} }
std::ifstream file(entryPointPath); std::ifstream file(entryPointPath);
if (!file.is_open()) { if (!file.is_open()) {
log("couldn't open " + std::string(entryPointPath)); fatal("couldn't open " + entryPointPath.string());
status = Status::error; state = State::error;
return false; return false;
} }
@ -47,16 +70,16 @@ bool Project::read() {
try { try {
data = json::parse(file); data = json::parse(file);
} catch (const json::exception& e) { } catch (const json::exception& e) {
log(e.what()); fatal(e.what());
status = Status::error; state = State::error;
return false; return false;
} }
try { try {
parse(data); parse(data);
} catch (const std::exception& e) { } catch (const std::exception& e) {
log(e.what()); fatal(e.what());
status = Status::error; state = State::error;
return false; return false;
} }
@ -126,21 +149,54 @@ void Project::createDepencencyFromObject(const nlohmann::json& entry) {
dependencies.emplace(url, Dependency{url, type, name, version}); dependencies.emplace(url, Dependency{url, type, name, version});
} }
void Project::discover() {
int fine = 0;
for (std::pair<const std::string, Dependency>& pair : dependencies) {
bool success = pair.second.prepare(location, destination);
if (success)
fine++;
}
}
uint32_t Project::dependenciesCount() const { uint32_t Project::dependenciesCount() const {
return dependencies.size(); return dependencies.size();
} }
void Project::log(Logger::Severity severity, const std::string& message) {
void Project::log(const std::string& message) const { if (logger != nullptr)
logStorage.emplace_back(message); logger->log(severity, message);
} }
Project::Log Project::getLog() const { void Project::info(const std::string& message) {
return logStorage; log(Logger::Severity::info, message);
} }
Project::Status Project::getStatus() const { void Project::debug(const std::string& message) {
return status; log(Logger::Severity::debug, message);
}
void Project::error(const std::string& message) {
log(Logger::Severity::error, message);
}
void Project::warn(const std::string& message) {
log(Logger::Severity::warning, message);
}
void Project::fatal(const std::string& message) {
log(Logger::Severity::fatal, message);
}
void Project::printLog() {
if (logger != nullptr)
logger->printLog();
}
Project::State Project::getStatus() const {
return state;
} }
std::string Project::getName() const { std::string Project::getName() const {

View File

@ -10,35 +10,47 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "dependency.h" #include "dependency.h"
#include "loggger.h"
class Project { class Project {
public: public:
typedef std::string LogMessage; enum class State {
typedef std::list<LogMessage> Log;
enum class Status {
unknown, unknown,
read, read,
discovering,
error error
}; };
Project(const std::filesystem::path& location); Project(const std::filesystem::path& location, const std::filesystem::path& destination);
~Project();
bool read(); bool read();
Status getStatus() const; void discover();
Log getLog() const; State getStatus() const;
std::string getName() const; std::string getName() const;
uint32_t dependenciesCount() const; uint32_t dependenciesCount() const;
static void log(Logger::Severity severity, const std::string& message);
static void debug(const std::string& message);
static void info(const std::string& message);
static void warn(const std::string& message);
static void error(const std::string& message);
static void fatal(const std::string& message);
static void printLog();
private: private:
void log(const std::string& message) const;
void parse(const nlohmann::json& json); void parse(const nlohmann::json& json);
void createDepencencyFromString(const std::string& entry); void createDepencencyFromString(const std::string& entry);
void createDepencencyFromObject(const nlohmann::json& entry); void createDepencencyFromObject(const nlohmann::json& entry);
private: private:
std::filesystem::path location; std::filesystem::path location;
Status status; std::filesystem::path destination;
State state;
std::string name; std::string name;
mutable Log logStorage;
std::map<std::string, Dependency> dependencies; std::map<std::string, Dependency> dependencies;
const bool root;
static Logger* logger;
}; };