mirror of https://github.com/vmware/tdnf.git
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:
parent
b7f1ee013b
commit
5f4b96d5eb
56
client/api.c
56
client/api.c
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
|
@ -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>
|
||||
|
|
|
@ -478,6 +478,7 @@ SolvLoadRepomdUpdateinfo(
|
|||
|
||||
uint32_t
|
||||
SolvReportProblems(
|
||||
PSolvSack pSack,
|
||||
Solver* pSolv,
|
||||
TDNF_SKIPPROBLEM_TYPE dwSkipProblem
|
||||
);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue