extracted downloaded archive

This commit is contained in:
Blue 2023-09-04 18:45:01 -03:00
parent 76bd9a0497
commit 5ee7ae7f73
Signed by: blue
GPG Key ID: 9B203B252A63EE38
3 changed files with 123 additions and 6 deletions

View File

@ -24,6 +24,7 @@ endif()
find_package(nlohmann_json REQUIRED) find_package(nlohmann_json REQUIRED)
find_package(CURL REQUIRED) find_package(CURL REQUIRED)
find_package(LibArchive REQUIRED)
add_executable(${PROJECT_NAME}) add_executable(${PROJECT_NAME})
@ -44,6 +45,7 @@ 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) target_link_libraries(${PROJECT_NAME} PRIVATE CURL::libcurl)
target_link_libraries(${PROJECT_NAME} PRIVATE LibArchive::LibArchive)
install(TARGETS ${PROJECT_NAME} install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets EXPORT ${PROJECT_NAME}Targets

View File

@ -4,6 +4,9 @@
#include "project.h" #include "project.h"
constexpr std::string_view downloads("downloads");
constexpr std::string_view build("build");
constexpr std::string_view acceptJson("accept: application/json"); constexpr std::string_view acceptJson("accept: application/json");
const std::regex http("^https?:\\/\\/"); const std::regex http("^https?:\\/\\/");
const std::regex repo("(^https?):\\/\\/([\\w\\d\\.\\-\\_]+)\\/([\\w\\d\\-\\_]+)\\/([\\w\\d\\-\\_]+)"); const std::regex repo("(^https?):\\/\\/([\\w\\d\\.\\-\\_]+)\\/([\\w\\d\\-\\_]+)\\/([\\w\\d\\-\\_]+)");
@ -74,9 +77,16 @@ bool Dependency::downloadRepo(
std::string fileName = branchName + ".tar.gz"; std::string fileName = branchName + ".tar.gz";
std::string url = protocol + "://" + host + "/api/v1/repos/" + owner + "/" + repo + "/archive/" + fileName; std::string url = protocol + "://" + host + "/api/v1/repos/" + owner + "/" + repo + "/archive/" + fileName;
res = download(url, destination / "downloads" / fileName); std::filesystem::path archivePath = destination/downloads/fileName;
if (res) res = download(url, archivePath);
Project::info("Successfully downloaded " + fileName); if (res) {
Project::info("Successfully downloaded " + archivePath.string());
res = extract(archivePath, destination/build);
if (!res) {
Project::error("Couldn't extract archive " + fileName);
}
}
} else { } else {
res = false; res = false;
} }
@ -139,9 +149,13 @@ CURLcode Dependency::httpGet(const std::string& url, std::string& result, const
bool Dependency::download(const std::string& url, const std::filesystem::path& destination) { bool Dependency::download(const std::string& url, const std::filesystem::path& destination) {
std::filesystem::create_directories(destination.parent_path()); std::filesystem::create_directories(destination.parent_path());
if (std::filesystem::exists(destination)) if (std::filesystem::exists(destination)) {
Project::minor("File " + destination.string() + " already exists, will be overwritten"); Project::minor("File " + destination.string() + " already exists, will be overwritten");
if (std::filesystem::is_directory(destination))
std::filesystem::remove_all(destination);
}
bool result = false; bool result = false;
CURL* curl = curl_easy_init(); CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
@ -169,14 +183,14 @@ bool Dependency::download(const std::string& url, const std::filesystem::path& d
Project::warn("Couldn't download file " + url + ": response code " + std::to_string(code)); Project::warn("Couldn't download file " + url + ": response code " + std::to_string(code));
} }
} else { } else {
Project::error(std::string("couldn't open output file ") + destination.c_str()); Project::error(std::string("Couldn't open output file ") + destination.c_str());
} }
curl_easy_cleanup(curl); curl_easy_cleanup(curl);
if (!result) { if (!result) {
Project::minor("Removing " + destination.string() + " since the donwload failed"); Project::minor("Removing " + destination.string() + " since the donwload failed");
std::filesystem::remove(destination); std::filesystem::remove_all(destination);
} }
return result; return result;
@ -211,3 +225,99 @@ int Dependency::trace(CURL* handle, curl_infotype type, char* data, size_t size,
return 0; return 0;
} }
bool Dependency::extract(const std::filesystem::path& source, const std::filesystem::path& destination) const {
int flags = ARCHIVE_EXTRACT_TIME;
flags |= ARCHIVE_EXTRACT_PERM;
flags |= ARCHIVE_EXTRACT_ACL;
flags |= ARCHIVE_EXTRACT_FFLAGS;
struct archive* a = archive_read_new();
struct archive* ext = archive_write_disk_new();
struct archive_entry *entry;
archive_read_support_format_all(a);
archive_read_support_filter_all(a);
archive_write_disk_set_options(ext, flags);
archive_write_disk_set_standard_lookup(ext);
bool result = true;
bool readOpen = false;
bool writeOpen = false;
int r = archive_read_open_filename(a, source.c_str(), 10240);
if (r) {
Project::major("Couldn't open file " + source.string());
result = false;
} else {
readOpen = true;
}
while (result) {
r = archive_read_next_header(a, &entry);
if (r == ARCHIVE_EOF)
break;
if (r < ARCHIVE_OK)
Project::major(archive_error_string(a));
if (r < ARCHIVE_WARN)
break;
std::string fileName(archive_entry_pathname(entry));
std::filesystem::path filePath = destination/fileName;
Project::debug("Extracting " + filePath.string());
archive_entry_set_pathname_utf8(entry, filePath.c_str());
r = archive_write_header(ext, entry);
if (r < ARCHIVE_OK) {
Project::major(archive_error_string(ext));
} else if (archive_entry_size(entry) > 0) {
writeOpen = true;
r = copy(a, ext);
if (r < ARCHIVE_OK)
Project::major(archive_error_string(ext));
if (r < ARCHIVE_WARN)
break;
}
r = archive_write_finish_entry(ext);
if (r < ARCHIVE_OK)
Project::major(archive_error_string(ext));
if (r < ARCHIVE_WARN)
break;
}
if (readOpen)
archive_read_close(a);
if (writeOpen)
archive_write_close(ext);
archive_read_free(a);
archive_write_free(ext);
return result;
}
int Dependency::copy(struct archive* ar, struct archive* aw) const {
int r;
const void *buff;
size_t size;
la_int64_t offset;
while (true) {
r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF)
return ARCHIVE_OK;
if (r < ARCHIVE_OK)
return r;
r = archive_write_data_block(aw, buff, size, offset);
if (r < ARCHIVE_OK) {
Project::major(archive_error_string(aw));
return r;
}
}
}

View File

@ -8,6 +8,8 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <curl/curl.h> #include <curl/curl.h>
#include <archive.h>
#include <archive_entry.h>
class Dependency { class Dependency {
public: public:
@ -54,6 +56,9 @@ private:
); );
CURLcode httpGet(const std::string& url, std::string& result, const std::list<std::string_view>& headers = {}); CURLcode httpGet(const std::string& url, std::string& result, const std::list<std::string_view>& headers = {});
bool extract(const std::filesystem::path& source, const std::filesystem::path& destination) const;
int copy(struct archive *ar, struct archive *aw) const;
private: private:
Type type; Type type;
std::optional<std::string> name; std::optional<std::string> name;