diff --git a/NEWS b/NEWS index d77b2c24..5d722ce7 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,15 @@ xbps-0.37 (???): + * xbps-install(8): it's possible now to update a single package (if it's already + installed) without using the -u, --update option. This implements + GH #35 (https://github.com/voidlinux/xbps/issues/35). + + $ xbps-install [-f] -y foo + + - if foo is installed, update it. + - if foo not installed, install it. + - if -f is set, reinstall or downgrade it. + * xbps-query(8): new option (-S, --show) which shows info of a package installed locally or in a repository with -R. This is the default mode if no other mode is set; to preserve compatibility with previous versions. diff --git a/bin/xbps-install/xbps-install.8 b/bin/xbps-install/xbps-install.8 index 339e69c4..86062b13 100644 --- a/bin/xbps-install/xbps-install.8 +++ b/bin/xbps-install/xbps-install.8 @@ -1,9 +1,9 @@ -.Dd April 21, 2014 +.Dd May 27, 2014 .Os Void Linux .Dt xbps-install 8 .Sh NAME .Nm xbps-install -.Nd XBPS utility to install and update packages +.Nd XBPS utility to (re)install and update packages .Sh SYNOPSYS .Nm xbps-install .Op OPTIONS @@ -11,12 +11,17 @@ .Sh DESCRIPTION The .Nm -utility installs and updates packages in the target root directory. +utility installs, reinstalls, downgrades and updates packages in the target root directory. The argument .Ar PKG is a package expression, which is explained in the .Em PACKAGE EXPRESSION -section. +section. If package is installed, it will be updated to the version available in repositories +matching the +.Em PACKAGE EXPRESSION . +Otherwise it will be installed, or reinstalled/downgraded if +.Fl f , Fl -force +option is set. .Sh PACKAGE EXPRESSION A package expression is a form to match a pattern; currently xbps supports 3 ways to specify them: @@ -61,8 +66,10 @@ Specifies a full path to the cache directory, where binary packages are stored. .It Fl d, Fl -debug Enables extra debugging shown to stderr. .It Fl f, Fl -force -Forcefully install target package even if another version is already installed, -overwritting regular package files and symlinks (if they have been modified) but +Force downgrade installation (if package version in repos is less than installed version), +or reinstallation (if package version in repos is the same) to the target +.Ar PKG , +overwriting regular package files and symlinks (if they have been modified) but .Em preserving configuration files . If .Fl f @@ -79,9 +86,8 @@ Specifies a full path for the target root directory. .It Fl S, Fl -sync Synchronize remote repository index files. .It Fl u, Fl -update -Update target package(s) rather than install. If -.Op PKG -not set, all installed packages will be updated. +Performs a full system upgrade: all installed packages will be updated to the greatest +versions that were found in repositories. .It Fl v, Fl -verbose Enables verbose messages. .It Fl y, Fl -yes diff --git a/lib/transaction_ops.c b/lib/transaction_ops.c index 44829da4..3090f5bd 100644 --- a/lib/transaction_ops.c +++ b/lib/transaction_ops.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009-2013 Juan Romero Pardines. + * Copyright (c) 2009-2014 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,17 +54,18 @@ */ enum { TRANS_INSTALL = 1, - TRANS_UPDATE + TRANS_UPDATE, + TRANS_REINSTALL }; static int -trans_find_pkg(struct xbps_handle *xhp, const char *pkg, int action) +trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) { - xbps_dictionary_t pkg_pkgdb = NULL, pkg_repod; + xbps_dictionary_t pkg_pkgdb = NULL, pkg_repod = NULL; xbps_array_t unsorted; const char *repoloc, *repopkgver, *instpkgver, *reason; char *pkgname; - int rv = 0; + int action = 0, rv = 0; pkg_state_t state = 0; bool autoinst = false; @@ -77,7 +78,9 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, int action) /* * Find out if the pkg has been found in repository pool. */ - if (action == TRANS_INSTALL) { + if (pkg_pkgdb == NULL) { + /* pkg not installed, perform installation */ + action = TRANS_INSTALL; reason = "install"; if (((pkg_repod = xbps_rpool_get_pkg(xhp, pkg)) == NULL) && ((pkg_repod = xbps_rpool_get_virtualpkg(xhp, pkg)) == NULL)) { @@ -85,21 +88,27 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, int action) return ENOENT; } } else { - if (pkg_pkgdb == NULL) - return ENODEV; - - reason = "update"; + /* pkg installed, update or reinstall */ + if (!reinstall) { + action = TRANS_UPDATE; + reason = "update"; + } else { + action = TRANS_REINSTALL; + reason = "install"; + } if ((pkg_repod = xbps_rpool_get_pkg(xhp, pkg)) == NULL) { /* not found */ return ENOENT; } } + xbps_dictionary_get_cstring_nocopy(pkg_repod, "pkgver", &repopkgver); xbps_dictionary_get_cstring_nocopy(pkg_repod, "repository", &repoloc); if (action == TRANS_UPDATE) { /* - * Compare installed version vs best pkg available in repos. + * Compare installed version vs best pkg available in repos + * for pkg updates. */ xbps_dictionary_get_cstring_nocopy(pkg_pkgdb, "pkgver", &instpkgver); @@ -109,16 +118,26 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, int action) repopkgver, instpkgver, repoloc); return EEXIST; } + } else if (action == TRANS_REINSTALL) { + /* + * For reinstallation check if installed version is less than + * or equal to the pkg in repos, if true, continue with reinstallation; + * otherwise perform an update. + */ + xbps_dictionary_get_cstring_nocopy(pkg_pkgdb, "pkgver", &instpkgver); + if (xbps_cmpver(repopkgver, instpkgver) == 1) { + action = TRANS_UPDATE; + reason = "update"; + } } + if (pkg_pkgdb) { /* * If pkg is already installed, respect its automatic-install * property. */ - xbps_dictionary_get_bool(pkg_pkgdb, "automatic-install", - &autoinst); - xbps_dictionary_set_bool(pkg_repod, "automatic-install", - autoinst); + xbps_dictionary_get_bool(pkg_pkgdb, "automatic-install", &autoinst); + xbps_dictionary_set_bool(pkg_repod, "automatic-install", autoinst); } /* * Prepare transaction dictionary. @@ -216,7 +235,7 @@ xbps_transaction_update_packages(struct xbps_handle *xhp) } pkgname = xbps_pkg_name(pkgver); assert(pkgname); - rv = trans_find_pkg(xhp, pkgname, TRANS_UPDATE); + rv = trans_find_pkg(xhp, pkgname, false); if (rv == 0) newpkg_found = true; else if (rv == ENOENT || rv == EEXIST || rv == ENODEV) { @@ -236,27 +255,14 @@ xbps_transaction_update_packages(struct xbps_handle *xhp) int xbps_transaction_update_pkg(struct xbps_handle *xhp, const char *pkg) { - return trans_find_pkg(xhp, pkg, TRANS_UPDATE); + return trans_find_pkg(xhp, pkg, false); } int xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) { - xbps_dictionary_t pkgd = NULL; - pkg_state_t state; - - if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkg)) || - (pkgd = xbps_pkgdb_get_virtualpkg(xhp, pkg))) { - if (xbps_pkg_state_dictionary(pkgd, &state) != 0) - return EINVAL; - if ((state == XBPS_PKG_STATE_INSTALLED) && !reinstall) { - /* error out if pkg installed and no reinstall */ - return EEXIST; - } - } - - return trans_find_pkg(xhp, pkg, TRANS_INSTALL); + return trans_find_pkg(xhp, pkg, reinstall); } int diff --git a/tests/xbps/libxbps/shell/install_test.sh b/tests/xbps/libxbps/shell/install_test.sh index 69527a95..8cdca0f8 100644 --- a/tests/xbps/libxbps/shell/install_test.sh +++ b/tests/xbps/libxbps/shell/install_test.sh @@ -66,7 +66,67 @@ install_with_vpkg_deps_body() { atf_check_equal $? 0 } +atf_test_case update_if_installed + +update_if_installed_head() { + atf_set "descr" "Tests for pkg installations: update if installed (issue #35)" +} + +update_if_installed_body() { + mkdir some_repo + mkdir -p pkg_A/usr/bin + cd some_repo + xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A + atf_check_equal $? 0 + + xbps-rindex -a *.xbps + atf_check_equal $? 0 + cd .. + + xbps-install -C empty.conf -r root --repository=$PWD/some_repo -y A + atf_check_equal $? 0 + + cd some_repo + xbps-create -A noarch -n A-1.1_1 -s "A pkg" ../pkg_A + atf_check_equal $? 0 + + xbps-rindex -a *.xbps + atf_check_equal $? 0 + cd .. + + xbps-install -C empty.conf -r root --repository=$PWD/some_repo -y A + atf_check_equal $? 0 + pkgver=$(xbps-query -r root -ppkgver A) + atf_check_equal $pkgver A-1.1_1 +} + +atf_test_case install_if_not_installed_on_update + +install_if_not_installed_on_update_head() { + atf_set "descr" "Tests for pkg installations: install if not installed on update (issue #35)" +} + +install_if_not_installed_on_update_body() { + mkdir some_repo + mkdir -p pkg_A/usr/bin + cd some_repo + xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A + atf_check_equal $? 0 + + xbps-rindex -a *.xbps + atf_check_equal $? 0 + cd .. + + xbps-install -C empty.conf -r root --repository=$PWD/some_repo -yu A + atf_check_equal $? 0 + + pkgver=$(xbps-query -r root -ppkgver A) + atf_check_equal $pkgver A-1.0_1 +} + atf_init_test_cases() { atf_add_test_case install_with_deps atf_add_test_case install_with_vpkg_deps + atf_add_test_case install_if_not_installed_on_update + atf_add_test_case update_if_installed }