* Copyright 2018-2025, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*
* Note that this file included code earlier from `MainWindow.cpp` and
* copyrights have been latterly been carried across in 2021.
*/
#include "PopulatePkgSizesProcess.h"
#include <Catalog.h>
#include "Logger.h"
#include "PackageKitUtils.h"
#include "PackageUtils.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "PopulatePkgSizesProcess"
PopulatePkgSizesProcess::PopulatePkgSizesProcess(Model* model)
:
fModel(model),
fProgress(0)
{
}
PopulatePkgSizesProcess::~PopulatePkgSizesProcess()
{
}
const char*
PopulatePkgSizesProcess::Name() const
{
return "PopulatePkgSizesProcess";
}
const char*
PopulatePkgSizesProcess::Description() const
{
return B_TRANSLATE("Populating package sizes");
}
float
PopulatePkgSizesProcess::Progress()
{
return fProgress;
}
status_t
PopulatePkgSizesProcess::RunInternal()
{
int32 countPkgs;
int32 countPkgSized = 0;
int32 countPkgUnsized = 0;
HDINFO("[%s] will populate size for pkgs without a size", Name());
const std::vector<PackageInfoRef> packages = _SnapshotOfPackages();
std::vector<PackageInfoRef> updatedPackages;
countPkgs = static_cast<int32>(packages.size());
for (int32 i = 0; i < countPkgs; i++) {
PackageInfoRef package = packages[i];
const char* packageName = package->Name().String();
if (!package.IsSet())
HDFATAL("package is not set");
PackageLocalInfoRef localInfo = package->LocalInfo();
if (_ShouldDeriveSize(localInfo)) {
off_t derivedSize = _DeriveSize(package);
if (derivedSize > 0) {
PackageLocalInfoBuilder localInfoBuilder;
if (localInfo.IsSet())
localInfoBuilder = PackageLocalInfoBuilder(localInfo);
localInfoBuilder.WithSize(derivedSize);
PackageLocalInfoRef localInfo = localInfoBuilder.BuildRef();
updatedPackages.push_back(
PackageInfoBuilder(package).WithLocalInfo(localInfo).BuildRef());
countPkgSized++;
HDDEBUG("[%s] did derive a size for package [%s]", Name(), packageName);
} else {
countPkgUnsized++;
HDDEBUG("[%s] unable to derive a size for package [%s]", Name(), packageName);
}
}
_SetProgress(static_cast<float>(i) / static_cast<float>(countPkgs));
}
fModel->AddPackagesWithChange(updatedPackages, PKG_CHANGED_LOCAL_INFO);
_SetProgress(1.0);
HDINFO("[%s] did populate size for %" B_PRId32 " packages with %" B_PRId32
" already having a size and %" B_PRId32 " unable to derive a size",
Name(), countPkgSized, countPkgs - (countPkgSized + countPkgUnsized), countPkgUnsized);
return B_OK;
}
const std::vector<PackageInfoRef>
PopulatePkgSizesProcess::_SnapshotOfPackages() const
{
return fModel->Packages();
}
bool
PopulatePkgSizesProcess::_ShouldDeriveSize(PackageLocalInfoRef localInfo) const
{
if (!localInfo.IsSet())
return true;
if (localInfo->Size() > 0)
return false;
PackageState state = localInfo->State();
return state == ACTIVATED || state == INSTALLED;
}
off_t
PopulatePkgSizesProcess::_DeriveSize(const PackageInfoRef package) const
{
BPath path;
if (PackageKitUtils::DeriveLocalFilePath(package, path) == B_OK) {
BEntry entry(path.Path());
struct stat s = {};
if (entry.GetStat(&s) == B_OK)
return s.st_size;
else
HDDEBUG("unable to get the size of local file [%s]", path.Path());
} else {
HDDEBUG("unable to get the local file of package [%s]", package->Name().String());
}
return 0;
}
void
PopulatePkgSizesProcess::_SetProgress(float value)
{
if (!_ShouldProcessProgress() && value != 1.0 && (value - fProgress) < 0.1)
return;
fProgress = value;
_NotifyChanged();
}