diff --git a/client/api.c b/client/api.c index bc89da10..aeb42ec7 100644 --- a/client/api.c +++ b/client/api.c @@ -224,11 +224,6 @@ TDNFGetSkipProblemOption( *pdwSkipProblem = SKIPPROBLEM_NONE; - if (strcasecmp(pTdnf->pArgs->ppszCmds[0], "check")) - { - goto cleanup; - } - for (pSetOpt = pTdnf->pArgs->pSetOpt; pSetOpt; pSetOpt = pSetOpt->pNext) { if (!strcasecmp(pSetOpt->pszOptName, "skipconflicts")) @@ -242,6 +237,11 @@ TDNFGetSkipProblemOption( } } + if (pTdnf->pArgs->nSkipBroken) + { + *pdwSkipProblem |= SKIPPROBLEM_BROKEN; + } + cleanup: return dwError; diff --git a/client/goal.c b/client/goal.c index 3fa1fcd9..2a12f0f3 100644 --- a/client/goal.c +++ b/client/goal.c @@ -359,7 +359,6 @@ TDNFSolv( { dwError = TDNFGetSkipProblemOption(pTdnf, &dwSkipProblem); BAIL_ON_TDNF_ERROR(dwError); - dwError = SolvReportProblems(pTdnf->pSack, pSolv, dwSkipProblem); BAIL_ON_TDNF_ERROR(dwError); } diff --git a/client/init.c b/client/init.c index 27337a68..63c09e2a 100644 --- a/client/init.c +++ b/client/init.c @@ -60,6 +60,7 @@ TDNFCloneCmdArgs( pCmdArgs->nNoAutoRemove = pCmdArgsIn->nNoAutoRemove; pCmdArgs->nJsonOutput = pCmdArgsIn->nJsonOutput; pCmdArgs->nTestOnly = pCmdArgsIn->nTestOnly; + pCmdArgs->nSkipBroken = pCmdArgsIn->nSkipBroken; pCmdArgs->nArgc = pCmdArgsIn->nArgc; pCmdArgs->ppszArgv = pCmdArgsIn->ppszArgv; diff --git a/client/resolve.c b/client/resolve.c index 1b7a2d3b..13b99368 100644 --- a/client/resolve.c +++ b/client/resolve.c @@ -345,9 +345,13 @@ TDNFPrepareSinglePkg( if (dwError == ERROR_TDNF_NO_MATCH) { pr_err("%s package not found or not installed\n", pszPkgName); + if (pTdnf->pArgs->nSkipBroken) + { + dwError = 0; + } } - BAIL_ON_TDNF_ERROR(dwError); + if (dwCount == 0) { dwError = ERROR_TDNF_NO_SEARCH_RESULTS; diff --git a/include/tdnftypes.h b/include/tdnftypes.h index 6ffacc69..3649c5ce 100644 --- a/include/tdnftypes.h +++ b/include/tdnftypes.h @@ -134,6 +134,7 @@ typedef enum SKIPPROBLEM_CONFLICTS = 0x01, SKIPPROBLEM_OBSOLETES = 0x02, SKIPPROBLEM_DISABLED = 0x04, + SKIPPROBLEM_BROKEN = 0x08 } TDNF_SKIPPROBLEM_TYPE; typedef struct _TDNF_ *PTDNF; @@ -225,6 +226,7 @@ typedef struct _TDNF_CMD_ARGS int nNoAutoRemove; //overide clean_requirements_on_remove config option int nJsonOutput; //output in json format int nTestOnly; //run test transaction only + int nSkipBroken; char* pszDownloadDir; //directory for download, if nDownloadOnly is set char* pszInstallRoot; //set install root char* pszConfFile; //set conf file location diff --git a/pytests/repo/tdnf-missing-dep.spec b/pytests/repo/tdnf-missing-dep.spec new file mode 100644 index 00000000..b624405d --- /dev/null +++ b/pytests/repo/tdnf-missing-dep.spec @@ -0,0 +1,37 @@ +# +# tdnf-missing spec file +# +Summary: basic install test file. +Name: tdnf-missing-dep +Version: 1.0.1 +Release: 2 +Vendor: VMware, Inc. +Distribution: Photon +License: VMware +Url: http://www.vmware.com +Group: Applications/tdnftest + +# requires something we do not have +Requires: missing + +%description +Part of tdnf test spec. Basic install/remove/upgrade test + +%prep + +%build + +%install +mkdir -p %_topdir/%buildroot/lib/systemd/system/ +cat << EOF >> %_topdir/%buildroot/lib/systemd/system/%name.service +[Unit] +Description=%name.service for whatprovides test. + +EOF + +%files +/lib/systemd/system/%name.service + +%changelog +* Fri Sep 16 Oliver Kurth 1.0 +- Initial build. First version diff --git a/pytests/tests/test_install.py b/pytests/tests/test_install.py index 782710b8..68570f80 100644 --- a/pytests/tests/test_install.py +++ b/pytests/tests/test_install.py @@ -69,6 +69,50 @@ def test_install_testonly(utils): assert not utils.check_package(pkgname) +# install multiple packages, one that doesn't exist +# expect other pkg will be installed if invoked with --skip-broken +def test_install_skip_broken_missing_pkg(utils): + pkgname = utils.config["mulversion_pkgname"] + utils.erase_package(pkgname) + pkgname_missing = "missing" + + utils.run(['tdnf', 'install', '-y', '--nogpgcheck', '--skip-broken', pkgname, pkgname_missing]) + assert utils.check_package(pkgname) + + +# install multiple packages, one that doesn't exist +# expect fail if invoked without --skip-broken +def test_install_missing_pkg(utils): + pkgname = utils.config["mulversion_pkgname"] + utils.erase_package(pkgname) + pkgname_missing = "missing" + + utils.run(['tdnf', 'install', '-y', '--nogpgcheck', pkgname, pkgname_missing]) + assert not utils.check_package(pkgname) + + +# install multiple packages, one with a missing dependency +# expect other pkg will be installed if invoked with --skip-broken +def test_install_skip_broken_missing_dep(utils): + pkgname = utils.config["mulversion_pkgname"] + utils.erase_package(pkgname) + pkgname_missing = "tdnf-missing-dep" + + utils.run(['tdnf', 'install', '-y', '--nogpgcheck', '--skip-broken', pkgname, pkgname_missing]) + assert utils.check_package(pkgname) + + +# install multiple packages, one with a missing dependency +# expect fail if invoked without --skip-broken +def test_install_missing_dep(utils): + pkgname = utils.config["mulversion_pkgname"] + utils.erase_package(pkgname) + pkgname_missing = "tdnf-missing-dep" + + utils.run(['tdnf', 'install', '-y', '--nogpgcheck', pkgname, pkgname_missing]) + assert not utils.check_package(pkgname) + + def test_install_memcheck(utils): pkgname = utils.config["mulversion_pkgname"] utils.erase_package(pkgname) diff --git a/solv/tdnfpackage.c b/solv/tdnfpackage.c index b4434a25..6f80a20d 100644 --- a/solv/tdnfpackage.c +++ b/solv/tdnfpackage.c @@ -1576,6 +1576,12 @@ SkipBasedOnType( type == SOLVER_RULE_PKG_INSTALLED_OBSOLETES; } + if (dwSkipProblem & SKIPPROBLEM_BROKEN) + { + /* see https://github.com/openSUSE/libsolv/blob/master/src/rules.h */ + result = result || type & SOLVER_RULE_PKG; + } + if (dwSkipProblem & SKIPPROBLEM_DISABLED) { /** @@ -1686,11 +1692,6 @@ SolvReportProblems( type = solver_ruleinfo(pSolv, dwProblemId, &dwSource, &dwTarget, &dwDep); - if (SkipBasedOnType(pSolv, type, dwSource, dwSkipProblem)) - { - continue; - } - pszProblem = solver_problemruleinfo2str(pSolv, type, dwSource, dwTarget, dwDep); @@ -1703,7 +1704,11 @@ SolvReportProblems( } } - dwError = ERROR_TDNF_SOLV_FAILED; + if (!SkipBasedOnType(pSolv, type, dwSource, dwSkipProblem)) + { + dwError = ERROR_TDNF_SOLV_FAILED; + } + pr_err("%u. %s\n", ++total_prblms, pszProblem); } diff --git a/tools/cli/lib/parseargs.c b/tools/cli/lib/parseargs.c index b8709866..7eb9d402 100644 --- a/tools/cli/lib/parseargs.c +++ b/tools/cli/lib/parseargs.c @@ -61,6 +61,7 @@ static struct option pstOptions[] = {"sec-severity", required_argument, 0, 0}, //--sec-severity {"security", no_argument, 0, 0}, //--security {"setopt", required_argument, 0, 0}, //--set or override options + {"skip-broken", no_argument, &_opt.nSkipBroken, 1}, {"skipconflicts", no_argument, 0, 0}, //--skipconflicts to skip conflict problems {"skipdigest", no_argument, 0, 0}, //--skipdigest to skip verifying RPM digest {"skipobsoletes", no_argument, 0, 0}, //--skipobsoletes to skip obsolete problems @@ -339,6 +340,7 @@ TDNFCopyOptions( pArgs->nNoAutoRemove = pOptionArgs->nNoAutoRemove; pArgs->nJsonOutput = pOptionArgs->nJsonOutput; pArgs->nTestOnly = pOptionArgs->nTestOnly; + pArgs->nSkipBroken = pOptionArgs->nSkipBroken; cleanup: return dwError;