diff --git a/NEWS b/NEWS index 487f1ddd..060f5545 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,13 @@ xbps-0.41 (???): * A performance improvement for xbps_file_hash(), by Enno Boland. + * Added reverts field to package definitions. If defined, a package will + replace all versions specified in this field even if the installed version is + newer. This is helpful when a broken package is released. The maintainer can + downgrade this package and define a reverts field to the broken version. On + the next update xbps-install will automatically replace the broken release by + the new downgraded release. + xbps-0.40 (2014-09-18): * xbps-install(8): handle xbps_transaction_prepare() returning ENOSPC, to diff --git a/bin/xbps-create/main.c b/bin/xbps-create/main.c index f84d630e..427c386a 100644 --- a/bin/xbps-create/main.c +++ b/bin/xbps-create/main.c @@ -94,6 +94,8 @@ usage(void) " -q --quiet Work silently.\n" " -R --replaces Replaces (blank separated list,\n" " e.g: 'foo>=1.0 blah<2.0').\n" + " -r --reverts Reverts (blank separated list,\n" + " e.g: '1.0_1 2.0_3').\n" " -S --long-desc Long description (80 cols per line).\n" " -s --desc Short description (max 80 characters).\n" " -t --tags A list of tags/categories (blank separated list).\n" @@ -591,7 +593,7 @@ set_build_date(void) int main(int argc, char **argv) { - const char *shortopts = "A:B:C:D:F:G:H:hl:M:m:n:P:pqR:S:s:t:V"; + const char *shortopts = "A:B:C:D:F:G:H:hl:M:m:n:P:pqr:R:S:s:t:V"; const struct option longopts[] = { { "architecture", required_argument, NULL, 'A' }, { "built-with", required_argument, NULL, 'B' }, @@ -609,6 +611,7 @@ main(int argc, char **argv) { "preserve", no_argument, NULL, 'p' }, { "quiet", no_argument, NULL, 'q' }, { "replaces", required_argument, NULL, 'R' }, + { "reverts", required_argument, NULL, 'r' }, { "long-desc", required_argument, NULL, 'S' }, { "desc", required_argument, NULL, 's' }, { "tags", required_argument, NULL, 't' }, @@ -624,7 +627,7 @@ main(int argc, char **argv) struct archive_entry_linkresolver *resolver; struct stat st; const char *conflicts, *deps, *homepage, *license, *maint, *bwith; - const char *provides, *pkgver, *replaces, *desc, *ldesc; + const char *provides, *pkgver, *replaces, *reverts, *desc, *ldesc; const char *arch, *config_files, *mutable_files, *version; const char *buildopts, *shlib_provides, *shlib_requires; const char *compression, *tags = NULL, *srcrevs = NULL; @@ -634,8 +637,9 @@ main(int argc, char **argv) mode_t myumask; arch = conflicts = deps = homepage = license = maint = compression = NULL; - provides = pkgver = replaces = desc = ldesc = bwith = buildopts = NULL; - config_files = mutable_files = shlib_provides = shlib_requires = NULL; + provides = pkgver = replaces = reverts = desc = ldesc = bwith = NULL; + buildopts = config_files = mutable_files = shlib_provides = NULL; + shlib_requires = NULL; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { if (optarg && strcmp(optarg, "") == 0) @@ -690,6 +694,9 @@ main(int argc, char **argv) case 'R': replaces = optarg; break; + case 'r': + reverts = optarg; + break; case 'S': ldesc = optarg; break; @@ -794,6 +801,7 @@ main(int argc, char **argv) process_array("conflicts", conflicts); process_array("provides", provides); process_array("replaces", replaces); + process_array("reverts", reverts); process_array("shlib-provides", shlib_provides); process_array("shlib-requires", shlib_requires); diff --git a/bin/xbps-create/xbps-create.8 b/bin/xbps-create/xbps-create.8 index 6c54bbed..f1b7f257 100644 --- a/bin/xbps-create/xbps-create.8 +++ b/bin/xbps-create/xbps-create.8 @@ -58,6 +58,9 @@ Enable quiet operation. .It Fl R, Fl -replaces Ar list A list of package patterns this package replaces, separated by whitespaces. Example: .Ar 'foo>=1.0 blah>=2.0' . +.It Fl r, Fl -reverts Ar list +A list of versions this package reverts, separated by whitespaces. Example: +.Ar '2.0_1 2.1_1' . .It Fl S, Fl -long-desc Ar string A long description for this package. .It Fl s, Fl -desc Ar string diff --git a/bin/xbps-rindex/index-add.c b/bin/xbps-rindex/index-add.c index a61e4e5e..e8955a81 100644 --- a/bin/xbps-rindex/index-add.c +++ b/bin/xbps-rindex/index-add.c @@ -117,6 +117,22 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force) xbps_dictionary_get_cstring(curpkgd, "pkgver", &opkgver); xbps_dictionary_get_cstring(curpkgd, "architecture", &oarch); ret = xbps_cmpver(pkgver, opkgver); + + /* + * If the considered package reverts the package in the index, + * consider the current package as the newer one. + */ + if(ret < 0 && xbps_pkg_reverts(binpkgd, opkgver)) { + ret = 1; + } + /* + * If package in the index reverts considered package, consider the + * package in the index as the newer one. + */ + else if (ret > 0 && xbps_pkg_reverts(curpkgd, pkgver)) { + ret = -1; + } + if (ret <= 0) { /* Same version or index version greater */ fprintf(stderr, "index: skipping `%s' (%s), already registered.\n", pkgver, arch); diff --git a/include/xbps.h.in b/include/xbps.h.in index f5a1a8fb..2e909a0f 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -48,7 +48,7 @@ * * This header documents the full API for the XBPS Library. */ -#define XBPS_API_VERSION "20140913" +#define XBPS_API_VERSION "20140923" #ifndef XBPS_VERSION #define XBPS_VERSION "UNSET" @@ -1835,6 +1835,21 @@ bool xbps_pkg_arch_match(struct xbps_handle *xhp, */ int xbps_humanize_number(char *buf, int64_t bytes); +/** + * Tests if pkgver is reverted by pkg + * + * The package version is defined by: + * ${NAME}-{${VERSION}_${REVISION}. + * + * the name part is ignored. + * + * @param[in] pkg a package which is a candidate to revert pkgver. + * @param[in] pkgver a package version string + * + * @return true if pkg reverts pkgver, false otherwise. + */ +bool xbps_pkg_reverts(xbps_dictionary_t pkg, const char *pkgver); + /** * Compares package version strings. * diff --git a/lib/transaction_ops.c b/lib/transaction_ops.c index 7dd52e4d..63e6edf4 100644 --- a/lib/transaction_ops.c +++ b/lib/transaction_ops.c @@ -117,7 +117,8 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) */ xbps_dictionary_get_cstring_nocopy(pkg_pkgdb, "pkgver", &instpkgver); - if (xbps_cmpver(repopkgver, instpkgver) <= 0) { + if (xbps_cmpver(repopkgver, instpkgver) <= 0 && + !xbps_pkg_reverts(pkg_repod, repopkgver)) { xbps_dbg_printf(xhp, "[rpool] Skipping `%s' " "(installed: %s) from repository `%s'\n", repopkgver, instpkgver, repoloc); diff --git a/lib/util.c b/lib/util.c index 11ea33b1..a05e6451 100644 --- a/lib/util.c +++ b/lib/util.c @@ -425,3 +425,26 @@ xbps_humanize_number(char *buf, int64_t bytes) return humanize_number(buf, 7, bytes, "B", HN_AUTOSCALE, HN_DECIMAL|HN_NOSPACE); } + +/* + * Check if pkg is explicitly marked to replace a specific installed version. + */ +bool +xbps_pkg_reverts(xbps_dictionary_t pkg, const char *pkgver) { + unsigned int i; + xbps_array_t reverts; + const char *version = xbps_pkg_version(pkgver); + const char *revertver; + + if ((reverts = xbps_dictionary_get(pkg, "reverts")) == NULL) + return false; + + for (i = 0; i < xbps_array_count(reverts); i++) { + xbps_array_get_cstring_nocopy(reverts, i, &revertver); + if (strcmp(version, revertver) == 0) { + return false; + } + } + + return false; +} diff --git a/tests/xbps/libxbps/pkgdb/main.c b/tests/xbps/libxbps/pkgdb/main.c index e810523f..b87b8ca8 100644 --- a/tests/xbps/libxbps/pkgdb/main.c +++ b/tests/xbps/libxbps/pkgdb/main.c @@ -146,11 +146,42 @@ ATF_TC_BODY(pkgdb_get_pkg_revdeps_test, tc) ATF_REQUIRE_STREQ(xbps_string_cstring_nocopy(pstr), eout); } +ATF_TC(pkgdb_pkg_reverts_test); +ATF_TC_HEAD(pkgdb_pkg_reverts_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test xbps_pkg_reverts()"); +} + +ATF_TC_BODY(pkgdb_pkg_reverts_test, tc) +{ + struct xbps_handle xh; + const char *tcsdir; + xbps_dictionary_t pkgd; + + /* get test source dir */ + tcsdir = atf_tc_get_config_var(tc, "srcdir"); + + memset(&xh, 0, sizeof(xh)); + strncpy(xh.rootdir, tcsdir, sizeof(xh.rootdir)); + strncpy(xh.metadir, tcsdir, sizeof(xh.metadir)); + xh.flags = XBPS_FLAG_DEBUG; + ATF_REQUIRE_EQ(xbps_init(&xh), 0); + + pkgd = xbps_pkgdb_get_pkg(&xh, "reverts"); + ATF_REQUIRE_EQ(xbps_object_type(pkgd), XBPS_TYPE_DICTIONARY); + + ATF_REQUIRE_EQ(xbps_pkg_reverts(pkgd, "reverts-0.2_1"), 0); + ATF_REQUIRE_EQ(xbps_pkg_reverts(pkgd, "reverts-0.3_1"), 1); + ATF_REQUIRE_EQ(xbps_pkg_reverts(pkgd, "reverts-0.4_1"), 1); + ATF_REQUIRE_EQ(xbps_pkg_reverts(pkgd, "reverts-0.5_1"), 0); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, pkgdb_get_pkg_test); ATF_TP_ADD_TC(tp, pkgdb_get_virtualpkg_test); ATF_TP_ADD_TC(tp, pkgdb_get_pkg_revdeps_test); + ATF_TP_ADD_TC(tp, pkgdb_pkg_reverts_test); return atf_no_error(); } diff --git a/tests/xbps/libxbps/pkgdb/pkgdb-0.38.plist b/tests/xbps/libxbps/pkgdb/pkgdb-0.38.plist index b6bfa35b..7c4393ad 100644 --- a/tests/xbps/libxbps/pkgdb/pkgdb-0.38.plist +++ b/tests/xbps/libxbps/pkgdb/pkgdb-0.38.plist @@ -94,5 +94,21 @@ state installed + reverts + + automatic-install + + pkgver + reverts-0.2_1 + reverts + + 0.3_1 + 0.4_1 + + short_desc + two descriptionm + state + installed + diff --git a/tests/xbps/xbps-rindex/add_test.sh b/tests/xbps/xbps-rindex/add_test.sh index 82302072..a84b5178 100644 --- a/tests/xbps/xbps-rindex/add_test.sh +++ b/tests/xbps/xbps-rindex/add_test.sh @@ -30,6 +30,33 @@ update_body() { atf_check_equal $rv 0 } +revert_head() { + atf_set "descr" "xbps-rindex(8) -a: revert version test" +} + +revert_body() { + mkdir -p some_repo pkg_A + touch pkg_A/file00 + cd some_repo + xbps-create -A noarch -n foo-1.1_1 -s "foo pkg" ../pkg_A + atf_check_equal $? 0 + xbps-rindex -a *.xbps + atf_check_equal $? 0 + xbps-create -A noarch -n foo-1.0_1 -r "1.1_1" -s "foo pkg" ../pkg_A + atf_check_equal $? 0 + xbps-rindex -a *.xbps + atf_check_equal $? 0 + cd .. + result="$(xbps-query -r root -C empty.conf --repository=some_repo -o \*)" + expected="foo-1.0_1: /file00 (some_repo)" + rv=0 + if [ "$result" != "$expected" ]; then + rv=1 + fi + atf_check_equal $rv 0 +} + atf_init_test_cases() { atf_add_test_case update + atf_add_test_case revert }