Support for installing pkgs from multiple repositories.

--HG--
extra : convert_revision : fc8a430e71d202aa9e7560b921669f62f1947ae1
This commit is contained in:
Juan RP 2008-12-26 04:36:51 +01:00
parent f8d7e7f66f
commit 91f7df59cd
6 changed files with 260 additions and 152 deletions

View File

@ -50,8 +50,9 @@ usage(void)
{
printf("Usage: xbps-bin [action] [arguments]\n\n"
" Available actions:\n"
" repo-add, repo-list, repo-rm, search, show\n"
" install, repo-add, repo-list, repo-rm, search, show\n"
" Action arguments:\n"
" install\t[<pkgname>] [<rootdir>]\n"
" repo-add\t[<URI>]\n"
" repo-list\t[none]\n"
" repo-rm\t[<URI>]\n"
@ -59,6 +60,7 @@ usage(void)
" show\t[<pkgname>]\n"
"\n"
" Examples:\n"
" $ xbps-bin install klibc\n"
" $ xbps-bin repo-add /path/to/directory\n"
" $ xbps-bin repo-add http://www.location.org/xbps-repo\n"
" $ xbps-bin repo-list\n"
@ -163,6 +165,7 @@ main(int argc, char **argv)
prop_dictionary_t dict;
repo_info_t *rinfo = NULL;
char dpkgidx[PATH_MAX], repolist[PATH_MAX];
int rv = 0;
if (argc < 2)
usage();
@ -269,19 +272,19 @@ main(int argc, char **argv)
} else if (strcasecmp(argv[1], "install") == 0) {
/* Installs a binary package and required deps. */
if (argc != 3)
if (argc < 3 || argc > 4)
usage();
dict = getrepolist_dict();
if (!xbps_callback_array_iter_in_dict(dict, "repository-list",
xbps_install_binary_pkg_from_repolist, argv[2])) {
prop_object_release(dict);
printf("ERROR: unable to find a binary package "
"for %s.\n", argv[2]);
exit(EINVAL);
if (argc == 3) {
/* Install into root directory by default. */
rv = xbps_install_binary_pkg(argv[2], "/");
} else {
/* install into specified directory. */
rv = xbps_install_binary_pkg(argv[2], argv[3]);
}
prop_object_release(dict);
if (rv)
exit(rv);
} else {
usage();
}

View File

@ -158,11 +158,12 @@ int xbps_cmpver_packages(const char *, const char *);
int xbps_cmpver_versions(const char *, const char *);
const char * xbps_get_pkg_version(const char *);
char * xbps_get_pkg_name(const char *);
int xbps_install_pkg_deps(prop_dictionary_t, prop_dictionary_t);
int xbps_install_binary_pkg(prop_dictionary_t, const char *,
const char *);
int xbps_install_pkg_deps(prop_array_t, prop_dictionary_t);
int xbps_install_binary_pkg(const char *, const char *);
bool xbps_install_binary_pkg_from_repolist(prop_object_t, void *, bool *);
int xbps_unpack_binary_pkg(prop_dictionary_t, int (*cb)(struct archive *));
int xbps_unpack_binary_pkg(prop_dictionary_t, prop_dictionary_t,
int (*cb)(struct archive *));
int xbps_unpack_archive_cb(struct archive *);
bool xbps_pkg_has_rundeps(prop_dictionary_t);
#endif /* !_XBPS_PLIST_H_ */

View File

@ -48,7 +48,7 @@
#define XBPS_REGPKGDB "regpkgdb.plist"
/* Return values for xbps_install_binary_pkg() */
#define XBPS_PKG_ENOTINREPO 1 /* Not found in repos */
#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 */

View File

@ -32,11 +32,11 @@
#include <xbps_api.h>
typedef struct pkg_dependency {
struct pkg_dependency {
LIST_ENTRY(pkg_dependency) deps;
prop_dictionary_t dict;
prop_dictionary_t repo;
char *name;
} pkg_dep_t;
};
static LIST_HEAD(, pkg_dependency) pkg_deps_list =
LIST_HEAD_INITIALIZER(pkg_deps_list);
@ -79,13 +79,26 @@ xbps_check_is_installed_pkg(const char *plist, const char *pkg)
}
void
xbps_add_pkg_dependency(const char *pkgname, prop_dictionary_t dict)
xbps_clean_pkg_depslist(void)
{
pkg_dep_t *dep;
struct pkg_dependency *dep;
LIST_FOREACH(dep, &pkg_deps_list, deps) {
LIST_REMOVE(dep, deps);
free(dep->name);
prop_object_release(dep->repo);
}
}
void
xbps_add_pkg_dependency(const char *pkgname, prop_dictionary_t repo)
{
struct pkg_dependency *dep;
size_t len = 0;
assert(repo != NULL);
assert(pkgname != NULL);
assert(dict != NULL);
assert(pkgdict != NULL);
LIST_FOREACH(dep, &pkg_deps_list, deps)
if (strcmp(dep->name, pkgname) == 0)
@ -97,38 +110,20 @@ xbps_add_pkg_dependency(const char *pkgname, prop_dictionary_t dict)
len = strlen(pkgname) + 1;
dep->name = malloc(len);
if (dep->name == NULL) {
free(dep);
return;
}
assert(dep != NULL);
memcpy(dep->name, pkgname, len - 1);
dep->name[len - 1] = '\0';
dep->dict = prop_dictionary_copy(dict);
dep->repo = prop_dictionary_copy(repo);
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(prop_dictionary_t repo, prop_dictionary_t pkg)
{
prop_dictionary_t pkgdict;
prop_array_t array;
prop_string_t name;
prop_object_t obj;
prop_object_iterator_t iter = NULL;
const char *reqpkg;
@ -142,19 +137,31 @@ find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg)
if (iter == NULL)
return -1;
name = prop_dictionary_get(pkg, "pkgname");
xbps_add_pkg_dependency(prop_string_cstring_nocopy(name), pkg);
/* Iterate over the list of required run dependencies for a pkg */
/*
* Iterate over the list of required run dependencies for
* a package.
*/
while ((obj = prop_object_iterator_next(iter))) {
/*
* If required package is not in repo, just pass to the
* next one.
*/
reqpkg = prop_string_cstring_nocopy(obj);
pkgname = xbps_get_pkg_name(reqpkg);
pkgdict = xbps_find_pkg_in_dict(repo, pkgname);
xbps_add_pkg_dependency(pkgname, pkgdict);
if (pkgdict == NULL) {
free(pkgname);
continue;
}
/*
* Package is on repo, add it into the list.
*/
xbps_add_pkg_dependency(pkgname, repo);
free(pkgname);
/* Iterate on required pkg to find more deps */
if (pkg_has_rundeps(pkgdict)) {
if (xbps_pkg_has_rundeps(pkgdict)) {
/* more deps? */
if (!find_deps_in_pkg(repo, pkgdict))
continue;
@ -167,47 +174,119 @@ find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg)
}
int
xbps_install_pkg_deps(prop_dictionary_t repo, prop_dictionary_t pkg)
xbps_install_pkg_deps(prop_array_t repolist, prop_dictionary_t pkg)
{
pkg_dep_t *dep;
prop_dictionary_t repo, pkgdict;
prop_array_t array;
prop_object_iterator_t iter;
prop_object_t obj;
prop_string_t pkgname, version;
struct pkg_dependency *dep;
size_t required_deps = 0, deps_found = 0;
const char *reqpkg, *verstr;
char plist[PATH_MAX], *namestr;
int rv = 0;
bool dep_found = false;
assert(pkg != NULL);
assert(repo != NULL);
assert(prop_object_type(pkg) == PROP_TYPE_DICTIONARY);
assert(prop_object_type(repo) == PROP_TYPE_DICTIONARY);
iter = prop_array_iterator(repolist);
if (iter == NULL)
return ENOMEM;
if (!pkg_has_rundeps(pkg)) {
/* Package has no required dependencies. */
return 0;
/*
* Iterate over the repository list and find out if we have
* all required dependencies.
*/
while ((obj = prop_object_iterator_next(iter)) != NULL) {
memset(plist, 0, sizeof(&plist));
if (!xbps_append_full_path(plist,
prop_string_cstring_nocopy(obj), XBPS_PKGINDEX)) {
xbps_clean_pkg_depslist();
prop_object_iterator_release(iter);
rv = EINVAL;
goto out;
}
repo = prop_dictionary_internalize_from_file(plist);
if (repo == NULL) {
prop_object_iterator_release(iter);
rv = errno;
goto out;
}
rv = find_deps_in_pkg(repo, pkg);
if (rv == -1) {
prop_object_release(repo);
prop_object_iterator_release(iter);
goto out;
}
prop_object_release(repo);
}
prop_object_iterator_release(iter);
/*
* Find out if all required dependencies and binary packages
* from repositories are there.
*/
array = prop_dictionary_get(pkg, "run_depends");
iter = prop_array_iterator(array);
if (iter == NULL) {
rv = ENOMEM;
goto out;
}
/* Check what dependencies are required. */
if (find_deps_in_pkg(repo, pkg) == -1) {
errno = XBPS_PKG_EINDEPS;
return -1;
while ((obj = prop_object_iterator_next(iter)) != NULL) {
dep_found = false;
required_deps++;
reqpkg = prop_string_cstring_nocopy(obj);
namestr = xbps_get_pkg_name(reqpkg);
verstr = xbps_get_pkg_version(reqpkg);
LIST_FOREACH(dep, &pkg_deps_list, deps) {
if (strcmp(dep->name, namestr) == 0) {
deps_found++;
dep_found = true;
break;
}
}
if (dep_found == false) {
printf("Cannot find %s >= %s in repository list.\n",
namestr, verstr);
(void)fflush(stdout);
}
free(namestr);
}
prop_object_iterator_release(iter);
if (required_deps != deps_found) {
rv = XBPS_PKG_ENOTINREPO;
goto out;
}
/*
* Iterate over the list of dependencies and install them.
*/
LIST_FOREACH(dep, &pkg_deps_list, deps) {
pkgname = prop_dictionary_get(dep->dict, "pkgname");
version = prop_dictionary_get(dep->dict, "version");
pkgdict = xbps_find_pkg_in_dict(dep->repo, dep->name);
if (pkgdict == NULL) {
rv = EINVAL;
break;
}
pkgname = prop_dictionary_get(pkgdict, "pkgname");
version = prop_dictionary_get(pkgdict, "version");
printf("Required package: %s >= %s\n",
prop_string_cstring_nocopy(pkgname),
prop_string_cstring_nocopy(version));
(void)fflush(stdout);
rv = xbps_unpack_binary_pkg(dep->dict, xbps_unpack_archive_cb);
rv = xbps_unpack_binary_pkg(dep->repo, pkgdict,
xbps_unpack_archive_cb);
if (rv != 0)
break;
LIST_REMOVE(dep, deps);
free(dep->name);
prop_object_release(dep->dict);
}
return 1;
out:
xbps_clean_pkg_depslist();
return rv;
}

View File

@ -32,105 +32,105 @@
#include <xbps_api.h>
bool
xbps_install_binary_pkg_from_repolist(prop_object_t obj, void *arg, bool *done)
int
xbps_install_binary_pkg(const char *pkgname, const char *destdir)
{
prop_dictionary_t dict;
prop_string_t oloc;
const char *repofile, *repoloc;
prop_array_t array;
prop_dictionary_t repolistd, repod, pkgrd;
prop_object_t obj;
prop_object_iterator_t iter;
char plist[PATH_MAX];
int rv = 0;
assert(prop_object_type(obj) == PROP_TYPE_STRING);
/* Get the location */
repofile = prop_string_cstring_nocopy(obj);
/* Get string for pkg-index.plist with full path. */
if (!xbps_append_full_path(plist, repofile, XBPS_PKGINDEX))
return false;
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL || prop_dictionary_count(dict) == 0)
return false;
oloc = prop_dictionary_get(dict, "location-remote");
if (oloc == NULL)
oloc = prop_dictionary_get(dict, "location-local");
if (oloc && prop_object_type(oloc) == PROP_TYPE_STRING)
repoloc = prop_string_cstring_nocopy(oloc);
else {
prop_object_release(dict);
return false;
}
printf("Searching in repository: %s\n", repoloc);
rv = xbps_install_binary_pkg(dict, arg, "/home/juan/root_xbps");
*done = true;
prop_object_release(dict);
if (rv != 0)
return false;
return true;
}
int
xbps_install_binary_pkg(prop_dictionary_t repo, const char *pkgname,
const char *dest)
{
prop_dictionary_t pkg_rdict, dict;
prop_object_t obj;
char dbfile[PATH_MAX];
int rv = 0;
assert(pkgname != NULL);
if (dest) {
if ((rv = chdir(dest)) != 0)
if (destdir) {
if ((rv = chdir(destdir)) != 0)
return XBPS_PKG_ECHDIRDEST;
}
/* Get pkg metadata from a repository */
pkg_rdict = xbps_find_pkg_in_dict(repo, pkgname);
if (pkg_rdict == NULL)
return XBPS_PKG_ENOTINREPO;
/* Check if package is already installed. */
if (!xbps_append_full_path(dbfile, NULL, XBPS_REGPKGDB))
/* Get the dictionary with list of repositories. */
if (!xbps_append_full_path(plist, NULL, XBPS_REPOLIST))
return EINVAL;
dict = prop_dictionary_internalize_from_file(dbfile);
if (dict && xbps_find_pkg_in_dict(dict, pkgname)) {
prop_object_release(dict);
return XBPS_PKG_EEXIST;
repolistd = prop_dictionary_internalize_from_file(plist);
if (repolistd == NULL)
return EINVAL;
/* Iterate over the list of repositories to find a pkg. */
array = prop_dictionary_get(repolistd, "repository-list");
if (array == NULL || prop_array_count(array) == 0) {
prop_object_release(repolistd);
return EINVAL;
}
obj = prop_dictionary_get(pkg_rdict, "version");
printf("Available package: %s-%s.\n",
pkgname, prop_string_cstring_nocopy(obj));
(void)fflush(stdout);
iter = prop_array_iterator(array);
if (iter == NULL) {
prop_object_release(repolistd);
return ENOMEM;
}
/*
* Install the package, and its dependencies if there are.
*/
switch (xbps_install_pkg_deps(repo, pkg_rdict)) {
case -1:
return XBPS_PKG_EINDEPS;
case 0:
while ((obj = prop_object_iterator_next(iter)) != NULL) {
/*
* Package has no dependencies, just install it.
* Get the dictionary from a repository's index file.
*/
rv = xbps_unpack_binary_pkg(pkg_rdict, xbps_unpack_archive_cb);
break;
case 1:
assert(prop_object_type(obj) == PROP_TYPE_STRING);
memset(plist, 0, sizeof(&plist));
if (!xbps_append_full_path(plist,
prop_string_cstring_nocopy(obj), XBPS_PKGINDEX)) {
prop_object_iterator_release(iter);
prop_object_release(repolistd);
return EINVAL;
}
repod = prop_dictionary_internalize_from_file(plist);
if (repod == NULL) {
prop_object_iterator_release(iter);
prop_object_release(repolistd);
return EINVAL;
}
/*
* 1 means that package has dependencies, but
* xbps_install_pkg_deps() takes care of it.
* Get the package dictionary from current repository.
*/
pkgrd = xbps_find_pkg_in_dict(repod, pkgname);
if (pkgrd == NULL) {
prop_object_release(repod);
continue;
}
/*
* Check if pkg needs deps.
*/
if (!xbps_pkg_has_rundeps(pkgrd)) {
/* pkg has no deps, just install it. */
rv = xbps_unpack_binary_pkg(repod, pkgrd,
xbps_unpack_archive_cb);
prop_object_release(repolistd);
prop_object_release(repod);
break;
}
/*
* Install all required dependencies.
*/
rv = xbps_install_pkg_deps(array, pkgrd);
if (rv != 0) {
prop_object_release(repolistd);
prop_object_release(repod);
break;
}
/*
* Finally install the package, now that all
* required dependencies were installed.
*/
rv = xbps_unpack_binary_pkg(repod, pkgrd,
xbps_unpack_archive_cb);
prop_object_release(repolistd);
prop_object_release(repod);
break;
}
prop_object_iterator_release(iter);
return rv;
}
@ -138,10 +138,14 @@ int
xbps_unpack_archive_cb(struct archive *ar)
{
struct archive_entry *entry;
static bool first;
int rv = 0;
while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) {
if ((rv = archive_read_extract(ar, entry, 0)) != 0) {
if (!first)
printf("\n");
first = true;
printf("couldn't write %s (%s), ignoring!\n",
archive_entry_pathname(entry), strerror(errno));
}
@ -152,9 +156,10 @@ xbps_unpack_archive_cb(struct archive *ar)
}
int
xbps_unpack_binary_pkg(prop_dictionary_t pkg, int (*cb)(struct archive *))
xbps_unpack_binary_pkg(prop_dictionary_t repo, prop_dictionary_t pkg,
int (*cb)(struct archive *))
{
prop_string_t pkgname, version, filename;
prop_string_t pkgname, version, filename, repoloc;
struct archive *ar;
char binfile[PATH_MAX];
int rv;
@ -163,14 +168,19 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg, int (*cb)(struct archive *))
/* Append filename to the full path for binary pkg */
filename = prop_dictionary_get(pkg, "filename");
if (!xbps_append_full_path(binfile, "/storage/xbps/binpkgs",
repoloc = prop_dictionary_get(repo, "location-local");
if (!xbps_append_full_path(binfile,
prop_string_cstring_nocopy(repoloc),
prop_string_cstring_nocopy(filename)))
return EINVAL;
pkgname = prop_dictionary_get(pkg, "pkgname");
version = prop_dictionary_get(pkg, "version");
printf("Unpacking %s-%s (from %s)... ",
printf("From repository %s ...\n",
prop_string_cstring_nocopy(repoloc));
printf(" Unpacking %s-%s (%s) ... ",
prop_string_cstring_nocopy(pkgname),
prop_string_cstring_nocopy(version),
prop_string_cstring_nocopy(filename));
@ -190,8 +200,10 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg, int (*cb)(struct archive *))
return rv;
}
if ((rv = (*cb)(ar)) == 0)
if ((rv = (*cb)(ar)) == 0) {
printf("done.\n");
(void)fflush(stdout);
}
return rv;
}

View File

@ -63,6 +63,19 @@ xbps_get_pkg_name(const char *pkg)
return pkgname;
}
bool
xbps_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;
}
bool
xbps_append_full_path(char *buf, const char *root, const char *plistf)
{