diff --git a/client/api.c b/client/api.c index a118fbea..a38e18ce 100644 --- a/client/api.c +++ b/client/api.c @@ -290,7 +290,7 @@ TDNFCheckLocalPackages( dwError = TDNFGetSkipProblemOption(pTdnf, &dwSkipProblem); BAIL_ON_TDNF_ERROR(dwError); - dwError = SolvReportProblems(pTdnf->pSack, pSolv, dwSkipProblem); + dwError = SolvReportProblems(pTdnf->pSack, pSolv, dwSkipProblem, pTdnf->pArgs->nVerbose); BAIL_ON_TDNF_ERROR(dwError); } diff --git a/client/goal.c b/client/goal.c index 87199b6c..f134c6fd 100644 --- a/client/goal.c +++ b/client/goal.c @@ -380,7 +380,7 @@ TDNFSolv( { dwError = TDNFGetSkipProblemOption(pTdnf, &dwSkipProblem); BAIL_ON_TDNF_ERROR(dwError); - dwError = SolvReportProblems(pTdnf->pSack, pSolv, dwSkipProblem); + dwError = SolvReportProblems(pTdnf->pSack, pSolv, dwSkipProblem, pTdnf->pArgs->nVerbose); BAIL_ON_TDNF_ERROR(dwError); } diff --git a/pytests/tests/test_install.py b/pytests/tests/test_install.py index 5b82c6b1..f9eb433f 100644 --- a/pytests/tests/test_install.py +++ b/pytests/tests/test_install.py @@ -172,3 +172,32 @@ def xxx_test_install_memcheck(utils): utils.run_memcheck(['tdnf', 'install', '-y', '--nogpgcheck', pkgname]) assert utils.check_package(pkgname) + + +# install a package with non-existing requirement, expect brief output without verbose +def test_install_no_providers_non_verbose(utils): + pkgname = utils.config['dummy_requires_pkgname'] + ret = utils.run(['tdnf', 'install', '-y', '--nogpgcheck', pkgname]) + # ERROR_TDNF_SOLV_FAILED - "Solv general runtime error" + assert ret['retval'] == 1301 + stderr = '\n'.join(ret['stderr']) + assert "nothing provides" in stderr + # Should recommend the verbose flag + assert "Please retry with --verbose to see detailed solver rules" in stderr + # Should NOT contain the detailed block format + assert "Problem 1:" not in stderr + + +# install a package with non-existing requirement, expect detailed output with verbose +def test_install_no_providers_verbose(utils): + pkgname = utils.config['dummy_requires_pkgname'] + ret = utils.run(['tdnf', 'install', '-y', '--nogpgcheck', '--verbose', pkgname]) + # ERROR_TDNF_SOLV_FAILED - "Solv general runtime error" + assert ret['retval'] == 1301 + stderr = '\n'.join(ret['stderr']) + # Should contain the detailed block format + assert "Problem 1:" in stderr + assert " - " in stderr + assert "nothing provides" in stderr + # Should NOT recommend the verbose flag + assert "Please retry with --verbose to see detailed solver rules" not in stderr diff --git a/solv/prototypes.h b/solv/prototypes.h index a5ecbab8..73ae08e3 100644 --- a/solv/prototypes.h +++ b/solv/prototypes.h @@ -570,7 +570,8 @@ uint32_t SolvReportProblems( PSolvSack pSack, Solver* pSolv, - TDNF_SKIPPROBLEM_TYPE dwSkipProblem + TDNF_SKIPPROBLEM_TYPE dwSkipProblem, + int nVerbose ); uint32_t diff --git a/solv/tdnfpackage.c b/solv/tdnfpackage.c index 93985292..88c30d07 100644 --- a/solv/tdnfpackage.c +++ b/solv/tdnfpackage.c @@ -1912,7 +1912,8 @@ uint32_t SolvReportProblems( PSolvSack pSack, Solver* pSolv, - TDNF_SKIPPROBLEM_TYPE dwSkipProblem + TDNF_SKIPPROBLEM_TYPE dwSkipProblem, + int nVerbose ) { int nCount = 0; @@ -1932,20 +1933,17 @@ SolvReportProblems( nCount = solver_problem_count(pSolv); for ( ; nCount > 0; nCount--) { - const char *pszProblem = NULL; - Id dwProblemId = solver_findproblemrule(pSolv, nCount); + const char *pszProblem = NULL; - type = solver_ruleinfo(pSolv, dwProblemId, - &dwSource, &dwTarget, &dwDep); + type = solver_ruleinfo(pSolv, dwProblemId, &dwSource, &dwTarget, &dwDep); - if (SkipBasedOnType(pSolv, type, dwSource, dwSkipProblem)) - { - continue; - } + if (SkipBasedOnType(pSolv, type, dwSource, dwSkipProblem)) + { + continue; + } - pszProblem = solver_problemruleinfo2str(pSolv, type, dwSource, - dwTarget, dwDep); + pszProblem = solver_problemruleinfo2str(pSolv, type, dwSource, dwTarget, dwDep); if (dwSkipProblem != SKIPPROBLEM_NONE && type == SOLVER_RULE_PKG_REQUIRES) @@ -1956,13 +1954,60 @@ SolvReportProblems( } } + total_prblms++; dwError = ERROR_TDNF_SOLV_FAILED; - pr_err("%u. %s\n", ++total_prblms, pszProblem); + + if (nVerbose) + { + Queue rids; + queue_init(&rids); + + solver_findallproblemrules(pSolv, nCount, &rids); + + pr_err("Problem %u:\n", total_prblms); + + for (int j = 0; j < rids.count; j++) + { + const char *pszSubProblem = NULL; + Id probr = rids.elements[j]; + type = solver_ruleinfo(pSolv, probr, &dwSource, &dwTarget, &dwDep); + + if (type == SOLVER_RULE_JOB) + { + pszSubProblem = pool_tmpjoin(pSolv->pool, "job ", pool_job2str(pSolv->pool, dwTarget, dwDep, 0), " conflicts with other jobs"); + } + else + { + pszSubProblem = solver_problemruleinfo2str(pSolv, type, dwSource, dwTarget, dwDep); + } + + if (dwSkipProblem != SKIPPROBLEM_NONE && + type == SOLVER_RULE_PKG_REQUIRES) + { + if (!check_for_providers(pSack, type, pszSubProblem, prv_pkgname)) + { + continue; + } + } + + pr_err(" - %s\n", pszSubProblem); + } + + queue_free(&rids); + } + else + { + pr_err("%u. %s\n", total_prblms, pszProblem); + } } if (dwError) { pr_err("Found %u problem(s) while resolving\n", total_prblms); + if (!nVerbose) + { + pr_err("Please retry with --verbose to see detailed solver rules\n"); + } } return dwError;