aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml40
-rwxr-xr-x.circleci/init.sh40
-rwxr-xr-x.circleci/install_reloc.sh4
-rwxr-xr-x.circleci/install_spm.sh4
-rw-r--r--.circleci/runtime.sh15
-rwxr-xr-x.circleci/test_spm.sh33
-rw-r--r--include/error_handler.h15
-rw-r--r--include/spm.h4
-rw-r--r--lib/config_global.c10
-rw-r--r--lib/error_handler.c22
-rw-r--r--lib/install.c40
-rw-r--r--lib/internal_cmd.c6
-rw-r--r--lib/manifest.c16
-rw-r--r--lib/user_input.c1
-rwxr-xr-xscripts/spmbuild36
-rw-r--r--src/spm.c1
-rw-r--r--tests/test_error_handler_spm_strerror.c9
-rw-r--r--tests/test_error_handler_spmerrno_cause.c33
18 files changed, 262 insertions, 67 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 270bd76..54b5d9e 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,7 +1,7 @@
version: 2.1
jobs:
- build:
+ build-centos7:
docker:
- image: centos:7
@@ -29,6 +29,36 @@ jobs:
command: |
.circleci/install_reloc.sh
+ - run:
+ name: "Install spm"
+ command: |
+ .circleci/install_spm.sh
+
+ - run:
+ name: "Run tests"
+ command: |
+ .circleci/test_spm.sh
+
+ build-macos:
+ macos:
+ xcode: 11.4.0
+
+ environment:
+ HOMEBREW_NO_AUTO_UPDATE: 1
+ DYLD_INSERT_LIBRARIES: /usr/lib/libgmalloc.dylib
+
+ steps:
+ - checkout
+
+ - run:
+ name: "Initialize"
+ command: |
+ .circleci/init.sh
+
+ - run:
+ name: "Install reloc"
+ command: |
+ .circleci/install_reloc.sh
- run:
name: "Install spm"
@@ -39,3 +69,11 @@ jobs:
name: "Run tests"
command: |
.circleci/test_spm.sh
+
+workflows:
+ version: 2
+ build-and-test:
+ jobs:
+ - build-centos7
+ - build-macos
+
diff --git a/.circleci/init.sh b/.circleci/init.sh
index 81c5091..877b9de 100755
--- a/.circleci/init.sh
+++ b/.circleci/init.sh
@@ -1,16 +1,26 @@
#!/bin/bash
-yum install -y \
- make \
- patchelf \
- binutils \
- curl-devel \
- openssl-devel \
- file \
- which \
- rsync \
- tar \
- cmake3 \
- gcc \
- gcc-c++ \
- gcc-gfortran \
- glibc-devel
+if [[ $(uname -s) == Linux ]]; then
+ yum install -y \
+ make \
+ patchelf \
+ binutils \
+ curl-devel \
+ openssl-devel \
+ file \
+ which \
+ rsync \
+ tar \
+ cmake3 \
+ gcc \
+ gcc-c++ \
+ gcc-gfortran \
+ glibc-devel
+
+ ln -s cmake3 /usr/bin/cmake
+ ln -s ctest3 /usr/bin/ctest
+
+elif [[ $(uname -s) == Darwin ]]; then
+ brew install cmake \
+ gnu-tar \
+ openssl@1.1
+fi
diff --git a/.circleci/install_reloc.sh b/.circleci/install_reloc.sh
index 35945f3..cd7be7b 100755
--- a/.circleci/install_reloc.sh
+++ b/.circleci/install_reloc.sh
@@ -1,8 +1,10 @@
#!/bin/bash
+source $(dirname "${BASH_SOURCE[0]}")/runtime.sh
+
git clone https://github.com/jhunkeler/reloc
mkdir -p reloc/build
pushd reloc/build
- cmake3 -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release ..
+ cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release ..
make install
popd
rm -rf reloc
diff --git a/.circleci/install_spm.sh b/.circleci/install_spm.sh
index 4aaea1c..33960c5 100755
--- a/.circleci/install_spm.sh
+++ b/.circleci/install_spm.sh
@@ -1,5 +1,7 @@
#!/bin/bash
+source $(dirname "${BASH_SOURCE[0]}")/runtime.sh
+
mkdir build
cd build
-cmake3 -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug ..
+cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug ..
make install
diff --git a/.circleci/runtime.sh b/.circleci/runtime.sh
new file mode 100644
index 0000000..0b41b9c
--- /dev/null
+++ b/.circleci/runtime.sh
@@ -0,0 +1,15 @@
+if [[ $(uname -s) == Linux ]]; then
+ :
+elif [[ $(uname -s) == Darwin ]]; then
+ OPENSSL_DIR=/usr/local/opt/openssl
+ PATH="$OPENSSL_DIR/bin:$PATH"
+ LDFLAGS="$LDFLAGS -L${OPENSSL_DIR}/lib"
+ CFLAGS="$CFLAGS -I${OPENSSL_DIR}/include"
+
+ GTAR_DIR=/usr/local/opt/gnu-tar
+ PATH="$GTAR_DIR/libexec/gnubin:$PATH"
+
+ export PATH
+ export LDFLAGS
+ export CFLAGS
+fi
diff --git a/.circleci/test_spm.sh b/.circleci/test_spm.sh
index bb70212..eb141e5 100755
--- a/.circleci/test_spm.sh
+++ b/.circleci/test_spm.sh
@@ -1,4 +1,5 @@
#!/bin/bash -e
+source $(dirname "${BASH_SOURCE[0]}")/runtime.sh
export PREFIX=/tmp/root
export SHELL=/bin/bash
@@ -6,31 +7,33 @@ cd build
set -x
-ctest3 -V
+ctest -V
spm --list
spm --search zlib
-spm --verbose --yes --root $PREFIX --install python
+if [[ $(uname -s) == Linux ]]; then
+ spm --verbose --yes --root $PREFIX --install python
-set +x
-echo ACTIVATING ROOT: $PREFIX
-spm --cmd mkruntime $PREFIX > $PREFIX/bin/activate || exit 1
-source $PREFIX/bin/activate || exit 1
-echo OK!
-set -x
+ set +x
+ echo ACTIVATING ROOT: $PREFIX
+ spm --cmd mkruntime $PREFIX > $PREFIX/bin/activate || exit 1
+ source $PREFIX/bin/activate || exit 1
+ echo OK!
+ set -x
-which python3
+ which python3
-python3 -V
+ python3 -V
-python3 -c 'from sysconfig import get_config_vars; from pprint import pprint; pprint(get_config_vars())'
+ python3 -c 'from sysconfig import get_config_vars; from pprint import pprint; pprint(get_config_vars())'
-python3 -m ensurepip
+ python3 -m ensurepip
-pip3 --version
+ pip3 --version
-pip3 install --upgrade pip setuptools
+ pip3 install --upgrade pip setuptools
-pip3 --version
+ pip3 --version
+fi
diff --git a/include/error_handler.h b/include/error_handler.h
index a731d28..92705fe 100644
--- a/include/error_handler.h
+++ b/include/error_handler.h
@@ -14,20 +14,13 @@
#define SPM_ERR_PKG_INVALID _SPM_ERR(4) // invalid package (wrong structure, missing data, etc)
#define SPM_ERR_PKG_CHECKSUM _SPM_ERR(5) // bad checksum
#define SPM_ERR_PKG_FETCH _SPM_ERR(6) // failed to download package
+#define SPM_ERR_MANIFEST_INVALID _SPM_ERR(7) // manifest file is invalid (no header)
+#define SPM_ERR_MANIFEST_EMPTY _SPM_ERR(8) // manifest file has no data
extern int spmerrno;
+extern const char *SPM_ERR_STRING[];
-static const char *SPM_ERR_STRING[] = {
- "Success",
- "No root record",
- "Dangerous root path",
- "Package not found",
- "Invalid package",
- "Bad package checksum",
- "Failed to fetch package",
- NULL,
-};
-
+void spmerrno_cause(const char *reason);
char *spm_strerror(int code);
void spm_perror(const char *msg);
diff --git a/include/spm.h b/include/spm.h
index b96554a..f9b2201 100644
--- a/include/spm.h
+++ b/include/spm.h
@@ -27,6 +27,8 @@
#include <utime.h>
#endif
+#include "conf.h"
+extern spm_vars SPM_GLOBAL;
#include "compat.h"
#include "error_handler.h"
#include "package.h"
@@ -44,7 +46,6 @@
#include "resolve.h"
#include "shell.h"
#include "relocation.h"
-#include "conf.h"
#include "archive.h"
#include "find.h"
#include "rpath.h"
@@ -96,7 +97,6 @@
_1________________________________________________"
// GLOBALS
-spm_vars SPM_GLOBAL;
#ifdef __APPLE__
extern char **environ;
diff --git a/lib/config_global.c b/lib/config_global.c
index e97cddb..52589d4 100644
--- a/lib/config_global.c
+++ b/lib/config_global.c
@@ -3,6 +3,10 @@
*/
#include "spm.h"
+// GLOBAL
+spm_vars SPM_GLOBAL;
+
+
/**
* Get path to user's local configuration directory
* (The path will be created if it doesn't exist)
@@ -125,7 +129,13 @@ void check_runtime_environment(void) {
int bad_rt = 0;
char *required[] = {
"file",
+#if defined(__linux) || defined(__linux__)
"patchelf",
+#elif defined(__APPLE__) && defined(__MACH__)
+ "install_name_tool",
+#elif defined(__WIN32__)
+ // TODO: Does windows provide some kind of equivalent?
+#endif
"objdump",
"rsync",
"tar",
diff --git a/lib/error_handler.c b/lib/error_handler.c
index baf56b4..4e06919 100644
--- a/lib/error_handler.c
+++ b/lib/error_handler.c
@@ -2,7 +2,25 @@
int spmerrno = 0;
static char spmerrbuf[255];
+static char spmerrbuf_reason[255];
+const char *SPM_ERR_STRING[] = {
+ "Success",
+ "No root record",
+ "Dangerous root path",
+ "Package not found",
+ "Invalid package",
+ "Bad package checksum",
+ "Failed to fetch package",
+ "Manifest has no header",
+ "Manifest has no data",
+ NULL,
+};
+void spmerrno_cause(const char *reason) {
+ char *buf = spmerrbuf_reason;
+ sprintf(buf, " (%s)", reason);
+ return;
+}
/**
*
* @param code
@@ -18,6 +36,10 @@ char *spm_strerror(int code) {
} else {
strcpy(buf, SPM_ERR_STRING[SPM_ERR_INDEX(code)]);
}
+
+ if (strlen(spmerrbuf_reason)) {
+ strcat(buf, spmerrbuf_reason);
+ }
return buf;
}
diff --git a/lib/install.c b/lib/install.c
index c5c2c4c..32348e2 100644
--- a/lib/install.c
+++ b/lib/install.c
@@ -200,8 +200,32 @@ int spm_do_install(SPM_Hierarchy *fs, ManifestList *mf, StrList *packages) {
size_t num_requirements = 0;
ManifestPackage **requirements = NULL;
char source[PATH_MAX];
- char *tmpdir = spm_mkdtemp(TMP_DIR, "spm_destroot", NULL);
+ char *tmpdir = NULL;
+ // Produce a dependency tree from requested package(s)
+ for (size_t i = 0; i < strlist_count(packages); i++) {
+ char *item = strlist_item(packages, i);
+
+ // Does the package exist in the manifest?
+ if (manifestlist_search(mf, item) == NULL) {
+ spmerrno = SPM_ERR_PKG_NOT_FOUND;
+ spmerrno_cause(item);
+ break;
+ }
+
+ requirements = resolve_dependencies(mf, item);
+ if (requirements != NULL) {
+ for (size_t c = num_requirements; requirements[c] != NULL; c++) {
+ num_requirements++;
+ }
+ }
+ }
+
+ if (spmerrno) {
+ return -1;
+ }
+
+ tmpdir = spm_mkdtemp(TMP_DIR, "spm_destroot", NULL);
if (tmpdir == NULL) {
perror("Could not create temporary destination root");
fprintf(SYSERROR);
@@ -214,20 +238,10 @@ int spm_do_install(SPM_Hierarchy *fs, ManifestList *mf, StrList *packages) {
if (spm_hierarchy_make_root(fs) < 0) {
spmerrno = SPM_ERR_ROOT_NO_RECORD;
+ rmdirs(tmpdir);
return -1;
}
- // Produce a dependency tree from requested package(s)
- for (size_t i = 0; i < strlist_count(packages); i++) {
- char *item = strlist_item(packages, i);
- requirements = resolve_dependencies(mf, item);
- if (requirements != NULL) {
- for (size_t c = num_requirements; requirements[c] != NULL; c++) {
- num_requirements++;
- }
- }
- }
-
// Install packages
printf("Requested package(s):\n");
for (size_t i = 0; requirements !=NULL && requirements[i] != NULL; i++) {
@@ -244,7 +258,7 @@ int spm_do_install(SPM_Hierarchy *fs, ManifestList *mf, StrList *packages) {
char *package_dir = strdup(SPM_GLOBAL.package_dir);
for (size_t i = 0; requirements != NULL && requirements[i] != NULL; i++) {
char *package_origin = calloc(PATH_MAX, sizeof(char));
- strncpy(package_origin, requirements[i]->origin, PATH_MAX);
+ strncpy(package_origin, requirements[i]->origin, PATH_MAX);
if (strstr(package_origin, SPM_GLOBAL.repo_target) == NULL) {
if (!endswith(package_origin, DIRSEPS)) {
diff --git a/lib/internal_cmd.c b/lib/internal_cmd.c
index b1e8faa..e5f875f 100644
--- a/lib/internal_cmd.c
+++ b/lib/internal_cmd.c
@@ -237,7 +237,13 @@ int mkruntime_interface(int argc, char **argv) {
}
runtime_set(rt, "CFLAGS", "-I$SPM_INCLUDE $CFLAGS");
+#if defined(__APPLE__) && defined (__MACH__)
+ runtime_set(rt, "LDFLAGS", "-rpath $SPM_LIB:$SPM_LIB64 -L$SPM_LIB -L$SPM_LIB64 $LDFLAGS");
+#elif defined(__linux) || defined (__linux__)
runtime_set(rt, "LDFLAGS", "-Wl,-rpath=$SPM_LIB:$SPM_LIB64 -L$SPM_LIB -L$SPM_LIB64 $LDFLAGS");
+#else
+ // TODO: Windows?
+#endif
runtime_export(rt, NULL);
runtime_free(rt);
diff --git a/lib/manifest.c b/lib/manifest.c
index a95b566..965665e 100644
--- a/lib/manifest.c
+++ b/lib/manifest.c
@@ -440,7 +440,16 @@ Manifest *manifest_read(char *file_or_url) {
while (fgets(dptr, BUFSIZ, fp) != NULL) {
total_records++;
}
- total_records--; // header does not count
+
+ if (total_records == 0) {
+ spmerrno = SPM_ERR_MANIFEST_INVALID;
+ return NULL;
+ }
+
+ // There's a header, but don't count it in the total
+ total_records--;
+
+ // Going to reprocess the file again, so rewind
rewind(fp);
Manifest *info = (Manifest *)calloc(1, sizeof(Manifest));
@@ -582,10 +591,13 @@ void manifestlist_free(ManifestList *pManifestList) {
*/
void manifestlist_append(ManifestList *pManifestList, char *path) {
Manifest *manifest = manifest_read(path);
- if (manifest == NULL) {
+ if (manifest == NULL && spmerrno == 0) {
fprintf(stderr, "Failed to create manifest in memory\n");
fprintf(SYSERROR);
exit(1);
+ } else if (spmerrno == SPM_ERR_MANIFEST_EMPTY || spmerrno == SPM_ERR_MANIFEST_INVALID) {
+ manifest = calloc(1, sizeof(Manifest));
+ manifest->packages = calloc(1, sizeof(ManifestPackage *));
}
Manifest **tmp = realloc(pManifestList->data, (pManifestList->num_alloc + 1) * sizeof(Manifest *));
diff --git a/lib/user_input.c b/lib/user_input.c
index 416b59f..589a084 100644
--- a/lib/user_input.c
+++ b/lib/user_input.c
@@ -37,4 +37,5 @@ int spm_prompt_user(const char *msg, int empty_input_is_yes) {
}
input_count++;
}
+ return -1;
}
diff --git a/scripts/spmbuild b/scripts/spmbuild
index 1af9641..a5e6300 100755
--- a/scripts/spmbuild
+++ b/scripts/spmbuild
@@ -40,8 +40,16 @@ function msg_warn() {
_msg "WARNING:" "$@"
}
+function tar() {
+ local cmd=tar
+ if [[ $(uname -s) == Darwin ]]; then
+ cmd=gtar
+ fi
+ $cmd "$@"
+}
+
function spm_build_initialize_stage1() {
- export SPMDEV=$(readlink -f $(dirname ${BASH_SOURCE[0]})/../cmake-build-debug/src/spm)
+ export SPMDEV=$(python -c "import os; print(os.path.abspath('$(dirname ${BASH_SOURCE[0]})/../cmake-build-debug/src/spm'))")
export SPM=$(which spm 2>/dev/null || echo ${SPMDEV})
spm_build_check_rt_env
@@ -95,10 +103,24 @@ function spm_build_initialize_stage1() {
fi
}
+function spm_build_new_root() {
+ local path
+
+ path=$(mktemp)
+ if [[ ! -f "${path}" ]]; then
+ msg_error "spm_build_new_root: failed to create temporary file"
+ exit 1
+ fi
+ spm_build_mkruntime "$1" > "${path}"
+ source "${path}"
+ rm -f "${path}"
+}
+
function spm_build_initialize_stage2() {
# In order to get the SPM_* variables out spm, we need to give a path...
# this is ugly but safe-ish
- source <(spm_build_mkruntime "/usr")
+ spm_build_new_root "/usr"
+
unset CFLAGS
unset CPPFLAGS
unset LDFLAGS
@@ -152,9 +174,15 @@ function spm_build_initialize_stage2() {
_maxjobs=1
fi
- source <(spm_build_mkruntime "${SPM_BUILD_RUNTIME}")
+ spm_build_new_root "${SPM_BUILD_RUNTIME}"
export LD_LIBRARY_PATH="${SPM_BUILD_RUNTIME}/lib:${SPM_BUILD_RUNTIME}/lib64"
export LD_RUN_PATH="${LD_LIBRARY_PATH}"
+ if [[ $(uname -s) == Darwin ]]; then
+ DYLD_LIBRARY_PATH="${LD_LIBRARY_PATH}"
+ DYLD_RUN_PATH="${LD_RUN_PATH}"
+ unset LD_LIBRARY_PATH
+ unset LD_RUNPATH_PATH
+ fi
export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1
export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1
}
@@ -214,7 +242,7 @@ function spm_build_fetch() {
local filename
local tmpdir
- if [[ $# < 2 ]]; then
+ if (( $# < 2 )); then
msg_error "spm_build_fetch: {url} {destination}"
spm_build_cleanup
exit 1
diff --git a/src/spm.c b/src/spm.c
index bb58401..971d506 100644
--- a/src/spm.c
+++ b/src/spm.c
@@ -29,6 +29,7 @@ void usage(const char *program_name) {
, program_name);
}
+extern spm_vars SPM_GLOBAL;
int main(int argc, char *argv[], char *arge[]) {
char *program_name = strdup(argv[0]);
diff --git a/tests/test_error_handler_spm_strerror.c b/tests/test_error_handler_spm_strerror.c
index f373a59..2164f93 100644
--- a/tests/test_error_handler_spm_strerror.c
+++ b/tests/test_error_handler_spm_strerror.c
@@ -3,12 +3,17 @@
const char *testFmt = "translated error code '%d': returned '%s', expected '%s'\n";
struct TestCase testCase[] = {
+#if defined(__APPLE__) && defined(__MACH__)
+ {.caseValue.signed_integer = 0, .truthValue.sptr = "Undefined error: 0", .arg[0].signed_integer = 0},
+ {.caseValue.signed_integer = -1, .truthValue.sptr = "Unknown error: -1", .arg[0].signed_integer = 0},
+#elif defined(__linux) || defined(__linux__)
{.caseValue.signed_integer = 0, .truthValue.sptr = "Success", .arg[0].signed_integer = 0},
+ {.caseValue.signed_integer = -1, .truthValue.sptr = "Unknown error -1", .arg[0].signed_integer = 0},
+#endif
{.caseValue.signed_integer = SPM_ERR_ROOT_NO_RECORD, .truthValue.sptr = "No root record", .arg[0].signed_integer = 0},
{.caseValue.signed_integer = SPM_ERR_ROOT_UNSAFE, .truthValue.sptr = "Dangerous root path", .arg[0].signed_integer = 0},
{.caseValue.signed_integer = ENOENT, .truthValue.sptr = "No such file or directory", .arg[0].signed_integer = ENOENT},
{.caseValue.signed_integer = EPIPE, .truthValue.sptr = "Broken pipe", .arg[0].signed_integer = EPIPE},
- {.caseValue.signed_integer = -1, .truthValue.sptr = "Unknown error -1", .arg[0].signed_integer = 0},
};
size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
@@ -24,4 +29,4 @@ int main(int argc, char *argv[]) {
myassert(strcmp(estr, testCase[i].truthValue.sptr) == 0, testFmt, testCase[i].caseValue.signed_integer, estr, testCase[i].truthValue.sptr);
}
return 0;
-} \ No newline at end of file
+}
diff --git a/tests/test_error_handler_spmerrno_cause.c b/tests/test_error_handler_spmerrno_cause.c
new file mode 100644
index 0000000..c24b996
--- /dev/null
+++ b/tests/test_error_handler_spmerrno_cause.c
@@ -0,0 +1,33 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "translated error code '%d': returned '%s', expected '%s'\n";
+struct TestCase testCase[] = {
+#if defined(__APPLE__) && defined(__MACH__)
+ {.caseValue.signed_integer = 0, .truthValue.sptr = "Undefined error: 0 (winning)", .arg[0].signed_integer = 0, .arg[1].sptr = "winning"},
+ {.caseValue.signed_integer = -1, .truthValue.sptr = "Unknown error: -1 (not winning)", .arg[0].signed_integer = 0, .arg[1].sptr = "not winning"},
+#elif defined(__linux) || defined(__linux__)
+ {.caseValue.signed_integer = 0, .truthValue.sptr = "Success (winning)", .arg[0].signed_integer = 0, .arg[1].sptr = "winning"},
+ {.caseValue.signed_integer = -1, .truthValue.sptr = "Unknown error -1 (not winning)", .arg[0].signed_integer = 0, .arg[1].sptr = "not winning"},
+#endif
+ {.caseValue.signed_integer = SPM_ERR_ROOT_NO_RECORD, .truthValue.sptr = "No root record (/some/path)", .arg[0].signed_integer = 0, .arg[1].sptr = "/some/path"},
+ {.caseValue.signed_integer = SPM_ERR_ROOT_UNSAFE, .truthValue.sptr = "Dangerous root path (was /)", .arg[0].signed_integer = 0, .arg[1].sptr = "was /"},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ // Mock global errno value to the value stored in the test case
+ errno = testCase[i].arg[0].signed_integer;
+ // Mock spmerrno value
+ spmerrno = testCase[i].caseValue.signed_integer;
+ spmerrno_cause(testCase[i].arg[1].sptr);
+
+ // Get SPM error (or system error)
+ char *estr = spm_strerror(testCase[i].caseValue.signed_integer);
+
+ // Assert error string matches error produced
+ myassert(strcmp(estr, testCase[i].truthValue.sptr) == 0, testFmt, testCase[i].caseValue.signed_integer, estr, testCase[i].truthValue.sptr);
+ }
+ return 0;
+}