From fa3b59b2464a482341e70a601efd366b15f7c51f Mon Sep 17 00:00:00 2001 From: Juan RP Date: Wed, 24 Dec 2008 07:20:19 +0100 Subject: [PATCH] Another checkpoint for installing binary packages. At least now dependencies are tracked, not sure it will be enough for real life :-) --HG-- extra : convert_revision : 962de22d515efa5599c148f918c14d32b5d9496d --- bin/xbps-pkgdb.c | 2 +- include/plist.h | 4 + lib/Makefile | 3 +- lib/depends.c | 197 ++++++++++++++++++++++++----------------------- lib/install.c | 50 ++++++++---- lib/plist.c | 25 ++++++ lib/util.c | 96 +++++++++++++++++++++++ 7 files changed, 266 insertions(+), 111 deletions(-) create mode 100644 lib/util.c diff --git a/bin/xbps-pkgdb.c b/bin/xbps-pkgdb.c index c5321e5ff7c..a1fdf0c1b3f 100644 --- a/bin/xbps-pkgdb.c +++ b/bin/xbps-pkgdb.c @@ -108,7 +108,7 @@ usage(void) " unregister\t[ ]\n" " version\t[]\n" " Environment:\n" - " XBPS_REGPKGDB_PATH\tPath to xbps pkgdb plist file\n\n" + " XBPS_META_PATH\tPath to xbps metadata root directory\n\n" " Examples:\n" " $ xbps-pkgdb list\n" " $ xbps-pkgdb register pkgname 2.0 \"A short description\"\n" diff --git a/include/plist.h b/include/plist.h index 46654ae753f..e5817c961f4 100644 --- a/include/plist.h +++ b/include/plist.h @@ -80,6 +80,9 @@ xbps_callback_array_iter_in_dict(prop_dictionary_t, const char *, prop_dictionary_t xbps_find_pkg_in_dict(prop_dictionary_t, const char *); +prop_dictionary_t +xbps_find_pkg_from_plist(const char *, const char *); + /* * Finds a string object in an array. * @@ -153,6 +156,7 @@ int xbps_check_reqdeps_in_pkg(const char *, prop_dictionary_t); /* Utils */ bool xbps_append_full_path(char *, const char *, const char *); +int xbps_check_is_installed_pkg(const char *, const char *); int xbps_cmpver_packages(const char *, const char *); int xbps_cmpver_versions(const char *, const char *); const char * xbps_get_pkg_version(const char *); diff --git a/lib/Makefile b/lib/Makefile index c8a3aaffda3..3f7821b7cd8 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -8,7 +8,8 @@ LIBXBPS_SO = $(LIBXBPS).$(MAJOR).$(MINOR).$(MICRO) LIBXBPS = libxbps.so LIBXBPS_LDFLAGS = -larchive -lprop -shared -Wl,-soname,$(LIBXBPS).$(MAJOR) -OBJECTS = cmpver.o depends.o humanize_number.o install.o plist.o sha256.o +OBJECTS = cmpver.o depends.o humanize_number.o install.o plist.o +OBJECTS += sha256.o util.o all: $(LIBXBPS) .PHONY: all diff --git a/lib/depends.c b/lib/depends.c index 25975fd46a7..9409dc30144 100644 --- a/lib/depends.c +++ b/lib/depends.c @@ -32,70 +32,16 @@ #include -const char * -xbps_get_pkg_version(const char *pkg) -{ - const char *tmp; +typedef struct pkg_dependency { + LIST_ENTRY(pkg_dependency) deps; + prop_dictionary_t dict; + char *name; +} pkg_dep_t; - /* Get the required version */ - tmp = strrchr(pkg, '-'); - assert(tmp != NULL); - return tmp + 1; /* skip first '-' */ -} +static LIST_HEAD(, pkg_dependency) pkg_deps_list = + LIST_HEAD_INITIALIZER(pkg_deps_list); -char * -xbps_get_pkg_name(const char *pkg) -{ - const char *tmp; - char *pkgname; - size_t len; - - /* Get the required version */ - tmp = strrchr(pkg, '-'); - assert(tmp != NULL); - len = strlen(pkg) - strlen(tmp); - - /* Get package name */ - pkgname = malloc(len + 1); - memcpy(pkgname, pkg, len); - pkgname[len + 1] = '\0'; - - return pkgname; -} - -bool -xbps_append_full_path(char *buf, const char *root, const char *plistf) -{ - const char *env, *tmp; - size_t len = 0; - - assert(buf != NULL); - assert(plistf != NULL); - - if (root) - env = root; - else { - env = getenv("XBPS_META_PATH"); - if (env == NULL) - env = XBPS_META_PATH; - } - - tmp = strncpy(buf, env, PATH_MAX - 1); - if (sizeof(*tmp) >= PATH_MAX) { - errno = ENOSPC; - return false; - } - - len = strlen(buf); - buf[len + 1] = '\0'; - if (buf[len - 2] != '/') - strncat(buf, "/", 1); - strncat(buf, plistf, sizeof(buf) - strlen(buf) - 1); - - return true; -} - -static int +int xbps_check_is_installed_pkg(const char *plist, const char *pkg) { prop_dictionary_t dict, pkgdict; @@ -132,58 +78,117 @@ xbps_check_is_installed_pkg(const char *plist, const char *pkg) return (xbps_cmpver_versions(instver, reqver) > 0) ? 1 : 0; } -int -xbps_check_reqdeps_in_pkg(const char *plist, prop_dictionary_t pkg) +void +xbps_add_pkg_dependency(const char *pkgname, prop_dictionary_t dict) { + pkg_dep_t *dep; + size_t len = 0; + + assert(pkgname != NULL); + assert(dict != NULL); + + LIST_FOREACH(dep, &pkg_deps_list, deps) + if (strcmp(dep->name, pkgname) == 0) + return; + + dep = NULL; + dep = malloc(sizeof(*dep)); + assert(dep != NULL); + + len = strlen(pkgname) + 1; + dep->name = malloc(len); + if (dep->name == NULL) + return; + + memcpy(dep->name, pkgname, len); + dep->name[len + 1] = '\0'; + dep->dict = prop_dictionary_copy(dict); + + LIST_INSERT_HEAD(&pkg_deps_list, dep, deps); +} + +static bool +pkg_has_rundeps(prop_dictionary_t pkg) +{ + prop_array_t array; + + assert(pkg != NULL); + + array = prop_dictionary_get(pkg, "run_depends"); + if (array && prop_array_count(array) > 0) + return true; + + return false; +} + +static int +find_deps_in_pkg(const char *plist, prop_dictionary_t pkg) +{ + prop_dictionary_t pkgdict; prop_array_t array; prop_object_t obj; prop_object_iterator_t iter; const char *reqpkg; - int rv = 0; - bool need_deps = false; + char *pkgname; + + array = prop_dictionary_get(pkg, "run_depends"); + if (array == NULL || prop_array_count(array) == 0) + return 0; + + iter = prop_array_iterator(array); + if (iter == NULL) + return -1; + + /* Iterate over the list of required run dependencies for a pkg */ + while ((obj = prop_object_iterator_next(iter))) { + reqpkg = prop_string_cstring_nocopy(obj); + pkgname = xbps_get_pkg_name(reqpkg); + pkgdict = xbps_find_pkg_from_plist(plist, pkgname); + xbps_add_pkg_dependency(pkgname, pkgdict); + free(pkgname); + + /* Iterate on required pkg to find more deps */ + if (pkg_has_rundeps(pkgdict)) { + /* more deps? */ + prop_object_iterator_release(iter); + if (!find_deps_in_pkg(plist, pkgdict)) { + prop_object_release(pkgdict); + return 0; + } + } + prop_object_release(pkgdict); + } + + prop_object_iterator_release(iter); + + return 0; +} + +int +xbps_check_reqdeps_in_pkg(const char *plist, prop_dictionary_t pkg) +{ + char repolist[PATH_MAX]; assert(pkg != NULL); assert(prop_object_type(pkg) == PROP_TYPE_DICTIONARY); assert(prop_dictionary_count(pkg) != 0); assert(plist != NULL); - array = prop_dictionary_get(pkg, "run_depends"); - if (array == NULL) { + if (!pkg_has_rundeps(pkg)) { /* Package has no required rundeps */ return 0; } - assert(prop_object_type(array) == PROP_TYPE_ARRAY); - assert(prop_array_count(array) != 0); - - iter = prop_array_iterator(array); - if (iter == NULL) { - errno = ENOMEM; + if (!xbps_append_full_path(repolist, + "/storage/xbps/binpkgs", XBPS_PKGINDEX)) { + errno = ENOENT; return -1; } - while ((obj = prop_object_iterator_next(iter))) { - assert(prop_object_type(obj) == PROP_TYPE_STRING); - reqpkg = prop_string_cstring_nocopy(obj); - - rv = xbps_check_is_installed_pkg(plist, reqpkg); - if (rv == XBPS_PKG_EEMPTY) { - /* No packages registered yet. */ - need_deps = true; - printf("Package '%s' not installed\n", reqpkg); - //xbps_add_pkg_dependency(reqpkg); - - } else if (rv == 1) { - need_deps = true; - printf("Package '%s' required.\n", reqpkg); - - } else if (rv == 0) { - printf("Package '%s' already installed.\n", reqpkg); - - } + if (find_deps_in_pkg(repolist, pkg) == -1) { + errno = XBPS_PKG_EINDEPS; + return -1; } - prop_object_iterator_release(iter); - - return need_deps; + return 1; } diff --git a/lib/install.c b/lib/install.c index 9806ef6593f..412330beef2 100644 --- a/lib/install.c +++ b/lib/install.c @@ -51,33 +51,56 @@ xbps_install_binary_pkg(const char *pkgname, const char *dest) /* Get pkg metadata from a repository */ repo_dict = prop_dictionary_internalize_from_file(repo); - pkg_rdict = xbps_find_pkg_in_dict(repo_dict, pkgname); - if (pkg_rdict == NULL) - return XBPS_PKG_ENOTINREPO; + if (repo_dict == NULL) + return -1; - if (!xbps_append_full_path(dbfile, NULL, XBPS_REGPKGDB)) + pkg_rdict = xbps_find_pkg_in_dict(repo_dict, pkgname); + if (pkg_rdict == NULL) { + prop_object_release(repo_dict); + return XBPS_PKG_ENOTINREPO; + } + + if (!xbps_append_full_path(dbfile, NULL, XBPS_REGPKGDB)) { + prop_object_release(repo_dict); return EINVAL; + } /* Check if package is already installed. */ dict = prop_dictionary_internalize_from_file(dbfile); - if (dict && xbps_find_pkg_in_dict(dict, pkgname)) + if (dict && xbps_find_pkg_in_dict(dict, pkgname)) { + prop_object_release(repo_dict); + prop_object_release(dict); return XBPS_PKG_EEXIST; + } + + /* Append filename to the full path for binary pkg */ + obj = prop_dictionary_get(pkg_rdict, "filename"); + if (!xbps_append_full_path(binfile, "/storage/xbps/binpkgs", + prop_string_cstring_nocopy(obj))) { + prop_object_release(repo_dict); + return EINVAL; + } + + obj = prop_dictionary_get(pkg_rdict, "version"); + printf("=> Found package: %s-%s.", + pkgname, prop_string_cstring_nocopy(obj)); + printf("\n"); + (void)fflush(stdout); + printf("==> Checking dependencies... "); + (void)fflush(stdout); /* Looks like it's not, check dependencies and install */ switch (xbps_check_reqdeps_in_pkg(dbfile, pkg_rdict)) { case -1: /* There was an error checking pkg deps */ + prop_object_release(repo_dict); + printf("error, exiting!\n"); + fflush(stdout); return XBPS_PKG_EINDEPS; case 0: /* Package has no deps, just install it */ - obj = prop_dictionary_get(pkg_rdict, "filename"); - strncpy(binfile, "/storage/xbps/binpkgs/", PATH_MAX - 1); - strncat(binfile, prop_string_cstring_nocopy(obj), PATH_MAX - 1); - obj = prop_dictionary_get(pkg_rdict, "version"); - - printf("=> Installing %s-%s ... ", pkgname, - prop_string_cstring_nocopy(obj)); - + printf("none, unpacking... "); + (void)fflush(stdout); rv = xbps_unpack_binary_pkg(binfile, unpack_archive_cb); break; case 1: @@ -85,6 +108,7 @@ xbps_install_binary_pkg(const char *pkgname, const char *dest) break; } + prop_object_release(repo_dict); return rv; } diff --git a/lib/plist.c b/lib/plist.c index b27f9326749..b4de1c8b6be 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -95,6 +95,31 @@ xbps_callback_array_iter_in_dict(prop_dictionary_t dict, const char *key, return ret; } +prop_dictionary_t +xbps_find_pkg_from_plist(const char *plist, const char *pkgname) +{ + prop_dictionary_t dict; + prop_dictionary_t obj; + + assert(plist != NULL); + assert(pkgname != NULL); + + dict = prop_dictionary_internalize_from_file(plist); + if (dict == NULL) { + errno = ENOENT; + return NULL; + } + + obj = xbps_find_pkg_in_dict(dict, pkgname); + if (obj == NULL) { + prop_object_release(dict); + errno = ENOENT; + return NULL; + } + + return obj; +} + prop_dictionary_t xbps_find_pkg_in_dict(prop_dictionary_t dict, const char *pkgname) { diff --git a/lib/util.c b/lib/util.c new file mode 100644 index 00000000000..7504feecd78 --- /dev/null +++ b/lib/util.c @@ -0,0 +1,96 @@ +/*- + * Copyright (c) 2008 Juan Romero Pardines. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include + +const char * +xbps_get_pkg_version(const char *pkg) +{ + const char *tmp; + + /* Get the required version */ + tmp = strrchr(pkg, '-'); + assert(tmp != NULL); + return tmp + 1; /* skip first '-' */ +} + +char * +xbps_get_pkg_name(const char *pkg) +{ + const char *tmp; + char *pkgname; + size_t len = 0; + + /* Get the required version */ + tmp = strrchr(pkg, '-'); + assert(tmp != NULL); + len = strlen(pkg) - strlen(tmp) + 1; + + /* Get package name */ + pkgname = malloc(len); + memcpy(pkgname, pkg, len - 1); + pkgname[len - 1] = '\0'; + + return pkgname; +} + +bool +xbps_append_full_path(char *buf, const char *root, const char *plistf) +{ + const char *env, *tmp; + size_t len = 0; + + assert(buf != NULL); + assert(plistf != NULL); + + if (root) + env = root; + else { + env = getenv("XBPS_META_PATH"); + if (env == NULL) + env = XBPS_META_PATH; + } + + tmp = strncpy(buf, env, PATH_MAX - 1); + if (sizeof(*tmp) >= PATH_MAX) { + errno = ENOSPC; + return false; + } + + len = strlen(buf); + buf[len + 1] = '\0'; + if (buf[len - 2] != '/') + strncat(buf, "/", 1); + strncat(buf, plistf, sizeof(buf) - strlen(buf) - 1); + + return true; +}