Added the concept of package properties in the API.

See the NEWS file and xbps-bin(8) for more information.
This commit is contained in:
Juan RP
2011-02-05 11:25:04 +01:00
parent d25bc35711
commit de296d8192
12 changed files with 820 additions and 212 deletions

View File

@@ -40,10 +40,10 @@ endif
OBJS = package_configure.o package_config_files.o package_orphans.o
OBJS += package_remove.o package_remove_obsoletes.o package_state.o
OBJS += package_unpack.o package_requiredby.o package_register.o
OBJS += package_purge.o package_replaces.o initend.o
OBJS += package_purge.o package_replaces.o package_properties.o
OBJS += transaction_dictionary.o transaction_sortdeps.o
OBJS += cmpver.o download.o fexec.o humanize_number.o plist.o
OBJS += util.o pkgmatch.o mkpath.o
OBJS += util.o pkgmatch.o mkpath.o initend.o
OBJS += regpkgdb_dictionary.o repository_register.o
OBJS += repository_findpkg.o repository_plist.o repository_finddeps.o
OBJS += repository_pool.o repository_sync_index.o

268
lib/package_properties.c Normal file
View File

@@ -0,0 +1,268 @@
/*-
* Copyright (c) 2011 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 <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <xbps_api.h>
#include "xbps_api_impl.h"
/**
* @file lib/package_properties.c
* @brief Package properties routines
* @defgroup pkgprops Package property functions
*
* Set and unset global properties for packages in the regpkgdb
* plist file and its "properties" array object.
*/
int
xbps_property_set(const char *key, const char *pkgname)
{
prop_dictionary_t d, repo_pkgd = NULL, pkgd = NULL;
prop_array_t props, provides = NULL, virtual = NULL;
prop_string_t virtualpkg;
char *plist;
int rv = 0;
bool regpkgd_alloc, pkgd_alloc, virtual_alloc, propbool;
assert(key != NULL);
assert(pkgname != NULL);
regpkgd_alloc = pkgd_alloc = virtual_alloc = propbool = false;
if ((d = xbps_regpkgdb_dictionary_get()) == NULL) {
/*
* If regpkgdb dictionary doesn't exist, create it
* and the properties array.
*/
d = prop_dictionary_create();
if (d == NULL) {
rv = ENOMEM;
goto out;
}
regpkgd_alloc = true;
props = prop_array_create();
if (props == NULL) {
rv = ENOMEM;
goto out;
}
if (!prop_dictionary_set(d, "properties", props)) {
rv = EINVAL;
prop_object_release(props);
goto out;
}
prop_object_release(props);
}
props = prop_dictionary_get(d, "properties");
if (prop_object_type(props) != PROP_TYPE_ARRAY) {
rv = EINVAL;
goto out;
}
/*
* If package dictionary doesn't exist, create it.
*/
pkgd = xbps_find_pkg_in_array_by_name(props, pkgname);
if (pkgd == NULL) {
pkgd = prop_dictionary_create();
if (pkgd == NULL) {
rv = ENOMEM;
goto out;
}
pkgd_alloc = true;
prop_dictionary_set_cstring_nocopy(pkgd, "pkgname", pkgname);
if (!prop_array_add(props, pkgd)) {
rv = EINVAL;
goto out;
}
}
if (strcmp(key, "virtual") == 0) {
/*
* Sets the "virtual" property in package.
*/
virtual = prop_dictionary_get(pkgd, "provides");
if (virtual == NULL) {
virtual = prop_array_create();
if (virtual == NULL) {
rv = ENOMEM;
goto out;
}
virtual_alloc = true;
virtualpkg = prop_string_create_cstring(pkgname);
if (virtualpkg == NULL) {
rv = ENOMEM;
goto out;
}
prop_string_append_cstring(virtualpkg, ">=0");
prop_dictionary_set(pkgd, "pkgpattern", virtualpkg);
prop_object_release(virtualpkg);
virtualpkg = NULL;
} else {
/* property already set */
xbps_dbg_printf("%s: property `%s' already set!\n",
pkgname, key);
rv = EEXIST;
goto out;
}
/*
* Get the package object from repository pool.
*/
repo_pkgd = xbps_repository_pool_find_pkg(pkgname, false, false);
if (repo_pkgd == NULL) {
xbps_dbg_printf("%s: cannot find pkg dictionary "
"in repository pool.\n", pkgname);
rv = ENOENT;
goto out;
}
provides = prop_dictionary_get(repo_pkgd, "provides");
if (provides == NULL) {
xbps_dbg_printf("%s: pkg dictionary no provides "
"array!\n", pkgname);
prop_object_release(repo_pkgd);
rv = EINVAL;
goto out;
}
if (!prop_dictionary_set(pkgd, "provides", provides)) {
prop_object_release(repo_pkgd);
rv = EINVAL;
goto out;
}
prop_object_release(repo_pkgd);
} else if ((strcmp(key, "hold") == 0) ||
(strcmp(key, "update-first") == 0)) {
/*
* Sets the property "key" in package.
*/
if (prop_dictionary_get_bool(pkgd, key, &propbool)) {
rv = EEXIST;
goto out;
}
prop_dictionary_set_bool(pkgd, key, true);
} else {
/* invalid property */
rv = EINVAL;
goto out;
}
/*
* Add array with new properties set into the regpkgdb
* dictionary.
*/
if (!prop_dictionary_set(d, "properties", props)) {
rv = errno;
goto out;
}
/*
* Write regpkgdb dictionary to plist file.
*/
plist = xbps_xasprintf("%s/%s/%s", xbps_get_rootdir(),
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL) {
rv = ENOMEM;
goto out;
}
if (!prop_dictionary_externalize_to_zfile(d, plist)) {
rv = errno;
goto out;
}
out:
if (virtual_alloc)
prop_object_release(virtual);
if (pkgd_alloc)
prop_object_release(pkgd);
if (regpkgd_alloc)
prop_object_release(d);
xbps_regpkgdb_dictionary_release();
return rv;
}
int
xbps_property_unset(const char *key, const char *pkgname)
{
prop_dictionary_t d, pkgd;
prop_array_t props;
char *plist;
int rv = 0;
assert(key != NULL);
assert(pkgname != NULL);
if ((d = xbps_regpkgdb_dictionary_get()) == NULL)
return ENODEV;
props = prop_dictionary_get(d, "properties");
if (prop_object_type(props) != PROP_TYPE_ARRAY) {
rv = ENODEV;
goto out;
}
pkgd = xbps_find_pkg_in_array_by_name(props, pkgname);
if (pkgd == NULL) {
rv = ENODEV;
goto out;
}
if ((strcmp(key, "virtual") == 0) ||
(strcmp(key, "hold") == 0) ||
(strcmp(key, "update-first") == 0)) {
/* remove the property object matching the key */
prop_dictionary_remove(pkgd, key);
} else {
/* invalid property */
rv = EINVAL;
goto out;
}
/*
* If pkg dictionary does not contain any property, remove
* the object completely.
*/
if (!prop_dictionary_get(d, "virtual") &&
!prop_dictionary_get(d, "hold") &&
!prop_dictionary_get(d, "update-first"))
xbps_remove_pkg_from_array_by_name(props, pkgname);
if (!prop_dictionary_set(d, "properties", props)) {
rv = EINVAL;
goto out;
}
/*
* Write regpkgdb dictionary to plist file.
*/
plist = xbps_xasprintf("%s/%s/%s", xbps_get_rootdir(),
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL) {
rv = ENOMEM;
goto out;
}
if (!prop_dictionary_externalize_to_zfile(d, plist)) {
rv = errno;
goto out;
}
out:
xbps_regpkgdb_dictionary_release();
return rv;
}

View File

@@ -216,10 +216,13 @@ xbps_set_pkg_state_installed(const char *pkgname, pkg_state_t state)
}
array = prop_dictionary_get(dict, "packages");
if (array == NULL) {
rv = EINVAL;
if (newpkg)
prop_object_release(pkgd);
goto out;
array = prop_array_create();
if (!prop_dictionary_set(dict, "packages", array)) {
rv = EINVAL;
if (newpkg)
prop_object_release(pkgd);
goto out;
}
}
if ((rv = set_new_state(pkgd, state)) != 0) {
if (newpkg)

View File

@@ -167,27 +167,32 @@ xbps_callback_array_iter_reverse_in_dict(prop_dictionary_t dict,
return rv;
}
prop_dictionary_t
xbps_find_pkg_dict_from_plist_by_name(const char *plist, const char *pkgname)
static prop_dictionary_t
find_pkg_dict_from_plist(const char *plist,
const char *key,
const char *str,
bool bypattern)
{
prop_dictionary_t dict, obj, res;
assert(plist != NULL);
assert(pkgname != NULL);
assert(str != NULL);
dict = prop_dictionary_internalize_from_zfile(plist);
if (dict == NULL) {
xbps_dbg_printf("cannot internalize %s for pkg %s: %s",
plist, pkgname, strerror(errno));
plist, str, strerror(errno));
return NULL;
}
if (bypattern)
obj = xbps_find_pkg_in_dict_by_pattern(dict, key, str);
else
obj = xbps_find_pkg_in_dict_by_name(dict, key, str);
obj = xbps_find_pkg_in_dict_by_name(dict, "packages", pkgname);
if (obj == NULL) {
prop_object_release(dict);
return NULL;
}
res = prop_dictionary_copy(obj);
prop_object_release(dict);
@@ -195,42 +200,19 @@ xbps_find_pkg_dict_from_plist_by_name(const char *plist, const char *pkgname)
}
prop_dictionary_t
xbps_find_pkg_dict_installed(const char *str, bool bypattern)
xbps_find_pkg_dict_from_plist_by_name(const char *plist,
const char *key,
const char *pkgname)
{
prop_dictionary_t d, pkgd, rpkgd = NULL;
pkg_state_t state = 0;
return find_pkg_dict_from_plist(plist, key, pkgname, false);
}
assert(str != NULL);
if ((d = xbps_regpkgdb_dictionary_get()) == NULL)
return NULL;
if (bypattern)
pkgd = xbps_find_pkg_in_dict_by_pattern(d, "packages", str);
else
pkgd = xbps_find_pkg_in_dict_by_name(d, "packages", str);
if (pkgd == NULL)
goto out;
if (xbps_get_pkg_state_dictionary(pkgd, &state) != 0)
goto out;
switch (state) {
case XBPS_PKG_STATE_INSTALLED:
case XBPS_PKG_STATE_UNPACKED:
rpkgd = prop_dictionary_copy(pkgd);
break;
case XBPS_PKG_STATE_CONFIG_FILES:
errno = ENOENT;
xbps_dbg_printf("'%s' installed but its state is "
"config-files\n",str);
break;
default:
break;
}
out:
xbps_regpkgdb_dictionary_release();
return rpkgd;
prop_dictionary_t
xbps_find_pkg_dict_from_plist_by_pattern(const char *plist,
const char *key,
const char *pattern)
{
return find_pkg_dict_from_plist(plist, key, pattern, true);
}
bool
@@ -254,7 +236,7 @@ static prop_dictionary_t
find_pkg_in_array(prop_array_t array, const char *str, bool bypattern)
{
prop_object_iterator_t iter;
prop_object_t obj;
prop_object_t obj = NULL;
const char *pkgver, *dpkgn;
assert(array != NULL);
@@ -266,19 +248,29 @@ find_pkg_in_array(prop_array_t array, const char *str, bool bypattern)
while ((obj = prop_object_iterator_next(iter))) {
if (bypattern) {
if (xbps_find_virtual_pkg_in_dict(obj, str, true))
break;
prop_dictionary_get_cstring_nocopy(obj,
"pkgver", &pkgver);
/*
* Check if package pattern matches the
* pkgver string object in dictionary.
*/
if (!prop_dictionary_get_cstring_nocopy(obj,
"pkgver", &pkgver))
continue;
if (xbps_pkgpattern_match(pkgver, __UNCONST(str)))
break;
} else {
if (xbps_find_virtual_pkg_in_dict(obj, str, false))
/*
* Finally check if package pattern matches
* any virtual package version in dictionary.
*/
if (xbps_find_virtual_pkg_in_dict(obj, str, true))
break;
prop_dictionary_get_cstring_nocopy(obj,
"pkgname", &dpkgn);
} else {
if (!prop_dictionary_get_cstring_nocopy(obj,
"pkgname", &dpkgn))
continue;
if (strcmp(dpkgn, str) == 0)
break;
if (xbps_find_virtual_pkg_in_dict(obj, str, false))
break;
}
}
prop_object_iterator_release(iter);
@@ -301,11 +293,93 @@ xbps_find_pkg_in_array_by_pattern(prop_array_t array, const char *pattern)
return find_pkg_in_array(array, pattern, true);
}
static const char *
find_virtualpkg_user_in_regpkgdb(const char *virtualpkg, bool bypattern)
{
prop_array_t virtual;
prop_dictionary_t d;
prop_object_iterator_t iter;
prop_object_t obj;
const char *pkg = NULL;
bool found = false;
if ((d = xbps_regpkgdb_dictionary_get()) == NULL)
return NULL;
if ((iter = xbps_get_array_iter_from_dict(d, "properties")) == NULL) {
xbps_regpkgdb_dictionary_release();
return NULL;
}
while ((obj = prop_object_iterator_next(iter)) != NULL) {
virtual = prop_dictionary_get(obj, "provides");
if (virtual == NULL)
continue;
if (bypattern)
found = xbps_find_pkgpattern_in_array(virtual, virtualpkg);
else
found = xbps_find_pkgname_in_array(virtual, virtualpkg);
if (!found)
continue;
if (bypattern)
prop_dictionary_get_cstring_nocopy(obj,
"pkgpattern", &pkg);
else
prop_dictionary_get_cstring_nocopy(obj,
"pkgname", &pkg);
break;
}
prop_object_iterator_release(iter);
xbps_regpkgdb_dictionary_release();
return pkg;
}
static prop_dictionary_t
find_virtualpkg_user_in_array(prop_array_t array,
const char *str,
bool bypattern)
{
prop_object_t obj = NULL;
prop_object_iterator_t iter;
const char *pkgver, *dpkgn, *virtualpkg;
assert(array != NULL);
assert(str != NULL);
virtualpkg = find_virtualpkg_user_in_regpkgdb(str, bypattern);
if (virtualpkg == NULL)
return NULL;
iter = prop_array_iterator(array);
if (iter == NULL)
return NULL;
while ((obj = prop_object_iterator_next(iter))) {
if (bypattern) {
prop_dictionary_get_cstring_nocopy(obj,
"pkgver", &pkgver);
if (xbps_pkgpattern_match(pkgver,
__UNCONST(virtualpkg)))
break;
} else {
prop_dictionary_get_cstring_nocopy(obj,
"pkgname", &dpkgn);
if (strcmp(dpkgn, virtualpkg) == 0)
break;
}
}
prop_object_iterator_release(iter);
return obj;
}
static prop_dictionary_t
find_pkg_in_dict(prop_dictionary_t d,
const char *key,
const char *str,
bool bypattern)
bool bypattern,
bool virtual)
{
prop_array_t array;
@@ -317,23 +391,78 @@ find_pkg_in_dict(prop_dictionary_t d,
if (prop_object_type(array) != PROP_TYPE_ARRAY)
return NULL;
if (virtual)
return find_virtualpkg_user_in_array(array, str, bypattern);
return find_pkg_in_array(array, str, bypattern);
}
prop_dictionary_t
xbps_find_pkg_in_dict_by_name(prop_dictionary_t dict,
xbps_find_pkg_in_dict_by_name(prop_dictionary_t d,
const char *key,
const char *pkgname)
{
return find_pkg_in_dict(dict, key, pkgname, false);
return find_pkg_in_dict(d, key, pkgname, false, false);
}
prop_dictionary_t
xbps_find_pkg_in_dict_by_pattern(prop_dictionary_t dict,
xbps_find_pkg_in_dict_by_pattern(prop_dictionary_t d,
const char *key,
const char *pattern)
{
return find_pkg_in_dict(dict, key, pattern, true);
return find_pkg_in_dict(d, key, pattern, true, false);
}
prop_dictionary_t HIDDEN
xbps_find_virtualpkg_user_in_dict_by_name(prop_dictionary_t d,
const char *key,
const char *name)
{
return find_pkg_in_dict(d, key, name, false, true);
}
prop_dictionary_t HIDDEN
xbps_find_virtualpkg_user_in_dict_by_pattern(prop_dictionary_t d,
const char *key,
const char *pattern)
{
return find_pkg_in_dict(d, key, pattern, true, true);
}
prop_dictionary_t
xbps_find_pkg_dict_installed(const char *str, bool bypattern)
{
prop_dictionary_t d, pkgd, rpkgd = NULL;
pkg_state_t state = 0;
assert(str != NULL);
if ((d = xbps_regpkgdb_dictionary_get()) == NULL)
return NULL;
pkgd = find_pkg_in_dict(d, "packages", str, bypattern, false);
if (pkgd == NULL)
goto out;
if (xbps_get_pkg_state_dictionary(pkgd, &state) != 0)
goto out;
switch (state) {
case XBPS_PKG_STATE_INSTALLED:
case XBPS_PKG_STATE_UNPACKED:
rpkgd = prop_dictionary_copy(pkgd);
break;
case XBPS_PKG_STATE_CONFIG_FILES:
errno = ENOENT;
xbps_dbg_printf("'%s' installed but its state is "
"config-files\n",str);
break;
default:
break;
}
out:
xbps_regpkgdb_dictionary_release();
return rpkgd;
}
static bool

View File

@@ -235,9 +235,34 @@ struct repo_pool_fpkg {
prop_dictionary_t pkgd;
const char *pattern;
bool bypattern;
bool newpkg_found;
bool pkgfound;
};
static int
repo_find_virtualpkg_cb(struct repository_pool_index *rpi, void *arg, bool *done)
{
struct repo_pool_fpkg *rpf = arg;
if (rpf->bypattern) {
rpf->pkgd =
xbps_find_virtualpkg_user_in_dict_by_pattern(rpi->rpi_repod,
"packages", rpf->pattern);
} else {
rpf->pkgd =
xbps_find_virtualpkg_user_in_dict_by_name(rpi->rpi_repod,
"packages", rpf->pattern);
}
if (rpf->pkgd) {
prop_dictionary_set_cstring(rpf->pkgd, "repository",
rpi->rpi_uri);
*done = true;
rpf->pkgfound = true;
return 0;
}
/* not found */
return 0;
}
static int
repo_find_pkg_cb(struct repository_pool_index *rpi, void *arg, bool *done)
{
@@ -250,7 +275,6 @@ repo_find_pkg_cb(struct repository_pool_index *rpi, void *arg, bool *done)
rpf->pkgd = xbps_find_pkg_in_dict_by_name(rpi->rpi_repod,
"packages", rpf->pattern);
}
if (rpf->pkgd) {
/*
* Package dictionary found, add the "repository"
@@ -259,11 +283,10 @@ repo_find_pkg_cb(struct repository_pool_index *rpi, void *arg, bool *done)
prop_dictionary_set_cstring(rpf->pkgd, "repository",
rpi->rpi_uri);
*done = true;
errno = 0;
rpf->pkgfound = true;
return 0;
}
/* Not found */
errno = ENOENT;
return 0;
}
@@ -290,6 +313,8 @@ repo_find_best_pkg_cb(struct repository_pool_index *rpi,
* the version currently installed.
*/
instpkgd = xbps_find_pkg_dict_installed(rpf->pattern, false);
if (instpkgd == NULL)
return 0;
prop_dictionary_get_cstring_nocopy(instpkgd,
"version", &instver);
prop_dictionary_get_cstring_nocopy(rpf->pkgd,
@@ -303,11 +328,11 @@ repo_find_best_pkg_cb(struct repository_pool_index *rpi,
/*
* New package version found, exit from the loop.
*/
rpf->newpkg_found = true;
prop_dictionary_set_cstring(rpf->pkgd, "repository",
rpi->rpi_uri);
errno = 0;
*done = true;
errno = 0;
rpf->pkgfound = true;
return 0;
}
xbps_dbg_printf("Skipping '%s-%s' (installed: %s) "
@@ -315,7 +340,6 @@ repo_find_best_pkg_cb(struct repository_pool_index *rpi,
rpi->rpi_uri);
errno = EEXIST;
}
return 0;
}
@@ -335,14 +359,41 @@ xbps_repository_pool_find_pkg(const char *pkg, bool bypattern, bool best)
rpf->pattern = pkg;
rpf->bypattern = bypattern;
if (best)
if (best) {
/*
* Look for the best package version of a package name or
* pattern in all repositories.
*/
rv = xbps_repository_pool_foreach(repo_find_best_pkg_cb, rpf);
else
rv = xbps_repository_pool_foreach(repo_find_pkg_cb, rpf);
if (rv != 0 || (rv == 0 && (errno == ENOENT || errno == EEXIST)))
goto out;
if (rv != 0) {
errno = rv;
goto out;
} else if (rpf->pkgfound == false) {
goto out;
}
} else {
/*
* Look for any virtual package set by the user matching
* the package name or pattern.
*/
rv = xbps_repository_pool_foreach(repo_find_virtualpkg_cb, rpf);
if (rv != 0) {
errno = rv;
goto out;
} else if (rpf->pkgfound == false) {
/*
* No virtual package found. Look for real package
* names or patterns instead.
*/
rv = xbps_repository_pool_foreach(repo_find_pkg_cb, rpf);
if (rv != 0) {
errno = rv;
goto out;
} else if (rpf->pkgfound == false) {
goto out;
}
}
}
pkgd = prop_dictionary_copy(rpf->pkgd);
out:
free(rpf);