Add an extra check to check the providers

tdnf check currently has options to skip conflicts & obsoletes.
However it reports error on providers even though the required packages
are available. This will fix that issue by adding an extra check on
providers.

Added a test script for the same

Signed-off-by: Shreenidhi Shedi <sshedi@vmware.com>
This commit is contained in:
Shreenidhi Shedi 2020-03-30 18:00:03 +05:30
parent b7f1ee013b
commit 5f4b96d5eb
6 changed files with 233 additions and 123 deletions

View File

@ -30,6 +30,7 @@ TDNFInit(
uint32_t dwError = 0;
int nLocked = 0;
pthread_mutex_lock (&gEnv.mutexInitialize);
nLocked = 1;
if(!gEnv.nInitialized)
@ -60,6 +61,7 @@ TDNFIsInitialized(
int nInitialized = 0;
int nLocked = 0;
if(!pnInitialized)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
@ -198,39 +200,43 @@ TDNFGetSkipProblemOption(
{
uint32_t dwError = 0;
PTDNF_CMD_OPT pSetOpt = NULL;
TDNF_SKIPPROBLEM_TYPE dwSkipProblem = SKIPPROBLEM_NONE;
if(!pTdnf || !pTdnf->pArgs || !pdwSkipProblem)
if (!pTdnf || !pTdnf->pArgs || !pdwSkipProblem)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
if (!strcasecmp(pTdnf->pArgs->ppszCmds[0], "check"))
{
pSetOpt = pTdnf->pArgs->pSetOpt;
*pdwSkipProblem = SKIPPROBLEM_NONE;
while(pSetOpt)
{
if(pSetOpt->nType == CMDOPT_KEYVALUE &&
!strcasecmp(pSetOpt->pszOptName, "skipconflicts"))
{
dwSkipProblem |= SKIPPROBLEM_CONFLICTS;
}
if(pSetOpt->nType == CMDOPT_KEYVALUE &&
!strcasecmp(pSetOpt->pszOptName, "skipobsoletes"))
{
dwSkipProblem |= SKIPPROBLEM_OBSOLETES;
}
pSetOpt = pSetOpt->pNext;
}
if (strcasecmp(pTdnf->pArgs->ppszCmds[0], "check"))
{
goto cleanup;
}
*pdwSkipProblem = dwSkipProblem;
for (pSetOpt = pTdnf->pArgs->pSetOpt; pSetOpt; pSetOpt = pSetOpt->pNext)
{
if (pSetOpt->nType != CMDOPT_KEYVALUE)
{
continue;
}
if (!strcasecmp(pSetOpt->pszOptName, "skipconflicts"))
{
*pdwSkipProblem |= SKIPPROBLEM_CONFLICTS;
}
if (!strcasecmp(pSetOpt->pszOptName, "skipobsoletes"))
{
*pdwSkipProblem |= SKIPPROBLEM_OBSOLETES;
}
}
cleanup:
return dwError;
error:
if(pdwSkipProblem)
if (pdwSkipProblem)
{
*pdwSkipProblem = SKIPPROBLEM_NONE;
}
@ -329,15 +335,13 @@ TDNFCheckLocalPackages(
solver_set_flag(pSolv, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
solver_set_flag(pSolv, SOLVER_FLAG_YUM_OBSOLETES, 1);
if (solver_solve(pSolv, &queueJobs) != 0)
if (solver_solve(pSolv, &queueJobs))
{
dwError = TDNFGetSkipProblemOption(pTdnf, &dwSkipProblem);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvReportProblems(pSolv, dwSkipProblem);
BAIL_ON_TDNF_ERROR(dwError);
//Fail the check
dwError = ERROR_TDNF_SOLV_FAILED;
dwError = SolvReportProblems(pTdnf->pSack, pSolv, dwSkipProblem);
BAIL_ON_TDNF_ERROR(dwError);
}
cleanup:

View File

@ -395,9 +395,12 @@ TDNFGoal(
solver_set_flag(pSolv, SOLVER_FLAG_INSTALL_ALSO_UPDATES, 1);
nProblems = solver_solve(pSolv, &queueJobs);
if(nProblems > 0)
if (nProblems > 0)
{
dwError = ERROR_TDNF_SOLV_FAILED;
dwError = TDNFGetSkipProblemOption(pTdnf, &dwSkipProblem);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvReportProblems(pTdnf->pSack, pSolv, dwSkipProblem);
BAIL_ON_TDNF_ERROR(dwError);
}
@ -438,11 +441,6 @@ cleanup:
return dwError;
error:
if(nProblems > 0 && pSolv)
{
TDNFGetSkipProblemOption(pTdnf, &dwSkipProblem);
SolvReportProblems(pSolv, dwSkipProblem);
}
TDNF_SAFE_FREE_MEMORY(pInfoTemp);
if(ppInfo)
{

View File

@ -0,0 +1,62 @@
#
# Copyright (C) 2019 VMware, Inc. All Rights Reserved.
#
# Licensed under the GNU General Public License v2 (the "License");
# you may not use this file except in compliance with the License. The terms
# of the License are located in the COPYING file of this distribution.
#
# Author: Shreenidhi Shedi <sshedi@vmware.com>
import os
import tempfile
import pytest
import shutil
import subprocess
isNotPhoton = -1
try:
isNotPhoton = subprocess.check_call("uname -a | grep -i photon > /dev/null", shell = True)
except Exception as e:
isNotPhoton = 1
def run_cmd(utils, cmd, retval):
ret = utils.run(cmd)
if retval == 0:
assert(ret['retval'] == 0)
else:
assert(ret['retval'] != 0)
@pytest.fixture(scope='module', autouse=True)
def setup_test(utils):
yield
teardown_test(utils)
def teardown_test(utils):
pass
def test_check_skipconflicts(utils):
cmd = [ 'tdnf', '--config', '/etc/tdnf/tdnf.conf', 'check', '--skipconflicts']
if isNotPhoton == 1:
cmd.pop(1)
cmd.pop(1)
retval = 0 if isNotPhoton == 1 else 1
run_cmd(utils, cmd, retval)
def test_check_skipobsoletes(utils):
cmd = [ 'tdnf', '--config', '/etc/tdnf/tdnf.conf', 'check', '--skipobsoletes']
if isNotPhoton == 1:
cmd.pop(1)
cmd.pop(1)
retval = 0 if isNotPhoton == 1 else 1
run_cmd(utils, cmd, retval)
def test_check_providers(utils):
cmd = [ 'tdnf', '--config', '/etc/tdnf/tdnf.conf', 'check', '--skipconflicts', '--skipobsoletes']
if isNotPhoton == 1:
cmd.pop(1)
cmd.pop(1)
retval = 1 if isNotPhoton == 1 else 0
run_cmd(utils, cmd, 0)

View File

@ -8,6 +8,8 @@
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdbool.h>
// libsolv
#include <solv/evr.h>
#include <solv/pool.h>

View File

@ -478,6 +478,7 @@ SolvLoadRepomdUpdateinfo(
uint32_t
SolvReportProblems(
PSolvSack pSack,
Solver* pSolv,
TDNF_SKIPPROBLEM_TYPE dwSkipProblem
);

View File

@ -8,6 +8,20 @@
#include "includes.h"
static bool
SkipBasedOnType(
SolverRuleinfo type,
TDNF_SKIPPROBLEM_TYPE dwSkipProblem
);
static uint32_t
check_for_providers(
PSolvSack pSack,
SolverRuleinfo type,
const char *pszProblem,
char *prv_pkgname
);
uint32_t
SolvCreatePackageList(
PSolvPackageList* ppSolvPackageList
@ -1515,137 +1529,166 @@ error:
* SolverRuleinfo : Solver problem type
* TDNF_SKIPPROBLEM_TYPE: user specified problem type
* Return:
* 1 : if solver problem type and user specified problem matches
* 0 : if not matches
* true : if solver problem type and user specified problem matches
* false : if not matches
*/
static uint32_t
__should_skip(
static bool
SkipBasedOnType(
SolverRuleinfo type,
TDNF_SKIPPROBLEM_TYPE dwSkipProblem
)
{
uint32_t dwResult = 0;
if (dwSkipProblem == SKIPPROBLEM_CONFLICTS)
{
switch(type)
{
case SOLVER_RULE_PKG_CONFLICTS:
case SOLVER_RULE_PKG_SELF_CONFLICT:
dwResult = 1;
break;
default:
break;
}
return (type == SOLVER_RULE_PKG_CONFLICTS ||
type == SOLVER_RULE_PKG_SELF_CONFLICT);
}
else if (dwSkipProblem == SKIPPROBLEM_OBSOLETES)
if (dwSkipProblem == SKIPPROBLEM_OBSOLETES)
{
switch(type)
{
case SOLVER_RULE_PKG_OBSOLETES:
case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
dwResult = 1;
break;
default:
break;
}
return (type == SOLVER_RULE_PKG_OBSOLETES ||
type == SOLVER_RULE_PKG_IMPLICIT_OBSOLETES ||
type == SOLVER_RULE_PKG_INSTALLED_OBSOLETES);
}
else if (dwSkipProblem == (SKIPPROBLEM_CONFLICTS | SKIPPROBLEM_OBSOLETES))
if (dwSkipProblem == (SKIPPROBLEM_CONFLICTS | SKIPPROBLEM_OBSOLETES))
{
switch(type)
return (type == SOLVER_RULE_PKG_CONFLICTS ||
type == SOLVER_RULE_PKG_SELF_CONFLICT ||
type == SOLVER_RULE_PKG_OBSOLETES ||
type == SOLVER_RULE_PKG_IMPLICIT_OBSOLETES ||
type == SOLVER_RULE_PKG_INSTALLED_OBSOLETES);
}
return false;
}
static uint32_t
check_for_providers(
PSolvSack pSack,
SolverRuleinfo type,
const char *pszProblem,
char *prv_pkgname
)
{
char *beg;
char *end;
uint32_t dwError = 0;
char pkgname[256] = {0};
PSolvPackageList pAvailabePkgList = NULL;
if (!pSack || !prv_pkgname)
{
return ERROR_TDNF_INVALID_PARAMETER;
}
if (type != SOLVER_RULE_PKG_REQUIRES)
{
return dwError;
}
beg = strstr(pszProblem, "requires ");
if (beg)
{
beg += strlen("requires ");
end = strchr(beg, ',');
}
if (!beg || !end)
{
fprintf(stderr, "Error while trying to resolve\n");
return ERROR_TDNF_SOLV_FAILED;
}
for (int32_t i = 0; end > beg; beg++)
{
if (*beg != ' ')
{
case SOLVER_RULE_PKG_CONFLICTS:
case SOLVER_RULE_PKG_SELF_CONFLICT:
case SOLVER_RULE_PKG_OBSOLETES:
case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
dwResult = 1;
break;
default:
break;
pkgname[i++] = *beg;
}
}
return dwResult;
if (!strcmp(pkgname, prv_pkgname))
{
return dwError;
}
strcpy(prv_pkgname, pkgname);
dwError = SolvFindAvailablePkgByName(pSack, pkgname, &pAvailabePkgList);
if (pAvailabePkgList)
{
SolvFreePackageList(pAvailabePkgList);
}
return dwError;
}
uint32_t
SolvReportProblems(
PSolvSack pSack,
Solver* pSolv,
TDNF_SKIPPROBLEM_TYPE dwSkipProblem
)
{
uint32_t dwError = 0;
uint32_t dwSkipProbCount = 0;
int i = 0;
int j = 0;
int nCount = 0;
Id dwProblemId = 0;
Id dwDep = 0;
Id dwSource = 0;
Id dwTarget = 0;
Id dwDep = 0;
const char* pszProblem = NULL;
Id dwProblemId = 0;
SolverRuleinfo type;
uint32_t dwError = 0;
uint32_t total_prblms = 0;
char prv_pkgname[256] = {0};
if(!pSolv)
if (!pSolv)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
return ERROR_TDNF_INVALID_PARAMETER;
}
nCount = solver_problem_count(pSolv);
/**
* Below condition check is added to count the number of skip problems
* */
if((nCount > 0) && (dwSkipProblem != SKIPPROBLEM_NONE))
for ( ; nCount > 0; nCount--)
{
for( i = 1; i <= nCount; ++i)
const char *pszProblem = NULL;
dwProblemId = solver_findproblemrule(pSolv, nCount);
type = solver_ruleinfo(pSolv, dwProblemId,
&dwSource, &dwTarget, &dwDep);
if (SkipBasedOnType(type, dwSkipProblem))
{
dwProblemId = solver_findproblemrule(pSolv, i);
type = solver_ruleinfo(
pSolv,
dwProblemId,
&dwSource,&dwTarget,
&dwDep);
if (__should_skip(type, dwSkipProblem))
{
dwSkipProbCount++;
}
continue;
}
}
if(nCount > 0)
{
fprintf(stderr, "Found %u problem(s) while resolving\n", nCount - dwSkipProbCount);
for( i = 1; i <= nCount; ++i)
pszProblem = solver_problemruleinfo2str(pSolv, type, dwSource,
dwTarget, dwDep);
if (type == SOLVER_RULE_PKG_REQUIRES)
{
dwProblemId = solver_findproblemrule(pSolv, i);
type = solver_ruleinfo(
pSolv,
dwProblemId,
&dwSource,&dwTarget,
&dwDep);
if (__should_skip(type, dwSkipProblem))
if (!check_for_providers(pSack, type, pszProblem, prv_pkgname))
{
continue;
}
pszProblem = solver_problemruleinfo2str(
pSolv,
type,
dwSource,
dwTarget,
dwDep);
fprintf(stderr, "%d. %s\n", ++j, pszProblem);
pszProblem = NULL;
else
{
dwError = ERROR_TDNF_SOLV_FAILED;
}
}
}
cleanup:
return dwError;
error:
goto cleanup;
dwError = ERROR_TDNF_SOLV_FAILED;
fprintf(stderr, "%u. %s\n", ++total_prblms, pszProblem);
}
if (dwError)
{
fprintf(stderr, "Found %u problem(s) while resolving\n", total_prblms);
}
else
{
printf("No problems found while resolving\n");
}
return dwError;
}
uint32_t