diff --git a/bin/xbps-repo/main.c b/bin/xbps-repo/main.c index 0a9a133f702..d6889bd75f1 100644 --- a/bin/xbps-repo/main.c +++ b/bin/xbps-repo/main.c @@ -170,7 +170,7 @@ main(int argc, char **argv) prop_dictionary_t dict; repo_info_t *rinfo = NULL; char dpkgidx[PATH_MAX], *root = NULL; - int c; + int c, rv = 0; while ((c = getopt(argc, argv, "r:")) != -1) { switch (c) { @@ -291,17 +291,17 @@ main(int argc, char **argv) usage(); dict = getrepolist_dict(root); - if (xbps_callback_array_iter_in_dict(dict, "repository-list", - show_pkg_info_from_repolist, argv[1]) != 0) { - prop_object_release(dict); - free(plist); - printf("ERROR: unable to locate package '%s'.\n", - argv[1]); - exit(EXIT_FAILURE); - } + rv = xbps_callback_array_iter_in_dict(dict, "repository-list", + show_pkg_info_from_repolist, argv[1]); prop_object_release(dict); free(plist); + if (rv == 0 && errno == ENOENT) { + printf("Unable to locate package '%s' from " + "repository pool.\n", argv[1]); + exit(EXIT_FAILURE); + } + } else { usage(); } diff --git a/bin/xbps-repo/util.c b/bin/xbps-repo/util.c index f10b451dfd0..0d68f8f2fd8 100644 --- a/bin/xbps-repo/util.c +++ b/bin/xbps-repo/util.c @@ -180,7 +180,8 @@ show_pkg_info_from_repolist(prop_object_t obj, void *arg, bool *loop_done) if (pkgdict == NULL) { prop_object_release(dict); free(plist); - return XBPS_PKG_ENOTINREPO; + errno = ENOENT; + return 0; } oloc = prop_dictionary_get(dict, "location-remote"); diff --git a/include/install.h b/include/install.h index 4cd19aadb35..ffac453fed9 100644 --- a/include/install.h +++ b/include/install.h @@ -37,7 +37,7 @@ int xbps_unpack_binary_pkg(prop_dictionary_t, prop_dictionary_t, const char *, void (*cb_print)(prop_dictionary_t)); int xbps_update_pkg_requiredby(prop_array_t, prop_dictionary_t); -int xbps_find_deps_in_pkg(prop_dictionary_t, prop_dictionary_t); +int xbps_find_deps_in_pkg(prop_dictionary_t); /* From lib/sortdeps.c */ int xbps_sort_pkg_deps(prop_dictionary_t); diff --git a/include/plist.h b/include/plist.h index bfebe88a08e..486d8bf45ff 100644 --- a/include/plist.h +++ b/include/plist.h @@ -44,9 +44,12 @@ bool xbps_add_obj_to_array(prop_array_t, prop_object_t); */ int xbps_callback_array_iter_in_dict(prop_dictionary_t, const char *, - int (*func)(prop_object_t, void *, bool *), + int (*fn)(prop_object_t, void *, bool *), void *); - +int +xbps_callback_array_iter_in_repolist(const char *, + int (*fn)(prop_object_t, void *, bool *), + void *); /* * Finds a package's dictionary into the main dictionary. * diff --git a/include/xbps_api.h b/include/xbps_api.h index 861135bdb50..beb597ea775 100644 --- a/include/xbps_api.h +++ b/include/xbps_api.h @@ -47,12 +47,11 @@ /* Filename of the packages register. */ #define XBPS_REGPKGDB "regpkgdb.plist" -/* Return values for xbps_install_binary_pkg() */ -#define XBPS_PKG_ENOTINREPO 1 /* Not found in repo */ -#define XBPS_PKG_EEXIST 2 /* Already installed */ -#define XBPS_PKG_EINDEPS 3 /* Check deps failed */ -#define XBPS_PKG_ECHDIRDEST 4 /* chdir() to dest failed */ -#define XBPS_PKG_EEMPTY 5 /* empty pkg list */ +#define XBPS_PKG_ENOTINREPO -1 /* Not found in repo */ +#define XBPS_PKG_EEXIST -2 /* Already installed */ +#define XBPS_PKG_EINDEPS -3 /* Check deps failed */ +#define XBPS_PKG_ECHDIRDEST -4 /* chdir() to dest failed */ +#define XBPS_PKG_EEMPTY -5 /* empty pkg list */ #include "cmpver.h" #include "fexec.h" diff --git a/lib/depends.c b/lib/depends.c index 63203ef9c0b..9d496690e67 100644 --- a/lib/depends.c +++ b/lib/depends.c @@ -33,8 +33,11 @@ #include static int add_missing_reqdep(const char *, const char *); -static int check_missing_reqdep(const char *, const char *, size_t *); -static void remove_missing_reqdep(size_t *); +static int remove_missing_reqdep(const char *); +static int find_pkg_deps_from_repo(prop_dictionary_t, prop_dictionary_t, + prop_array_t); +static int find_pkg_missing_deps_from_repo(prop_dictionary_t, + prop_dictionary_t); static prop_dictionary_t chaindeps; @@ -44,7 +47,7 @@ static prop_dictionary_t chaindeps; static int create_deps_dictionary(void) { - prop_array_t installed, unsorted, missing; + prop_array_t unsorted, missing; int rv = 0; chaindeps = prop_dictionary_create(); @@ -57,36 +60,24 @@ create_deps_dictionary(void) goto fail; } - installed = prop_array_create(); - if (installed == NULL) { + unsorted = prop_array_create(); + if (unsorted == NULL) { rv = ENOMEM; goto fail2; } - unsorted = prop_array_create(); - if (unsorted == NULL) { - rv = ENOMEM; - goto fail3; - } - if (!xbps_add_obj_to_dict(chaindeps, missing, "missing_deps")) { rv = EINVAL; - goto fail4; - } - if (!xbps_add_obj_to_dict(chaindeps, installed, "installed_deps")) { - rv = EINVAL; - goto fail4; + goto fail3; } if (!xbps_add_obj_to_dict(chaindeps, unsorted, "unsorted_deps")) { rv = EINVAL; - goto fail4; + goto fail3; } return rv; -fail4: - prop_object_release(unsorted); fail3: - prop_object_release(installed); + prop_object_release(unsorted); fail2: prop_object_release(missing); fail: @@ -105,7 +96,7 @@ store_dependency(prop_dictionary_t origind, prop_dictionary_t depd, uint32_t prio = 0; size_t len = 0, dirdepscnt = 0, indirdepscnt = 0; const char *pkgname, *version, *reqbyname, *reqbyver; - const char *repoloc, *binfile, *array_key, *originpkg, *short_desc; + const char *repoloc, *binfile, *originpkg, *short_desc; char *reqby, *pkgnver; int rv = 0; bool indirectdep = false; @@ -143,51 +134,34 @@ store_dependency(prop_dictionary_t origind, prop_dictionary_t depd, (void)snprintf(pkgnver, len, "%s-%s", pkgname, version); /* - * Check if dependency is already installed to select the - * correct array object. + * Required dependency is not installed. Check if it's + * already registered in the chain, and update some objects + * or add the object into array otherwise. */ - if (xbps_check_is_installed_pkg(pkgnver) == 0) { - /* - * Dependency is already installed. - */ - array_key = "installed_deps"; - dict = xbps_find_pkg_in_dict(chaindeps, array_key, pkgname); - if (dict) - goto out; + prop_dictionary_get_cstring_nocopy(chaindeps, "origin", &originpkg); + curdict = xbps_find_pkg_in_dict(chaindeps, "unsorted_deps", pkgname); + /* + * Update priority and required_by objects. + */ + if (curdict) { + prop_dictionary_get_uint32(curdict, "priority", &prio); + prop_dictionary_set_uint32(curdict, "priority", ++prio); + reqby_array = prop_dictionary_get(curdict, "required_by"); + if (!xbps_find_string_in_array(reqby_array, reqby)) + prop_array_add(reqby_array, reqbystr); + goto out; + } + if (strcmp(originpkg, reqbyname)) { + indirectdep = true; + prop_dictionary_get_uint32(chaindeps, "indirectdeps_count", + &indirdepscnt); + prop_dictionary_set_uint32(chaindeps, "indirectdeps_count", + ++indirdepscnt); } else { - /* - * Required dependency is not installed. Check if it's - * already registered in the chain, and update some objects - * or add the object into array otherwise. - */ - array_key = "unsorted_deps"; - prop_dictionary_get_cstring_nocopy(chaindeps, - "origin", &originpkg); - curdict = xbps_find_pkg_in_dict(chaindeps, array_key, pkgname); - /* - * Update priority and required_by objects. - */ - if (curdict) { - prop_dictionary_get_uint32(curdict, "priority", &prio); - prop_dictionary_set_uint32(curdict, "priority", ++prio); - reqby_array = prop_dictionary_get(curdict, - "required_by"); - if (!xbps_find_string_in_array(reqby_array, reqby)) - prop_array_add(reqby_array, reqbystr); - goto out; - } - if (strcmp(originpkg, reqbyname)) { - indirectdep = true; - prop_dictionary_get_uint32(chaindeps, - "indirectdeps_count", &indirdepscnt); - prop_dictionary_set_uint32(chaindeps, - "indirectdeps_count", ++indirdepscnt); - } else { - prop_dictionary_get_uint32(chaindeps, - "directdeps_count", &dirdepscnt); - prop_dictionary_set_uint32(chaindeps, - "directdeps_count", ++dirdepscnt); - } + prop_dictionary_get_uint32(chaindeps, "directdeps_count", + &dirdepscnt); + prop_dictionary_set_uint32(chaindeps, "directdeps_count", + ++dirdepscnt); } /* @@ -199,7 +173,7 @@ store_dependency(prop_dictionary_t origind, prop_dictionary_t depd, goto out; } - array = prop_dictionary_get(chaindeps, array_key); + array = prop_dictionary_get(chaindeps, "unsorted_deps"); if (array == NULL) { prop_object_release(dict); rv = ENOENT; @@ -223,21 +197,18 @@ store_dependency(prop_dictionary_t origind, prop_dictionary_t depd, } prop_array_add(reqby_array, reqbystr); prop_dictionary_set(dict, "required_by", reqby_array); + prop_dictionary_set_cstring(dict, "repository", repoloc); + prop_dictionary_set_cstring(dict, "filename", binfile); + prop_dictionary_set_uint32(dict, "priority", prio); + prop_dictionary_set_cstring(dict, "short_desc", short_desc); + prop_dictionary_set_bool(dict, "indirect_dep", indirectdep); - if (strcmp(array_key, "unsorted_deps") == 0) { - prop_dictionary_set_cstring(dict, "repository", repoloc); - prop_dictionary_set_cstring(dict, "filename", binfile); - prop_dictionary_set_uint32(dict, "priority", prio); - prop_dictionary_set_cstring(dict, "short_desc", short_desc); - prop_dictionary_set_bool(dict, "indirect_dep", indirectdep); - } /* * Add the dictionary into the array. */ if (!xbps_add_obj_to_array(array, dict)) { prop_object_release(dict); rv = EINVAL; - goto out; } out: @@ -253,7 +224,6 @@ add_missing_reqdep(const char *pkgname, const char *version) { prop_array_t array; prop_dictionary_t depd; - size_t idx = 0; assert(pkgname != NULL); assert(version != NULL); @@ -261,7 +231,7 @@ add_missing_reqdep(const char *pkgname, const char *version) /* * Adds a package into the missing deps array. */ - if (check_missing_reqdep(pkgname, version, &idx) == 0) + if (xbps_find_pkg_in_dict(chaindeps, "missing_deps", pkgname)) return EEXIST; array = prop_dictionary_get(chaindeps, "missing_deps"); @@ -269,8 +239,8 @@ add_missing_reqdep(const char *pkgname, const char *version) if (depd == NULL) return ENOMEM; - prop_dictionary_set_cstring_nocopy(depd, "pkgname", pkgname); - prop_dictionary_set_cstring_nocopy(depd, "version", version); + prop_dictionary_set_cstring(depd, "pkgname", pkgname); + prop_dictionary_set_cstring(depd, "version", version); if (!xbps_add_obj_to_array(array, depd)) { prop_object_release(depd); return EINVAL; @@ -280,85 +250,250 @@ add_missing_reqdep(const char *pkgname, const char *version) } static int -check_missing_reqdep(const char *pkgname, const char *version, - size_t *idx) +remove_missing_reqdep(const char *pkgname) { - prop_array_t array; - prop_object_t obj; - prop_object_iterator_t iter; - const char *missname, *missver; - size_t lidx = 0; - int rv = 0; - - assert(pkgname != NULL); - assert(version != NULL); - assert(idx != NULL); - - array = prop_dictionary_get(chaindeps, "missing_deps"); - assert(array != NULL); - - iter = prop_array_iterator(array); - if (iter == NULL) - return ENOMEM; - - /* - * Finds the index of a package in the missing deps array. - */ - while ((obj = prop_object_iterator_next(iter)) != NULL) { - prop_dictionary_get_cstring_nocopy(obj, "pkgname", &missname); - prop_dictionary_get_cstring_nocopy(obj, "version", &missver); - if ((strcmp(pkgname, missname) == 0) && - (strcmp(version, missver) == 0)) { - *idx = lidx; - goto out; - } - idx++; - } - - rv = ENOENT; - -out: - prop_object_iterator_release(iter); - return rv; -} - -static void -remove_missing_reqdep(size_t *idx) -{ - prop_array_t array; - - array = prop_dictionary_get(chaindeps, "missing_deps"); - assert(array != NULL); - prop_array_remove(array, *idx); -} - -int -xbps_find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg) -{ - prop_dictionary_t pkgdict; prop_array_t array; prop_object_t obj; prop_object_iterator_t iter; size_t idx = 0; - const char *reqpkg, *reqvers; - char *pkgname; - int rv = 0; - static bool deps_dict; + const char *curname; + bool found = false; - array = prop_dictionary_get(pkg, "run_depends"); - if (array == NULL || prop_array_count(array) == 0) + array = prop_dictionary_get(chaindeps, "missing_deps"); + assert(pkgname != NULL); + assert(version != NULL); + assert(array != NULL); + iter = prop_array_iterator(array); + if (iter == NULL) + return ENOMEM; + /* + * Finds the index of a package in the missing deps array. + */ + while ((obj = prop_object_iterator_next(iter)) != NULL) { + prop_dictionary_get_cstring_nocopy(obj, "pkgname", &curname); + if (strcmp(pkgname, curname) == 0) { + found = true; + break; + } + idx++; + } + prop_object_iterator_release(iter); + if (found) { + prop_array_remove(array, idx); + return 0; + } + + return ENOENT; +} + +int +xbps_find_deps_in_pkg(prop_dictionary_t pkg) +{ + prop_array_t array, pkg_rdeps, missing_rdeps; + prop_dictionary_t repolistd, repod; + prop_object_t obj; + prop_object_iterator_t iter; + char *plist; + int rv = 0; + + assert(pkg != NULL); + + /* + * Get the dictionary with the list of registered repositories. + */ + plist = xbps_append_full_path(true, NULL, XBPS_REPOLIST); + if (plist == NULL) + return EINVAL; + /* + * Get the dictionary with the list of registered repositories. + */ + repolistd = prop_dictionary_internalize_from_file(plist); + if (repolistd == NULL) { + free(plist); + return EINVAL; + } + free(plist); + plist = NULL; + + array = prop_dictionary_get(repolistd, "repository-list"); + if (array == NULL) { + prop_object_release(repolistd); + return EINVAL; + } + + iter = prop_array_iterator(array); + if (iter == NULL) { + prop_object_release(repolistd); + return ENOMEM; + } + + pkg_rdeps = prop_dictionary_get(pkg, "run_depends"); + + /* + * Iterate over the repository pool and find out if we have + * all available binary packages. + */ + while ((obj = prop_object_iterator_next(iter)) != NULL) { + plist = xbps_append_full_path(false, + prop_string_cstring_nocopy(obj), XBPS_PKGINDEX); + if (plist == NULL) { + rv = EINVAL; + goto out; + } + repod = prop_dictionary_internalize_from_file(plist); + if (repod == NULL) { + free(plist); + rv = errno; + goto out; + } + free(plist); + + /* + * This will find direct and indirect deps, + * if any of them is not there it will be added + * into the missing_deps array. + */ + rv = find_pkg_deps_from_repo(repod, pkg, pkg_rdeps); + if (rv != 0) { + if (rv == ENOENT) { + rv = 0; + prop_object_release(repod); + continue; + } + prop_object_release(repod); + break; + } + prop_object_release(repod); + } + + missing_rdeps = prop_dictionary_get(chaindeps, "missing_deps"); + if (prop_array_count(missing_rdeps) == 0) + goto out; + /* + * If there are missing deps, iterate one more time + * just in case that indirect deps weren't found. + */ + prop_object_iterator_reset(iter); + while ((obj = prop_object_iterator_next(iter)) != NULL) { + plist = xbps_append_full_path(false, + prop_string_cstring_nocopy(obj), XBPS_PKGINDEX); + if (plist == NULL) { + rv = EINVAL; + goto out; + } + repod = prop_dictionary_internalize_from_file(plist); + if (repod == NULL) { + free(plist); + rv = errno; + goto out; + } + free(plist); + + rv = find_pkg_missing_deps_from_repo(repod, pkg); + if (rv != 0 && rv != ENOENT) { + prop_object_release(repod); + break; + } + + prop_object_release(repod); + } + +out: + prop_object_iterator_release(iter); + prop_object_release(repolistd); + + return rv; +} + +static int +find_pkg_missing_deps_from_repo(prop_dictionary_t repo, prop_dictionary_t pkg) +{ + prop_array_t array; + prop_dictionary_t curpkgd; + prop_object_t obj; + prop_object_iterator_t iter; + const char *pkgname, *version; + int rv = 0; + + assert(repo != NULL); + assert(pkg != NULL); + + array = prop_dictionary_get(chaindeps, "missing_deps"); + if (prop_array_count(array) == 0) return 0; iter = prop_array_iterator(array); if (iter == NULL) return ENOMEM; + while ((obj = prop_object_iterator_next(iter)) != NULL) { + prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); + prop_dictionary_get_cstring_nocopy(obj, "version", &version); + /* + * If required package is not in repo, add it into the + * missing deps array and pass to the next one. + */ + curpkgd = xbps_find_pkg_in_dict(repo, "packages", pkgname); + if (curpkgd == NULL) { + rv = add_missing_reqdep(pkgname, version); + if (rv != 0 && rv != EEXIST) + break; + else { + rv = ENOENT; + continue; + } + } + /* + * Package is on repo, add it into the dictionary. + */ + if ((rv = store_dependency(pkg, curpkgd, repo)) != 0) + break; + /* + * Remove package from missing now. + */ + rv = remove_missing_reqdep(pkgname); + if (rv != 0 && rv != ENOENT) + break; + + prop_object_iterator_reset(iter); + } + prop_object_iterator_release(iter); + + return rv; +} + +static int +find_pkg_deps_from_repo(prop_dictionary_t repo, prop_dictionary_t pkg, + prop_array_t pkg_rdeps) +{ + prop_dictionary_t curpkgd; + prop_array_t curpkg_rdeps; + prop_object_t obj; + prop_object_iterator_t iter; + const char *reqpkg, *reqvers; + char *pkgname; + int rv = 0; + static bool deps_dict; + + /* + * Package doesn't have deps, check to be sure. + */ + if (pkg_rdeps == NULL || prop_array_count(pkg_rdeps) == 0) + return 0; + + iter = prop_array_iterator(pkg_rdeps); + if (iter == NULL) + return ENOMEM; + /* + * Save the name of the origin package once. + */ if (deps_dict == false) { deps_dict = true; rv = create_deps_dictionary(); - if (rv != 0) - goto out; - + if (rv != 0) { + prop_object_iterator_release(iter); + return rv; + } prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &reqpkg); prop_dictionary_set_cstring_nocopy(chaindeps, "origin", reqpkg); @@ -366,57 +501,76 @@ xbps_find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg) /* * Iterate over the list of required run dependencies for - * a package. + * current package. */ while ((obj = prop_object_iterator_next(iter))) { + reqpkg = prop_string_cstring_nocopy(obj); + pkgname = xbps_get_pkg_name(reqpkg); + reqvers = xbps_get_pkg_version(reqpkg); + /* + * Check if required dep is satisfied and installed. + */ + if (xbps_check_is_installed_pkg(reqpkg) == 0) { + free(pkgname); + continue; + } + /* + * Check if package is already added in the + * array of unsorted deps. + */ + if (xbps_find_pkg_in_dict(chaindeps, "unsorted_deps", + pkgname)) { + free(pkgname); + continue; + } + /* * If required package is not in repo, add it into the * missing deps array and pass to the next one. */ - reqpkg = prop_string_cstring_nocopy(obj); - pkgname = xbps_get_pkg_name(reqpkg); - reqvers = xbps_get_pkg_version(reqpkg); - pkgdict = xbps_find_pkg_in_dict(repo, "packages", pkgname); - if (pkgdict == NULL) { + curpkgd = xbps_find_pkg_in_dict(repo, "packages", pkgname); + if (curpkgd == NULL) { rv = add_missing_reqdep(pkgname, reqvers); free(pkgname); if (rv != 0 && rv != EEXIST) break; - else if (rv == EEXIST) - continue; else { - rv = XBPS_PKG_ENOTINREPO; + rv = ENOENT; continue; } } - /* - * Check if dependency wasn't found before. - */ - rv = check_missing_reqdep(pkgname, reqvers, &idx); - free(pkgname); - if (rv == 0) { - /* - * Found in current repository, remove it. - */ - remove_missing_reqdep(&idx); - - } else if (rv != 0 && rv != ENOENT) - break; - /* * Package is on repo, add it into the dictionary. */ - if ((rv = store_dependency(pkg, pkgdict, repo)) != 0) + if ((rv = store_dependency(pkg, curpkgd, repo)) != 0) { + free(pkgname); break; + } + + /* + * Remove package from missing_deps now it's been found. + */ + rv = remove_missing_reqdep(pkgname); + if (rv != 0 && rv != ENOENT) { + free(pkgname); + break; + } + free(pkgname); + + /* + * If package doesn't have rundeps, pass to the next one. + */ + curpkg_rdeps = prop_dictionary_get(curpkgd, "run_depends"); + if (curpkg_rdeps == NULL) + continue; + /* * Iterate on required pkg to find more deps. */ - if (!xbps_find_deps_in_pkg(repo, pkgdict)) + if (!find_pkg_deps_from_repo(repo, curpkgd, curpkg_rdeps)) continue; } - -out: prop_object_iterator_release(iter); return rv; @@ -425,28 +579,32 @@ out: int xbps_install_pkg_deps(prop_dictionary_t pkg, const char *destdir) { - prop_array_t required; + prop_array_t required, missing; prop_object_t obj; prop_object_iterator_t iter; int rv = 0; assert(pkg != NULL); + /* + * If there are missing deps, bail out. + */ + missing = prop_dictionary_get(chaindeps, "missing_deps"); + if (prop_array_count(missing) > 0) + return ENOTSUP; /* * Sort the dependency chain into an array. */ if ((rv = xbps_sort_pkg_deps(chaindeps)) != 0) - goto out; + return rv; required = prop_dictionary_get(chaindeps, "required_deps"); if (required == NULL) return 0; iter = prop_array_iterator(required); - if (iter == NULL) { - rv = ENOMEM; - goto out; - } + if (iter == NULL) + return ENOMEM; /* * Install all required dependencies, previously sorted. @@ -458,6 +616,5 @@ xbps_install_pkg_deps(prop_dictionary_t pkg, const char *destdir) } prop_object_iterator_release(iter); -out: return rv; } diff --git a/lib/install.c b/lib/install.c index d87520e20e0..73c8663ba04 100644 --- a/lib/install.c +++ b/lib/install.c @@ -34,6 +34,13 @@ #include +struct cbargs { + const char *destdir; + const char *pkgname; +}; + +static int install_binpkg_repo_cb(prop_object_t, void *, bool *); + int xbps_install_binary_pkg_fini(prop_dictionary_t repo, prop_dictionary_t pkg, const char *destdir) @@ -62,10 +69,7 @@ xbps_install_binary_pkg_fini(prop_dictionary_t repo, prop_dictionary_t pkg, int xbps_install_binary_pkg(const char *pkgname, const char *destdir) { - prop_array_t array; - prop_dictionary_t repolistd, repod, pkgrd = NULL; - prop_object_t obj; - prop_object_iterator_t iter; + struct cbargs cb; char *plist; int rv = 0; @@ -83,93 +87,84 @@ xbps_install_binary_pkg(const char *pkgname, const char *destdir) if (plist == NULL) return EINVAL; - repolistd = prop_dictionary_internalize_from_file(plist); - if (repolistd == NULL) { - free(plist); - return EINVAL; - } - free(plist); - + cb.pkgname = pkgname; + cb.destdir = destdir; /* * Iterate over the repository pool and find out if we have * all available binary packages. */ - array = prop_dictionary_get(repolistd, "repository-list"); - assert(array != NULL); + rv = xbps_callback_array_iter_in_repolist(plist, + install_binpkg_repo_cb, (void *)&cb); + free(plist); - iter = prop_array_iterator(array); - if (iter == NULL) { - prop_object_release(repolistd); - return ENOMEM; - } + return rv; +} - while ((obj = prop_object_iterator_next(iter)) != NULL) { - plist = xbps_append_full_path(false, - prop_string_cstring_nocopy(obj), XBPS_PKGINDEX); - if (plist == NULL) { - rv = EINVAL; - goto out; - } +static int +install_binpkg_repo_cb(prop_object_t obj, void *arg, bool *cbloop_done) +{ + prop_dictionary_t repod, pkgrd; + struct cbargs *cb = arg; + const char *pkgname = cb->pkgname; + const char *destdir = cb->destdir; + char *plist; + int rv = 0; - repod = prop_dictionary_internalize_from_file(plist); - if (repod == NULL) { - free(plist); - rv = errno; - goto out; - } + plist = xbps_append_full_path(false, + prop_string_cstring_nocopy(obj), XBPS_PKGINDEX); + if (plist == NULL) + return EINVAL; + + repod = prop_dictionary_internalize_from_file(plist); + if (repod == NULL) { free(plist); + return errno; + } + free(plist); - /* - * Get the package dictionary from current repository. - * If it's not there, pass to the next repository. - */ - pkgrd = xbps_find_pkg_in_dict(repod, "packages", pkgname); - if (pkgrd == NULL) { - prop_object_release(repod); - rv = XBPS_PKG_ENOTINREPO; - continue; - } + /* + * Get the package dictionary from current repository. + * If it's not there, pass to the next repository. + */ + pkgrd = xbps_find_pkg_in_dict(repod, "packages", pkgname); + if (pkgrd == NULL) { + prop_object_release(repod); + return 0; + } - /* - * Check if this package needs dependencies. - */ - if (!xbps_pkg_has_rundeps(pkgrd)) { - /* pkg has no deps, just install it. */ - rv = xbps_install_binary_pkg_fini(repod, pkgrd, - destdir); - prop_object_release(repod); - goto out; - } + /* + * Check if this package needs dependencies. + */ + if (!xbps_pkg_has_rundeps(pkgrd)) { + /* pkg has no deps, just install it. */ + rv = xbps_install_binary_pkg_fini(repod, pkgrd, destdir); + prop_object_release(repod); + return rv; + } - /* - * Construct the dependency chain for this package. If any - * dependency is not available, pass to the next repository. - */ - rv = xbps_find_deps_in_pkg(repod, pkgrd); - if (rv != 0) { - prop_object_release(repod); - if (rv == XBPS_PKG_ENOTINREPO) - continue; + /* + * Construct the dependency chain for this package. + */ + rv = xbps_find_deps_in_pkg(pkgrd); + if (rv != 0) { + prop_object_release(repod); + if (rv == ENOENT) + return 0; - goto out; - } + return rv; + } - /* - * Install all required dependencies and the package itself. - */ - rv = xbps_install_pkg_deps(pkgrd, destdir); - if (rv == 0) { - rv = xbps_install_binary_pkg_fini(repod, pkgrd, - destdir); - } + /* + * Install all required dependencies and the package itself. + */ + rv = xbps_install_pkg_deps(pkgrd, destdir); + if (rv == 0) { + rv = xbps_install_binary_pkg_fini(repod, pkgrd, destdir); prop_object_release(repod); - break; + if (rv == 0) + *cbloop_done = true; } -out: - prop_object_release(repolistd); - prop_object_iterator_release(iter); - return rv; } diff --git a/lib/plist.c b/lib/plist.c index 33c7c1672ec..f1eda055244 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -65,29 +65,57 @@ xbps_add_obj_to_array(prop_array_t array, prop_object_t obj) return true; } +int +xbps_callback_array_iter_in_repolist(const char *plist, + int (*fn)(prop_object_t, void *, bool *), + void *arg) +{ + prop_dictionary_t repolistd; + int rv = 0; + + assert(plist != NULL); + assert(fn != NULL); + + /* + * Get the dictionary with the list of registered repositories. + */ + repolistd = prop_dictionary_internalize_from_file(plist); + if (repolistd == NULL) + return EINVAL; + + /* + * Iterate over the repository pool and run the associated + * callback function. The loop is stopped when the bool + * argument is true or the cb returns non 0. + */ + rv = xbps_callback_array_iter_in_dict(repolistd, "repository-list", + fn, arg); + prop_object_release(repolistd); + + return rv; +} + int xbps_callback_array_iter_in_dict(prop_dictionary_t dict, const char *key, - int (*func)(prop_object_t, void *, bool *), + int (*fn)(prop_object_t, void *, bool *), void *arg) { prop_object_iterator_t iter; prop_object_t obj; int rv = 0; - bool run, cbloop_done; + bool cbloop_done = false; assert(dict != NULL); assert(key != NULL); - assert(func != NULL); - - run = cbloop_done = false; + assert(fn != NULL); iter = xbps_get_array_iter_from_dict(dict, key); if (iter == NULL) return EINVAL; while ((obj = prop_object_iterator_next(iter))) { - rv = (*func)(obj, arg, &cbloop_done); - if (rv == 0 && cbloop_done) + rv = (*fn)(obj, arg, &cbloop_done); + if (rv != 0 || cbloop_done) break; } diff --git a/lib/sortdeps.c b/lib/sortdeps.c index b38e59b485a..b9af49ef85c 100644 --- a/lib/sortdeps.c +++ b/lib/sortdeps.c @@ -35,10 +35,9 @@ struct sorted_dependency { TAILQ_ENTRY(sorted_dependency) chain; prop_dictionary_t dict; + prop_array_t reqby; size_t idx; - ssize_t newidx; - bool unsorted; - bool reorg; + size_t prio; }; static TAILQ_HEAD(sdep_head, sorted_dependency) sdep_list = @@ -91,6 +90,31 @@ find_pkgdict_with_highest_prio(prop_array_t array, uint32_t *maxprio, return curidx; } +static struct sorted_dependency * +find_sorteddep_with_highest_prio(void) +{ + struct sorted_dependency *sdep; + size_t maxprio = 0; + size_t curidx = 0, idx = 0; + + TAILQ_FOREACH(sdep, &sdep_list, chain) { + if (maxprio <= sdep->prio) { + curidx = idx; + maxprio = sdep->prio; + } + idx++; + } + + idx = 0; + TAILQ_FOREACH(sdep, &sdep_list, chain) { + if (idx == curidx) + break; + idx++; + } + + return sdep; +} + static struct sorted_dependency * find_sorteddep_by_name(const char *pkgname) { @@ -110,7 +134,7 @@ find_sorteddep_by_name(const char *pkgname) int xbps_sort_pkg_deps(prop_dictionary_t chaindeps) { - prop_array_t installed, sorted, unsorted, rundeps_array; + prop_array_t sorted, unsorted, rundeps_array, reqby; prop_dictionary_t dict; prop_object_t obj; prop_object_iterator_t iter; @@ -130,10 +154,8 @@ xbps_sort_pkg_deps(prop_dictionary_t chaindeps) /* * All required deps are satisfied (already installed). */ - installed = prop_dictionary_get(chaindeps, "installed_deps"); unsorted = prop_dictionary_get(chaindeps, "unsorted_deps"); - if (prop_array_count(unsorted) == 0 && - prop_array_count(installed) > 0) { + if (prop_array_count(unsorted) == 0) { prop_object_release(sorted); return 0; } @@ -165,7 +187,10 @@ xbps_sort_pkg_deps(prop_dictionary_t chaindeps) } sdep->dict = prop_dictionary_copy(dict); sdep->idx = cnt; - sdep->newidx = -1; + prop_dictionary_get_uint32(dict, "priority", &sdep->prio); + reqby = prop_dictionary_get(dict, "required_by"); + if (reqby && prop_array_count(reqby) > 0) + sdep->reqby = prop_array_copy(reqby); TAILQ_INSERT_TAIL(&sdep_list, sdep, chain); prop_array_remove(unsorted, curidx); maxprio = 0; @@ -195,7 +220,10 @@ xbps_sort_pkg_deps(prop_dictionary_t chaindeps) } sdep->dict = prop_dictionary_copy(dict); sdep->idx = cnt + indirdepscnt; - sdep->newidx = -1; + prop_dictionary_get_uint32(dict, "priority", &sdep->prio); + reqby = prop_dictionary_get(dict, "required_by"); + if (reqby && prop_array_count(reqby) > 0) + sdep->reqby = prop_array_copy(reqby); TAILQ_INSERT_TAIL(&sdep_list, sdep, chain); prop_array_remove(unsorted, curidx); maxprio = 0; @@ -203,8 +231,8 @@ xbps_sort_pkg_deps(prop_dictionary_t chaindeps) } /* - * Pass 3: update new index position by looking at run_depends and - * its current index position. + * Pass 3: increase priority of dependencies any time + * a package requires them. */ TAILQ_FOREACH(sdep, &sdep_list, chain) { prop_dictionary_get_cstring_nocopy(sdep->dict, @@ -218,7 +246,6 @@ xbps_sort_pkg_deps(prop_dictionary_t chaindeps) rv = ENOMEM; goto out; } - curidx = sdep->idx; while ((obj = prop_object_iterator_next(iter)) != NULL) { rundep = prop_string_cstring_nocopy(obj); @@ -238,58 +265,46 @@ xbps_sort_pkg_deps(prop_dictionary_t chaindeps) sdep2 = find_sorteddep_by_name(pkgname); free(pkgname); - /* - * If required dependency is before current package, - * pass to the next one. - */ - if (curidx > sdep2->idx) - continue; - /* - * Update index position for the two objects. - */ - if (!sdep2->unsorted) { - sdep2->unsorted = true; - sdep2->newidx = curidx; - sdep->newidx = curidx + 1; - } + sdep2->prio++; } prop_object_iterator_release(iter); } prop_dictionary_remove(chaindeps, "unsorted_deps"); /* - * Pass 4: copy dictionaries into the final array with the - * correct index position for all dependencies. + * Pass 4: increase priority of a package, by looking at + * its required_by array member's priority. */ TAILQ_FOREACH(sdep, &sdep_list, chain) { - if (sdep->reorg) + iter = prop_array_iterator(sdep->reqby); + if (iter == NULL) continue; - if (sdep->newidx != -1) { - TAILQ_FOREACH(sdep2, &sdep_list, chain) { - if (sdep2->unsorted) { - if (!prop_array_set(sorted, - sdep2->newidx, sdep2->dict)) { - rv = errno; - goto out; - } - sdep2->newidx = -1; - sdep2->unsorted = false; - sdep2->reorg = true; - break; - } - } - if (!prop_array_set(sorted, sdep->newidx, sdep->dict)) { - rv = errno; - goto out; - } - sdep->newidx = -1; - } else { - if (!prop_array_add(sorted, sdep->dict)) { - rv = errno; - goto out; + while ((obj = prop_object_iterator_next(iter))) { + rundep = prop_string_cstring_nocopy(obj); + pkgname = xbps_get_pkg_name(rundep); + sdep2 = find_sorteddep_by_name(pkgname); + if (sdep2 == NULL) { + free(pkgname); + continue; } + free(pkgname); + sdep->prio += sdep2->prio + 1; } + prop_object_iterator_release(iter); + } + + /* + * Pass 5: copy dictionaries into the final array with the + * correct index position for all dependencies and release + * resources used by the sorting passes. + */ + while ((sdep = find_sorteddep_with_highest_prio()) != NULL) { + prop_array_add(sorted, sdep->dict); + TAILQ_REMOVE(&sdep_list, sdep, chain); + prop_object_release(sdep->dict); + prop_object_release(sdep->reqby); + free(sdep); } /* @@ -312,6 +327,7 @@ out: while ((sdep = TAILQ_FIRST(&sdep_list)) != NULL) { TAILQ_REMOVE(&sdep_list, sdep, chain); prop_object_release(sdep->dict); + prop_object_release(sdep->reqby); free(sdep); }