Skip to content

Commit

Permalink
Add total download size reporting to installs.
Browse files Browse the repository at this point in the history
  • Loading branch information
prestonsn committed Jul 11, 2022
1 parent e5044ff commit 0a98a83
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 7 deletions.
3 changes: 3 additions & 0 deletions client/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,9 @@ TDNFResolve(
pSolvedPkgInfo->pPkgsToDowngrade ||
pSolvedPkgInfo->pPkgsToReinstall;

dwError = TDNFCalculateTotalDownloadSize(pSolvedPkgInfo);
BAIL_ON_TDNF_ERROR(dwError);

pSolvedPkgInfo->ppszPkgsNotResolved = ppszPkgsNotResolved;
*ppSolvedPkgInfo = pSolvedPkgInfo;

Expand Down
14 changes: 14 additions & 0 deletions client/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,20 @@ typedef enum
"ERROR_TDNF_DOWNGRADE_NOT_ALLOWED",\
"a downgrade is not allowed below the minimal version. Check 'minversions' in the configuration."},\
{ERROR_TDNF_PERM, "ERROR_TDNF_PERM", "Operation not permitted. You have to be root."},\
{ERROR_TDNF_INVALID_PARAMETER, "ERROR_TDNF_INVALID_PARAMETER", "Invalid argument."},\
{ERROR_TDNF_OUT_OF_MEMORY, "ERROR_TDNF_OUT_OF_MEMORY", "Out of memory."},\
{ERROR_TDNF_NO_DATA, "ERROR_TDNF_NO_DATA", "No data available."},\
{ERROR_TDNF_FILE_NOT_FOUND, "ERROR_TDNF_FILE_NOT_FOUND", "File not found."},\
{ERROR_TDNF_ACCESS_DENIED, "ERROR_TDNF_ACCESS_DENIED", "Permission denied."},\
{ERROR_TDNF_ALREADY_EXISTS, "ERROR_TDNF_ALREADY_EXISTS", "File exists."},\
{ERROR_TDNF_INVALID_ADDRESS, "ERROR_TDNF_INVALID_ADDRESS", "Bad address."},\
{ERROR_TDNF_CALL_INTERRUPTED, "ERROR_TDNF_CALL_INTERRUPTED", "Interrupted syscall."},\
{ERROR_TDNF_FILESYS_IO, "ERROR_TDNF_FILESYS_IO", "Filesystem I/O error."},\
{ERROR_TDNF_SYM_LOOP, "ERROR_TDNF_SYM_LOOP", "Too many links."},\
{ERROR_TDNF_NAME_TOO_LONG, "ERROR_TDNF_NAME_TOO_LONG", "File name too long."},\
{ERROR_TDNF_CALL_NOT_SUPPORTED, "ERROR_TDNF_CALL_NOT_SUPPORTED", "Invalid syscall number."},\
{ERROR_TDNF_INVALID_DIR, "ERROR_TDNF_INVALID_DIR", "Not a directory."},\
{ERROR_TDNF_OVERFLOW, "ERROR_TDNF_OVERFLOW", "Value too large for defined data type."},\
{ERROR_TDNF_OPT_NOT_FOUND, "ERROR_TDNF_OPT_NOT_FOUND", "A required option was not found"},\
{ERROR_TDNF_OPERATION_ABORTED, "ERROR_TDNF_OPERATION_ABORTED", "Operation aborted."},\
{ERROR_TDNF_INVALID_INPUT, "ERROR_TDNF_INVALID_INPUT", "Invalid input."},\
Expand Down
65 changes: 65 additions & 0 deletions client/packageutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,22 @@ TDNFPopulatePkgInfoArray(
&pPkgInfo->dwInstallSizeBytes);
BAIL_ON_TDNF_ERROR(dwError);

dwError = SolvGetPkgDownloadSizeFromId(
pSack,
dwPkgId,
&pPkgInfo->dwDownloadSizeBytes);
BAIL_ON_TDNF_ERROR(dwError);

dwError = TDNFUtilsFormatSize(
pPkgInfo->dwInstallSizeBytes,
&pPkgInfo->pszFormattedSize);
BAIL_ON_TDNF_ERROR(dwError);

dwError = TDNFUtilsFormatSize(
pPkgInfo->dwDownloadSizeBytes,
&pPkgInfo->pszFormattedDownloadSize);
BAIL_ON_TDNF_ERROR(dwError);

dwError = SolvGetPkgSummaryFromId(
pSack,
dwPkgId,
Expand Down Expand Up @@ -933,6 +944,50 @@ TDNFCheckProtectedPkgs(
return dwError;
}

uint32_t
TDNFCalculateTotalDownloadSize(
PTDNF_SOLVED_PKG_INFO pSolvedPkgInfo
)
{
uint32_t dwError = 0;
uint32_t dwTotalDownloadSizeBytes = 0;
uint8_t byPkgIndex = 0;
PTDNF_PKG_INFO pPkgInfo = NULL;

if(!pSolvedPkgInfo)
{
dwError = ERROR_TDNF_INVALID_PARAMETER;
BAIL_ON_TDNF_ERROR(dwError);
}

if(!pSolvedPkgInfo->nNeedDownload)
{
pSolvedPkgInfo->dwTotalDownloadSizeBytes = 0;
BAIL_ON_TDNF_ERROR(dwError);
}

PTDNF_PKG_INFO ppPkgsNeedDownload[4] = {
pSolvedPkgInfo->pPkgsToInstall,
pSolvedPkgInfo->pPkgsToDowngrade,
pSolvedPkgInfo->pPkgsToUpgrade,
pSolvedPkgInfo->pPkgsToReinstall
};

for (byPkgIndex = 0; byPkgIndex < ARRAY_SIZE(ppPkgsNeedDownload); byPkgIndex++)
{
pPkgInfo = ppPkgsNeedDownload[byPkgIndex];
while(pPkgInfo) {
dwTotalDownloadSizeBytes += pPkgInfo->dwDownloadSizeBytes;
pPkgInfo = pPkgInfo->pNext;
}
}

pSolvedPkgInfo->dwTotalDownloadSizeBytes = dwTotalDownloadSizeBytes;

error:
return dwError;
}

uint32_t
TDNFPopulatePkgInfos(
PSolvSack pSack,
Expand Down Expand Up @@ -1004,14 +1059,24 @@ TDNFPopulatePkgInfos(
pSack,
dwPkgId,
&pPkgInfo->dwInstallSizeBytes);
BAIL_ON_TDNF_ERROR(dwError);

dwError = SolvGetPkgDownloadSizeFromId(
pSack,
dwPkgId,
&pPkgInfo->dwDownloadSizeBytes);
BAIL_ON_TDNF_ERROR(dwError);

dwError = TDNFUtilsFormatSize(
pPkgInfo->dwInstallSizeBytes,
&pPkgInfo->pszFormattedSize);
BAIL_ON_TDNF_ERROR(dwError);

dwError = TDNFUtilsFormatSize(
pPkgInfo->dwDownloadSizeBytes,
&pPkgInfo->pszFormattedDownloadSize);
BAIL_ON_TDNF_ERROR(dwError);

pPkgInfo->pNext = pPkgInfos;
pPkgInfos = pPkgInfo;
pPkgInfo = NULL;
Expand Down
5 changes: 5 additions & 0 deletions client/prototypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,11 @@ TDNFCheckProtectedPkgs(
PTDNF_SOLVED_PKG_INFO pSolvedPkgInfo
);

uint32_t
TDNFCalculateTotalDownloadSize(
PTDNF_SOLVED_PKG_INFO pSolvedPkgInfo
);

uint32_t
TDNFPopulatePkgInfoArrayDependencies(
PSolvSack pSack,
Expand Down
3 changes: 1 addition & 2 deletions common/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,7 @@ TDNFUtilsFormatSize(
dwError = TDNFAllocateMemory(1, nMaxSize, (void**)&pszFormattedSize);
BAIL_ON_TDNF_ERROR(dwError);

if(sprintf(pszFormattedSize, "%6.2f%c %lu", dSize, pszSizes[nIndex],
(unsigned long)unSize) < 0)
if(sprintf(pszFormattedSize, "%6.2f%c", dSize, pszSizes[nIndex]) < 0)
{
dwError = ERROR_TDNF_OUT_OF_MEMORY;
BAIL_ON_TDNF_ERROR(dwError);
Expand Down
8 changes: 8 additions & 0 deletions include/tdnferror.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ extern "C" {
#define ERROR_TDNF_FILE_NOT_FOUND (ERROR_TDNF_SYSTEM_BASE + ENOENT)
#define ERROR_TDNF_ACCESS_DENIED (ERROR_TDNF_SYSTEM_BASE + EACCES)
#define ERROR_TDNF_ALREADY_EXISTS (ERROR_TDNF_SYSTEM_BASE + EEXIST)
#define ERROR_TDNF_INVALID_ADDRESS (ERROR_TDNF_SYSTEM_BASE + EFAULT)
#define ERROR_TDNF_CALL_INTERRUPTED (ERROR_TDNF_SYSTEM_BASE + EINTR)
#define ERROR_TDNF_FILESYS_IO (ERROR_TDNF_SYSTEM_BASE + EIO)
#define ERROR_TDNF_SYM_LOOP (ERROR_TDNF_SYSTEM_BASE + ELOOP)
#define ERROR_TDNF_NAME_TOO_LONG (ERROR_TDNF_SYSTEM_BASE + ENAMETOOLONG)
#define ERROR_TDNF_CALL_NOT_SUPPORTED (ERROR_TDNF_SYSTEM_BASE + ENOSYS)
#define ERROR_TDNF_INVALID_DIR (ERROR_TDNF_SYSTEM_BASE + ENOTDIR)
#define ERROR_TDNF_OVERFLOW (ERROR_TDNF_SYSTEM_BASE + EOVERFLOW)

#define ERROR_TDNF_JSONDUMP 1700

Expand Down
3 changes: 3 additions & 0 deletions include/tdnftypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ typedef struct _TDNF_PKG_INFO
{
uint32_t dwEpoch;
uint32_t dwInstallSizeBytes;
uint32_t dwDownloadSizeBytes;
char* pszName;
char* pszRepoName;
char* pszVersion;
Expand All @@ -159,6 +160,7 @@ typedef struct _TDNF_PKG_INFO
char* pszLicense;
char* pszDescription;
char* pszFormattedSize;
char* pszFormattedDownloadSize;
char* pszRelease;
char* pszLocation;
char **ppszDependencies;
Expand All @@ -172,6 +174,7 @@ typedef struct _TDNF_SOLVED_PKG_INFO
{
int nNeedAction;
int nNeedDownload;
uint32_t dwTotalDownloadSizeBytes;
TDNF_ALTERTYPE nAlterType;
PTDNF_PKG_INFO pPkgsNotAvailable;
PTDNF_PKG_INFO pPkgsExisting;
Expand Down
22 changes: 22 additions & 0 deletions pytests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,28 @@ def create_repoconf(self, filename, baseurl, name):
with open(filename, "w") as f:
f.write(templ.format(name=name, baseurl=baseurl))

def _get_stdout_total_download_size(self, stdout):
key = "Total download size"
for line in stdout:
if key in line:
return line.split()[-1]

def download_size_to_bytes(self, stdout):
size_chars = 'bkMG'
raw_str = self._get_stdout_total_download_size(stdout)
size, unit = float(raw_str[:-1]), raw_str[-1]
return size * (1024 ** size_chars.index(unit))

def get_cached_package_sizes(self, cache_dir):
ret = self.run(['find', cache_dir, '-name', '*.rpm'])
pkg_size_map = {}
for rpm in ret['stdout']:
pkg_size_map[rpm] = os.path.getsize(rpm)
return pkg_size_map

def floats_approx_equal(self, x, y, tol=500):
return abs(x - y) <= tol


@pytest.fixture(scope='session')
def utils():
Expand Down
37 changes: 37 additions & 0 deletions pytests/tests/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,40 @@ def test_enable_repo_make_cache_verbose(utils):
utils.run(['tdnf', '-v', '--disablerepo=*', '--enablerepo=photon-test', 'makecache'])
after = os.path.getmtime(lastrefresh)
assert(before < after)


def test_download_vs_cache_size_single_package(utils):
clean_cache(utils)
enable_cache(utils)

cache_dir = utils.tdnf_config.get('main', 'cachedir')
pkgname = utils.config["mulversion_pkgname"]
utils.erase_package(pkgname)
ret = utils.run(['tdnf', 'install', '-y', '--nogpgcheck', pkgname])

down_bytes = utils.download_size_to_bytes(ret['stdout'])
cached_rpm_bytes = sum(utils.get_cached_package_sizes(cache_dir).values())

assert(utils.floats_approx_equal(down_bytes, cached_rpm_bytes))


def test_download_vs_cache_size_multiple_packages(utils):
clean_cache(utils)
enable_cache(utils)

cache_dir = utils.tdnf_config.get('main', 'cachedir')
run_args = ['tdnf', 'install', '-y', '--nogpgcheck']
pkg_list = [
utils.config["mulversion_pkgname"],
utils.config["sglversion_pkgname"],
utils.config["sglversion2_pkgname"],
]
for pkgname in pkg_list:
utils.erase_package(pkgname)
run_args.append(pkgname)

ret = utils.run(run_args)
down_bytes = utils.download_size_to_bytes(ret['stdout'])
cached_rpm_bytes = sum(utils.get_cached_package_sizes(cache_dir).values())

assert(utils.floats_approx_equal(down_bytes, cached_rpm_bytes))
6 changes: 6 additions & 0 deletions solv/prototypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ SolvGetPkgInstallSizeFromId(
uint32_t dwPkgId,
uint32_t * pdwSize);

uint32_t
SolvGetPkgDownloadSizeFromId(
PSolvSack pSack,
uint32_t dwPkgId,
uint32_t * pdwSize);

uint32_t
SolvGetPkgSummaryFromId(
PSolvSack pSack,
Expand Down
37 changes: 37 additions & 0 deletions solv/tdnfpackage.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,43 @@ SolvGetPkgInstallSizeFromId(
goto cleanup;;
}

uint32_t
SolvGetPkgDownloadSizeFromId(
PSolvSack pSack,
uint32_t dwPkgId,
uint32_t* pdwSize)
{
uint32_t dwError = 0;
uint32_t dwDownloadSize = 0;
Solvable *pSolv = NULL;

if(!pSack || !pdwSize)
{
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);
}

dwDownloadSize = solvable_lookup_num(pSolv, SOLVABLE_DOWNLOADSIZE, 0);
*pdwSize = dwDownloadSize;

cleanup:
return dwError;

error:
if(pdwSize)
{
*pdwSize = 0;
}
goto cleanup;;
}

uint32_t
SolvGetPkgSummaryFromId(
PSolvSack pSack,
Expand Down
24 changes: 19 additions & 5 deletions tools/cli/lib/installcmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -602,12 +602,14 @@ PrintAction(
PTDNF_PKG_INFO pPkgInfo = NULL;

uint32_t dwTotalInstallSize = 0;
uint32_t dwTotalDownloadSize = 0;
char* pszTotalInstallSize = NULL;
char* pszTotalDownloadSize = NULL;
char *pszEmptyString = "";

#define COL_COUNT 5
//Name | Arch | [Epoch:]Version-Release | Repository | Install Size
int nColPercents[COL_COUNT] = {30, 15, 20, 15, 10};
#define COL_COUNT 6
//Name | Arch | [Epoch:]Version-Release | Repository | Install Size | Download Size
int nColPercents[COL_COUNT] = {20, 15, 20, 15, 10, 10};
int nColWidths[COL_COUNT] = {0};

#define MAX_COL_LEN 256
Expand Down Expand Up @@ -653,6 +655,7 @@ PrintAction(
while(pPkgInfo)
{
dwTotalInstallSize += pPkgInfo->dwInstallSizeBytes;
dwTotalDownloadSize += pPkgInfo->dwDownloadSizeBytes;
memset(szEpochVersionRelease, 0, MAX_COL_LEN);
if(pPkgInfo->dwEpoch)
{
Expand Down Expand Up @@ -691,8 +694,10 @@ PrintAction(
pszEmptyString : pPkgInfo->pszRepoName;
ppszInfoToPrint[4] = pPkgInfo->pszFormattedSize == NULL ?
pszEmptyString : pPkgInfo->pszFormattedSize;
ppszInfoToPrint[5] = pPkgInfo->pszFormattedDownloadSize == NULL ?
pszEmptyString : pPkgInfo->pszFormattedDownloadSize;
pr_info(
"%-*s %-*s %-*s %-*s %*s\n",
"%-*s %-*s %-*s %-*s %-*s %*s\n",
nColWidths[0],
ppszInfoToPrint[0],
nColWidths[1],
Expand All @@ -702,18 +707,27 @@ PrintAction(
nColWidths[3],
ppszInfoToPrint[3],
nColWidths[4],
ppszInfoToPrint[4]);
ppszInfoToPrint[4],
nColWidths[5],
ppszInfoToPrint[5]);
pPkgInfo = pPkgInfo->pNext;
}

TDNFUtilsFormatSize(dwTotalInstallSize, &pszTotalInstallSize);
pr_info("\nTotal installed size: %s\n", pszTotalInstallSize);

TDNFUtilsFormatSize(dwTotalDownloadSize, &pszTotalDownloadSize);
pr_info("Total download size: %s\n", pszTotalDownloadSize);

cleanup:
if (pszTotalInstallSize)
{
free(pszTotalInstallSize);
}
if (pszTotalDownloadSize)
{
free(pszTotalDownloadSize);
}
return dwError;

error:
Expand Down

0 comments on commit 0a98a83

Please sign in to comment.