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

18
NEWS
View File

@ -1,5 +1,23 @@
xbps-0.8.0 (???):
* Added the concept of package properties in the API. At this moment
only one property is fully working, "virtual". When xbps-bin(8)
sets this property for a package, its virtual package list will be
set in the XBPS_REGPKGDB plist in a package dictionary and the matching
logic will always prefer its virtual packages over the real ones.
You can do wonderful things with this, like always using development
package versions, or simply customize what packages you want to
install rather than the default ones. As a real example, you can now
use the 'xbps-devel' package rather than the stable package version
'xbps' before installing the system and package dependencies will
still be resolved:
"$ xbps-bin set-prop virtual xbps-devel"
"$ xbps-bin install xbps-base-system"
Only packages that have the "provides" object are valid for the
"virtual" property.
* Moved the "replaces" handling logic into the API. But instead of
removing any package, the packages that should be replaced are
added into the transaction dictionary and marked as "remove".

View File

@ -46,6 +46,7 @@ struct list_pkgver_cb {
static void __attribute__((noreturn))
usage(void)
{
xbps_end();
fprintf(stderr,
"Usage: xbps-bin [options] [target] [arguments]\n"
"See xbps-bin(8) for more information.\n");
@ -434,6 +435,23 @@ main(int argc, char **argv)
rv = find_files_in_packages(argv[1]);
} else if (strcasecmp(argv[0], "set-prop") == 0) {
if (argc < 2 || argc > 3)
usage();
/*
* Sets a property in a package.
*/
rv = xbps_property_set(argv[1], argv[2]);
} else if (strcasecmp(argv[0], "unset-prop") == 0) {
/*
* Unsets a property in a package.
*/
if (argc < 2 || argc > 3)
usage();
rv = xbps_property_unset(argv[1], argv[2]);
} else {
usage();
}

View File

@ -37,15 +37,31 @@
int
show_pkg_info_from_metadir(const char *pkgname)
{
prop_dictionary_t d;
prop_dictionary_t d, regpkgd, pkgpropsd;
d = xbps_get_pkg_dict_from_metadata_plist(pkgname, XBPS_PKGPROPS);
if (d == NULL)
return errno;
return EINVAL;
regpkgd = xbps_regpkgdb_dictionary_get();
pkgpropsd = xbps_find_pkg_in_dict_by_name(regpkgd,
"properties", pkgname);
if (pkgpropsd == NULL) {
show_pkg_info(d, false);
prop_object_release(d);
goto out;
}
if (prop_dictionary_get(pkgpropsd, "hold"))
prop_dictionary_set_bool(d, "hold", true);
if (prop_dictionary_get(pkgpropsd, "update-first"))
prop_dictionary_set_bool(d, "update-first", true);
if (prop_dictionary_get(pkgpropsd, "provides"))
prop_dictionary_set_bool(d, "virtual-prefer", true);
show_pkg_info(d, false);
prop_object_release(d);
out:
xbps_regpkgdb_dictionary_release();
return 0;
}
@ -57,7 +73,7 @@ show_pkg_files_from_metadir(const char *pkgname)
d = xbps_get_pkg_dict_from_metadata_plist(pkgname, XBPS_PKGFILES);
if (d == NULL)
return errno;
return EINVAL;
rv = show_pkg_files(d);
prop_object_release(d);

View File

@ -1,4 +1,13 @@
.TH "XBPS\-BIN" "8" "30/01/2011" "\ \&" "\ \&"
'\" t
.\" Title: xbps-bin
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
.\" Date: 02/05/2011
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "XBPS\-BIN" "8" "02/05/2011" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
@ -16,18 +25,15 @@ xbps-bin \- XBPS command for binary packages
\fBxbps\-bin\fR [\fIoptions\fR] \fItarget\fR [\fIpkgname\fR]
.SH "DESCRIPTION"
.sp
The xbps\-bin(8) command is used to handle binary packages created for the \fBXBPS binary package system\fR\&. You can use it to install, remove, list or show information about any binary package\&. Binary packages can be installed from local (\fIdirectory\fR) or remote repositories (\fIhttp\fR, \fIhttps\fR or \fIftp\fR), see xbps\-repo(8) for information about repositories\&.
The xbps\-bin(8) command is used to handle binary packages created for the XBPS binary package system\&. You can use it to install, remove, update, list or show information about any binary package\&. Binary packages can be installed from \fIlocal (directories)\fR or \fIremote repositories (http, https or ftp)\fR, see xbps\-repo(8) for information about repositories\&.
.SH "OPTIONS"
.PP
\fB\-c\fR \fIcachedir\fR
.RS 4
Sets the
\fIcache\fR
directory to store downloaded binary packages from remote repositories\&. By default it\(cqs set to
Sets the cache directory to store downloaded binary packages from remote repositories\&. By default it\(cqs set to
\fI/var/cache/xbps\fR
and it\(cqs always relative to the
\fIroot\fR
directory\&. So if you use a
\fIroot directory\fR\&. So if you use a
\fIrootdir\fR
of
\fI/blah\fR, it will become
@ -36,22 +42,22 @@ of
.PP
\fB\-d\fR
.RS 4
Enables extra debugging output to be shown to stderr.
Enables extra debugging output to be shown to stderr\&.
.RE
.PP
\fB\-D\fR
.RS 4
Only show the URLs to download the binary packages from repositories.
This is useful if you want to download them by other means, and later you
can move them to the \fIcachedir\fR to start the installation.
This option can be used for the \fIinstall\fR, \fIupdate\fR and \fIautoupdate\fR
targets.
Only show the URLs to download the binary packages from repositories\&. This is useful if you want to download them by other means, and later you can move them to the
\fIcachedir\fR
to start the installation\&. This option can be used for the install, update and autoupdate targets\&.
.RE
.PP
\fB\-F\fR
.RS 4
Used currently in the \fIremove\fR target. If set, package will be removed even if other packages
are currently depending on it, i.e package is a dependency of other packages. Use this option with care.
Used currently in the
\fIremove\fR
target\&. If set, package will be removed even if other packages are currently depending on it, i\&.e package is a dependency of other packages\&.
\fIUse this option with care\fR\&.
.RE
.PP
\fB\-f\fR
@ -61,8 +67,14 @@ Used currently in the
\fIreconfigure\fR
and
\fIremove\fR
targets\&. If set, package(s) will be reconfigured regardless of its state if working with the
\fIreconfigure target, or to force removal of package files even if its hash doesn\(cqt match in the "purge\fR"
targets\&. If set,
\fIpackage(s)\fR
will be
\fIreconfigured\fR
regardless of its state in the reconfigure target, or to
\fIforce\fR
removal of package files even if its hash doesn\(cqt match in the
\fIpurge\fR
and
\fIremove\fR
targets\&.
@ -81,8 +93,7 @@ targets, if enabled after removing a package it is also purged\&.
.RS 4
Used currently in the
\fIremove\fR
target, to recursively remove packages that aren\(cqt required by other installed
packages and that were installed by the package that we want to remove\&.
target, to recursively remove packages that aren\(cqt required by other installed packages and that were installed by the package that we want to remove\&.
.RE
.PP
\fB\-r\fR \fIrootdir\fR
@ -93,9 +104,7 @@ directory\&. By default the root directory is set to
\fI/\fR\&. Please note that the database directory is always set to
\fI/var/db/xbps\fR
independently of
\fIrootdir\fR\&. So if you use a
\fIrootdir\fR
of
\fIrootdir\fR\&. So if you use a rootdir of
\fI/blah\fR, metadata stuff will go into
\fI/blah/var/db/xbps\fR\&.
.RE
@ -107,7 +116,9 @@ Shows verbose messages\&. Useful while installing and removing packages\&.
.PP
\fB\-y\fR
.RS 4
Assume "yes" to all questions\&. This will bypass all questions and immediately proceed with the task, use this option with care\&.
Assume
\fIyes\fR
to all questions\&. This will bypass all questions and immediately proceed with the task, use this option with care\&.
.RE
.PP
\fB\-V\fR
@ -116,14 +127,11 @@ Shows the current XBPS release version (library and code)\&.
.RE
.SH "TARGETS"
.sp
Please note that all targets are \fBcase insensitive\fR\&.
Please note that all targets are case insensitive\&.
.PP
\fBautoremove\fR
.RS 4
Removes
\fIleaf\fR
packages\&. These packages were installed as dependencies and currently there is not any package depending on it, directly or indirectly\&. Usually it is safe to always answer
\fIyes\fR\&.
Removes leaf packages\&. These packages were installed as dependencies and currently there is not any package depending on it, directly or indirectly\&. Usually it is safe to always answer yes\&.
.RE
.PP
\fBautoupdate\fR
@ -131,108 +139,117 @@ packages\&. These packages were installed as dependencies and currently there is
Updates all currently installed packages to the most newer version available in repository pool\&.
.RE
.PP
\fBcheck \fR\fB\fIpkgname(s)\fR\fR\fB | \fR\fB\fIall\fR\fR
\fBcheck \fR\fB\fIpkgname(s) | all\fR\fR
.RS 4
Checks for integrity errors in installed packages\&. The checks are to found missing run\-time dependencies, missing and modified package files and metadata files\&. If the
\fBall\fR
keyword is used,
\fIall\fR
packages currently installed will be checked, otherwise only
\fBpkgname\fR\&.
keyword is used, all packages currently installed will be checked, otherwise only
\fIpkgname(s)\fR\&.
.RE
.PP
\fBfind-files\fR \fR\fB\fIpattern\fR\fR
\fBfind\-files \fR\fB\fIpattern\fR\fR
.RS 4
Prints the name of the installed "\fBpackage(s)\fR" matching the \fBpattern\fR on its file list.
Prints the name of the installed
\fIpackage(s)\fR
matching the pattern on its file list\&.
.RE
.PP
\fBinstall \fR\fB\fIpkgname(s)\fR\fR\fB | \fR\fB\fIpkgpattern(s)\fR\fR
\fBinstall \fR\fB\fIpkgname(s) | pkgpattern(s)\fR\fR
.RS 4
Install binary package(s) from repository pool by specifying "\fBpkgname(s)\fR" or "\fBpackage pattern(s)\fR"\&. The first repository matching the arguments will be used\&. The package(s) will be
Install binary package(s) from repository pool by specifying
\fIpkgname(s)\fR
or
\fIpackage pattern(s)\fR\&. The first repository matching the arguments will be used\&. The package(s) will be
\fIdownloaded\fR
(if found in a remote repository),
\fIunpacked\fR
and
\fIconfigured\fR\&. The
\fIunpack stage will execute the \fR\fI\fBpre\-install\fR\fR\fI action on its \fR\fI\fBINSTALL\fR\fR\fI script, and unpack its files\&. The "configure\fR"
stage will run the
\fBpost\-install\fR
action set on its
\fBINSTALL\fR
script and will change its state to
\fBinstalled\fR
in the package database\&.
\fIunpack\fR
stage will execute the pre\-install action on its INSTALL script, and unpack its files\&. The
\fIconfigure\fR
stage will run the post\-install action set on its INSTALL script and will change its
\fIstate\fR
to installed in the package database\&.
.RE
.PP
\fBlist [\fR\fB\fIstate\fR\fR]
\fBlist [\fR\fB\fIstate\fR\fR\fB]\fR
.RS 4
Lists all currently installed packages\&. Optionally another argument can be specified to
list only packages with the specified \fIstate\fR. By default only packages that are fully
installed will be listed if no \fIstate\fR has been specified. Accepted states are:
\fBconfig\-files\fR, \fBunpacked\fR and \fBinstalled\fR.
Lists all currently installed packages\&. Optionally another argument can be specified to list only packages with the specified
\fIstate\fR\&. By default only packages that are
\fIfully installed\fR
will be listed if
\fIstate\fR
has not been specified\&. Accepted states are:
\fIconfig\-files\fR,
\fIunpacked\fR
and
\fIinstalled\fR\&.
.RE
.PP
\fBlist\-manual\fR
.RS 4
Lists packages that were installed
\fImanually\fR
by the user, i\&.e not as dependencies of any other package\&.
Lists packages that were installed manually by the user, i\&.e not as dependencies of any other package\&.
.RE
.PP
\fBpurge \fR\fB\fIpkgname\fR\fR\fB | \fR\fB\fIall\fR\fR
\fBpurge \fR\fB\fIpkgname | all\fR\fR
.RS 4
Purge an installed package,
\fBpkgname\fR
Purge an installed package:
\fIpkgname\fR
or
\fBall\fR
packages\&. The
\fIpurge\fR
stage runs the
\fBpost\-remove\fR
action set in the
\fBREMOVE\fR
script in its metadata directory ( /var/db/xbps/metadata/\fIpkgname\fR
) and will remove configuration (if they were not modified by the user) and metadata files\&. The package will be fully removed from the system once it has been
\fBpurged\fR\&. If
\fIall\fR
packages\&. The purge stage runs the post\-remove action set in the REMOVE script in its metadata directory
\fI(/var/db/xbps/metadata/pkgname)\fR
and will remove configuration (if they were not modified by the user) and metadata files\&. The package will be fully removed from the system once it has been purged\&. If
\fB\-f\fR
option is used, configuration files that have been modified
\fBWILL BE REMOVED, BEWARE WITH THIS!\fR\&.
option is used, configuration files that have been
\fImodified WILL BE REMOVED\&. BEWARE WITH THIS!\fR
.RE
.PP
\fBreconfigure \fR\fB\fIpkgname\fR\fR\fB | \fR\fB\fIall\fR\fR
\fBreconfigure \fR\fB\fIpkgname | all\fR\fR
.RS 4
Reconfigure an
\fBunpacked\fR
package\&. Packages in this state are not fully installed, because they were not configured for whatever reason\&. The
\fIconfigure\fR
stage will run the
\fIpost\-install\fR
action set on its
\fBINSTALL\fR
script and will change its state to
\fBinstalled\fR
in the package database\&. The
Reconfigure an unpacked package\&. Packages in this state are not fully installed, because they were not configured for whatever reason\&. The configure stage will run the post\-install action set on its INSTALL script and will change its state to installed in the package database\&. The
\fIall\fR
keyword can be used to reconfigure all not configured packages\&. If
\fB\-f\fR
option is used, the package will be reconfigured even if its state is already
\fBinstalled\fR\&.
option is used, the package will be reconfigured even if its state is already installed\&.
.RE
.PP
\fBremove \fR\fB\fIpkgname(s)\fR\fR
.RS 4
Removes the installed package
\fIpkgname(s)\fR\&. Its files will be removed and its state will be changed to
\fBconfig\-files\fR
\fIconfig\-files\fR
in the package database\&. Configuration files, its metadata directory/files and its information in the package database are preserved\&. To fully remove a package in
\fBconfig\-files\fR
state, it must be
\fBpurged\fR
with the
\fBpurge\fR
command or alternatively use the \fI\-p\fR flag \&. If
\fIconfig\-files\fR
state, it must be purged with the
\fIpurge\fR
command or alternatively use the
\fB\-p\fR
flag \&. If
\fB\-f\fR
option is used, package files will be removed even if its SHA256 hash doesn\(cqt match\&.
option is used, package files will be
\fBremoved even if its SHA256 hash don\(cqt match\fR\&.
.RE
.PP
\fBset\-prop \fR\fB\fIproperty\fR\fR\fB \fR\fB\fIpkgname\fR\fR
.RS 4
Sets a
\fIproperty\fR
for a package as specified in
\fIpkgname\fR\&. See the
\fIPROPERTIES\fR
section below for more information\&.
.RE
.PP
\fBunset\-prop \fR\fB\fIproperty\fR\fR\fB \fR\fB\fIpkgname\fR\fR
.RS 4
Unsets a
\fIproperty\fR
for a package as specified in
\fIpkgname\fR\&. See the
\fIPROPERTIES\fR
section below for more information\&.
.RE
.PP
\fBshow \fR\fB\fIpkgname\fR\fR
@ -243,31 +260,23 @@ Shows information for installed package
.PP
\fBshow\-deps \fR\fB\fIpkgname\fR\fR
.RS 4
Shows the list of dependencies that
\fIpkgname\fR
requires at run time\&.
Shows the list of dependencies that pkgname requires at run time\&.
.RE
.PP
\fBshow\-files \fR\fB\fIpkgname\fR\fR
.RS 4
Shows the list of files that
\fIpkgname\fR
contains\&.
Shows the list of files that pkgname contains\&.
.RE
.PP
\fBshow\-orphans\fR
.RS 4
Shows the list of package orphans currently installed. Package orphans
are packages that were installed as dependencies of another package, but
no other package currently depends on.
Shows the list of package orphans currently installed\&. Package orphans are packages that were installed as dependencies of another package, but no other package currently depends on\&.
.RE
.PP
\fBshow\-revdeps \fR\fB\fIpkgname\fR\fR
.RS 4
Shows the reverse dependencies for
\fIpkgname\fR\&. Reverse dependencies are packages that are currently depending in
\fIpkgname\fR
directly\&.
\fIpkgname\fR\&. Reverse dependencies are packages that are currently depending in pkgname directly\&.
.RE
.PP
\fBupdate \fR\fB\fIpkgname(s)\fR\fR
@ -276,8 +285,8 @@ Updates
\fIpkgname(s)\fR
to the most newer version available in repository pool\&. This can be used if only
\fIpkgname(s)\fR
needs to be updated, unlike the
\fBautoupdate\fR
need to be updated, unlike the
\fIautoupdate\fR
target that will update all currently installed packages\&.
.RE
.SH "PACKAGE STATES"
@ -296,17 +305,40 @@ The package has been unpacked in destination root directory, but it is not fully
.PP
\fBconfig\-files\fR
.RS 4
The package has been removed but configuration files and its metadata directory are still available (and it is still registered in the package database)\&. You can
\fIpurge\fR
safely packages that are in this state, modified configuration files will be preserved\&.
The package has been removed but configuration files and its metadata directory are still available (and it is still registered in the package database)\&. You can purge safely packages that are in this state, modified configuration files will be preserved\&.
.RE
.SH "PROPERTIES"
.sp
Properties can be specified for packages to control behaviour of some aspects in XBPS\&. The following is the list of properties currently implemented:
.PP
\fBhold\fR
.RS 4
When this property is set for a package, it will be put on
\fIhold\fR
i\&.e the package won\(cqt be updated even if there is a newer version in registered repositories\&.
.RE
.PP
\fBupdate\-first\fR
.RS 4
When this property is set, the package will always be updated before all other packages, regardless of its package dependencies\&.
.RE
.PP
\fBvirtual\fR
.RS 4
When this property is set, the virtual packages that target package supports via the
\fBproperties\fR
object will have preference over other packages matching its
\fIpackage name\fR\&. A real example is any package that
\fIprovides\fR
the
\fBsyslog\-daemon\-0\fR
virtual package, if there are two packages supporting this you can choose which one will be installed\&.
.RE
.SH "FILES"
.PP
\fB/var/db/xbps\fR
.RS 4
xbps global
\fImetadata\fR
directory\&.
xbps global metadata directory\&.
.RE
.PP
\fB/var/db/xbps/metadata/<pkgname>\fR
@ -326,64 +358,80 @@ Installed package metadata properties\&.
.PP
\fB/var/db/xbps/regpkgdb\&.plist\fR
.RS 4
Registered packages plist database\&.
xbps master packages/properties database plist file\&.
.RE
.PP
\fB/var/cache/xbps\fR
.RS 4
xbps
\fIcache\fR
directory for downloaded binary packages\&.
xbps cache directory for downloaded binary packages\&.
.RE
.SH "EXAMPLES"
.PP
Install a package by specifying its name:
\fBInstall\fR a package by specifying its \fBname\fR:
.RS 4
$ xbps\-bin install foo
.RE
.PP
Install a package by specifying a package pattern:
\fBInstall\fR a package by specifying a \fBpackage pattern\fR:
.RS 4
$ xbps\-bin install "\fBfoo>=3\&.0\fR"
$ xbps\-bin install "foo>=3\&.0"
.RE
.PP
Install multiple packages by specifying names and package patterns:
\fBInstall multiple\fR packages by specifying \fBnames\fR and \fBpackage patterns\fR:
.RS 4
$ xbps\-bin install foo "\fBblah⇐4\&.0\fR" baz\-2\&.0 "\fBblob>4\&.[0\-9]\fR"
$ xbps\-bin install foo "blah<=4\&.0" baz\-2\&.0 "blob>4\&.[0\-9]"
.RE
.PP
Find the package that owns the file \fB/bin/mount\fR:
\fBFind\fR the package that owns the file \fB/bin/mount\fR:
.RS 4
$ xbps\-bin find\-files /bin/mount
.RE
.PP
Find the packages that match the pattern "\fB/usr/lib/libav\&*\fR":
\fBFind\fR the packages that match the pattern \fB"/usr/lib/libav\fR"*:
.RS 4
$ xbps\-bin find\-files "/usr/lib/libav\&*"
$ xbps\-bin find\-files "/usr/lib/libav*"
.RE
.PP
Remove and purge the package \fBproplib-devel\fR:
\fBRemove and purge\fR the package \fBproplib\-devel\fR:
.RS 4
$ xbps\-bin -yp remove proplib\-devel
$ xbps\-bin \-yp remove proplib\-devel
.RE
.PP
Remove and purge the package \fBbsdtar\fR and recursively all packages that
were installed automatically by it:
\fBRemove and purge\fR the package \fBbsdtar\fR and \fBrecursively\fR all packages that were installed automatically by it:
.RS 4
$ xbps\-bin -Rp remove bsdtar
$ xbps\-bin \-Rp remove bsdtar
.RE
.PP
\fBSets\fR the \fIvirtual\fR property in the \fBxbps\-devel\fR package:
.RS 4
$ xbps\-bin set\-prop virtual xbps\-devel
.RE
.PP
\fBUnsets\fR the \fIhold\fR property in the \fBcoreutils\fR package:
.RS 4
$ xbps\-bin unset\-prop hold coreutils
.RE
.SH "BUGS"
.sp
Probably, but I try to make this not happen\&. Use it under your own responsability and enjoy your life\&.
.sp
Report bugs in \fIhttp://code\&.google\&.com/p/xbps\fR\&.
Report bugs in http://code\&.google\&.com/p/xbps\&.
.SH "SEE ALSO"
.sp
xbps\-repo(8), xbps\-src(8)
.sp
The XBPS project: \fIhttp://code\&.google\&.com/p/xbps\fR
The XBPS project: http://code\&.google\&.com/p/xbps
.sp
To build binary packages, the xbps\-src(8) shell script is the command designed for this task\&. This must be retrieved from a Mercurial repository, available at \fIhttp://xbps\-src\&.xbps\&.googlecode\&.com/hg/\fR\&.
To build binary packages, the xbps\-src(8) shell script is the command designed for this task\&. This must be retrieved from a Mercurial repository, available at http://xbps\-src\&.xbps\&.googlecode\&.com/hg/\&.
.SH "AUTHORS"
.sp
The \fBXBPS binary package system\fR has been designed and implemented by Juan Romero Pardines <xtraeme@gmail\&.com>\&.
The X Binary Package System has been designed and implemented by Juan Romero Pardines <xtraeme@gmail\&.com>\&.

View File

@ -216,7 +216,8 @@ main(int argc, char **argv)
if (argc != 2)
usage();
dict = xbps_find_pkg_dict_from_plist_by_name(plist, argv[1]);
dict = xbps_find_pkg_dict_from_plist_by_name(plist,
"packages", argv[1]);
if (dict == NULL)
exit(EXIT_FAILURE);

View File

@ -53,7 +53,7 @@
* @def XBPS_RELVER
* Current library release date.
*/
#define XBPS_RELVER "20110201"
#define XBPS_RELVER "20110205"
/**
* @def XBPS_META_PATH
@ -174,6 +174,31 @@ int xbps_configure_all_pkgs(void);
/*@}*/
/** @addtogroup pkgprops */
/*@{*/
/**
* Sets the property \a prop in a package matching the name \a pkgname.
*
* @param[in] prop Property key to be set.
* @param[in] pkgname Package name to set the property.
*
* @return 0 on success, otherwise an errno value.
*/
int xbps_property_set(const char *prop, const char *pkgname);
/**
* Unsets the property \a prop in a package matching the name \a pkgname.
*
* @param[in] prop Property key to be unset.
* @param[in] pkgname Package name to unset the property.
*
* @return 0 on success, otherwise an errno value.
*/
int xbps_property_unset(const char *prop, const char *pkgname);
/*@}*/
/**
* @ingroup vermatch
*
@ -436,7 +461,8 @@ prop_dictionary_t xbps_find_pkg_in_dict_by_pattern(prop_dictionary_t dict,
* a package name.
*
* @param[in] plist Path to a plist file.
* @param[in] pkgname Package name to look for.
* @param[in] key Proplib array's key name.
* @param[in] pkgname Package name to match in array.
*
* @return The package's proplib dictionary on success, NULL otherwise and
* errno is set appropiately. Returned dictionary is copied via
@ -444,8 +470,25 @@ prop_dictionary_t xbps_find_pkg_in_dict_by_pattern(prop_dictionary_t dict,
* release the object with prop_object_release() when done.
*/
prop_dictionary_t xbps_find_pkg_dict_from_plist_by_name(const char *plist,
const char *key,
const char *pkgname);
/**
* Finds the package's proplib dictionary in a plist file by specifying
* a package pattern.
*
* @param[in] plist Path to a plist file.
* @param[in] key Proplib array's key name.
* @param[in] pattern Package pattern to match in array.
*
* @return The package's proplib dictionary on success, NULL otherwise and
* errno is set appropiately. Returned dictionary should be released with
* prop_object_release() when it's not any longer needed.
*/
prop_dictionary_t xbps_find_pkg_dict_from_plist_by_pattern(const char *plist,
const char *key,
const char *pattern);
/**
* Finds a package's dictionary searching in the registered packages
* database by using a package name or a package pattern.

View File

@ -199,6 +199,19 @@ int HIDDEN xbps_file_chdir_exec(const char *path, const char *arg, ...);
int HIDDEN xbps_repository_pkg_replaces(prop_dictionary_t,
prop_dictionary_t);
/**
* @private
* From lib/plist.c
*/
prop_dictionary_t HIDDEN
xbps_find_virtualpkg_user_in_dict_by_name(prop_dictionary_t,
const char *,
const char *);
prop_dictionary_t HIDDEN
xbps_find_virtualpkg_user_in_dict_by_pattern(prop_dictionary_t,
const char *,
const char *);
__END_DECLS
#endif /* !_XBPS_API_IMPL_H_ */

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,11 +216,14 @@ xbps_set_pkg_state_installed(const char *pkgname, pkg_state_t state)
}
array = prop_dictionary_get(dict, "packages");
if (array == NULL) {
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)
prop_object_release(pkgd);

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;
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;
return find_pkg_dict_from_plist(plist, key, pkgname, false);
}
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)))
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);