From 7d8247ae56c6dbebd1914f733770591c0e9f2335 Mon Sep 17 00:00:00 2001 From: Juan RP Date: Thu, 23 Apr 2020 06:03:56 +0200 Subject: [PATCH] Multiple changes to pkgs on hold mode. - Added transaction stats for pkgs on hold. - Always add packages on hold to the transaction dictionary, its type will be set to XBPS_TRANS_HOLD. - Changed xbps_transaction_update_pkg() to have a new "force" bool argument to force an update with a pkg on hold. - As discussed in #274 with @Duncaen the only way to update a pkg on hold is by using `-f`, i.e `xbps-install -f foo`. Closes #265 Closes #274 --- bin/xbps-install/defs.h | 4 +- bin/xbps-install/main.c | 10 +-- bin/xbps-install/transaction.c | 88 +++++++++++---------------- bin/xbps-install/util.c | 59 ++++++++++-------- bin/xbps-install/xbps-install.1 | 7 ++- include/xbps.h.in | 12 ++-- lib/transaction_ops.c | 30 +++++---- lib/transaction_prepare.c | 9 ++- tests/xbps/libxbps/shell/hold_test.sh | 16 +++++ 9 files changed, 127 insertions(+), 108 deletions(-) diff --git a/bin/xbps-install/defs.h b/bin/xbps-install/defs.h index 9f72c33a..34680b2a 100644 --- a/bin/xbps-install/defs.h +++ b/bin/xbps-install/defs.h @@ -43,11 +43,12 @@ struct transaction { uint32_t cf_pkgcnt; uint32_t rm_pkgcnt; uint32_t dl_pkgcnt; + uint32_t hold_pkgcnt; }; /* from transaction.c */ int install_new_pkg(struct xbps_handle *, const char *, bool); -int update_pkg(struct xbps_handle *, const char *); +int update_pkg(struct xbps_handle *, const char *, bool); int dist_upgrade(struct xbps_handle *, unsigned int, bool, bool); int exec_transaction(struct xbps_handle *, unsigned int, bool, bool); @@ -65,5 +66,6 @@ int state_cb(const struct xbps_state_cb_data *, void *); void print_package_line(const char *, unsigned int, bool); bool print_trans_colmode(struct transaction *, unsigned int); int get_maxcols(void); +const char *ttype2str(xbps_dictionary_t); #endif /* !_XBPS_INSTALL_DEFS_H_ */ diff --git a/bin/xbps-install/main.c b/bin/xbps-install/main.c index d7c3e6c4..c626d407 100644 --- a/bin/xbps-install/main.c +++ b/bin/xbps-install/main.c @@ -124,12 +124,12 @@ main(int argc, char **argv) struct xferstat xfer; const char *rootdir, *cachedir, *confdir; int i, c, flags, rv, fflag = 0; - bool syncf, yes, reinstall, drun, update; + bool syncf, yes, force, drun, update; int maxcols, eexist = 0; rootdir = cachedir = confdir = NULL; flags = rv = 0; - syncf = yes = reinstall = drun = update = false; + syncf = yes = force = drun = update = false; memset(&xh, 0, sizeof(xh)); @@ -157,7 +157,7 @@ main(int argc, char **argv) fflag++; if (fflag > 1) flags |= XBPS_FLAG_FORCE_UNPACK; - reinstall = true; + force = true; break; case 'h': usage(false); @@ -258,7 +258,7 @@ main(int argc, char **argv) } else if (update) { /* Update target packages */ for (i = optind; i < argc; i++) { - rv = update_pkg(&xh, argv[i]); + rv = update_pkg(&xh, argv[i], force); if (rv == EEXIST) { /* pkg already updated, ignore */ rv = 0; @@ -275,7 +275,7 @@ main(int argc, char **argv) } else if (!update) { /* Install target packages */ for (i = optind; i < argc; i++) { - rv = install_new_pkg(&xh, argv[i], reinstall); + rv = install_new_pkg(&xh, argv[i], force); if (rv == EEXIST) { /* pkg already installed, ignore */ rv = 0; diff --git a/bin/xbps-install/transaction.c b/bin/xbps-install/transaction.c index 5342c4ed..d747c760 100644 --- a/bin/xbps-install/transaction.c +++ b/bin/xbps-install/transaction.c @@ -47,38 +47,6 @@ print_array(xbps_array_t a) } } -static const char * -ttype2str(xbps_dictionary_t pkg_repod) -{ - uint8_t r; - - assert(pkg_repod); - - if (!xbps_dictionary_get_uint8(pkg_repod, "transaction", &r)) - return NULL; - - switch (r) { - case XBPS_TRANS_INSTALL: - return "install"; - case XBPS_TRANS_REINSTALL: - return "reinstall"; - case XBPS_TRANS_UPDATE: - return "update"; - case XBPS_TRANS_REMOVE: - return "remove"; - case XBPS_TRANS_CONFIGURE: - return "configure"; - case XBPS_TRANS_HOLD: - return "hold"; - case XBPS_TRANS_DOWNLOAD: - return "download"; - default: - return "unknown"; - } - - return NULL; -} - static void show_actions(xbps_object_iterator_t iter) { @@ -123,7 +91,11 @@ show_package_list(struct transaction *trans, xbps_trans_type_t ttype, unsigned i xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); xbps_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); xbps_dictionary_get_bool(obj, "download", &dload); - tt = xbps_transaction_pkg_type(obj); + if (ttype == XBPS_TRANS_DOWNLOAD && dload) { + tt = XBPS_TRANS_DOWNLOAD; + } else { + tt = xbps_transaction_pkg_type(obj); + } buf = NULL; if (tt == XBPS_TRANS_UPDATE) { @@ -135,7 +107,7 @@ show_package_list(struct transaction *trans, xbps_trans_type_t ttype, unsigned i iversion = xbps_pkg_version(ipkgver); buf = xbps_xasprintf("%s (%s -> %s)", pkgname, iversion, version); } - if ((ttype && (ttype == tt)) || (!ttype && dload)) { + if (ttype == tt) { if (buf) { print_package_line(buf, cols, false); free(buf); @@ -154,51 +126,62 @@ show_transaction_sizes(struct transaction *trans, int cols) uint64_t dlsize = 0, instsize = 0, rmsize = 0, disk_free_size = 0; char size[8]; + /* + * Get stats from transaction dictionary. + */ + xbps_dictionary_get_uint32(trans->d, "total-download-pkgs", + &trans->dl_pkgcnt); + xbps_dictionary_get_uint32(trans->d, "total-install-pkgs", + &trans->inst_pkgcnt); + xbps_dictionary_get_uint32(trans->d, "total-update-pkgs", + &trans->up_pkgcnt); + xbps_dictionary_get_uint32(trans->d, "total-configure-pkgs", + &trans->cf_pkgcnt); + xbps_dictionary_get_uint32(trans->d, "total-remove-pkgs", + &trans->rm_pkgcnt); + xbps_dictionary_get_uint32(trans->d, "total-hold-pkgs", + &trans->hold_pkgcnt); + if (!print_trans_colmode(trans, cols)) { /* - * Show the list of packages that will be downloaded, installed, updated, - * removed or configured. + * Show the list of packages and its action. */ - xbps_dictionary_get_uint32(trans->d, "total-download-pkgs", - &trans->dl_pkgcnt); if (trans->dl_pkgcnt) { printf("%u package%s will be downloaded:\n", trans->dl_pkgcnt, trans->dl_pkgcnt == 1 ? "" : "s"); show_package_list(trans, XBPS_TRANS_DOWNLOAD, cols); printf("\n"); } - xbps_dictionary_get_uint32(trans->d, "total-install-pkgs", - &trans->inst_pkgcnt); if (trans->inst_pkgcnt) { printf("%u package%s will be installed:\n", trans->inst_pkgcnt, trans->inst_pkgcnt == 1 ? "" : "s"); show_package_list(trans, XBPS_TRANS_INSTALL, cols); printf("\n"); } - xbps_dictionary_get_uint32(trans->d, "total-update-pkgs", - &trans->up_pkgcnt); if (trans->up_pkgcnt) { printf("%u package%s will be updated:\n", trans->up_pkgcnt, trans->up_pkgcnt == 1 ? "" : "s"); show_package_list(trans, XBPS_TRANS_UPDATE, cols); printf("\n"); } - xbps_dictionary_get_uint32(trans->d, "total-configure-pkgs", - &trans->cf_pkgcnt); if (trans->cf_pkgcnt) { printf("%u package%s will be configured:\n", trans->cf_pkgcnt, trans->cf_pkgcnt == 1 ? "" : "s"); show_package_list(trans, XBPS_TRANS_CONFIGURE, cols); printf("\n"); } - xbps_dictionary_get_uint32(trans->d, "total-remove-pkgs", - &trans->rm_pkgcnt); if (trans->rm_pkgcnt) { printf("%u package%s will be removed:\n", trans->rm_pkgcnt, trans->rm_pkgcnt == 1 ? "" : "s"); show_package_list(trans, XBPS_TRANS_REMOVE, cols); printf("\n"); } + if (trans->hold_pkgcnt) { + printf("%u package%s are on hold:\n", + trans->hold_pkgcnt, trans->hold_pkgcnt == 1 ? "" : "s"); + show_package_list(trans, XBPS_TRANS_HOLD, cols); + printf("\n"); + } } /* * Show total download/installed/removed size for all required packages. @@ -294,11 +277,11 @@ dist_upgrade(struct xbps_handle *xhp, unsigned int cols, bool yes, bool drun) } int -install_new_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) +install_new_pkg(struct xbps_handle *xhp, const char *pkg, bool force) { int rv; - rv = xbps_transaction_install_pkg(xhp, pkg, reinstall); + rv = xbps_transaction_install_pkg(xhp, pkg, force); if (rv == EEXIST) printf("Package `%s' already installed.\n", pkg); else if (rv == ENOENT) @@ -317,11 +300,11 @@ install_new_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) } int -update_pkg(struct xbps_handle *xhp, const char *pkg) +update_pkg(struct xbps_handle *xhp, const char *pkg, bool force) { int rv; - rv = xbps_transaction_update_pkg(xhp, pkg); + rv = xbps_transaction_update_pkg(xhp, pkg, force); if (rv == EEXIST) printf("Package '%s' is up to date.\n", pkg); else if (rv == ENOENT) @@ -441,11 +424,12 @@ exec_transaction(struct xbps_handle *xhp, unsigned int maxcols, bool yes, bool d */ if ((rv = xbps_transaction_commit(xhp)) == 0) { printf("\n%u downloaded, %u installed, %u updated, " - "%u configured, %u removed.\n", + "%u configured, %u removed, %u on hold.\n", trans->dl_pkgcnt, trans->inst_pkgcnt, trans->up_pkgcnt, trans->cf_pkgcnt + trans->inst_pkgcnt + trans->up_pkgcnt, - trans->rm_pkgcnt); + trans->rm_pkgcnt, + trans->hold_pkgcnt); } else { fprintf(stderr, "Transaction failed! see above for errors.\n"); } diff --git a/bin/xbps-install/util.c b/bin/xbps-install/util.c index 7cabdd16..510f9835 100644 --- a/bin/xbps-install/util.c +++ b/bin/xbps-install/util.c @@ -95,6 +95,38 @@ find_longest_pkgname(struct transaction *trans) return max+1; } +const char * +ttype2str(xbps_dictionary_t pkgd) +{ + uint8_t r; + + assert(pkgd); + + if (!xbps_dictionary_get_uint8(pkgd, "transaction", &r)) + return NULL; + + switch (r) { + case XBPS_TRANS_INSTALL: + return "install"; + case XBPS_TRANS_REINSTALL: + return "reinstall"; + case XBPS_TRANS_UPDATE: + return "update"; + case XBPS_TRANS_REMOVE: + return "remove"; + case XBPS_TRANS_CONFIGURE: + return "configure"; + case XBPS_TRANS_HOLD: + return "hold"; + case XBPS_TRANS_DOWNLOAD: + return "download"; + default: + return "unknown"; + } + + return NULL; +} + bool print_trans_colmode(struct transaction *trans, unsigned int cols) { @@ -131,36 +163,11 @@ print_trans_colmode(struct transaction *trans, unsigned int cols) xbps_dictionary_get_bool(obj, "download", &dload); ttype = xbps_transaction_pkg_type(obj); - - tract = "unknown"; + tract = ttype2str(obj); if (trans->xhp->flags & XBPS_FLAG_DOWNLOAD_ONLY) { tract = "download"; } - if (ttype == XBPS_TRANS_INSTALL) { - trans->inst_pkgcnt++; - tract = "install"; - } else if (ttype == XBPS_TRANS_REINSTALL) { - trans->inst_pkgcnt++; - tract = "reinstall"; - } else if (ttype == XBPS_TRANS_UPDATE) { - trans->up_pkgcnt++; - tract = "update"; - } else if (ttype == XBPS_TRANS_REMOVE) { - trans->rm_pkgcnt++; - tract = "remove"; - } else if (ttype == XBPS_TRANS_CONFIGURE) { - trans->cf_pkgcnt++; - tract = "configure"; - } else if (ttype == XBPS_TRANS_HOLD) { - tract = "hold"; - } else if (ttype == XBPS_TRANS_DOWNLOAD) { - tract = "download"; - } - if (dload) { - trans->dl_pkgcnt++; - } - ipkgd = xbps_pkgdb_get_pkg(trans->xhp, pkgname); if (trans->xhp->flags & XBPS_FLAG_DOWNLOAD_ONLY) { ipkgd = NULL; diff --git a/bin/xbps-install/xbps-install.1 b/bin/xbps-install/xbps-install.1 index 1c2c6752..56e1e874 100644 --- a/bin/xbps-install/xbps-install.1 +++ b/bin/xbps-install/xbps-install.1 @@ -1,4 +1,4 @@ -.Dd March 3, 2020 +.Dd April 23, 2020 .Dt XBPS-INSTALL 1 .Sh NAME .Nm xbps-install @@ -78,11 +78,14 @@ This may be useful for doing system upgrades while offline, or automatically downloading updates while leaving you with the option of still manually running the update. .It Fl f, Fl -force -Force downgrade installation (if package version in repos is less than installed version), +Force installation (downgrade 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 . +The only way to update packages on +.Em hold +mode is by using this flag. If .Fl f is specified twice all files will be unpacked, even diff --git a/include/xbps.h.in b/include/xbps.h.in index a864fe4c..b0f42156 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -51,7 +51,7 @@ * * This header documents the full API for the XBPS Library. */ -#define XBPS_API_VERSION "20200414" +#define XBPS_API_VERSION "20200423" #ifndef XBPS_VERSION #define XBPS_VERSION "UNSET" @@ -1186,8 +1186,8 @@ xbps_object_iterator_t xbps_array_iter_from_dict(xbps_dictionary_t dict, const c * @param[in] xhp Pointer to the xbps_handle struct. * @param[in] pkg Package name, package/version or package pattern to match, i.e * `foo', `foo-1.0_1' or `foo>=1.2'. - * @param[in] reinstall If true, package will be queued (if \a str matches) - * even if package is already installed. + * @param[in] Force If true, package will be queued (if \a str matches) + * even if package is already installed or in hold mode. * * @return 0 on success, otherwise an errno value. * @retval EEXIST Package is already installed (reinstall wasn't enabled). @@ -1197,7 +1197,7 @@ xbps_object_iterator_t xbps_array_iter_from_dict(xbps_dictionary_t dict, const c * @retval EINVAL Any other error ocurred in the process. * @retval EBUSY The xbps package must be updated. */ -int xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall); +int xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, bool force); /** * Marks a package as "going to be updated" in the transaction dictionary. @@ -1210,6 +1210,8 @@ int xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, bool * * @param[in] xhp Pointer to the xbps_handle struct. * @param[in] pkgname The package name to update. + * @param[in] force If true, package will be queued (if \a str matches) + * even if package is already installed or in hold mode. * * @return 0 on success, otherwise an errno value. * @retval EEXIST Package is already up-to-date. @@ -1219,7 +1221,7 @@ int xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, bool * @retval EINVAL Any other error ocurred in the process. * @retval EBUSY The xbps package must be updated. */ -int xbps_transaction_update_pkg(struct xbps_handle *xhp, const char *pkgname); +int xbps_transaction_update_pkg(struct xbps_handle *xhp, const char *pkgname, bool force); /** * Finds newer versions for all installed packages by looking at the diff --git a/lib/transaction_ops.c b/lib/transaction_ops.c index 1eb16da9..5c0deda4 100644 --- a/lib/transaction_ops.c +++ b/lib/transaction_ops.c @@ -53,7 +53,7 @@ * data type is specified on its edge, i.e string, array, integer, dictionary. */ static int -trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) +trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool force) { xbps_dictionary_t pkg_pkgdb = NULL, pkg_repod = NULL; xbps_object_t obj; @@ -92,7 +92,7 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) return ENOENT; } } else { - if (reinstall) { + if (force) { ttype = XBPS_TRANS_REINSTALL; } else { ttype = XBPS_TRANS_UPDATE; @@ -195,12 +195,14 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) return rv; } - if (ttype != XBPS_TRANS_HOLD) { - if (state == XBPS_PKG_STATE_UNPACKED) - ttype = XBPS_TRANS_CONFIGURE; - else if (state == XBPS_PKG_STATE_NOT_INSTALLED) - ttype = XBPS_TRANS_INSTALL; - } + if (state == XBPS_PKG_STATE_UNPACKED) + ttype = XBPS_TRANS_CONFIGURE; + else if (state == XBPS_PKG_STATE_NOT_INSTALLED) + ttype = XBPS_TRANS_INSTALL; + + if (!force && xbps_dictionary_get(pkg_repod, "hold")) + ttype = XBPS_TRANS_HOLD; + /* * Store pkgd from repo into the transaction. */ @@ -318,9 +320,6 @@ xbps_transaction_update_packages(struct xbps_handle *xhp) char pkgname[XBPS_NAME_SIZE] = {0}; pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj); - if (xbps_dictionary_get(pkgd, "hold")) { - continue; - } if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) { continue; } @@ -346,7 +345,7 @@ xbps_transaction_update_packages(struct xbps_handle *xhp) } int -xbps_transaction_update_pkg(struct xbps_handle *xhp, const char *pkg) +xbps_transaction_update_pkg(struct xbps_handle *xhp, const char *pkg, bool force) { xbps_array_t rdeps; int rv; @@ -391,14 +390,13 @@ xbps_transaction_update_pkg(struct xbps_handle *xhp, const char *pkg) } } /* add pkg repod */ - rv = trans_find_pkg(xhp, pkg, false); + rv = trans_find_pkg(xhp, pkg, force); xbps_dbg_printf(xhp, "%s: trans_find_pkg %s: %d\n", __func__, pkg, rv); return rv; } int -xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, - bool reinstall) +xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, bool force) { xbps_array_t rdeps; int rv; @@ -441,7 +439,7 @@ xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, return rv; } } - rv = trans_find_pkg(xhp, pkg, reinstall); + rv = trans_find_pkg(xhp, pkg, force); xbps_dbg_printf(xhp, "%s: trans_find_pkg %s: %d\n", __func__, pkg, rv); return rv; } diff --git a/lib/transaction_prepare.c b/lib/transaction_prepare.c index 6e54d49c..b6ff1a9d 100644 --- a/lib/transaction_prepare.c +++ b/lib/transaction_prepare.c @@ -62,8 +62,10 @@ compute_transaction_stats(struct xbps_handle *xhp) struct statvfs svfs; uint64_t rootdir_free_size, tsize, dlsize, instsize, rmsize; uint32_t inst_pkgcnt, up_pkgcnt, cf_pkgcnt, rm_pkgcnt, dl_pkgcnt; + uint32_t hold_pkgcnt; - inst_pkgcnt = up_pkgcnt = cf_pkgcnt = rm_pkgcnt = dl_pkgcnt = 0; + inst_pkgcnt = up_pkgcnt = cf_pkgcnt = rm_pkgcnt = 0; + hold_pkgcnt = dl_pkgcnt = 0; tsize = dlsize = instsize = rmsize = 0; iter = xbps_array_iter_from_dict(xhp->transd, "packages"); @@ -92,6 +94,8 @@ compute_transaction_stats(struct xbps_handle *xhp) inst_pkgcnt++; } else if (ttype == XBPS_TRANS_UPDATE) { up_pkgcnt++; + } else if (ttype == XBPS_TRANS_HOLD) { + hold_pkgcnt++; } if ((ttype != XBPS_TRANS_CONFIGURE) && (ttype != XBPS_TRANS_REMOVE) && @@ -152,6 +156,9 @@ compute_transaction_stats(struct xbps_handle *xhp) if (!xbps_dictionary_set_uint32(xhp->transd, "total-download-pkgs", dl_pkgcnt)) return EINVAL; + if (!xbps_dictionary_set_uint32(xhp->transd, + "total-hold-pkgs", hold_pkgcnt)) + return EINVAL; if (!xbps_dictionary_set_uint64(xhp->transd, "total-installed-size", instsize)) return EINVAL; diff --git a/tests/xbps/libxbps/shell/hold_test.sh b/tests/xbps/libxbps/shell/hold_test.sh index 40ffbbdf..951c2678 100644 --- a/tests/xbps/libxbps/shell/hold_test.sh +++ b/tests/xbps/libxbps/shell/hold_test.sh @@ -120,9 +120,25 @@ keep_on_update_body() { xbps-rindex -d -a $PWD/*.xbps atf_check_equal $? 0 cd .. + # no update + xbps-install -r root --repository=$PWD/repo -yuvd + atf_check_equal $? 0 + out=$(xbps-query -r root -p pkgver A) + atf_check_equal $out A-1.0_1 + # no update without -f xbps-install -r root --repository=$PWD/repo -yuvd A atf_check_equal $? 0 out=$(xbps-query -r root -p pkgver A) + atf_check_equal $out A-1.0_1 + # no update with -fu + xbps-install -r root --repository=$PWD/repo -yuvdf + atf_check_equal $? 0 + out=$(xbps-query -r root -p pkgver A) + atf_check_equal $out A-1.0_1 + # update with -f + xbps-install -r root --repository=$PWD/repo -yuvdf A + atf_check_equal $? 0 + out=$(xbps-query -r root -p pkgver A) atf_check_equal $out A-1.1_1 out=$(xbps-query -r root -p hold A) atf_check_equal $out yes