diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2020-02-25 12:54:08 -0500 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2020-02-25 12:54:08 -0500 |
commit | e711ec23316ffe6218d23125eab5ad8bca58e09d (patch) | |
tree | 516474007f6cab45dcbb5a300d93b17a1c2d233d /src/install.c | |
parent | ba9f28653fb3a54d604c13227ce50f33c524cbe6 (diff) | |
download | spmc-e711ec23316ffe6218d23125eab5ad8bca58e09d.tar.gz |
Refactor installation:
* install() accepts a temporary directory as an argument
* Add install_package_record()
* Add is_installed()
* Add do_install() wrapper
* Use spm_user_yesno() before installation
Diffstat (limited to 'src/install.c')
-rw-r--r-- | src/install.c | 204 |
1 files changed, 167 insertions, 37 deletions
diff --git a/src/install.c b/src/install.c index cf22d23..3603af5 100644 --- a/src/install.c +++ b/src/install.c @@ -46,10 +46,11 @@ void install_show_package(ManifestPackage *package) { * The destination is created if it does not exist. * @param _destroot directory to install package * @param _package name of archive to install (not a path) - * @return success=0, error=-1 (general), -2 (unable to create `destroot`) + * @return success=0, exists=1, error=-1 (general), -2 (unable to create `destroot`) */ -int install(const char *destroot, const char *_package) { +int install(const char *destroot, const char *tmpdir, const char *_package) { char *package = strdup(_package); + if (!package) { fprintf(SYSERROR); return -1; @@ -61,66 +62,195 @@ int install(const char *destroot, const char *_package) { } if (mkdirs(destroot, 0755) != 0) { fprintf(SYSERROR); + free(package); return -2; } } - char source[PATH_MAX]; - char template[PATH_MAX]; + if (SPM_GLOBAL.verbose) { + printf("Extracting archive: %s\n", package); + } - // circumvent -Wformat-truncation - char *suffix = (char *) calloc(PATH_MAX, sizeof(char)); - if (!suffix) { - perror("suffix"); - fprintf(SYSERROR); + if (tar_extract_archive(package, tmpdir) != 0) { + fprintf(stderr, "%s: %s\n", package, strerror(errno)); + free(package); return -1; } - strcpy(suffix, "spm_destroot_XXXXXX"); - snprintf(template, PATH_MAX, "%s%c%s", TMP_DIR, DIRSEP, suffix); - free(suffix); - // Create a new temporary directory and extract the requested package into it - char *tmpdir = mkdtemp(template); - if (exists(tmpdir) != 0) { - fprintf(stderr, "Failed to create temporary storage directory\n"); + free(package); + return 0; +} + +int install_package_record(char *from_root, char *package_name) { + RuntimeEnv *rt = runtime_copy(__environ); + char *records_topdir = normpath(runtime_expand_var(rt, "$SPM_LOCALSTATE/db/records")); + char *records_pkgdir = join((char *[]) {records_topdir, package_name, NULL}, DIRSEPS); + char *descriptor = join((char *[]) {from_root, SPM_META_DESCRIPTOR, NULL}, DIRSEPS); + char *filelist = join((char *[]) {from_root, SPM_META_FILELIST, NULL}, DIRSEPS); + + if (exists(records_pkgdir) != 0) { + if (mkdirs(records_pkgdir, 0755) != 0) { + return -1; + } + } + + if (exists(descriptor) != 0) { + fprintf(stderr, "Missing: %s\n", descriptor); + return 1; + } + + if (exists(filelist) != 0) { + fprintf(stderr, "Missing: %s\n", filelist); + return 2; + } + + if (rsync(NULL, descriptor, records_pkgdir) != 0) { + fprintf(stderr, "Failed to copy '%s' to '%s'\n", descriptor, records_pkgdir); + return 3; + } + + if (rsync(NULL, filelist, records_pkgdir) != 0) { + fprintf(stderr, "Failed to copy '%s' to '%s'\n", filelist, records_pkgdir); + return 4; + } + + free(records_topdir); + free(records_pkgdir); + free(descriptor); + free(filelist); + runtime_free(rt); + return 0; +} + +int is_installed(const char *rootdir, char *package_name) { + RuntimeEnv *rt = runtime_copy(__environ); + char *records_topdir = normpath(runtime_expand_var(rt, "$SPM_LOCALSTATE/db/records")); + char *records_pkgdir = join((char *[]) {records_topdir, package_name, NULL}, DIRSEPS); + int result = 1; // 1 == exists + + if (exists(records_pkgdir) != 0) { + // does not exist + result = 0; + } + + free(records_topdir); + free(records_pkgdir); + // exists + return result; +} + +/** + * Perform a full package installation + * @param mf + * @param rootdir + * @param packages + * @return 0=success, -1=failed to create storage, -2=denied by user + */ +int do_install(ManifestList *mf, const char *rootdir, StrList *packages) { + size_t num_requirements = 0; + ManifestPackage **requirements = NULL; + char source[PATH_MAX]; + char *tmpdir = spm_mkdtemp("spm_destroot"); + + if (tmpdir == NULL) { + perror("Could not create temporary destination root"); fprintf(SYSERROR); - exit(errno); + return -1; } if (SPM_GLOBAL.verbose) { - printf("Extracting archive: %s\n", package); + printf("Installation root: %s\n", rootdir); } - if (tar_extract_archive(package, tmpdir) != 0) { - fprintf(stderr, "%s: %s\n", package, strerror(errno)); - return -1; + + // Produce a dependency tree from requested package(s) + for (size_t i = 0; i < strlist_count(packages); i++) { + requirements = resolve_dependencies(mf, strlist_item(packages, i)); + if (requirements != NULL) { + for (size_t c = 0; requirements[c] != NULL; c++) { + num_requirements++; + } + } } - // Relocate temporary directory - relocate_root(destroot, tmpdir); + // Append requested package(s) to requirements array + for (size_t i = 0; i < strlist_count(packages); i++) { + char *name = strlist_item(packages, i); + ManifestPackage *package = manifestlist_search(mf, name); + requirements[i + num_requirements] = package; + } - // Append a trailing slash to tmpdir to direct rsync to copy files, not the directory, into destroot - sprintf(source, "%s%c", tmpdir, DIRSEP); + // Install packages + printf("Requested package(s):\n"); + for (size_t i = 0; requirements !=NULL && requirements[i] != NULL; i++) { + install_show_package(requirements[i]); + } - // Remove metadata files before copying - if (SPM_GLOBAL.verbose) { - printf("Removing metadata\n"); + if (SPM_GLOBAL.prompt_user) { + int user_choice; + int status_choice; + printf("\nProceed with installation? [Y/n] "); + while ((user_choice = getchar())) { + status_choice = spm_user_yesno(user_choice, 1); + if (status_choice == 0) { // No + exit(-2); + } else if (status_choice == 1) { // Yes + break; + } else { // Only triggers when spm_user_yesno's second argument is zero + puts("Please answer 'y' or 'n'..."); + } + } + puts(""); } - metadata_remove(source); - // Copy temporary directory to destination - if (SPM_GLOBAL.verbose) { - printf("Installing tree: '%s' => '%s'\n", source, destroot); + printf("Installing package(s):\n"); + size_t num_installed = 0; + for (size_t i = 0; requirements != NULL && requirements[i] != NULL; i++) { + char *package_path = join((char *[]) {requirements[i]->origin, SPM_GLOBAL.repo_target, requirements[i]->archive, NULL}, DIRSEPS); + + if (is_installed(rootdir, requirements[i]->name)) { + printf(" -> %s is already installed\n", requirements[i]->name); + free(package_path); + continue; + } + + install_show_package(requirements[i]); + install(rootdir, tmpdir, package_path); + install_package_record(tmpdir, requirements[i]->name); + num_installed++; + free(package_path); + } + + // free requirements array + for (size_t i = 0; requirements != NULL && requirements[i] != NULL; i++) { + manifest_package_free(requirements[i]); } - if (rsync(NULL, source, destroot) != 0) { - exit(1); + if (num_installed != 0) { + // Relocate installation root + relocate_root(rootdir, tmpdir); + + // Append a trailing slash to tmpdir to direct rsync to copy files, not the directory, into destroot + sprintf(source, "%s%c", tmpdir, DIRSEP); + + // Remove metadata files before copying + if (SPM_GLOBAL.verbose) { + printf("Removing metadata\n"); + } + metadata_remove(source); + + // Copy temporary directory to destination + if (SPM_GLOBAL.verbose) { + printf("Installing tree: '%s' => '%s'\n", source, rootdir); + } + + if (rsync(NULL, source, rootdir) != 0) { + exit(1); + } } if (SPM_GLOBAL.verbose) { printf("Removing temporary storage: '%s'\n", tmpdir); } rmdirs(tmpdir); - - free(package); return 0; -} +}
\ No newline at end of file |