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

View file

@ -158,11 +158,12 @@ int xbps_cmpver_packages(const char *, const char *);
int xbps_cmpver_versions(const char *, const char *); int xbps_cmpver_versions(const char *, const char *);
const char * xbps_get_pkg_version(const char *); const char * xbps_get_pkg_version(const char *);
char * xbps_get_pkg_name(const char *); char * xbps_get_pkg_name(const char *);
int xbps_install_pkg_deps(prop_dictionary_t, prop_dictionary_t); int xbps_install_pkg_deps(prop_array_t, prop_dictionary_t);
int xbps_install_binary_pkg(prop_dictionary_t, const char *, int xbps_install_binary_pkg(const char *, const char *);
const char *);
bool xbps_install_binary_pkg_from_repolist(prop_object_t, void *, bool *); 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 *); int xbps_unpack_archive_cb(struct archive *);
bool xbps_pkg_has_rundeps(prop_dictionary_t);
#endif /* !_XBPS_PLIST_H_ */ #endif /* !_XBPS_PLIST_H_ */

View file

@ -48,7 +48,7 @@
#define XBPS_REGPKGDB "regpkgdb.plist" #define XBPS_REGPKGDB "regpkgdb.plist"
/* Return values for xbps_install_binary_pkg() */ /* 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_EEXIST 2 /* Already installed */
#define XBPS_PKG_EINDEPS 3 /* Check deps failed */ #define XBPS_PKG_EINDEPS 3 /* Check deps failed */
#define XBPS_PKG_ECHDIRDEST 4 /* chdir() to dest failed */ #define XBPS_PKG_ECHDIRDEST 4 /* chdir() to dest failed */

View file

@ -32,11 +32,11 @@
#include <xbps_api.h> #include <xbps_api.h>
typedef struct pkg_dependency { struct pkg_dependency {
LIST_ENTRY(pkg_dependency) deps; LIST_ENTRY(pkg_dependency) deps;
prop_dictionary_t dict; prop_dictionary_t repo;
char *name; char *name;
} pkg_dep_t; };
static LIST_HEAD(, pkg_dependency) pkg_deps_list = static LIST_HEAD(, pkg_dependency) pkg_deps_list =
LIST_HEAD_INITIALIZER(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 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; size_t len = 0;
assert(repo != NULL);
assert(pkgname != NULL); assert(pkgname != NULL);
assert(dict != NULL); assert(pkgdict != NULL);
LIST_FOREACH(dep, &pkg_deps_list, deps) LIST_FOREACH(dep, &pkg_deps_list, deps)
if (strcmp(dep->name, pkgname) == 0) 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; len = strlen(pkgname) + 1;
dep->name = malloc(len); dep->name = malloc(len);
if (dep->name == NULL) { assert(dep != NULL);
free(dep);
return;
}
memcpy(dep->name, pkgname, len - 1); memcpy(dep->name, pkgname, len - 1);
dep->name[len - 1] = '\0'; 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); 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 static int
find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg) find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg)
{ {
prop_dictionary_t pkgdict; prop_dictionary_t pkgdict;
prop_array_t array; prop_array_t array;
prop_string_t name;
prop_object_t obj; prop_object_t obj;
prop_object_iterator_t iter = NULL; prop_object_iterator_t iter = NULL;
const char *reqpkg; const char *reqpkg;
@ -142,19 +137,31 @@ find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg)
if (iter == NULL) if (iter == NULL)
return -1; 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 package.
/* Iterate over the list of required run dependencies for a pkg */ */
while ((obj = prop_object_iterator_next(iter))) { 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); reqpkg = prop_string_cstring_nocopy(obj);
pkgname = xbps_get_pkg_name(reqpkg); pkgname = xbps_get_pkg_name(reqpkg);
pkgdict = xbps_find_pkg_in_dict(repo, pkgname); 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); free(pkgname);
/* Iterate on required pkg to find more deps */ /* Iterate on required pkg to find more deps */
if (pkg_has_rundeps(pkgdict)) { if (xbps_pkg_has_rundeps(pkgdict)) {
/* more deps? */ /* more deps? */
if (!find_deps_in_pkg(repo, pkgdict)) if (!find_deps_in_pkg(repo, pkgdict))
continue; continue;
@ -167,47 +174,119 @@ find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg)
} }
int 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; 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; int rv = 0;
bool dep_found = false;
assert(pkg != NULL); iter = prop_array_iterator(repolist);
assert(repo != NULL); if (iter == NULL)
assert(prop_object_type(pkg) == PROP_TYPE_DICTIONARY); return ENOMEM;
assert(prop_object_type(repo) == PROP_TYPE_DICTIONARY);
if (!pkg_has_rundeps(pkg)) { /*
/* Package has no required dependencies. */ * Iterate over the repository list and find out if we have
return 0; * 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. */ while ((obj = prop_object_iterator_next(iter)) != NULL) {
if (find_deps_in_pkg(repo, pkg) == -1) { dep_found = false;
errno = XBPS_PKG_EINDEPS; required_deps++;
return -1; 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. * Iterate over the list of dependencies and install them.
*/ */
LIST_FOREACH(dep, &pkg_deps_list, deps) { LIST_FOREACH(dep, &pkg_deps_list, deps) {
pkgname = prop_dictionary_get(dep->dict, "pkgname"); pkgdict = xbps_find_pkg_in_dict(dep->repo, dep->name);
version = prop_dictionary_get(dep->dict, "version"); if (pkgdict == NULL) {
rv = EINVAL;
break;
}
pkgname = prop_dictionary_get(pkgdict, "pkgname");
version = prop_dictionary_get(pkgdict, "version");
printf("Required package: %s >= %s\n", printf("Required package: %s >= %s\n",
prop_string_cstring_nocopy(pkgname), prop_string_cstring_nocopy(pkgname),
prop_string_cstring_nocopy(version)); prop_string_cstring_nocopy(version));
(void)fflush(stdout); (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) if (rv != 0)
break; 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> #include <xbps_api.h>
bool int
xbps_install_binary_pkg_from_repolist(prop_object_t obj, void *arg, bool *done) xbps_install_binary_pkg(const char *pkgname, const char *destdir)
{ {
prop_dictionary_t dict; prop_array_t array;
prop_string_t oloc; prop_dictionary_t repolistd, repod, pkgrd;
const char *repofile, *repoloc; prop_object_t obj;
prop_object_iterator_t iter;
char plist[PATH_MAX]; char plist[PATH_MAX];
int rv = 0; 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); assert(pkgname != NULL);
if (dest) { if (destdir) {
if ((rv = chdir(dest)) != 0) if ((rv = chdir(destdir)) != 0)
return XBPS_PKG_ECHDIRDEST; return XBPS_PKG_ECHDIRDEST;
} }
/* Get pkg metadata from a repository */ /* Get the dictionary with list of repositories. */
pkg_rdict = xbps_find_pkg_in_dict(repo, pkgname); if (!xbps_append_full_path(plist, NULL, XBPS_REPOLIST))
if (pkg_rdict == NULL)
return XBPS_PKG_ENOTINREPO;
/* Check if package is already installed. */
if (!xbps_append_full_path(dbfile, NULL, XBPS_REGPKGDB))
return EINVAL; return EINVAL;
dict = prop_dictionary_internalize_from_file(dbfile); repolistd = prop_dictionary_internalize_from_file(plist);
if (dict && xbps_find_pkg_in_dict(dict, pkgname)) { if (repolistd == NULL)
prop_object_release(dict); return EINVAL;
return XBPS_PKG_EEXIST;
/* 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"); iter = prop_array_iterator(array);
printf("Available package: %s-%s.\n", if (iter == NULL) {
pkgname, prop_string_cstring_nocopy(obj)); prop_object_release(repolistd);
(void)fflush(stdout); return ENOMEM;
}
/* while ((obj = prop_object_iterator_next(iter)) != NULL) {
* 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:
/* /*
* 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); assert(prop_object_type(obj) == PROP_TYPE_STRING);
break; memset(plist, 0, sizeof(&plist));
case 1: 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 * Get the package dictionary from current repository.
* xbps_install_pkg_deps() takes care of it.
*/ */
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; break;
} }
prop_object_iterator_release(iter);
return rv; return rv;
} }
@ -138,10 +138,14 @@ int
xbps_unpack_archive_cb(struct archive *ar) xbps_unpack_archive_cb(struct archive *ar)
{ {
struct archive_entry *entry; struct archive_entry *entry;
static bool first;
int rv = 0; int rv = 0;
while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) { while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) {
if ((rv = archive_read_extract(ar, entry, 0)) != 0) { if ((rv = archive_read_extract(ar, entry, 0)) != 0) {
if (!first)
printf("\n");
first = true;
printf("couldn't write %s (%s), ignoring!\n", printf("couldn't write %s (%s), ignoring!\n",
archive_entry_pathname(entry), strerror(errno)); archive_entry_pathname(entry), strerror(errno));
} }
@ -152,9 +156,10 @@ xbps_unpack_archive_cb(struct archive *ar)
} }
int 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; struct archive *ar;
char binfile[PATH_MAX]; char binfile[PATH_MAX];
int rv; 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 */ /* Append filename to the full path for binary pkg */
filename = prop_dictionary_get(pkg, "filename"); 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))) prop_string_cstring_nocopy(filename)))
return EINVAL; return EINVAL;
pkgname = prop_dictionary_get(pkg, "pkgname"); pkgname = prop_dictionary_get(pkg, "pkgname");
version = prop_dictionary_get(pkg, "version"); 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(pkgname),
prop_string_cstring_nocopy(version), prop_string_cstring_nocopy(version),
prop_string_cstring_nocopy(filename)); prop_string_cstring_nocopy(filename));
@ -190,8 +200,10 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg, int (*cb)(struct archive *))
return rv; return rv;
} }
if ((rv = (*cb)(ar)) == 0) if ((rv = (*cb)(ar)) == 0) {
printf("done.\n"); printf("done.\n");
(void)fflush(stdout);
}
return rv; return rv;
} }

View file

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