diff --git a/bin/xbps-pkgdb/check_pkg_rundeps.c b/bin/xbps-pkgdb/check_pkg_rundeps.c index ebf3a71e..6fa72d49 100644 --- a/bin/xbps-pkgdb/check_pkg_rundeps.c +++ b/bin/xbps-pkgdb/check_pkg_rundeps.c @@ -58,6 +58,8 @@ check_pkg_rundeps(struct xbps_handle *xhp, const char *pkgname, void *arg) array = xbps_dictionary_get(pkg_propsd, "run_depends"); for (unsigned int i = 0; i < xbps_array_count(array); i++) { xbps_array_get_cstring_nocopy(array, i, &reqpkg); + if (xbps_pkg_is_ignored(xhp, reqpkg)) + continue; if (xbps_pkg_is_installed(xhp, reqpkg) <= 0) { xbps_error_printf("%s: dependency not satisfied: %s\n", pkgname, reqpkg); diff --git a/data/xbps.d.5 b/data/xbps.d.5 index 5754cc73..ceeb88c0 100644 --- a/data/xbps.d.5 +++ b/data/xbps.d.5 @@ -56,6 +56,10 @@ Sets the default cache directory to store downloaded binary packages from remote repositories, as well as its signatures. If path starts with '/' it's an absolute path, otherwise it will be relative to .Ar rootdir . +.It Sy ignorepkg=pkgname +Declares a ignored package. +If a package depends on an ignored package the dependency is always satisfied, +without installing the ignored package. .It Sy include=path/file.conf Imports settings from the specified configuration file. .Em NOTE diff --git a/include/xbps.h.in b/include/xbps.h.in index 06aa3c3f..44e183d0 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -512,6 +512,7 @@ struct xbps_handle { * @private */ xbps_array_t preserved_files; + xbps_array_t ignored_pkgs; /** * @var repositories * @@ -1843,6 +1844,17 @@ bool xbps_verify_file_signature(struct xbps_repo *repo, const char *fname); */ int xbps_pkg_is_installed(struct xbps_handle *xhp, const char *pkg); +/** + * Checks if a package is currently ignored by matching \a pkg. + * To be ignored, the pkg must be ignored by the users configuration. + * + * @param[in] xhp The pointer to an xbps_handle struct. + * @param[in] pkg Package name, version pattern or exact pkg to match. + * + * @return True if the package is ignored, false otherwise. + */ +bool xbps_pkg_is_ignored(struct xbps_handle *xhp, const char *pkg); + /** * Returns true if binary package exists in cachedir or in a local repository, * false otherwise. diff --git a/lib/initend.c b/lib/initend.c index a6a78921..f3ee9aa9 100644 --- a/lib/initend.c +++ b/lib/initend.c @@ -141,6 +141,17 @@ store_repo(struct xbps_handle *xhp, const char *repo) return xbps_repo_store(xhp, repo); } +static void +store_ignored_pkg(struct xbps_handle *xhp, const char *pkgname) +{ + if (xhp->ignored_pkgs == NULL) { + xhp->ignored_pkgs = xbps_array_create(); + assert(xhp->ignored_pkgs); + } + xbps_array_add_cstring(xhp->ignored_pkgs, pkgname); + xbps_dbg_printf(xhp, "Added ignored package: %s\n", pkgname); +} + static bool parse_option(char *buf, char **k, char **v) { @@ -153,6 +164,7 @@ parse_option(char *buf, char **k, char **v) "repository", "virtualpkg", "include", + "ignorepkg", "preserve", "bestmatching", "architecture" @@ -264,6 +276,8 @@ parse_file(struct xbps_handle *xhp, const char *cwd, const char *path, bool nest xbps_dbg_printf(xhp, "%s: added repository %s\n", path, v); } else if (strcmp(k, "virtualpkg") == 0) { store_vars(xhp, &xhp->vpkgd, k, path, nlines, v); + } else if (strcmp(k, "ignorepkg") == 0) { + store_ignored_pkg(xhp, v); } else if (strcmp(k, "preserve") == 0) { store_preserved_file(xhp, v); } else if (strcmp(k, "bestmatching") == 0) { diff --git a/lib/repo_pkgdeps.c b/lib/repo_pkgdeps.c index 0008e923..0dbb0010 100644 --- a/lib/repo_pkgdeps.c +++ b/lib/repo_pkgdeps.c @@ -161,6 +161,14 @@ find_repo_deps(struct xbps_handle *xhp, rv = ENXIO; break; } + /* + * Pass 0: check if required dependency is ignored. + */ + if (xbps_pkg_is_ignored(xhp, pkgname)) { + xbps_dbg_printf_append(xhp, "%s ignored.\n", pkgname); + free(pkgname); + continue; + } /* * Pass 1: check if required dependency is provided as virtual * package via "provides", if true ignore dependency. diff --git a/lib/util.c b/lib/util.c index 57e7dede..2864b77a 100644 --- a/lib/util.c +++ b/lib/util.c @@ -86,6 +86,28 @@ xbps_pkg_is_installed(struct xbps_handle *xhp, const char *pkg) return 0; /* not fully installed */ } +bool +xbps_pkg_is_ignored(struct xbps_handle *xhp, const char *pkg) +{ + char *pkgname; + bool rv = false; + + assert(xhp); + assert(pkg); + + if (!xhp->ignored_pkgs) + return false; + + if ((pkgname = xbps_pkgpattern_name(pkg)) != NULL || + (pkgname = xbps_pkg_name(pkg)) != NULL) { + rv = xbps_match_string_in_array(xhp->ignored_pkgs, pkgname); + free(pkgname); + return rv; + } + + return xbps_match_string_in_array(xhp->ignored_pkgs, pkg); +} + const char * xbps_pkg_version(const char *pkg) { diff --git a/tests/xbps/libxbps/shell/Kyuafile b/tests/xbps/libxbps/shell/Kyuafile index 731a78cc..55a533d7 100644 --- a/tests/xbps/libxbps/shell/Kyuafile +++ b/tests/xbps/libxbps/shell/Kyuafile @@ -24,3 +24,4 @@ atf_test_program{name="update_itself"} atf_test_program{name="cyclic_deps"} atf_test_program{name="conflicts"} atf_test_program{name="downgrade_hold"} +atf_test_program{name="ignore"} diff --git a/tests/xbps/libxbps/shell/Makefile b/tests/xbps/libxbps/shell/Makefile index 8a517945..c35da2a9 100644 --- a/tests/xbps/libxbps/shell/Makefile +++ b/tests/xbps/libxbps/shell/Makefile @@ -7,7 +7,7 @@ TESTSHELL+= replace_test installmode_test obsoletefiles_test TESTSHELL+= issue31_test scripts_test incorrect_deps_test TESTSHELL+= vpkg_test install_test preserve_files_test configure_test TESTSHELL+= update_shlibs update_hold update_repolock cyclic_deps conflicts -TESTSHELL+= update_itself downgrade_hold +TESTSHELL+= update_itself downgrade_hold ignore EXTRA_FILES = Kyuafile include $(TOPDIR)/mk/test.mk diff --git a/tests/xbps/libxbps/shell/ignore.sh b/tests/xbps/libxbps/shell/ignore.sh new file mode 100644 index 00000000..892c4f53 --- /dev/null +++ b/tests/xbps/libxbps/shell/ignore.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env atf-sh + +atf_test_case install_with_ignored_dep + +install_with_ignored_dep_head() { + atf_set "descr" "Tests for pkg install: with ignored dependency" +} + +install_with_ignored_dep_body() { + mkdir -p repo pkg_A pkg_B + cd repo + xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A + atf_check_equal $? 0 + xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B + atf_check_equal $? 0 + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + cd .. + echo "ignorepkg=B" > ignore.conf + out=$(xbps-install -r root -C ignore.conf --repository=$PWD/repo -n A) + set -- $out + exp="$1 $2 $3 $4" + atf_check_equal "$exp" "A-1.0_1 install noarch $PWD/repo" + xbps-install -r root -C ignore.conf --repository=$PWD/repo -yd A + atf_check_equal $? 0 + xbps-query -r root A + atf_check_equal $? 0 + xbps-query -r root B + atf_check_equal $? 2 +} + +atf_test_case update_with_ignored_dep + +update_with_ignored_dep_head() { + atf_set "descr" "Tests for pkg update: with ignored dependency" +} + +update_with_ignored_dep_body() { + mkdir -p repo pkg_A pkg_B + cd repo + xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A + atf_check_equal $? 0 + xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B + atf_check_equal $? 0 + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + cd .. + echo "ignorepkg=B" > ignore.conf + xbps-install -r root -C ignore.conf --repository=$PWD/repo -yd A + atf_check_equal $? 0 + cd repo + 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 .. + out=$(xbps-install -r root -C ignore.conf --repository=$PWD/repo -un) + set -- $out + exp="$1 $2 $3 $4" + atf_check_equal "$exp" "A-1.1_1 update noarch $PWD/repo" + 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.1_1 +} + +atf_init_test_cases() { + atf_add_test_case install_with_ignored_dep + atf_add_test_case update_with_ignored_dep +}