From de296d819273ac5d2afd29af834b860292e143da Mon Sep 17 00:00:00 2001 From: Juan RP Date: Sat, 5 Feb 2011 11:25:04 +0100 Subject: [PATCH] Added the concept of package properties in the API. See the NEWS file and xbps-bin(8) for more information. --- NEWS | 18 ++ bin/xbps-bin/main.c | 18 ++ bin/xbps-bin/show-info-files.c | 24 ++- bin/xbps-bin/xbps-bin.8 | 310 +++++++++++++++++++-------------- bin/xbps-uhelper/main.c | 3 +- include/xbps_api.h | 47 ++++- include/xbps_api_impl.h | 13 ++ lib/Makefile | 4 +- lib/package_properties.c | 268 ++++++++++++++++++++++++++++ lib/package_state.c | 11 +- lib/plist.c | 237 +++++++++++++++++++------ lib/repository_pool.c | 79 +++++++-- 12 files changed, 820 insertions(+), 212 deletions(-) create mode 100644 lib/package_properties.c diff --git a/NEWS b/NEWS index 595ea3e1..3e5fd5e4 100644 --- a/NEWS +++ b/NEWS @@ -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". diff --git a/bin/xbps-bin/main.c b/bin/xbps-bin/main.c index 5631ac96..ef93a3f9 100644 --- a/bin/xbps-bin/main.c +++ b/bin/xbps-bin/main.c @@ -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(); } diff --git a/bin/xbps-bin/show-info-files.c b/bin/xbps-bin/show-info-files.c index b4fa401f..cb8404d0 100644 --- a/bin/xbps-bin/show-info-files.c +++ b/bin/xbps-bin/show-info-files.c @@ -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); diff --git a/bin/xbps-bin/xbps-bin.8 b/bin/xbps-bin/xbps-bin.8 index 13e12619..4c6ba15d 100644 --- a/bin/xbps-bin/xbps-bin.8 +++ b/bin/xbps-bin/xbps-bin.8 @@ -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 +.\" 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/\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 \&. +The X Binary Package System has been designed and implemented by Juan Romero Pardines \&. diff --git a/bin/xbps-uhelper/main.c b/bin/xbps-uhelper/main.c index 8750e91b..1b44c768 100644 --- a/bin/xbps-uhelper/main.c +++ b/bin/xbps-uhelper/main.c @@ -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); diff --git a/include/xbps_api.h b/include/xbps_api.h index 32470276..20b9e3cb 100644 --- a/include/xbps_api.h +++ b/include/xbps_api.h @@ -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. diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h index e5594313..505724bb 100644 --- a/include/xbps_api_impl.h +++ b/include/xbps_api_impl.h @@ -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_ */ diff --git a/lib/Makefile b/lib/Makefile index d272a343..f1b28555 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -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 diff --git a/lib/package_properties.c b/lib/package_properties.c new file mode 100644 index 00000000..f98f5813 --- /dev/null +++ b/lib/package_properties.c @@ -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 +#include +#include +#include +#include + +#include +#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; +} diff --git a/lib/package_state.c b/lib/package_state.c index d072b805..76ea58f0 100644 --- a/lib/package_state.c +++ b/lib/package_state.c @@ -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) diff --git a/lib/plist.c b/lib/plist.c index e3167e3b..292d8a88 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -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 diff --git a/lib/repository_pool.c b/lib/repository_pool.c index 9523d1a2..c6c48738 100644 --- a/lib/repository_pool.c +++ b/lib/repository_pool.c @@ -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);