Merge pull request #248 from oliverkurth/topic/okurth/repoquery

implement the repoquery command
This commit is contained in:
Oliver Kurth 2021-10-29 10:44:14 -07:00 committed by GitHub
commit 8445b0f0f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1941 additions and 18 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2018 VMware, Inc. All Rights Reserved.
* Copyright (C) 2015-2021 VMware, Inc. All Rights Reserved.
*
* Licensed under the GNU Lesser General Public License v2.1 (the "License");
* you may not use this file except in compliance with the License. The terms
@ -1345,6 +1345,174 @@ error:
goto cleanup;
}
uint32_t
TDNFRepoQuery(
PTDNF pTdnf,
PTDNF_REPOQUERY_ARGS pRepoqueryArgs,
PTDNF_PKG_INFO* ppPkgInfo,
uint32_t *pdwCount
)
{
uint32_t dwError = 0;
PTDNF_PKG_INFO pPkgInfo = NULL;
PSolvQuery pQuery = NULL;
PSolvPackageList pPkgList = NULL;
int nDetail;
uint32_t dwCount = 0;
TDNF_SCOPE nScope = SCOPE_ALL;
if(!pTdnf || !pTdnf->pSack || !pRepoqueryArgs ||
!ppPkgInfo || !pdwCount)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
/* check if args make sense. extra packages are installed by definition */
if (pRepoqueryArgs->nExtras &&
(pRepoqueryArgs->nInstalled || pRepoqueryArgs->nAvailable ||
pRepoqueryArgs->nDuplicates))
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
/* duplicate packages are also installed by definition */
if (pRepoqueryArgs->nDuplicates &&
(pRepoqueryArgs->nInstalled || pRepoqueryArgs->nAvailable))
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFRefresh(pTdnf);
BAIL_ON_TDNF_ERROR(dwError);
/* handle select options */
dwError = SolvCreateQuery(pTdnf->pSack, &pQuery);
BAIL_ON_TDNF_ERROR(dwError);
if (!pRepoqueryArgs->nExtras)
{
if (!pRepoqueryArgs->nInstalled || pRepoqueryArgs->nAvailable)
{
nScope = SCOPE_AVAILABLE;
}
else if (pRepoqueryArgs->nInstalled || pRepoqueryArgs->nDuplicates)
{
nScope = SCOPE_INSTALLED;
}
else if(pRepoqueryArgs->nUpgrades)
{
nScope = SCOPE_UPGRADES;
}
}
dwError = TDNFApplyScopeFilter(pQuery, nScope);
BAIL_ON_TDNF_ERROR(dwError);
/* filter for package(s) given as arguments, if any */
if (pRepoqueryArgs->pszSpec)
{
dwError = SolvApplySinglePackageFilter(pQuery, pRepoqueryArgs->pszSpec);
BAIL_ON_TDNF_ERROR(dwError);
}
/* run all the filters */
dwError = SolvApplyListQuery(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
/* now filter for extras or duplicates */
if (pRepoqueryArgs->nExtras)
{
dwError = SolvApplyExtrasFilter(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
}
else if (pRepoqueryArgs->nDuplicates)
{
dwError = SolvApplyDuplicatesFilter(pQuery);
BAIL_ON_TDNF_ERROR(dwError);
}
/* filter for package(s) that depend on give package(s) */
if (pRepoqueryArgs->pppszWhatKeys)
{
REPOQUERY_WHAT_KEY whatKey;
for (whatKey = 0; whatKey < REPOQUERY_WHAT_KEY_COUNT; whatKey++)
{
if (pRepoqueryArgs->pppszWhatKeys[whatKey])
{
dwError = SolvApplyDepsFilter(pQuery,
pRepoqueryArgs->pppszWhatKeys[whatKey],
whatKey);
BAIL_ON_TDNF_ERROR(dwError);
}
}
}
/* filter for package(s) that provide a given file */
if (pRepoqueryArgs->pszFile)
{
dwError = SolvApplyFileProvidesFilter(pQuery, pRepoqueryArgs->pszFile);
BAIL_ON_TDNF_ERROR(dwError);
}
/* get results in list */
dwError = SolvGetQueryResult(pQuery, &pPkgList);
BAIL_ON_TDNF_ERROR(dwError);
/* handle query options */
/* TDNFPopulatePkgInfoArray fills in details */
nDetail = pRepoqueryArgs->nChangeLogs ? DETAIL_CHANGELOG :
pRepoqueryArgs->nSource ? DETAIL_SOURCEPKG :
DETAIL_LIST;
dwError = TDNFPopulatePkgInfoArray(pTdnf->pSack, pPkgList, nDetail,
&pPkgInfo, &dwCount);
BAIL_ON_TDNF_ERROR(dwError);
/* fill in file list or dependencies */
if (pRepoqueryArgs->nList)
{
dwError = TDNFPopulatePkgInfoArrayFileList(
pTdnf->pSack,
pPkgList,
pPkgInfo);
BAIL_ON_TDNF_ERROR(dwError);
}
else if (pRepoqueryArgs->depKey)
{
dwError = TDNFPopulatePkgInfoArrayDependencies(
pTdnf->pSack,
pPkgList,
pRepoqueryArgs->depKey,
pPkgInfo);
BAIL_ON_TDNF_ERROR(dwError);
}
*ppPkgInfo = pPkgInfo;
*pdwCount = dwCount;
cleanup:
if(pQuery)
{
SolvFreeQuery(pQuery);
}
if(pPkgList)
{
SolvFreePackageList(pPkgList);
}
return dwError;
error:
TDNFFreePackageInfo(pPkgInfo);
if(dwError == ERROR_TDNF_NO_MATCH)
{
dwError = ERROR_TDNF_NO_DATA;
}
goto cleanup;
}
//Resolve alter command before presenting
//the goal steps to user for approval
uint32_t

View File

@ -24,8 +24,11 @@
typedef enum
{
/* this should be a bitmask */
DETAIL_LIST,
DETAIL_INFO
DETAIL_INFO,
DETAIL_CHANGELOG,
DETAIL_SOURCEPKG
}TDNF_PKG_DETAIL;
#define BAIL_ON_TDNF_RPM_ERROR(dwError) \
@ -56,6 +59,7 @@ typedef enum
#define TDNF_REPOMD_TYPE_PRIMARY "primary"
#define TDNF_REPOMD_TYPE_FILELISTS "filelists"
#define TDNF_REPOMD_TYPE_UPDATEINFO "updateinfo"
#define TDNF_REPOMD_TYPE_OTHER "other"
//Repo defines
#define TDNF_REPO_EXT ".repo"

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 VMware, Inc. All Rights Reserved.
* Copyright (C) 2015-2021 VMware, Inc. All Rights Reserved.
*
* Licensed under the GNU Lesser General Public License v2.1 (the "License");
* you may not use this file except in compliance with the License. The terms
@ -93,10 +93,13 @@ TDNFPopulatePkgInfoArray(
{
uint32_t dwError = 0;
uint32_t dwCount = 0;
int dwPkgIndex = 0;
uint32_t dwPkgIndex = 0;
Id dwPkgId = 0;
PTDNF_PKG_INFO pPkgInfos = NULL;
PTDNF_PKG_INFO pPkgInfo = NULL;
char *pszSrcName = NULL;
char *pszSrcArch = NULL;
char *pszSrcEVR = NULL;
if(!ppPkgInfo || !pdwCount || !pSack || !pPkgList)
{
@ -184,12 +187,43 @@ TDNFPopulatePkgInfoArray(
&pPkgInfo->pszDescription);
BAIL_ON_TDNF_ERROR(dwError);
}
else if (nDetail == DETAIL_CHANGELOG)
{
dwError = SolvGetChangeLogFromId(
pSack,
dwPkgId,
&pPkgInfo->pChangeLogEntries);
BAIL_ON_TDNF_ERROR(dwError);
}
else if (nDetail == DETAIL_SOURCEPKG)
{
dwError = SolvGetSourceFromId(
pSack,
dwPkgId,
&pszSrcName,
&pszSrcArch,
&pszSrcEVR);
BAIL_ON_TDNF_ERROR(dwError);
dwError = TDNFAllocateStringPrintf(
&pPkgInfo->pszSourcePkg,
"%s-%s.%s",
pszSrcName, pszSrcEVR, pszSrcArch);
BAIL_ON_TDNF_ERROR(dwError);
}
if (dwPkgIndex < dwCount - 1)
{
pPkgInfo->pNext = &pPkgInfos[dwPkgIndex+1];
}
}
*pdwCount = dwCount;
*ppPkgInfo = pPkgInfos;
cleanup:
TDNF_SAFE_FREE_MEMORY(pszSrcName);
TDNF_SAFE_FREE_MEMORY(pszSrcArch);
TDNF_SAFE_FREE_MEMORY(pszSrcEVR);
return dwError;
error:
@ -362,7 +396,7 @@ TDNFPkgInfoFilterNewest(
older versions of the same packages. The linked list will only
touch the newest (first) version of a package.
The same package in different repos will be handled as two different
packages. */
packages. */
pPkgInfo = ppPkgInfos[0];
for (i = 1; i < dwCount; i++)
{
@ -1084,3 +1118,97 @@ error:
}
goto cleanup;
}
uint32_t
TDNFPopulatePkgInfoArrayDependencies(
PSolvSack pSack,
PSolvPackageList pPkgList,
REPOQUERY_DEP_KEY depKey,
PTDNF_PKG_INFO pPkgInfos
)
{
uint32_t dwError = 0;
uint32_t dwCount = 0;
uint32_t dwPkgIndex = 0;
Id dwPkgId = 0;
PTDNF_PKG_INFO pPkgInfo = NULL;
if(!pPkgInfos || !pSack || !pPkgList)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvGetPackageListSize(pPkgList, &dwCount);
BAIL_ON_TDNF_ERROR(dwError);
if(dwCount == 0)
{
dwError = ERROR_TDNF_NO_MATCH;
BAIL_ON_TDNF_ERROR(dwError);
}
for (dwPkgIndex = 0; dwPkgIndex < dwCount; dwPkgIndex++)
{
pPkgInfo = &pPkgInfos[dwPkgIndex];
dwError = SolvGetPackageId(pPkgList, dwPkgIndex, &dwPkgId);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvGetDependenciesFromId(pSack, dwPkgId, depKey, &pPkgInfo->ppszDependencies);
BAIL_ON_TDNF_ERROR(dwError);
}
cleanup:
return dwError;
error:
goto cleanup;
}
uint32_t
TDNFPopulatePkgInfoArrayFileList(
PSolvSack pSack,
PSolvPackageList pPkgList,
PTDNF_PKG_INFO pPkgInfos
)
{
uint32_t dwError = 0;
uint32_t dwCount = 0;
uint32_t dwPkgIndex = 0;
Id dwPkgId = 0;
PTDNF_PKG_INFO pPkgInfo = NULL;
if(!pPkgInfos || !pSack || !pPkgList)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = SolvGetPackageListSize(pPkgList, &dwCount);
BAIL_ON_TDNF_ERROR(dwError);
if(dwCount == 0)
{
dwError = ERROR_TDNF_NO_MATCH;
BAIL_ON_TDNF_ERROR(dwError);
}
for (dwPkgIndex = 0; dwPkgIndex < dwCount; dwPkgIndex++)
{
pPkgInfo = &pPkgInfos[dwPkgIndex];
dwError = SolvGetPackageId(pPkgList, dwPkgIndex, &dwPkgId);
BAIL_ON_TDNF_ERROR(dwError);
dwError = SolvGetFileListFromId(pSack, dwPkgId, &pPkgInfo->ppszFileList);
BAIL_ON_TDNF_ERROR(dwError);
}
cleanup:
return dwError;
error:
goto cleanup;
}

View File

@ -430,6 +430,21 @@ TDNFCheckMinVersions(
PTDNF_SOLVED_PKG_INFO pSolvedPkgInfo
);
uint32_t
TDNFPopulatePkgInfoArrayDependencies(
PSolvSack pSack,
PSolvPackageList pPkgList,
REPOQUERY_DEP_KEY depKey,
PTDNF_PKG_INFO pPkgInfos
);
uint32_t
TDNFPopulatePkgInfoArrayFileList(
PSolvSack pSack,
PSolvPackageList pPkgList,
PTDNF_PKG_INFO pPkgInfos
);
//goal.c
uint32_t
TDNFGoal(

View File

@ -160,7 +160,8 @@ TDNFInitRepoFromMetadata(
pRepoMD->pszRepoMD,
pRepoMD->pszPrimary,
pRepoMD->pszFileLists,
pRepoMD->pszUpdateInfo);
pRepoMD->pszUpdateInfo,
pRepoMD->pszOther);
cleanup:
return dwError;
@ -942,7 +943,8 @@ TDNFGetRepoMD(
if (nReplaceRepoMD)
{
/* Remove the old repodata, solvcache and lastRefreshMarker before replacing the new repomd file and metalink files. */
/* Remove the old repodata, solvcache and lastRefreshMarker before
replacing the new repomd file and metalink files. */
TDNFRepoRemoveCache(pTdnf, pRepoData->pszId);
TDNFRemoveSolvCache(pTdnf, pRepoData->pszId);
TDNFRemoveLastRefreshMarker(pTdnf, pRepoData->pszId);
@ -1137,6 +1139,23 @@ TDNFEnsureRepoMDParts(
pRepoMD->pszUpdateInfo);
BAIL_ON_TDNF_ERROR(dwError);
}
if(!IsNullOrEmptyString(pRepoMDRel->pszOther))
{
dwError = TDNFAppendPath(
pRepoMDRel->pszRepoCacheDir,
pRepoMDRel->pszOther,
&pRepoMD->pszOther);
BAIL_ON_TDNF_ERROR(dwError);
dwError = TDNFDownloadRepoMDPart(
pTdnf,
pszBaseUrl,
pRepoMDRel->pszRepo,
pRepoMDRel->pszOther,
pRepoMD->pszOther);
BAIL_ON_TDNF_ERROR(dwError);
}
*ppRepoMD = pRepoMD;
cleanup:
@ -1272,6 +1291,16 @@ TDNFParseRepoMD(
}
BAIL_ON_TDNF_ERROR(dwError);
dwError = TDNFFindRepoMDPart(
pRepo,
TDNF_REPOMD_TYPE_OTHER,
&pRepoMD->pszOther);
if(dwError == ERROR_TDNF_NO_DATA)
{
dwError = 0;
}
BAIL_ON_TDNF_ERROR(dwError);
cleanup:
if (fp)
{
@ -1306,6 +1335,7 @@ TDNFFreeRepoMetadata(
TDNF_SAFE_FREE_MEMORY(pRepoMD->pszPrimary);
TDNF_SAFE_FREE_MEMORY(pRepoMD->pszFileLists);
TDNF_SAFE_FREE_MEMORY(pRepoMD->pszUpdateInfo);
TDNF_SAFE_FREE_MEMORY(pRepoMD->pszOther);
TDNF_SAFE_FREE_MEMORY(pRepoMD);
}

View File

@ -104,6 +104,7 @@ typedef struct _TDNF_REPO_METADATA
char *pszPrimary;
char *pszFileLists;
char *pszUpdateInfo;
char *pszOther;
}TDNF_REPO_METADATA,*PTDNF_REPO_METADATA;
typedef struct _TDNF_EVENT_DATA_

View File

@ -124,6 +124,11 @@ TDNFStringArrayCount(
int *pnCount
);
uint32_t
TDNFStringArraySort(
char **ppszArray
);
//configreader.c
void
TDNFPrintConfigData(

View File

@ -524,3 +524,33 @@ error:
goto cleanup;
}
static int
_cmpstringp(const void *p1, const void *p2)
{
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
uint32_t
TDNFStringArraySort(
char **ppszArray
)
{
uint32_t dwError = 0;
int nCount;
if (IsNullOrEmptyString(ppszArray))
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}
for(nCount = 0; ppszArray[nCount]; nCount++);
qsort(ppszArray, nCount, sizeof(char *), _cmpstringp);
cleanup:
return dwError;
error:
goto cleanup;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2018 VMware, Inc. All Rights Reserved.
* Copyright (C) 2015-2021 VMware, Inc. All Rights Reserved.
*
* Licensed under the GNU Lesser General Public License v2.1 (the "License");
* you may not use this file except in compliance with the License. The terms
@ -209,11 +209,26 @@ TDNFFreePackageInfoArray(
TDNF_SAFE_FREE_MEMORY(pPkgInfoArray);
}
void
TDNFFreeChangeLogEntry(
PTDNF_PKG_CHANGELOG_ENTRY pEntry
)
{
if (pEntry)
{
TDNF_SAFE_FREE_MEMORY(pEntry->pszAuthor);
TDNF_SAFE_FREE_MEMORY(pEntry->pszText);
TDNF_SAFE_FREE_MEMORY(pEntry);
}
}
void
TDNFFreePackageInfoContents(
PTDNF_PKG_INFO pPkgInfo
)
{
PTDNF_PKG_CHANGELOG_ENTRY pEntry, pEntryNext;
if(pPkgInfo)
{
TDNF_SAFE_FREE_MEMORY(pPkgInfo->pszName);
@ -228,6 +243,15 @@ TDNFFreePackageInfoContents(
TDNF_SAFE_FREE_MEMORY(pPkgInfo->pszFormattedSize);
TDNF_SAFE_FREE_MEMORY(pPkgInfo->pszRelease);
TDNF_SAFE_FREE_MEMORY(pPkgInfo->pszLocation);
TDNF_SAFE_FREE_STRINGARRAY(pPkgInfo->ppszDependencies);
TDNF_SAFE_FREE_STRINGARRAY(pPkgInfo->ppszFileList);
for (pEntry = pPkgInfo->pChangeLogEntries;
pEntry;
pEntry = pEntryNext)
{
pEntryNext = pEntry->pNext;
TDNFFreeChangeLogEntry(pEntry);
}
}
}

View File

@ -113,13 +113,22 @@ TDNFProvides(
PTDNF_PKG_INFO* ppPkgInfo
);
//query repo
//sync repo
uint32_t
TDNFRepoSync(
PTDNF pTdnf,
PTDNF_REPOSYNC_ARGS pReposyncArgs
);
//query repo
uint32_t
TDNFRepoQuery(
PTDNF pTdnf,
PTDNF_REPOQUERY_ARGS pRepoqueryArgs,
PTDNF_PKG_INFO* ppPkgInfo,
uint32_t *pdwCount
);
//Show update info for specified scope
uint32_t
TDNFUpdateInfo(
@ -223,6 +232,11 @@ TDNFFreePackageInfoArray(
uint32_t dwLength
);
void
TDNFFreeChangeLogEntry(
PTDNF_PKG_CHANGELOG_ENTRY pEntry
);
void
TDNFFreeRepos(
PTDNF_REPO_DATA pRepos

View File

@ -77,6 +77,12 @@ TDNFCliParseRepoSyncArgs(
PTDNF_REPOSYNC_ARGS* ppReposyncArgs
);
uint32_t
TDNFCliParseRepoQueryArgs(
PTDNF_CMD_ARGS pCmdArgs,
PTDNF_REPOQUERY_ARGS* ppRepoqueryArgs
);
uint32_t
TDNFCliParseMode(
const char* pszOutMode,
@ -127,6 +133,11 @@ TDNFCliFreeRepoSyncArgs(
PTDNF_REPOSYNC_ARGS pReposyncArgs
);
void
TDNFCliFreeRepoQueryArgs(
PTDNF_REPOQUERY_ARGS pRepoqueryArgs
);
//Commands
uint32_t
TDNFCliAutoEraseCommand(
@ -206,6 +217,12 @@ TDNFCliRepoSyncCommand(
PTDNF_CMD_ARGS pCmdArgs
);
uint32_t
TDNFCliRepoQueryCommand(
PTDNF_CLI_CONTEXT pContext,
PTDNF_CMD_ARGS pCmdArgs
);
uint32_t
TDNFCliUpdateInfoCommand(
PTDNF_CLI_CONTEXT pContext,

View File

@ -23,5 +23,6 @@
#define ERROR_TDNF_CLI_SETOPT_NO_EQUALS (ERROR_TDNF_CLI_BASE + 11)
#define ERROR_TDNF_CLI_NO_SUCH_CMD (ERROR_TDNF_CLI_BASE + 12)
#define ERROR_TDNF_CLI_DOWNLOADDIR_REQUIRES_DOWNLOADONLY (ERROR_TDNF_CLI_BASE + 13)
#define ERROR_TDNF_CLI_ONE_DEP_ONLY (ERROR_TDNF_CLI_BASE + 14)
#endif /* __TDNF_CLI_ERR_H__ */

View File

@ -113,6 +113,14 @@ typedef uint32_t
PTDNF_REPOSYNC_ARGS
);
typedef uint32_t
(*PFN_TDNF_REPOQUERY)(
PTDNF_CLI_CONTEXT,
PTDNF_REPOQUERY_ARGS,
PTDNF_PKG_INFO *,
uint32_t *
);
typedef uint32_t
(*PFN_TDNF_RESOLVE)(
PTDNF_CLI_CONTEXT,
@ -155,6 +163,7 @@ typedef struct _TDNF_CLI_CONTEXT_
PFN_TDNF_PROVIDES pFnProvides;
PFN_TDNF_REPOLIST pFnRepoList;
PFN_TDNF_REPOSYNC pFnRepoSync;
PFN_TDNF_REPOQUERY pFnRepoQuery;
PFN_TDNF_RESOLVE pFnResolve;
PFN_TDNF_SEARCH pFnSearch;
PFN_TDNF_UPDATEINFO pFnUpdateInfo;

View File

@ -152,6 +152,14 @@ typedef enum
typedef struct _TDNF_ *PTDNF;
typedef struct _TDNF_PKG_CHANGELOG_ENTRY
{
time_t timeTime;
char *pszAuthor;
char *pszText;
struct _TDNF_PKG_CHANGELOG_ENTRY *pNext;
} TDNF_PKG_CHANGELOG_ENTRY, *PTDNF_PKG_CHANGELOG_ENTRY;
typedef struct _TDNF_PKG_INFO
{
uint32_t dwEpoch;
@ -168,6 +176,10 @@ typedef struct _TDNF_PKG_INFO
char* pszFormattedSize;
char* pszRelease;
char* pszLocation;
char **ppszDependencies;
char **ppszFileList;
char *pszSourcePkg;
PTDNF_PKG_CHANGELOG_ENTRY pChangeLogEntries;
struct _TDNF_PKG_INFO* pNext;
}TDNF_PKG_INFO, *PTDNF_PKG_INFO;
@ -351,6 +363,54 @@ typedef struct _TDNF_REPOSYNC_ARGS
char **ppszArchs;
}TDNF_REPOSYNC_ARGS, *PTDNF_REPOSYNC_ARGS;
typedef enum {
REPOQUERY_WHAT_KEY_PROVIDES,
REPOQUERY_WHAT_KEY_OBSOLETES,
REPOQUERY_WHAT_KEY_CONFLICTS,
REPOQUERY_WHAT_KEY_REQUIRES,
REPOQUERY_WHAT_KEY_RECOMMENDS,
REPOQUERY_WHAT_KEY_SUGGESTS,
REPOQUERY_WHAT_KEY_SUPPLEMENTS,
REPOQUERY_WHAT_KEY_ENHANCES,
REPOQUERY_WHAT_KEY_DEPENDS,
REPOQUERY_WHAT_KEY_COUNT
} REPOQUERY_WHAT_KEY;
typedef enum {
REPOQUERY_DEP_KEY_NONE = 0,
REPOQUERY_DEP_KEY_PROVIDES,
REPOQUERY_DEP_KEY_OBSOLETES,
REPOQUERY_DEP_KEY_CONFLICTS,
REPOQUERY_DEP_KEY_REQUIRES,
REPOQUERY_DEP_KEY_RECOMMENDS,
REPOQUERY_DEP_KEY_SUGGESTS,
REPOQUERY_DEP_KEY_SUPPLEMENTS,
REPOQUERY_DEP_KEY_ENHANCES,
REPOQUERY_DEP_KEY_DEPENDS,
REPOQUERY_DEP_KEY_REQUIRES_PRE,
REPOQUERY_DEP_KEY_COUNT
} REPOQUERY_DEP_KEY;
typedef struct _TDNF_REPOQUERY_ARGS
{
char *pszSpec;
/* select options */
int nAvailable; /* list what's available (default) */
int nDuplicates;
int nExtras; /* packages that are installed but not available */
int nInstalled;
int nUpgrades;
char *pszFile; /* packages that own this file */
char ***pppszWhatKeys;
/* query options */
int nChangeLogs;
REPOQUERY_DEP_KEY depKey; /* list dependencies of this type, 0 => unset */
int nList; /* list files of packages(s) */
int nSource; /* show source packages */
}TDNF_REPOQUERY_ARGS, *PTDNF_REPOQUERY_ARGS;
#ifdef __cplusplus
}
#endif

View File

@ -54,6 +54,10 @@ cat << EOF > ~/.rpmmacros
%__gpg /usr/bin/gpg
EOF
for d in conflicts enhances obsoletes provides recommends requires suggests supplements ; do
sed s/@@dep@@/$d/ < ${REPO_SRC_DIR}/tdnf-repoquery-deps.spec.in > ${REPO_SRC_DIR}/tdnf-repoquery-$d.spec
done
echo building packages
rpmbuild --define "_topdir ${BUILD_PATH}" \
-r ${BUILD_PATH} -ba ${REPO_SRC_DIR}/*.spec

View File

@ -0,0 +1,27 @@
Summary: Repoquery Test
Name: tdnf-repoquery-base
Version: 1.0.1
Release: 2
Vendor: VMware, Inc.
Distribution: Photon
License: VMware
Url: http://www.vmware.com
Group: Applications/tdnftest
%description
Part of tdnf test spec. For repoquery tests, other packages will
depend on this in some way.
%prep
%build
%install
mkdir -p %_topdir/%buildroot/usr/lib/repoquery
touch %_topdir/%buildroot/usr/lib/repoquery/%name
%files
/usr/lib/repoquery/%name
%changelog
* Tue Jul 06 2021 Oliver Kurth <okurth@vmware.com> 1.0.1-2
- first repoquery version

View File

@ -0,0 +1,30 @@
Summary: Repoquery Test
Name: tdnf-repoquery-changelog
Version: 1.0.1
Release: 2
Vendor: VMware, Inc.
Distribution: Photon
License: VMware
Url: http://www.vmware.com
Group: Applications/tdnftest
%description
Part of tdnf test spec. For repoquery tests, other packages will
depend on this in some way.
%prep
%build
%install
mkdir -p %_topdir/%buildroot/usr/lib/repoquery
touch %_topdir/%buildroot/usr/lib/repoquery/%name
%files
/usr/lib/repoquery/%name
%changelog
* Tue Jul 06 2021 Oliver Kurth <okurth@vmware.com> 1.2.3-4
- needle in a haystack
* Wed Jan 01 2020 John Doe <jdoe@jdoe.com> 1.0.0-1
- wrong date, needed for testing. Fedora ignores dates before
some time 2018.

View File

@ -0,0 +1,29 @@
Summary: Repoquery Test
Name: tdnf-repoquery-@@dep@@
Version: 1.0.1
Release: 2
Vendor: VMware, Inc.
Distribution: Photon
License: VMware
Url: http://www.vmware.com
Group: Applications/tdnftest
@@dep@@: tdnf-repoquery-base
%description
Part of tdnf test spec. For repoquery tests, this package will
depend on tdnf-repoquery-base (or provide, ...)
%prep
%build
%install
mkdir -p %_topdir/%buildroot/usr/lib/repoquery
touch %_topdir/%buildroot/usr/lib/repoquery/%name
%files
/usr/lib/repoquery/%name
%changelog
* Tue Jul 06 2021 Oliver Kurth <okurth@vmware.com> 1.0.1-2
- first repoquery version

View File

@ -0,0 +1,200 @@
#
# Copyright (C) 2021 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: Oliver Kurth <okurth@vmware.com>
import os
import shutil
import errno
import pytest
BASE_PKG = 'tdnf-repoquery-base'
@pytest.fixture(scope='function', autouse=True)
def setup_test(utils):
yield
teardown_test(utils)
def teardown_test(utils):
ret = utils.run(['tdnf',
'remove', '-y',
BASE_PKG])
# repoquery should list all packages that depend on BASE_PKG
# (one of 'enhances', 'recommends', 'requires', 'suggests', 'supplements')
def test_whatdepends(utils):
ret = utils.run(['tdnf',
'repoquery',
'--whatdepends',
BASE_PKG])
assert(ret['retval'] == 0)
for d in ['enhances', 'recommends', 'requires', 'suggests', 'supplements']:
assert('tdnf-repoquery-{}'.format(d) in '\n'.join(ret['stdout']))
# repoquery should list the package that has a specific
# relation to BASE_PKG
def test_what_alldeps(utils):
dep_types = ['conflicts', 'enhances', 'obsoletes', 'provides',
'recommends', 'requires', 'suggests', 'supplements']
for dep in dep_types:
ret = utils.run(['tdnf',
'repoquery',
'--what{}'.format(dep),
BASE_PKG
])
assert(ret['retval'] == 0)
assert('tdnf-repoquery-{}'.format(dep) in '\n'.join(ret['stdout']))
# repoquery should list the package that requires BASE_PKG
# or some other package that may or may not exist. Tests multiple
# args to --whatrequires separated by a comma
def test_what_2(utils):
ret = utils.run(['tdnf',
'repoquery',
'--whatrequires',
"{},{}".format('doesnotexist', BASE_PKG)
])
assert(ret['retval'] == 0)
assert('tdnf-repoquery-requires' in '\n'.join(ret['stdout']))
# packages should have specified relation to BASE_PKG
def test_alldeps(utils):
dep_types = ['conflicts', 'enhances', 'obsoletes', 'provides',
'recommends', 'requires', 'suggests', 'supplements']
for dep in dep_types:
ret = utils.run(['tdnf',
'repoquery',
'--{}'.format(dep),
'tdnf-repoquery-{}'.format(dep)
])
assert(ret['retval'] == 0)
assert(BASE_PKG in '\n'.join(ret['stdout']))
# all these packages depend on BASE_PKG
def test_depends(utils):
for dep in ['enhances', 'recommends', 'requires', 'suggests', 'supplements']:
ret = utils.run(['tdnf',
'repoquery',
'--depends',
'tdnf-repoquery-{}'.format(dep)])
assert(ret['retval'] == 0)
assert(BASE_PKG in '\n'.join(ret['stdout']))
# each package has a file with its name
def test_list(utils):
dep_types = ['conflicts', 'enhances', 'obsoletes', 'provides',
'recommends', 'requires', 'suggests', 'supplements']
for dep in dep_types:
ret = utils.run(['tdnf',
'repoquery',
'--list',
'tdnf-repoquery-{}'.format(dep)
])
assert(ret['retval'] == 0)
assert('/usr/lib/repoquery/tdnf-repoquery-{}'.format(dep) in '\n'.join(ret['stdout']))
# like test_list(), but the other way around
def test_file(utils):
dep_types = ['conflicts', 'enhances', 'obsoletes', 'provides',
'recommends', 'requires', 'suggests', 'supplements']
for dep in dep_types:
ret = utils.run(['tdnf',
'repoquery',
'--file',
'/usr/lib/repoquery/tdnf-repoquery-{}'.format(dep)
])
assert(ret['retval'] == 0)
assert('tdnf-repoquery-{}'.format(dep) in '\n'.join(ret['stdout']))
def test_available(utils):
ret = utils.run(['tdnf',
'repoquery',
'--available'])
assert(ret['retval'] == 0)
assert(BASE_PKG in '\n'.join(ret['stdout']))
def test_installed(utils):
ret = utils.run(['tdnf',
'install', '-y', '--nogpgcheck',
BASE_PKG])
assert(ret['retval'] == 0)
ret = utils.run(['tdnf',
'repoquery',
'--installed'])
assert(ret['retval'] == 0)
assert(BASE_PKG in '\n'.join(ret['stdout']))
def test_extras(utils):
ret = utils.run(['tdnf',
'repoquery',
'--extras'])
assert(ret['retval'] == 0)
# we are using just the 'photon-test repo,
# so any real system package is 'extra'
assert('glibc' in '\n'.join(ret['stdout']))
def test_upgrades(utils):
pkg_low = "{}-{}".format(utils.config["mulversion_pkgname"], utils.config["mulversion_lower"])
pkg_high = "{}-{}".format(utils.config["mulversion_pkgname"], utils.config["mulversion_higher"])
ret = utils.run(['tdnf',
'install', '-y', '--nogpgcheck',
pkg_low])
assert(ret['retval'] == 0)
ret = utils.run(['tdnf',
'repoquery',
'--upgrades'])
assert(ret['retval'] == 0)
assert(pkg_high in '\n'.join(ret['stdout']))
def test_changelog(utils):
ret = utils.run(['tdnf',
'repoquery',
'--changelogs',
'tdnf-repoquery-changelog'])
assert(ret['retval'] == 0)
# tests changelog text, author and date
output = '\n'.join(ret['stdout'])
assert("needle in a haystack" in output)
assert("John Doe" in output)
assert("Wed Jan 01 2020" in output)
def test_source(utils):
# any package should do that has
# the same name as the source
pkgname = 'tdnf-repoquery-base'
ret = utils.run(['tdnf',
'repoquery',
'--source',
pkgname])
assert(ret['retval'] == 0)
output = '\n'.join(ret['stdout'])
assert(pkgname in output)
assert('src' in output)
assert(not 'x86_64' in output)
# each package has a file with its name
def test_list(utils):
dep = 'requires'
ret = utils.run_memcheck(['tdnf',
'repoquery',
'--list',
'tdnf-repoquery-{}'.format(dep)
])
assert(ret['retval'] == 0)

View File

@ -11,6 +11,10 @@
#ifdef __cplusplus
extern "C" {
#endif
#define TDNF_ID_DEPENDS "tdnf:depends"
#define TDNF_ID_REQUIRES_PRE "tdnf:requires-pre"
typedef struct _SolvSack
{
Pool* pPool;
@ -44,6 +48,8 @@ typedef struct _SOLV_REPO_INFO_INTERNAL_
int nCookieSet;
}SOLV_REPO_INFO_INTERNAL, *PSOLV_REPO_INFO_INTERNAL;
extern Id allDepKeyIds[];
// tdnfpackage.c
uint32_t
SolvGetPkgInfoFromId(
@ -266,6 +272,35 @@ SolvGetNevraFromId(
char **ppszEVR
);
uint32_t
SolvGetDependenciesFromId(
PSolvSack pSack,
uint32_t dwPkgId,
REPOQUERY_DEP_KEY depKey,
char ***pppszDependencies);
uint32_t
SolvGetFileListFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char ***pppszFiles);
uint32_t
SolvGetSourceFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char **ppszName,
char **ppszArch,
char **ppszEVR
);
uint32_t
SolvGetChangeLogFromId(
PSolvSack pSack,
uint32_t dwPkgId,
PTDNF_PKG_CHANGELOG_ENTRY *ppEntries
);
// tdnfpool.c
uint32_t
SolvCreateSack(
@ -429,6 +464,25 @@ SolvGetUpdateAdvisories(
Id dwPkgIdpkg,
PSolvPackageList* ppPkgList);
uint32_t
SolvApplyDepsFilter(
PSolvQuery pQuery,
char **ppszDeps,
REPOQUERY_WHAT_KEY whatKey);
uint32_t
SolvApplyExtrasFilter(
PSolvQuery pQuery);
uint32_t
SolvApplyDuplicatesFilter(
PSolvQuery pQuery);
uint32_t
SolvApplyFileProvidesFilter(
PSolvQuery pQuery,
char *pszFile);
// tdnfrepo.c
uint32_t
SolvReadYumRepo(
@ -437,7 +491,8 @@ SolvReadYumRepo(
const char *pszRepomd,
const char *pszPrimary,
const char *pszFilelists,
const char *pszUpdateinfo
const char *pszUpdateinfo,
const char *pszOther
);
uint32_t

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 VMware, Inc. All Rights Reserved.
* Copyright (C) 2015-2021 VMware, Inc. All Rights Reserved.
*
* Licensed under the GNU Lesser General Public License v2.1 (the "License");
* you may not use this file except in compliance with the License. The terms
@ -1924,3 +1924,299 @@ error:
TDNF_SAFE_FREE_MEMORY(pszEVR);
goto cleanup;
}
uint32_t
SolvGetDependenciesFromId(
PSolvSack pSack,
uint32_t dwPkgId,
REPOQUERY_DEP_KEY depKey,
char ***pppszDependencies)
{
uint32_t dwError = 0;
Solvable *pSolv = NULL;
Queue queueDeps = {0};
char **ppszDependencies = NULL;
const char *pszDep = NULL;
int nNumDeps, i, j;
if(!pSack || !pppszDependencies)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
if (depKey == REPOQUERY_DEP_KEY_DEPENDS)
{
Id allDepKeys[] = {
SOLVABLE_REQUIRES,
SOLVABLE_RECOMMENDS,
SOLVABLE_SUGGESTS,
SOLVABLE_SUPPLEMENTS,
SOLVABLE_ENHANCES
};
queue_init(&queueDeps);
for (i = 0; i < (int)ARRAY_SIZE(allDepKeys); i++)
{
Queue queueTmp = {0};
solvable_lookup_deparray(pSolv, allDepKeys[i], &queueTmp, -1);
for (j = 0; j < queueTmp.count; j++)
{
queue_pushunique(&queueDeps, queueTmp.elements[j]);
}
queue_free(&queueTmp);
}
}
else if (depKey == REPOQUERY_DEP_KEY_REQUIRES_PRE)
{
solvable_lookup_deparray(pSolv, SOLVABLE_REQUIRES, &queueDeps, 1);
}
else
{
Id allDepKeyIds[] = {
ID_NULL,
SOLVABLE_PROVIDES,
SOLVABLE_OBSOLETES,
SOLVABLE_CONFLICTS,
SOLVABLE_REQUIRES,
SOLVABLE_RECOMMENDS,
SOLVABLE_SUGGESTS,
SOLVABLE_SUPPLEMENTS,
SOLVABLE_ENHANCES
};
solvable_lookup_deparray(pSolv, allDepKeyIds[depKey], &queueDeps, -1);
}
nNumDeps = queueDeps.count;
dwError = TDNFAllocateMemory(nNumDeps + 1, sizeof(char *), (void**)&ppszDependencies);
BAIL_ON_TDNF_ERROR(dwError);
for (i = 0; i < nNumDeps; i++)
{
pszDep = pool_id2str(pSack->pPool, queueDeps.elements[i]);
dwError = TDNFAllocateString(pszDep, &ppszDependencies[i]);
BAIL_ON_TDNF_ERROR(dwError);
}
*pppszDependencies = ppszDependencies;
cleanup:
queue_free(&queueDeps);
return dwError;
error:
TDNFFreeStringArray(ppszDependencies);
goto cleanup;
}
uint32_t
SolvGetFileListFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char ***pppszFiles)
{
uint32_t dwError = 0;
Solvable *pSolv = NULL;
Dataiterator di;
int i = 0, nCount = 0;
char **ppszFiles = NULL;
if(!pSack || !pppszFiles)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dataiterator_init(&di, pSack->pPool, pSolv->repo, dwPkgId, SOLVABLE_FILELIST, NULL,
SEARCH_FILES | SEARCH_COMPLETE_FILELIST);
while (dataiterator_step(&di)) {
nCount++;
}
dataiterator_free(&di);
dwError = TDNFAllocateMemory(nCount + 1, sizeof(char *), (void**)&ppszFiles);
BAIL_ON_TDNF_ERROR(dwError);
dataiterator_init(&di, pSack->pPool, pSolv->repo, dwPkgId, SOLVABLE_FILELIST, NULL,
SEARCH_FILES | SEARCH_COMPLETE_FILELIST);
while (dataiterator_step(&di)) {
dwError = TDNFAllocateString(di.kv.str, &ppszFiles[i++]);
BAIL_ON_TDNF_ERROR(dwError);
}
dataiterator_free(&di);
*pppszFiles = ppszFiles;
cleanup:
return dwError;
error:
TDNFFreeStringArray(ppszFiles);
goto cleanup;
}
uint32_t
SolvGetSourceFromId(
PSolvSack pSack,
uint32_t dwPkgId,
char **ppszName,
char **ppszArch,
char **ppszEVR
)
{
uint32_t dwError = 0;
const char* pszTmp = NULL;
Solvable *pSolv = NULL;
char *pszName = NULL;
char *pszArch = NULL;
char *pszEVR = NULL;
if(!pSack || !ppszName || !ppszArch || !ppszEVR)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_SOURCENAME);
if(!pszTmp)
{
/* if the name is the same we get NULL */
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_NAME);
}
if(!pszTmp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTmp, &pszName);
BAIL_ON_TDNF_ERROR(dwError);
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_SOURCEARCH);
if(!pszTmp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTmp, &pszArch);
BAIL_ON_TDNF_ERROR(dwError);
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_SOURCEEVR);
if(!pszTmp)
{
/* if the evr is the same we get NULL */
pszTmp = solvable_lookup_str(pSolv, SOLVABLE_EVR);
}
if(!pszTmp)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dwError = TDNFAllocateString(pszTmp, &pszEVR);
BAIL_ON_TDNF_ERROR(dwError);
*ppszName = pszName;
*ppszArch = pszArch;
*ppszEVR = pszEVR;
cleanup:
return dwError;
error:
*ppszName = NULL;
*ppszArch = NULL;
*ppszEVR = NULL;
TDNF_SAFE_FREE_MEMORY(pszName);
TDNF_SAFE_FREE_MEMORY(pszArch);
TDNF_SAFE_FREE_MEMORY(pszEVR);
goto cleanup;
}
uint32_t
SolvGetChangeLogFromId(
PSolvSack pSack,
uint32_t dwPkgId,
PTDNF_PKG_CHANGELOG_ENTRY *ppEntries
)
{
uint32_t dwError = 0;
Solvable *pSolv = NULL;
Dataiterator di;
PTDNF_PKG_CHANGELOG_ENTRY pEntry = NULL;
PTDNF_PKG_CHANGELOG_ENTRY pEntryNext = NULL;
PTDNF_PKG_CHANGELOG_ENTRY pEntries = NULL;
if(!pSack || !ppEntries)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pSolv = pool_id2solvable(pSack->pPool, dwPkgId);
if(!pSolv)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
dataiterator_init(&di, pSack->pPool, pSolv->repo, dwPkgId,
SOLVABLE_CHANGELOG_AUTHOR, NULL, 0);
dataiterator_prepend_keyname(&di, SOLVABLE_CHANGELOG);
while (dataiterator_step(&di)) {
dataiterator_setpos_parent(&di);
pEntryNext = pEntry;
dwError = TDNFAllocateMemory(sizeof(TDNF_PKG_CHANGELOG_ENTRY), 1, (void **)&pEntry);
BAIL_ON_TDNF_ERROR(dwError);
if (pEntries == NULL)
{
pEntries = pEntry;
}
pEntry->pNext = pEntryNext;
pEntry->timeTime =
(time_t)pool_lookup_num(pSack->pPool, SOLVID_POS,
SOLVABLE_CHANGELOG_TIME, 0);
dwError = TDNFAllocateString(
pool_lookup_str(pSack->pPool, SOLVID_POS, SOLVABLE_CHANGELOG_AUTHOR),
&pEntry->pszAuthor);
BAIL_ON_TDNF_ERROR(dwError);
dwError = TDNFAllocateString(
pool_lookup_str(pSack->pPool, SOLVID_POS, SOLVABLE_CHANGELOG_TEXT),
&pEntry->pszText);
BAIL_ON_TDNF_ERROR(dwError);
}
dataiterator_free(&di);
*ppEntries = pEntry;
cleanup:
return dwError;
error:
for (pEntry = pEntries; pEntry; pEntry = pEntryNext)
{
pEntryNext = pEntry->pNext;
TDNFFreeChangeLogEntry(pEntry);
}
goto cleanup;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2018 VMware, Inc. All Rights Reserved.
* Copyright (C) 2015-2021 VMware, Inc. All Rights Reserved.
*
* Licensed under the GNU Lesser General Public License v2.1 (the "License");
* you may not use this file except in compliance with the License. The terms
@ -177,6 +177,7 @@ SolvCreateQuery(
queue_init(&pQuery->queueJob);
queue_init(&pQuery->queueRepoFilter);
queue_init(&pQuery->queueResult);
*ppQuery = pQuery;
cleanup:
@ -724,7 +725,6 @@ SolvApplyListQuery(
}
}
cleanup:
queue_free(&queueTmp);
return dwError;
@ -1114,3 +1114,297 @@ cleanup:
error:
goto cleanup;
}
uint32_t
SolvApplyDepsFilter(
PSolvQuery pQuery,
char **ppszDeps,
REPOQUERY_WHAT_KEY whatKey)
{
uint32_t dwError = 0;
Queue queueDeps = {0};
Queue queueFiltered = {0};
int i, j;
Id idDep;
if(!pQuery || !pQuery->pSack || !ppszDeps)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
/* convert string dep array to id queue */
queue_init(&queueDeps);
for(i = 0; ppszDeps[i] != NULL; i++)
{
idDep = pool_str2id(pQuery->pSack->pPool, ppszDeps[i], 0);
/* if it's not found, nothing can depend on it */
if (idDep)
{
queue_push(&queueDeps, idDep);
}
}
queue_init(&queueFiltered);
for (j = 0; j < pQuery->queueResult.count; j++)
{
Id idPkg = pQuery->queueResult.elements[j];
Solvable *pSolvable = pool_id2solvable(pQuery->pSack->pPool, idPkg);
if(!pSolvable)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
for (i = 0; i < queueDeps.count; i++)
{
idDep = queueDeps.elements[i];
if (whatKey != REPOQUERY_WHAT_KEY_DEPENDS)
{
Id allDepKeyIds[] = {
SOLVABLE_PROVIDES,
SOLVABLE_OBSOLETES,
SOLVABLE_CONFLICTS,
SOLVABLE_REQUIRES,
SOLVABLE_RECOMMENDS,
SOLVABLE_SUGGESTS,
SOLVABLE_SUPPLEMENTS,
SOLVABLE_ENHANCES
};
/* single dependency type */
if (solvable_matchesdep(pSolvable, allDepKeyIds[whatKey], idDep, 0))
{
queue_push(&queueFiltered, idPkg);
break;
}
}
else
{
size_t k;
Id allDepKeys[] = {
SOLVABLE_REQUIRES,
SOLVABLE_RECOMMENDS,
SOLVABLE_SUGGESTS,
SOLVABLE_SUPPLEMENTS,
SOLVABLE_ENHANCES
};
for (k = 0; k < ARRAY_SIZE(allDepKeys); k++)
{
if (solvable_matchesdep(pSolvable, allDepKeys[k], idDep, 0))
{
queue_push(&queueFiltered, idPkg);
break;
}
}
if (k < ARRAY_SIZE(allDepKeys))
{
break;
}
}
}
}
queue_free(&pQuery->queueResult);
pQuery->queueResult = queueFiltered;
cleanup:
queue_free(&queueDeps);
return dwError;
error:
queue_free(&queueFiltered);
goto cleanup;
}
uint32_t
SolvApplyExtrasFilter(
PSolvQuery pQuery)
{
uint32_t dwError = 0;
Pool *pPool;
Queue queueExtras = {0};
int i, j;
if(!pQuery)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pPool = pQuery->pSack->pPool;
queue_init(&queueExtras);
/* Outer loop iterates over all installed solvables,
inner loop over all solvables that are *not* installed.
If we don't find a match, it's an extra package */
for (i = 0; i < pQuery->queueResult.count; i++)
{
Id idPkg = pQuery->queueResult.elements[i];
Solvable *pSolvable = pool_id2solvable(pPool, idPkg);
if(!pSolvable)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
if (pSolvable->repo == pPool->installed)
{
int nFound = 0;
for (j = 0; j < pQuery->queueResult.count; j++)
{
if (i != j)
{
Id idPkg2 = pQuery->queueResult.elements[j];
Solvable *pSolvable2 = pool_id2solvable(pPool, idPkg2);
if(!pSolvable2)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
if (pSolvable2->repo == pPool->installed)
{
continue;
}
if (pSolvable2->name == pSolvable->name &&
pSolvable2->arch == pSolvable->arch &&
pSolvable2->evr == pSolvable->evr)
{
nFound = 1;
}
}
}
if (!nFound)
{
queue_push(&queueExtras, idPkg);
}
}
}
queue_free(&pQuery->queueResult);
pQuery->queueResult = queueExtras;
cleanup:
return dwError;
error:
queue_free(&queueExtras);
goto cleanup;
}
uint32_t
SolvApplyDuplicatesFilter(
PSolvQuery pQuery)
{
uint32_t dwError = 0;
Pool *pPool;
Queue queueDuplicates = {0};
int i, j;
if(!pQuery)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pPool = pQuery->pSack->pPool;
queue_init(&queueDuplicates);
for (i = 0; i < pQuery->queueResult.count; i++)
{
Id idPkg = pQuery->queueResult.elements[i];
Solvable *pSolvable = pool_id2solvable(pPool, idPkg);
if(!pSolvable)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
if (pSolvable->repo == pPool->installed)
{
int nFound = 0;
/* no need to compare b with a if we already compared b with a,
so we can start with j = i + 1 */
for (j = i + 1; j < pQuery->queueResult.count; j++)
{
Id idPkg2 = pQuery->queueResult.elements[j];
Solvable *pSolvable2 = pool_id2solvable(pPool, idPkg2);
if(!pSolvable2)
{
dwError = ERROR_TDNF_NO_DATA;
BAIL_ON_TDNF_ERROR(dwError);
}
if (pSolvable2->repo != pPool->installed)
{
continue;
}
if (pSolvable2->name == pSolvable->name &&
pSolvable2->arch == pSolvable->arch)
{
nFound = 1;
}
}
if (nFound)
{
queue_push(&queueDuplicates, idPkg);
}
}
}
queue_free(&pQuery->queueResult);
pQuery->queueResult = queueDuplicates;
cleanup:
return dwError;
error:
queue_free(&queueDuplicates);
goto cleanup;
}
uint32_t
SolvApplyFileProvidesFilter(
PSolvQuery pQuery,
char *pszFile)
{
uint32_t dwError = 0;
Pool *pool;
Queue queueFiltered = {0};
Dataiterator di;
int i;
if(!pQuery || IsNullOrEmptyString(pszFile))
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
pool = pQuery->pSack->pPool;
queue_init(&queueFiltered);
for (i = 0; i < pQuery->queueResult.count; i++)
{
Id idPkg = pQuery->queueResult.elements[i];
dataiterator_init(&di, pool, NULL, idPkg, SOLVABLE_FILELIST, pszFile,
SEARCH_FILES | SEARCH_STRING);
/* using 'if' instead of 'while' because one match is enough */
if (dataiterator_step(&di)) {
queue_push(&queueFiltered, idPkg);
}
dataiterator_free(&di);
}
queue_free(&pQuery->queueResult);
pQuery->queueResult = queueFiltered;
cleanup:
return dwError;
error:
queue_free(&queueFiltered);
goto cleanup;
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2015 VMware, Inc. All Rights Reserved.
* Copyright (C) 2015-2021 VMware, Inc. All Rights Reserved.
*
* Licensed under the GNU Lesser General Public License v2.1 (the "License");
* you may not use this file except in compliance with the License. The terms
@ -150,6 +150,43 @@ error:
goto cleanup;
}
uint32_t
SolvLoadRepomdOther(
Repo* pRepo,
const char* pszOther
)
{
uint32_t dwError = 0;
FILE *fp = NULL;
if( !pRepo || IsNullOrEmptyString(pszOther))
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
fp = solv_xfopen(pszOther, "r");
if (fp == NULL)
{
dwError = ERROR_TDNF_SOLV_IO;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
if (repo_add_rpmmd(pRepo, fp, 0, REPO_EXTEND_SOLVABLES))
{
dwError = ERROR_TDNF_SOLV_IO;
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
cleanup:
if(fp != NULL)
{
fclose(fp);
}
return dwError;
error:
goto cleanup;
}
uint32_t
SolvReadYumRepo(
Repo *pRepo,
@ -157,7 +194,8 @@ SolvReadYumRepo(
const char *pszRepomd,
const char *pszPrimary,
const char *pszFilelists,
const char *pszUpdateinfo
const char *pszUpdateinfo,
const char *pszOther
)
{
uint32_t dwError = 0;
@ -167,7 +205,6 @@ SolvReadYumRepo(
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
dwError = SolvLoadRepomd(pRepo, pszRepomd);
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
@ -187,6 +224,12 @@ SolvReadYumRepo(
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
if(pszOther)
{
dwError = SolvLoadRepomdOther(pRepo, pszOther);
BAIL_ON_TDNF_LIBSOLV_ERROR(dwError);
}
cleanup:

View File

@ -67,4 +67,5 @@
{ERROR_TDNF_CLI_SETOPT_NO_EQUALS, "ERROR_TDNF_CLI_SETOPT_NO_EQUALS", "Missing equal sign in setopt argument. setopt requires an argument of the form key=value."}, \
{ERROR_TDNF_CLI_NO_SUCH_CMD, "ERROR_TDNF_CLI_NO_SUCH_CMD", "Please check your command"}, \
{ERROR_TDNF_CLI_DOWNLOADDIR_REQUIRES_DOWNLOADONLY, "ERROR_TDNF_CLI_DOWNLOADDIR_REQUIRES_DOWNLOADONLY", "--downloaddir requires --downloadonly"}, \
{ERROR_TDNF_CLI_ONE_DEP_ONLY, "ERROR_TDNF_CLI_ONE_DEP_ONLY", "only one dependency allowed"}, \
};

View File

@ -23,6 +23,7 @@ add_library(${LIB_TDNF_CLI} SHARED
parselistargs.c
parserepolistargs.c
parsereposyncargs.c
parserepoqueryargs.c
parseupdateinfo.c
updateinfocmd.c
)

View File

@ -485,6 +485,128 @@ error:
goto cleanup;
}
uint32_t
TDNFCliRepoQueryCommand(
PTDNF_CLI_CONTEXT pContext,
PTDNF_CMD_ARGS pCmdArgs
)
{
uint32_t dwError = 0;
uint32_t dwCount = 0;
PTDNF_REPOQUERY_ARGS pRepoqueryArgs;
PTDNF_PKG_INFO pPkgInfo = NULL;
PTDNF_PKG_INFO pPkgInfos = NULL;
int nCount = 0, i, j, k;
char **ppszLines = NULL;
if(!pContext || !pContext->hTdnf || !pCmdArgs || !pContext->pFnRepoQuery)
{
dwError = ERROR_TDNF_CLI_INVALID_ARGUMENT;
BAIL_ON_CLI_ERROR(dwError);
}
dwError = TDNFCliParseRepoQueryArgs(pCmdArgs, &pRepoqueryArgs);
BAIL_ON_CLI_ERROR(dwError);
dwError = pContext->pFnRepoQuery(pContext, pRepoqueryArgs, &pPkgInfos, &dwCount);
BAIL_ON_CLI_ERROR(dwError);
for (i = 0; i < (int)dwCount; i++)
{
pPkgInfo = &pPkgInfos[i];
if (pPkgInfo->ppszDependencies)
{
for (j = 0; pPkgInfo->ppszDependencies[j]; j++);
nCount += j;
}
else if (pPkgInfo->ppszFileList)
{
for (j = 0; pPkgInfo->ppszFileList[j]; j++);
nCount += j;
}
else if (pPkgInfo->pChangeLogEntries)
{
PTDNF_PKG_CHANGELOG_ENTRY pEntry;
for (pEntry = pPkgInfo->pChangeLogEntries; pEntry; pEntry = pEntry->pNext)
{
char szTime[20] = {0};
if (strftime(szTime, 20, "%a %b %d %Y", localtime(&pEntry->timeTime)))
{
pr_crit("%s %s\n%s\n",
szTime,
pEntry->pszAuthor,
pEntry->pszText);
}
else
{
dwError = ERROR_TDNF_CLI_INVALID_ARGUMENT;
BAIL_ON_CLI_ERROR(dwError);
}
}
}
else if (pPkgInfo->pszSourcePkg)
{
pr_crit("%s\n", pPkgInfo->pszSourcePkg);
}
else
{
pr_crit("%s-%s-%s.%s\n",
pPkgInfo->pszName,
pPkgInfo->pszVersion,
pPkgInfo->pszRelease,
pPkgInfo->pszArch);
}
}
if (nCount > 0)
{
dwError = TDNFAllocateMemory(nCount + 1, sizeof(char *), (void**)&ppszLines);
BAIL_ON_CLI_ERROR(dwError);
for (k = 0, i = 0; i < (int)dwCount; i++)
{
pPkgInfo = &pPkgInfos[i];
if (pPkgInfo->ppszDependencies)
{
for (j = 0; pPkgInfo->ppszDependencies[j]; j++)
{
ppszLines[k++] = pPkgInfo->ppszDependencies[j];
}
}
else if (pPkgInfo->ppszFileList)
{
for (j = 0; pPkgInfo->ppszFileList[j]; j++)
{
ppszLines[k++] = pPkgInfo->ppszFileList[j];
}
}
}
dwError = TDNFStringArraySort(ppszLines);
BAIL_ON_CLI_ERROR(dwError);
for (j = 0; ppszLines[j]; j++)
{
if (j == 0 || strcmp(ppszLines[j], ppszLines[j-1]))
{
pr_crit("%s\n", ppszLines[j]);
}
}
}
cleanup:
if(pPkgInfos)
{
TDNFFreePackageInfoArray(pPkgInfos, dwCount);
}
TDNF_CLI_SAFE_FREE_MEMORY(ppszLines);
TDNFCliFreeRepoQueryArgs(pRepoqueryArgs);
return dwError;
error:
goto cleanup;
}
uint32_t
TDNFCliCheckUpdateCommand(
PTDNF_CLI_CONTEXT pContext,

View File

@ -61,6 +61,33 @@ TDNFCliShowHelp(
pr_crit(" [--downloadonly]\n");
pr_crit(" [--downloaddir=<directory>]\n");
pr_crit("\n");
pr_crit("repoquery select options:\n");
pr_crit(" [--available\n");
pr_crit(" [--duplicates\n");
pr_crit(" [--extras\n");
pr_crit(" [--file <file>\n");
pr_crit(" [--installed\n");
pr_crit(" [--whatdepends <capability1>[,<capability2>[..]]]\n");
pr_crit(" [--whatrequires <capability1>[,<capability2>[..]]]\n");
pr_crit(" [--whatenhances <capability1>[,<capability2>[..]]]\n");
pr_crit(" [--whatobsoletes <capability1>[,<capability2>[..]]]\n");
pr_crit(" [--whatprovides <capability1>[,<capability2>[..]]]\n");
pr_crit(" [--whatrecommends <capability1>[,<capability2>[..]]]\n");
pr_crit(" [--whatrequires <capability1>[,<capability2>[..]]]\n");
pr_crit(" [--whatsuggests <capability1>[,<capability2>[..]]]\n");
pr_crit(" [--whatsupplements <capability1>[,<capability2>[..]]]\n");
pr_crit("repoquery query options:\n");
pr_crit(" [--depends\n");
pr_crit(" [--enhances\n");
pr_crit(" [--list\n");
pr_crit(" [--obsoletes\n");
pr_crit(" [--provides\n");
pr_crit(" [--recommends\n");
pr_crit(" [--requires\n");
pr_crit(" [--requires-pre\n");
pr_crit(" [--suggests\n");
pr_crit(" [--supplements\n");
pr_crit("\n");
pr_crit("reposync options:\n");
pr_crit(" [--arch=<arch> [--arch=<arch> [..]]\n");
pr_crit(" [--delete]\n");
@ -92,6 +119,7 @@ TDNFCliShowHelp(
pr_crit("remove Remove a package or packages from your system\n");
pr_crit("reinstall reinstall a package\n");
pr_crit("repolist Display the configured software repositories\n");
pr_crit("repoquery Query repositories\n");
pr_crit("reposync Download all packages from one or more repositories to a directory\n");
pr_crit("search Search package details for the given string\n");
pr_crit("update Upgrade a package or packages on your system (same as 'upgrade')\n");

View File

@ -37,7 +37,36 @@ static SetOptArgs OptValTable[] = {
{CMDOPT_KEYVALUE, "skipconflicts;skipobsoletes;skipsignature;skipdigest;"
"noplugins;reboot-required;security;"
"delete;download-metadata;gpgcheck;newest-only;norepopath;source;urls",
"1"}
"1"},
{CMDOPT_KEYVALUE, "available", "1"},
{CMDOPT_KEYVALUE, "installed", "1"},
{CMDOPT_KEYVALUE, "extras", "1"},
{CMDOPT_KEYVALUE, "changelogs", "1"},
{CMDOPT_KEYVALUE, "duplicates", "1"},
/* "depends" must be before "whatdepends",
same for the others with partial string matches */
{CMDOPT_KEYVALUE, "depends", "1"},
{CMDOPT_KEYVALUE, "provides", "1"},
{CMDOPT_KEYVALUE, "obsoletes", "1"},
{CMDOPT_KEYVALUE, "conflicts", "1"},
{CMDOPT_KEYVALUE, "requires", "1"},
{CMDOPT_KEYVALUE, "recommends", "1"},
{CMDOPT_KEYVALUE, "suggests", "1"},
{CMDOPT_KEYVALUE, "supplements", "1"},
{CMDOPT_KEYVALUE, "enhances", "1"},
{CMDOPT_KEYVALUE, "requires-pre", "1"},
{CMDOPT_KEYVALUE, "list", "1"},
{CMDOPT_KEYVALUE, "upgrades", "1"},
{CMDOPT_KEYVALUE, "file", NULL},
{CMDOPT_KEYVALUE, "whatdepends", NULL},
{CMDOPT_KEYVALUE, "whatprovides", NULL},
{CMDOPT_KEYVALUE, "whatobsoletes", NULL},
{CMDOPT_KEYVALUE, "whatconflicts", NULL},
{CMDOPT_KEYVALUE, "whatrequires", NULL},
{CMDOPT_KEYVALUE, "whatrecommends", NULL},
{CMDOPT_KEYVALUE, "whatsuggests", NULL},
{CMDOPT_KEYVALUE, "whatsupplements", NULL},
{CMDOPT_KEYVALUE, "whatenhances", NULL},
};
static TDNF_CMD_ARGS _opt = {0};
@ -94,6 +123,36 @@ static struct option pstOptions[] =
{"download-path", required_argument, 0, 0},
{"source", no_argument, 0, 0},
{"urls", no_argument, 0, 0},
// repoquery option
// repoquery select options
{"file", required_argument, 0, 0},
{"whatdepends", required_argument, 0, 0},
{"whatprovides", required_argument, 0, 0},
{"whatobsoletes", required_argument, 0, 0},
{"whatconflicts", required_argument, 0, 0},
{"whatrequires", required_argument, 0, 0},
{"whatrecommends",required_argument, 0, 0},
{"whatsuggests", required_argument, 0, 0},
{"whatsupplements", required_argument, 0, 0},
{"whatenhances", required_argument, 0, 0},
// repoquery query options
{"available", no_argument, 0, 0},
{"changelogs", no_argument, 0, 0},
{"installed", no_argument, 0, 0},
{"extras", no_argument, 0, 0},
{"duplicates", no_argument, 0, 0},
{"depends", no_argument, 0, 0},
{"provides", no_argument, 0, 0},
{"obsoletes", no_argument, 0, 0},
{"conflicts", no_argument, 0, 0},
{"requires", no_argument, 0, 0},
{"recommends", no_argument, 0, 0},
{"suggests", no_argument, 0, 0},
{"supplements", no_argument, 0, 0},
{"enhances", no_argument, 0, 0},
{"requires-pre", no_argument, 0, 0},
{"list", no_argument, 0, 0},
{"upgrades", no_argument, 0, 0},
{0, 0, 0, 0}
};

View File

@ -0,0 +1,200 @@
/*
* Copyright (C) 2021 VMware, Inc. All Rights Reserved.
*
* Licensed under the GNU Lesser General Public License v2.1 (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.
*/
/*
* Module : parserepoqueryargs.c
*
* Abstract :
*
* tdnf
*
* command line tools
*/
#include "includes.h"
char *depKeys[] = {
"provides",
"obsoletes",
"conflicts",
"requires",
"recommends",
"suggests",
"supplements",
"enhances",
"depends",
"requires-pre"
};
char *whatKeys[REPOQUERY_WHAT_KEY_COUNT] = {
"whatprovides",
"whatobsoletes",
"whatconflicts",
"whatrequires",
"whatrecommends",
"whatsuggests",
"whatsupplements",
"whatenhances",
"whatdepends"
};
uint32_t
TDNFCliParseRepoQueryArgs(
PTDNF_CMD_ARGS pArgs,
PTDNF_REPOQUERY_ARGS* ppRepoqueryArgs
)
{
uint32_t dwError = 0;
PTDNF_REPOQUERY_ARGS pRepoqueryArgs = NULL;
PTDNF_CMD_OPT pSetOpt = NULL;
if (!pArgs || !ppRepoqueryArgs)
{
dwError = ERROR_TDNF_CLI_INVALID_ARGUMENT;
BAIL_ON_CLI_ERROR(dwError);
}
dwError = TDNFAllocateMemory(
1,
sizeof(TDNF_REPOQUERY_ARGS),
(void**) &pRepoqueryArgs);
BAIL_ON_CLI_ERROR(dwError);
dwError = TDNFAllocateMemory(
REPOQUERY_WHAT_KEY_COUNT,
sizeof(char **),
(void **) &pRepoqueryArgs->pppszWhatKeys);
for (pSetOpt = pArgs->pSetOpt;
pSetOpt;
pSetOpt = pSetOpt->pNext)
{
if(pSetOpt->nType == CMDOPT_KEYVALUE)
{
if (strcasecmp(pSetOpt->pszOptName, "file") == 0)
{
dwError = TDNFAllocateString(pSetOpt->pszOptValue,
&pRepoqueryArgs->pszFile);
BAIL_ON_CLI_ERROR(dwError);
}
else if (strcasecmp(pSetOpt->pszOptName, "changelogs") == 0)
{
pRepoqueryArgs->nChangeLogs = 1;
}
else if (strcasecmp(pSetOpt->pszOptName, "available") == 0)
{
pRepoqueryArgs->nAvailable = 1;
}
else if (strcasecmp(pSetOpt->pszOptName, "installed") == 0)
{
pRepoqueryArgs->nInstalled = 1;
}
else if (strcasecmp(pSetOpt->pszOptName, "extras") == 0)
{
pRepoqueryArgs->nExtras = 1;
}
else if (strcasecmp(pSetOpt->pszOptName, "duplicates") == 0)
{
pRepoqueryArgs->nDuplicates = 1;
}
else if (strcasecmp(pSetOpt->pszOptName, "list") == 0)
{
pRepoqueryArgs->nList = 1;
}
else if (strcasecmp(pSetOpt->pszOptName, "source") == 0)
{
pRepoqueryArgs->nSource = 1;
}
else if (strcasecmp(pSetOpt->pszOptName, "upgrades") == 0)
{
pRepoqueryArgs->nUpgrades = 1;
}
else
{
REPOQUERY_DEP_KEY depKey;
for (depKey = 0; depKey < REPOQUERY_DEP_KEY_COUNT - 1; depKey++)
{
if (strcasecmp(pSetOpt->pszOptName, depKeys[depKey]) == 0)
{
if (pRepoqueryArgs->depKey == 0)
{
pRepoqueryArgs->depKey = depKey + 1;
break;
}
else
{
dwError = ERROR_TDNF_CLI_ONE_DEP_ONLY;
BAIL_ON_CLI_ERROR(dwError);
}
}
}
if (depKey == REPOQUERY_DEP_KEY_COUNT - 1) /* not found in loop above */
{
REPOQUERY_WHAT_KEY whatKey;
for (whatKey = 0; whatKey < REPOQUERY_WHAT_KEY_COUNT; whatKey++)
{
if (strcasecmp(pSetOpt->pszOptName, whatKeys[whatKey]) == 0)
{
dwError = TDNFSplitStringToArray(pSetOpt->pszOptValue,
",",
&pRepoqueryArgs->pppszWhatKeys[whatKey]);
BAIL_ON_CLI_ERROR(dwError);
break;
}
}
} /* if (i == REPOQUERY_WHAT_KEY_COUNT) */
} /* if (strcasecmp(pSetOpt->pszOptName, ... */
} /* if(pSetOpt->nType == CMDOPT_KEYVALUE) */
} /* for (pSetOpt ... */
if(pArgs->nCmdCount > 2)
{
dwError = ERROR_TDNF_CLI_INVALID_ARGUMENT;
BAIL_ON_CLI_ERROR(dwError);
}
if(pArgs->nCmdCount > 1)
{
dwError = TDNFAllocateString(pArgs->ppszCmds[1],
&pRepoqueryArgs->pszSpec);
BAIL_ON_CLI_ERROR(dwError);
}
*ppRepoqueryArgs = pRepoqueryArgs;
cleanup:
return dwError;
error:
TDNFCliFreeRepoQueryArgs(pRepoqueryArgs);
goto cleanup;
}
void
TDNFCliFreeRepoQueryArgs(
PTDNF_REPOQUERY_ARGS pRepoqueryArgs
)
{
if(pRepoqueryArgs)
{
if (pRepoqueryArgs->pppszWhatKeys)
{
int i;
for (i = 0; i < REPOQUERY_WHAT_KEY_COUNT; i++)
{
TDNF_CLI_SAFE_FREE_STRINGARRAY(pRepoqueryArgs->pppszWhatKeys[i]);
TDNFFreeMemory(pRepoqueryArgs->pppszWhatKeys[i]);
}
TDNFFreeMemory(pRepoqueryArgs->pppszWhatKeys);
}
TDNF_CLI_SAFE_FREE_MEMORY(pRepoqueryArgs->pszFile);
TDNF_CLI_SAFE_FREE_MEMORY(pRepoqueryArgs->pszSpec);
TDNF_CLI_SAFE_FREE_MEMORY(pRepoqueryArgs);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2018 VMware, Inc. All Rights Reserved.
* Copyright (C) 2015-2021 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
@ -56,6 +56,7 @@ int main(int argc, char* argv[])
{"remove", TDNFCliEraseCommand},
{"repolist", TDNFCliRepoListCommand},
{"reposync", TDNFCliRepoSyncCommand},
{"repoquery", TDNFCliRepoQueryCommand},
{"search", TDNFCliSearchCommand},
{"update", TDNFCliUpgradeCommand},
{"update-to", TDNFCliUpgradeCommand},
@ -104,6 +105,7 @@ int main(int argc, char* argv[])
_context.pFnProvides = TDNFCliInvokeProvides;
_context.pFnRepoList = TDNFCliInvokeRepoList;
_context.pFnRepoSync = TDNFCliInvokeRepoSync;
_context.pFnRepoQuery = TDNFCliInvokeRepoQuery;
/*
* Alter and resolve will address commands like
@ -455,6 +457,17 @@ TDNFCliInvokeRepoSync(
return TDNFRepoSync(pContext->hTdnf, pRepoSyncArgs);
}
uint32_t
TDNFCliInvokeRepoQuery(
PTDNF_CLI_CONTEXT pContext,
PTDNF_REPOQUERY_ARGS pRepoQueryArgs,
PTDNF_PKG_INFO *ppPkgInfos,
uint32_t *pdwCount
)
{
return TDNFRepoQuery(pContext->hTdnf, pRepoQueryArgs, ppPkgInfos, pdwCount);
}
uint32_t
TDNFCliInvokeResolve(
PTDNF_CLI_CONTEXT pContext,

View File

@ -97,6 +97,14 @@ TDNFCliInvokeRepoSync(
PTDNF_REPOSYNC_ARGS pReposyncArgs
);
uint32_t
TDNFCliInvokeRepoQuery(
PTDNF_CLI_CONTEXT pContext,
PTDNF_REPOQUERY_ARGS pRepoqueryArgs,
PTDNF_PKG_INFO *ppPkgInfos,
uint32_t *pdwCount
);
uint32_t
TDNFCliInvokeResolve(
PTDNF_CLI_CONTEXT pContext,
@ -314,6 +322,13 @@ TDNFCliParseRepoSyncArgs(
PTDNF_REPOSYNC_ARGS* ppReposyncArgs
);
//parserepoqueryargs.c
uint32_t
TDNFCliParseRepoQueryArgs(
PTDNF_CMD_ARGS pCmdArgs,
PTDNF_REPOQUERY_ARGS* ppRepoqueryArgs
);
//parseupdateinfo.c
uint32_t
ParseMode(