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
This commit is contained in:
Juan RP 2020-04-23 06:03:56 +02:00
parent 6b6b394686
commit 7d8247ae56
No known key found for this signature in database
GPG Key ID: AF19F6CB482F9368
9 changed files with 127 additions and 108 deletions

View File

@ -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_ */

View File

@ -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;

View File

@ -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");
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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