aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/config_global.c13
-rw-r--r--src/internal_cmd.c33
-rw-r--r--src/manifest.c45
-rw-r--r--src/mirrors.c100
-rw-r--r--src/spm.c10
6 files changed, 187 insertions, 16 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0d53e9b..020e2e5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,7 +3,7 @@ include_directories(
${CMAKE_BINARY_DIR}/include
)
-add_executable(spm spm.c config.c compat.c deps.c fs.c rpath.c find.c shell.c archive.c strings.c relocation.c install.c config_global.c manifest.c checksum.c extern/url.c version_spec.c spm_build.c mime.c internal_cmd.c environment.c)
+add_executable(spm spm.c config.c compat.c deps.c fs.c rpath.c find.c shell.c archive.c strings.c relocation.c install.c config_global.c manifest.c checksum.c extern/url.c version_spec.c spm_build.c mime.c internal_cmd.c environment.c mirrors.c)
target_link_libraries(spm rt crypto ssl curl)
if(MSVC)
diff --git a/src/config_global.c b/src/config_global.c
index 14f3a26..0c32ebb 100644
--- a/src/config_global.c
+++ b/src/config_global.c
@@ -164,6 +164,7 @@ void init_config_global(void) {
SPM_GLOBAL.config = NULL;
SPM_GLOBAL.verbose = 0;
SPM_GLOBAL.repo_target = NULL;
+ SPM_GLOBAL.mirror_list = NULL;
if (uname(&SPM_GLOBAL.sysinfo) != 0) {
fprintf(SYSERROR);
@@ -205,6 +206,18 @@ void init_config_global(void) {
SPM_GLOBAL.repo_target = normpath(item->value);
}
+ // Initialize mirror list filename
+ SPM_GLOBAL.mirror_config = join((char *[]) {SPM_GLOBAL.user_config_basedir, SPM_MIRROR_FILENAME, NULL}, DIRSEPS);
+ item = config_get(SPM_GLOBAL.config, "mirror_config");
+ if (item) {
+ free(SPM_GLOBAL.mirror_config);
+ SPM_GLOBAL.mirror_config = normpath(item->value);
+ }
+
+ if (SPM_GLOBAL.mirror_config != NULL) {
+ SPM_GLOBAL.mirror_list = mirror_list(SPM_GLOBAL.mirror_config);
+ }
+
// Initialize temp directory
item = config_get(SPM_GLOBAL.config, "tmp_dir");
if (item) {
diff --git a/src/internal_cmd.c b/src/internal_cmd.c
index 2390671..530d008 100644
--- a/src/internal_cmd.c
+++ b/src/internal_cmd.c
@@ -10,6 +10,7 @@ static char *internal_commands[] = {
"mkprefixbin", "generate prefix manifest (binary)",
"mkprefixtext", "generate prefix manifest (text)",
"mkmanifest", "generate package repository manifest",
+ "mirror_clone", "mirror a mirror",
"rpath_set", "modify binary RPATH",
"rpath_autoset", "determine nearest lib directory and set RPATH",
NULL, NULL,
@@ -133,6 +134,35 @@ int mkmanifest_interface(int argc, char **argv) {
/**
*
*/
+void mirror_clone_interface_usage(void) {
+ printf("usage: mirror_clone {url} {output_dir}");
+}
+
+/**
+ * Mirror packages referenced by a remote manifest
+ * @param argc
+ * @param argv
+ * @return value of `manifest_write`
+ */
+int mirror_clone_interface(int argc, char **argv) {
+ if (argc < 3) {
+ mirror_clone_interface_usage();
+ return -1;
+ }
+ char *url = argv[1];
+ char *path = argv[2];
+
+ Manifest *manifest = manifest_read(url);
+ if (manifest == NULL) {
+ return -2;
+ }
+
+ mirror_clone(manifest, path);
+ return 0;
+}
+/**
+ *
+ */
void rpath_set_interface_usage(void) {
printf("usage: rpath_set {file} {rpath}\n");
}
@@ -231,6 +261,9 @@ int internal_cmd(int argc, char **argv) {
else if (strcmp(command, "mkmanifest") == 0) {
return mkmanifest_interface(arg_count, arg_array);
}
+ else if (strcmp(command, "mirror_clone") == 0) {
+ return mirror_clone_interface(arg_count, arg_array);
+ }
else if (strcmp(command, "rpath_set") == 0) {
return rpath_set_interface(arg_count, arg_array);
}
diff --git a/src/manifest.c b/src/manifest.c
index 28cf2c4..d1298cf 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -292,6 +292,7 @@ int manifest_validate(void) {
Manifest *manifest_read(char *file_or_url) {
FILE *fp = NULL;
char *filename = SPM_MANIFEST_FILENAME;
+ char *tmpdir = NULL;
char path[PATH_MAX];
// When file_or_url is NULL we want to use the global manifest
@@ -300,25 +301,38 @@ Manifest *manifest_read(char *file_or_url) {
strcpy(path, SPM_GLOBAL.package_manifest);
}
else {
- strcpy(path, file_or_url);
+ char *template = join((char *[]) {TMP_DIR, "spm_manifest_read_XXXXXX", NULL}, DIRSEPS);
+ tmpdir = mkdtemp(template);
+ if (exists(tmpdir) != 0) {
+ fprintf(stderr, "Failed to create temporary storage directory\n");
+ fprintf(SYSERROR);
+ return NULL;
+ }
+
+ snprintf(path, PATH_MAX, "%s%c%s", template, DIRSEP, filename);
}
// Handle receiving a path without the manifest filename
// by appending the manifest to the path
- if (endswith(path, filename) != 0) {
+ if (startswith(path, "http") != 0 && endswith(path, filename) != 0) {
strcat(path, DIRSEPS);
strcat(path, filename);
}
if (exists(path) != 0) {
// TODO: Move this out
- char *remote_manifest = join((char *[]) {"http://astroconda.org/spm", SPM_GLOBAL.repo_target, filename, NULL}, DIRSEPS);
+ //char *remote_manifest = join((char *[]) {"http://astroconda.org/spm", SPM_GLOBAL.repo_target, filename, NULL}, DIRSEPS);
+ char *remote_manifest = join((char *[]) {file_or_url, SPM_GLOBAL.repo_target, filename, NULL}, DIRSEPS);
int fetch_status = fetch(remote_manifest, path);
if (fetch_status >= 400) {
fprintf(stderr, "HTTP %d: %s: %s\n", fetch_status, http_response_str(fetch_status), remote_manifest);
free(remote_manifest);
return NULL;
}
+ else if (fetch_status == 1 || fetch_status < 0) {
+ free(remote_manifest);
+ return NULL;
+ }
free(remote_manifest);
}
@@ -361,18 +375,24 @@ Manifest *manifest_read(char *file_or_url) {
dptr = strip(dptr);
char *garbage;
char **parts = split(dptr, &separator);
- char *_origin = dirname(path);
+ char *_origin = NULL;
+ if (file_or_url != NULL) {
+ _origin = strdup(file_or_url);
+ }
+ else {
+ _origin = dirname(path);
+ }
info->packages[i] = (ManifestPackage *)calloc(1, sizeof(ManifestPackage));
- strncpy(info->packages[i]->origin, _origin, strlen(_origin));
+ strncpy(info->packages[i]->origin, _origin, PACKAGE_MEMBER_ORIGIN_SIZE);
free(_origin);
- strncpy(info->packages[i]->archive, parts[0], strlen(parts[0]));
+ strncpy(info->packages[i]->archive, parts[0], PACKAGE_MEMBER_SIZE);
info->packages[i]->size = strtoul(parts[1], &garbage, 10);
- strncpy(info->packages[i]->name, parts[2], strlen(parts[2]));
- strncpy(info->packages[i]->version, parts[3], strlen(parts[3]));
- strncpy(info->packages[i]->revision, parts[4], strlen(parts[4]));
+ strncpy(info->packages[i]->name, parts[2], PACKAGE_MEMBER_SIZE);
+ strncpy(info->packages[i]->version, parts[3], PACKAGE_MEMBER_SIZE);
+ strncpy(info->packages[i]->revision, parts[4], PACKAGE_MEMBER_SIZE);
info->packages[i]->requirements_records = (size_t) atoi(parts[5]);
info->packages[i]->requirements = NULL;
@@ -381,7 +401,9 @@ Manifest *manifest_read(char *file_or_url) {
}
if (strncmp(parts[7], SPM_MANIFEST_NODATA, strlen(SPM_MANIFEST_NODATA)) != 0) {
- strncpy(info->packages[i]->checksum_sha256, parts[7], strlen(parts[7]));
+ memset(info->packages[i]->checksum_sha256, '\0', SHA256_DIGEST_LENGTH);
+ strncpy(info->packages[i]->checksum_sha256, parts[7], SHA256_DIGEST_LENGTH);
+
}
split_free(parts);
@@ -389,6 +411,9 @@ Manifest *manifest_read(char *file_or_url) {
i++;
}
+ if (tmpdir != NULL) {
+ free(tmpdir);
+ }
fclose(fp);
return info;
}
diff --git a/src/mirrors.c b/src/mirrors.c
new file mode 100644
index 0000000..5c18a1c
--- /dev/null
+++ b/src/mirrors.c
@@ -0,0 +1,100 @@
+#include "spm.h"
+
+char **file_readlines(const char *filename) {
+ FILE *fp = NULL;
+ char **result = NULL;
+ char *buffer = NULL;
+ size_t lines = 0;
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ perror(filename);
+ fprintf(SYSERROR);
+ return NULL;
+ }
+
+ // Allocate buffer
+ if ((buffer = calloc(BUFSIZ + 1, sizeof(char))) == NULL) {
+ perror("line buffer");
+ fprintf(SYSERROR);
+ fclose(fp);
+ return NULL;
+ }
+
+ // count number the of lines in the file
+ while ((fgets(buffer, BUFSIZ, fp)) != NULL) {
+ lines++;
+ }
+
+ if (!lines) {
+ free(buffer);
+ fclose(fp);
+ return NULL;
+ }
+
+ rewind(fp);
+
+ // Populate results array
+ result = calloc(lines + 1, sizeof(char *));
+ for (size_t i = 0; i < lines; i++) {
+ if (fgets(buffer, BUFSIZ, fp) == NULL) {
+ break;
+ }
+ result[i] = strdup(buffer);
+ }
+
+ free(buffer);
+ fclose(fp);
+ return result;
+}
+
+char **mirror_list(const char *filename) {
+ char **mirrors = file_readlines(filename);
+ char **result = NULL;
+ size_t count;
+ for (count = 0; mirrors[count] != NULL; count++);
+
+ if (!count) {
+ return NULL;
+ }
+
+ result = calloc(count + 1, sizeof(char **));
+ for (size_t i = 0; mirrors[i] != NULL; i++) {
+ if (startswith(mirrors[i], "#") == 0 || isempty(mirrors[i])) {
+ continue;
+ }
+ result[i] = join((char *[]) {mirrors[i], SPM_GLOBAL.repo_target, NULL}, DIRSEPS);
+ free(mirrors[i]);
+ }
+ free(mirrors);
+ return result;
+}
+
+void mirror_clone(Manifest *info, char *dest) {
+ if (exists(dest) != 0 && mkdir(dest, 0755) != 0) {
+ perror("Unable to create mirror directory");
+ fprintf(SYSERROR);
+ exit(1);
+ }
+
+ for (size_t i = 0; i < info->records; i++) {
+ long response = 0;
+ char *url = join((char *[]) {info->packages[i]->origin, SPM_GLOBAL.repo_target, info->packages[i]->archive, NULL}, DIRSEPS);
+ char *path = join((char *[]) {dest, info->packages[i]->archive, NULL}, DIRSEPS);
+ if (exists(path) == 0) {
+ char *checksum = sha256sum(path);
+ char *wtf_orig = checksum;
+ char *wtf_new = info->packages[i]->checksum_sha256;
+ if (strcmp(checksum, info->packages[i]->checksum_sha256) == 0) {
+ free(url);
+ free(path);
+ continue;
+ }
+ }
+ printf("Downloading: %s\n", url);
+ if ((response = fetch(url, path)) >= 400) {
+ fprintf(stderr, "Failed to retrieve (error: %ld): %s\n", response, url);
+ }
+ free(url);
+ free(path);
+ }
+} \ No newline at end of file
diff --git a/src/spm.c b/src/spm.c
index 052ac09..e0eec10 100644
--- a/src/spm.c
+++ b/src/spm.c
@@ -152,11 +152,11 @@ int main(int argc, char *argv[], char *arge[]) {
// TODO: Move environment allocation out of (above) this loop if possible
// TODO: replace variables below with SPM_Hierarchy, and write some control functions
- char *spm_binpath = join((char *[]) {root, "bin"}, DIRSEPS);
- char *spm_includepath = join((char *[]) {root, "include"}, DIRSEPS);
- char *spm_libpath = join((char *[]) {root, "lib"}, DIRSEPS);
- char *spm_datapath = join((char *[]) {root, "share"}, DIRSEPS);
- char *spm_manpath = join((char *[]) {spm_datapath, "man"}, DIRSEPS);
+ char *spm_binpath = join((char *[]) {root, "bin", NULL}, DIRSEPS);
+ char *spm_includepath = join((char *[]) {root, "include", NULL}, DIRSEPS);
+ char *spm_libpath = join((char *[]) {root, "lib", NULL}, DIRSEPS);
+ char *spm_datapath = join((char *[]) {root, "share", NULL}, DIRSEPS);
+ char *spm_manpath = join((char *[]) {spm_datapath, "man", NULL}, DIRSEPS);
runtime_set(rt, "SPM_BIN", spm_binpath);
runtime_set(rt, "SPM_INCLUDE", spm_includepath);