From 5ee7ae7f73d08235875eed26b65c9a198a931047 Mon Sep 17 00:00:00 2001 From: blue Date: Mon, 4 Sep 2023 18:45:01 -0300 Subject: [PATCH] extracted downloaded archive --- CMakeLists.txt | 2 + src/dependency.cpp | 122 ++++++++++++++++++++++++++++++++++++++++++--- src/dependency.h | 5 ++ 3 files changed, 123 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f914b59..24e3875 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ endif() find_package(nlohmann_json REQUIRED) find_package(CURL REQUIRED) +find_package(LibArchive REQUIRED) 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 CURL::libcurl) +target_link_libraries(${PROJECT_NAME} PRIVATE LibArchive::LibArchive) install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets diff --git a/src/dependency.cpp b/src/dependency.cpp index d75c854..5d3fce8 100644 --- a/src/dependency.cpp +++ b/src/dependency.cpp @@ -4,6 +4,9 @@ #include "project.h" +constexpr std::string_view downloads("downloads"); +constexpr std::string_view build("build"); + constexpr std::string_view acceptJson("accept: application/json"); const std::regex http("^https?:\\/\\/"); 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 url = protocol + "://" + host + "/api/v1/repos/" + owner + "/" + repo + "/archive/" + fileName; - res = download(url, destination / "downloads" / fileName); - if (res) - Project::info("Successfully downloaded " + fileName); + std::filesystem::path archivePath = destination/downloads/fileName; + res = download(url, archivePath); + if (res) { + Project::info("Successfully downloaded " + archivePath.string()); + + res = extract(archivePath, destination/build); + if (!res) { + Project::error("Couldn't extract archive " + fileName); + } + } } else { 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) { 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"); + if (std::filesystem::is_directory(destination)) + std::filesystem::remove_all(destination); + } + bool result = false; CURL* curl = curl_easy_init(); 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)); } } 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); if (!result) { Project::minor("Removing " + destination.string() + " since the donwload failed"); - std::filesystem::remove(destination); + std::filesystem::remove_all(destination); } return result; @@ -211,3 +225,99 @@ int Dependency::trace(CURL* handle, curl_infotype type, char* data, size_t size, 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; + } + } +} + + diff --git a/src/dependency.h b/src/dependency.h index 86dbcbb..d3e0d86 100644 --- a/src/dependency.h +++ b/src/dependency.h @@ -8,6 +8,8 @@ #include #include +#include +#include class Dependency { public: @@ -54,6 +56,9 @@ private: ); CURLcode httpGet(const std::string& url, std::string& result, const std::list& headers = {}); + bool extract(const std::filesystem::path& source, const std::filesystem::path& destination) const; + int copy(struct archive *ar, struct archive *aw) const; + private: Type type; std::optional name;