diff --git a/NEWS b/NEWS index ac10d540..8901ff0e 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,10 @@ xbps-0.44 (???): + * xbps-pkgdb(8): added a new mode to set in installed packages: "repolock". + If that mode is set with `-m repo(un)lock`, a package will only be updated + if there's an update in the same repository that was used for installing. + This implements #77 (https://github.com/voidlinux/xbps/issues/77) + * libxbps: properly detect when a file has been moved between packages: if the mtime stored in the pkg metadata does not match the mtime of the same file stored on disk, don't detect this as an obsolete file. diff --git a/bin/xbps-pkgdb/main.c b/bin/xbps-pkgdb/main.c index c0b8e19e..ee1eff34 100644 --- a/bin/xbps-pkgdb/main.c +++ b/bin/xbps-pkgdb/main.c @@ -44,7 +44,8 @@ usage(bool fail) " -C --config Path to confdir (xbps.d)\n" " -d --debug Debug mode shown to stderr\n" " -h --help Print usage help\n" - " -m --mode Change PKGNAME to this mode\n" + " -m --mode \n" + " Change PKGNAME to this mode\n" " -r --rootdir Full path to rootdir\n" " -u --update Update pkgdb to the latest format\n" " -v --verbose Verbose messages\n" @@ -69,6 +70,10 @@ change_pkg_mode(struct xbps_handle *xhp, const char *pkgname, const char *mode) xbps_dictionary_set_bool(pkgd, "hold", true); else if (strcmp(mode, "unhold") == 0) xbps_dictionary_remove(pkgd, "hold"); + else if (strcmp(mode, "repolock") == 0) + xbps_dictionary_set_bool(pkgd, "repolock", true); + else if (strcmp(mode, "repounlock") == 0) + xbps_dictionary_remove(pkgd, "repolock"); else usage(true); diff --git a/bin/xbps-pkgdb/xbps-pkgdb.8 b/bin/xbps-pkgdb/xbps-pkgdb.8 index 1d76a6b6..bc421c8b 100644 --- a/bin/xbps-pkgdb/xbps-pkgdb.8 +++ b/bin/xbps-pkgdb/xbps-pkgdb.8 @@ -1,4 +1,4 @@ -.Dd February 22, 2014 +.Dd March 3, 2014 .Dt XBPS-PKGDB 8 .Sh NAME .Nm xbps-pkgdb @@ -47,10 +47,11 @@ If the first character is not '\/' then it's a relative path of Enables extra debugging shown to stderr. .It Fl h, Fl -help Show the help usage. -.It Fl m, Fl -mode Ar auto|manual|hold|unhold +.It Fl m, Fl -mode Ar auto|manual|hold|unhold|repolock|repounlock Switches .Ar PKGNAME -to the specified mode: automatic or manual installation mode, or to (un)set it on hold mode. +to the specified mode: automatic or manual installation mode, or to (un)set the on hold mode, +and repository locked mode. A package that was installed as dependency will be in .Sy automatic mode, otherwise will be set to @@ -60,6 +61,10 @@ A package in mode won't be updated in full system upgrades. The list of packages in this mode can be seen with .Xr xbps-query 8 . +A package in +.Sy repolock +mode will only accept updates that are available in the same repository that was used +for installing. .It Fl r, Fl -rootdir Ar dir Specifies a full path for the target root directory. .It Fl u, Fl -update diff --git a/lib/transaction_ops.c b/lib/transaction_ops.c index 35d1ec65..93f8874d 100644 --- a/lib/transaction_ops.c +++ b/lib/transaction_ops.c @@ -68,7 +68,7 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall, char *pkgname; int action = 0, rv = 0; pkg_state_t state = 0; - bool autoinst = false; + bool autoinst = false, repolock = false; assert(pkg != NULL); @@ -102,7 +102,20 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall, action = TRANS_REINSTALL; reason = "install"; } - if ((pkg_repod = xbps_rpool_get_pkg(xhp, pkg)) == NULL) { + xbps_dictionary_get_bool(pkg_pkgdb, "repolock", &repolock); + if (repolock) { + struct xbps_repo *repo; + /* find update from repo */ + xbps_dictionary_get_cstring_nocopy(pkg_pkgdb, "repository", &repoloc); + assert(repoloc); + if ((repo = xbps_rpool_get_repo(repoloc)) == NULL) + return EINVAL; + pkg_repod = xbps_repo_get_pkg(repo, pkg); + } else { + /* find update from rpool */ + pkg_repod = xbps_rpool_get_pkg(xhp, pkg); + } + if (pkg_repod == NULL) { /* not found */ return ENOENT; } @@ -141,11 +154,12 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall, if (pkg_pkgdb) { /* - * If pkg is already installed, respect its automatic-install - * property. + * If pkg is already installed, respect some properties. */ if (xbps_dictionary_get_bool(pkg_pkgdb, "automatic-install", &autoinst)) xbps_dictionary_set_bool(pkg_repod, "automatic-install", autoinst); + if (xbps_dictionary_get_bool(pkg_pkgdb, "repolock", &repolock)) + xbps_dictionary_set_bool(pkg_repod, "repolock", repolock); } /* * Prepare transaction dictionary. diff --git a/tests/xbps/libxbps/shell/Kyuafile b/tests/xbps/libxbps/shell/Kyuafile index 9b48c916..29203594 100644 --- a/tests/xbps/libxbps/shell/Kyuafile +++ b/tests/xbps/libxbps/shell/Kyuafile @@ -18,3 +18,4 @@ atf_test_program{name="install_test"} atf_test_program{name="preserve_files_test"} atf_test_program{name="update_shlibs"} atf_test_program{name="update_hold"} +atf_test_program{name="update_repolock"} diff --git a/tests/xbps/libxbps/shell/Makefile b/tests/xbps/libxbps/shell/Makefile index 46586503..0b191262 100644 --- a/tests/xbps/libxbps/shell/Makefile +++ b/tests/xbps/libxbps/shell/Makefile @@ -6,7 +6,7 @@ TESTSHELL = conf_files_test issue6_test issue18_test issue20_test remove_test TESTSHELL+= replace_test installmode_test obsoletefiles_test TESTSHELL+= issue31_test scripts_test incorrect_deps_test TESTSHELL+= vpkg_test install_test preserve_files_test -TESTSHELL+= update_shlibs update_hold +TESTSHELL+= update_shlibs update_hold update_repolock EXTRA_FILES = Kyuafile include $(TOPDIR)/mk/test.mk diff --git a/tests/xbps/libxbps/shell/update_repolock.sh b/tests/xbps/libxbps/shell/update_repolock.sh new file mode 100644 index 00000000..c5640ddf --- /dev/null +++ b/tests/xbps/libxbps/shell/update_repolock.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env atf-sh + +atf_test_case update_repolock + +update_repolock_head() { + atf_set "descr" "Tests for pkg update: pkg is in repository locked mode" +} + +update_repolock_body() { + mkdir -p repo repo2 pkg_A + cd repo + xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A + atf_check_equal $? 0 + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + cd ../repo2 + xbps-create -A noarch -n A-1.1_1 -s "A pkg" ../pkg_A + atf_check_equal $? 0 + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + cd .. + # install A-1.0_1 from repository "repo" + xbps-install -r root --repository=repo --repository=repo2 -yvd A-1.0_1 + atf_check_equal $? 0 + # A-1.0_1 is now locked + xbps-pkgdb -r root -m repolock A + atf_check_equal $? 0 + out=$(xbps-query -r root -p repository A) + atf_check_equal "$out" "$(realpath repo)" + # no update due to repository locking + xbps-install -r root --repository=repo --repository=repo2 -yuvd + atf_check_equal $? 0 + out=$(xbps-query -r root -p pkgver A) + atf_check_equal $out A-1.0_1 + # disable repolock + xbps-pkgdb -r root -m repounlock A + atf_check_equal $? 0 + out=$(xbps-query -r root -p repolock A) + atf_check_equal "$out" "" + # update A to 1.1_1 from repo2 + xbps-install -r root --repository=repo2 --repository=repo -yuvd + 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 repository A) + atf_check_equal "$out" "$(realpath repo2)" +} + +atf_init_test_cases() { + atf_add_test_case update_repolock +}