aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2017-12-12 17:33:03 +0100
committerdec05eba <dec05eba@protonmail.com>2017-12-12 17:34:16 +0100
commitf3b7b7d34b3bf2b1be18914577c96b66dead379a (patch)
treef24a08256bc959929d51045eb49283fcab7e8b54 /src
parentcfe578ec12198d09a9a89a2e0b40bccaa06aa8ae (diff)
Download and extract missing dependencies from github
Using libcurl and libarchive
Diffstat (limited to 'src')
-rw-r--r--src/Archive.cpp171
-rw-r--r--src/GlobalLib.cpp36
-rw-r--r--src/PkgConfig.cpp3
-rw-r--r--src/curl.cpp87
-rw-r--r--src/main.cpp3
5 files changed, 294 insertions, 6 deletions
diff --git a/src/Archive.cpp b/src/Archive.cpp
new file mode 100644
index 0000000..08ab42b
--- /dev/null
+++ b/src/Archive.cpp
@@ -0,0 +1,171 @@
+#include "../include/Archive.hpp"
+#include "../include/utils.hpp"
+#include <cstring>
+#include <archive.h>
+#include <archive_entry.h>
+
+using namespace std;
+
+class FileHandler
+{
+ DISABLE_COPY(FileHandler)
+public:
+ FileHandler(FILE *_file) : file(_file)
+ {
+
+ }
+
+ FileHandler(FileHandler &&other)
+ {
+ file = other.file;
+ other.file = nullptr;
+ }
+
+ ~FileHandler()
+ {
+ fclose(file);
+ }
+
+ FILE *file;
+};
+
+// libarchive code is modified version of: https://github.com/libarchive/libarchive/wiki/Examples#A_Complete_Extractor
+namespace sibs
+{
+ static int copy_data(struct archive *ar, struct archive *aw)
+ {
+ 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;
+ else if (r < ARCHIVE_OK)
+ return r;
+
+ r = archive_write_data_block(aw, buff, size, offset);
+ if (r < ARCHIVE_OK)
+ return r;
+ }
+ }
+
+ Result<bool> Archive::extract(const char *source, const char *destination)
+ {
+ struct archive *a;
+ struct archive *ext;
+ struct archive_entry *entry;
+ int flags;
+ int r;
+
+ /* Select which attributes we want to restore. */
+ flags = ARCHIVE_EXTRACT_TIME;
+ flags |= ARCHIVE_EXTRACT_PERM;
+ flags |= ARCHIVE_EXTRACT_ACL;
+ flags |= ARCHIVE_EXTRACT_FFLAGS;
+
+ string rootName;
+
+ a = archive_read_new();
+ archive_read_support_format_all(a);
+ archive_read_support_compression_all(a);
+ ext = archive_write_disk_new();
+ archive_write_disk_set_options(ext, flags);
+ archive_write_disk_set_standard_lookup(ext);
+
+
+ if ((r = archive_read_open_filename(a, source, 10240)))
+ {
+ string errMsg = "Failed to extract archive: ";
+ errMsg += source;
+ return Result<bool>::Err(errMsg);
+ }
+
+ while(true)
+ {
+ r = archive_read_next_header(a, &entry);
+ if (r == ARCHIVE_EOF)
+ break;
+ else if (r < ARCHIVE_OK)
+ {
+ string errMsg = "Failed to extract archive: ";
+ errMsg += source;
+ errMsg += "; reason: ";
+ errMsg += archive_error_string(a);
+ return Result<bool>::Err(errMsg);
+ }
+ else if (r < ARCHIVE_WARN)
+ {
+ string errMsg = "Failed to extract archive: ";
+ errMsg += source;
+ errMsg += "; reason: ";
+ errMsg += archive_error_string(a);
+ return Result<bool>::Err(errMsg);
+ }
+
+ const char* currentFile = archive_entry_pathname(entry);
+ if(rootName.empty())
+ rootName = currentFile;
+
+ std::string fullOutputPath = destination;
+ fullOutputPath += (currentFile + (rootName.empty() ? 0 : rootName.size() - 1));
+ archive_entry_set_pathname(entry, fullOutputPath.c_str());
+
+ r = archive_write_header(ext, entry);
+ if (r < ARCHIVE_OK)
+ {
+ string errMsg = "Failed to extract archive: ";
+ errMsg += source;
+ errMsg += "; reason: ";
+ errMsg += archive_error_string(ext);
+ return Result<bool>::Err(errMsg);
+ }
+ else if (archive_entry_size(entry) > 0) {
+ r = copy_data(a, ext);
+ if (r < ARCHIVE_OK)
+ {
+ string errMsg = "Failed to extract archive: ";
+ errMsg += source;
+ errMsg += "; reason: ";
+ errMsg += archive_error_string(ext);
+ return Result<bool>::Err(errMsg);
+ }
+ else if (r < ARCHIVE_WARN)
+ {
+ string errMsg = "Failed to extract archive: ";
+ errMsg += source;
+ errMsg += "; reason: ";
+ errMsg += archive_error_string(ext);
+ return Result<bool>::Err(errMsg);
+ }
+ }
+
+ r = archive_write_finish_entry(ext);
+ if (r < ARCHIVE_OK)
+ {
+ string errMsg = "Failed to extract archive: ";
+ errMsg += source;
+ errMsg += "; reason: ";
+ errMsg += archive_error_string(ext);
+ return Result<bool>::Err(errMsg);
+ }
+ else if (r < ARCHIVE_WARN)
+ {
+ string errMsg = "Failed to extract archive: ";
+ errMsg += source;
+ errMsg += "; reason: ";
+ errMsg += archive_error_string(ext);
+ return Result<bool>::Err(errMsg);
+ }
+ }
+
+ archive_read_close(a);
+ archive_read_free(a);
+ archive_write_close(ext);
+ archive_write_free(ext);
+ return Result<bool>::Ok(true);
+ }
+} \ No newline at end of file
diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp
index 7503a7a..ce9426d 100644
--- a/src/GlobalLib.cpp
+++ b/src/GlobalLib.cpp
@@ -2,6 +2,8 @@
#include "../include/FileUtil.hpp"
#include "../backend/ninja/Ninja.hpp"
#include "../include/Conf.hpp"
+#include "../include/curl.hpp"
+#include "../include/Archive.hpp"
using namespace std;
@@ -18,7 +20,7 @@ namespace sibs
{
string errMsg = "Global lib dependency not found: ";
errMsg += name;
- return Result<bool>::Err(errMsg);
+ return Result<bool>::Err(errMsg, DependencyError::DEPENDENCY_NOT_FOUND);
}
case FileType::REGULAR:
{
@@ -57,7 +59,7 @@ namespace sibs
{
Result<bool> packageExistsResult = validatePackageExists(globalLibRootDir, name);
if(packageExistsResult.isErr())
- return Result<string>::Err(packageExistsResult.getErrMsg());
+ return Result<string>::Err(packageExistsResult);
string packageDir = globalLibRootDir + "/";
packageDir += name;
@@ -76,7 +78,7 @@ namespace sibs
});
if(foundVersion.empty())
- return Result<string>::Err("Global lib dependency found, but version doesn't match dependency version");
+ return Result<string>::Err("Global lib dependency found, but version doesn't match dependency version", DependencyError::DEPENDENCY_VERSION_NO_MATCH);
packageDir += "/";
packageDir += version;
@@ -156,4 +158,32 @@ namespace sibs
return Result<string>::Ok(staticLibPath);
}
}
+
+ Result<bool> GlobalLib::downloadDependency(const Dependency &dependency)
+ {
+ string url = "https://github.com/DEC05EBA/";
+ url += dependency.name;
+ url += "/archive/";
+ url += dependency.version;
+ url += ".tar.gz";
+
+ // TODO: Create library path if it doesn't exist
+ string libPath = getHomeDir();
+ libPath += "/.sibs/lib/";
+ libPath += dependency.name;
+ libPath += "/";
+ libPath += dependency.version;
+
+ // TODO: Create archive directory if it doesn't exist
+ string libArchivedFilePath = getHomeDir();
+ libArchivedFilePath += "/.sibs/archive/";
+ libArchivedFilePath += dependency.name;
+ libArchivedFilePath += "/";
+ libArchivedFilePath += dependency.version;
+ Result<bool> downloadResult = curl::downloadFile(url.c_str(), libArchivedFilePath.c_str());
+ if(downloadResult.isErr())
+ return downloadResult;
+
+ return Archive::extract(libArchivedFilePath.c_str(), libPath.c_str());
+ }
} \ No newline at end of file
diff --git a/src/PkgConfig.cpp b/src/PkgConfig.cpp
index 11e1cf0..3307ff1 100644
--- a/src/PkgConfig.cpp
+++ b/src/PkgConfig.cpp
@@ -3,6 +3,9 @@
using namespace std;
+// TODO: Do not use pkg-config program. The same functionality can easily be achieved
+// by reading files in /usr/bin/pkgconfig
+// Or is there no downside to calling pkg-config program?
namespace sibs
{
string trimRight(const string &input)
diff --git a/src/curl.cpp b/src/curl.cpp
new file mode 100644
index 0000000..f39cab8
--- /dev/null
+++ b/src/curl.cpp
@@ -0,0 +1,87 @@
+#include "../include/curl.hpp"
+#include "../include/env.hpp"
+#include <curl/curl.h>
+#include <cstring>
+
+using namespace std;
+
+#ifdef DEBUG
+#define CURL_DEBUG
+#endif
+
+#undef CURL_DEBUG
+
+class CurlSession
+{
+public:
+ CurlSession()
+ {
+ curl_global_init(CURL_GLOBAL_ALL);
+ }
+};
+
+static CurlSession curlSession;
+
+namespace sibs
+{
+ // TODO: Instead of writing to file, reading from file and extracting it;
+ // we can extract to file directly by putting libarchive code here
+ size_t writeToFile(void *ptr, size_t size, size_t nmemb, void *stream)
+ {
+ return fwrite(ptr, size, nmemb, (FILE*)stream);
+ }
+
+ Result<bool> curl::downloadFile(const char *url, const char *filepath)
+ {
+ CURL *curl_handle = curl_easy_init();
+ curl_easy_setopt(curl_handle, CURLOPT_URL, url);
+#ifdef CURL_DEBUG
+ long verbose = 1L;
+ long noProgressMeter = 0L;
+#else
+ long verbose = 0L;
+ long noProgressMeter = 1L;
+#endif
+ curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, verbose);
+ curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, noProgressMeter);
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeToFile);
+ curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, true);
+
+ FILE *file = fopen(filepath, "wb");
+ if(!file)
+ {
+ int error = errno;
+ curl_easy_cleanup(curl_handle);
+
+ string errMsg = "Failed to open file for writing: ";
+ errMsg += filepath;
+ if(error != 0)
+ {
+ errMsg += "; Reason: ";
+ errMsg += strerror(error);
+ return Result<bool>::Err(errMsg);
+ }
+ else
+ {
+ return Result<bool>::Err(errMsg);
+ }
+ }
+
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, file);
+ printf("Downloading from url: %s\n", url);
+ CURLcode curlResponse = curl_easy_perform(curl_handle);
+ curl_easy_cleanup(curl_handle);
+ fclose(file);
+
+ if(curlResponse != CURLE_OK)
+ {
+ string errMsg = "Failed to download file from url: ";
+ errMsg += url;
+ errMsg += "\nReason: ";
+ errMsg += curl_easy_strerror(curlResponse);
+ return Result<bool>::Err(errMsg);
+ }
+
+ return Result<bool>::Ok(true);
+ }
+} \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index b1982bd..ce379c2 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,10 +1,7 @@
#include <cstdio>
#include "../include/FileUtil.hpp"
#include "../include/Conf.hpp"
-#include "../include/Dependency.hpp"
#include "../backend/ninja/Ninja.hpp"
-#include <string>
-#include <cassert>
using namespace std;
using namespace sibs;