/* * Copyright 2018-2025, Andrew Lindesay . * Copyright 2013-2014, Stephan Aßmus . * Copyright 2013, Rene Gollent, rene@gollent.com. * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. * 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 "LocalPkgDataLoadProcess.h" #include #include #include #include #include #include #include #include #include #include "AppUtils.h" #include "HaikuDepotConstants.h" #include "Logger.h" #include "PackageInfo.h" #include "PackageKitUtils.h" #include "PackageManager.h" #include "PackageUtils.h" #include "StorageUtils.h" #include "package/RepositoryCache.h" #include #include #include #include #include #include #include #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "LocalPkgDataLoadProcess" using namespace BPackageKit; using namespace BPackageKit::BManager::BPrivate; class LocalPkgDataLoadProcessUtilsData { public: int32 CountPackages() const; void AddPackage(PackageInfoRef packageInfo); const PackageInfoRef PackageByName(const BString& name) const; int32 CountDepots() const; void AddDepot(DepotInfoRef depotInfo); const DepotInfoRef DepotByName(const BString& name) const; int32 CountSolverPackages() const; void AddSolverPackage(const BSolverPackage* solverPackage); void AddRemotePackageName(const BString& name); bool IsRemotePackageName(const BString& name) const; void AddSystemFlaggedPackageFilename(const BString& filename); void AddSystemInstalledPackage(const BPackageInfo& solverPackageInfo); const PackageInfoRef PackageBySystemInstalledFilename(const BString& filename); public: std::map fDepots; std::vector fSolverPackages; std::map fFoundPackages; // if a given package is installed locally, we will potentially // get back multiple entries, one for each local installation // location, and one for each remote repository the package // is available in. The above map is used to ensure that in such // cases we consolidate the information, rather than displaying // duplicates. std::set fRemotePackageNames; // any package that we find in a remote repository goes in this map. // this is later used to discern which packages came from a local // installation only, as those must be handled a bit differently // upon uninstallation, since we'd no longer be able to pull them // down remotely. std::set fSystemFlaggedPackageFilenames; // any packages flagged as a system package are added to this list. // such packages cannot be uninstalled, nor can any of their deps. std::map fSystemInstalledFilenamesToPackageNames; // any packages installed in system are added to this list. // This is later used for dependency resolution of the actual // system packages in order to compute the list of protected // dependencies indicated above. }; class LocalPkgDataLoadProcessUtils { public: static void _NotifyError(const BString& messageText); static status_t _CollateDepotInfos(LocalPkgDataLoadProcessUtilsData& data); static status_t _InitPackageManager(PackageManager& manager); static status_t _CollateSolverPackages(PackageManager& manager, LocalPkgDataLoadProcessUtilsData& data); static status_t _CollatePackagesData(PackageManager& manager, LocalPkgDataLoadProcessUtilsData& data); static status_t _CollatePackageData(PackageManager& manager, const BSolverPackage* solverPackage, LocalPkgDataLoadProcessUtilsData& data); static status_t _CollateLocalDepotAndPackageData( LocalPkgDataLoadProcessUtilsData& data); static status_t _EnhanceSystemPackages( LocalPkgDataLoadProcessUtilsData& data); static status_t _PopulateModel(LocalPkgDataLoadProcessUtilsData& data, Model* model, bool force); static bool _IsHomeRepository(PackageManager& manager, BSolverRepository* solverRepository); static bool _IsSystemRepository(PackageManager& manager, BSolverRepository* solverRepository); static BString _LogMessageFromFatalError(BFatalErrorException& ex); }; /*! \param packageInfoListener is assigned to each package model object. */ LocalPkgDataLoadProcess::LocalPkgDataLoadProcess(Model* model, bool force) : AbstractProcess(), fModel(model), fForce(force) { } LocalPkgDataLoadProcess::~LocalPkgDataLoadProcess() { } const char* LocalPkgDataLoadProcess::Name() const { return "LocalPkgDataLoadProcess"; } const char* LocalPkgDataLoadProcess::Description() const { return B_TRANSLATE("Reading repository data"); } /*! The contents of this method implementation have been 'lifted and shifted' from MainWindow.cpp in order that the logic fits into the background loading processes. The code needs to be broken up into methods with some sort of a state object carrying the state of the process. As part of this, better error handling and error reporting would also be advantageous. */ status_t LocalPkgDataLoadProcess::RunInternal() { HDINFO("[%s] will refresh the package list", Name()); status_t result = B_OK; LocalPkgDataLoadProcessUtilsData data; // Find all of the depots (repositories) that are known about in the system. if (result == B_OK) { result = LocalPkgDataLoadProcessUtils::_CollateDepotInfos(data); if (result == B_OK) HDINFO("[%s] did collate %" B_PRIi32 " depots", Name(), data.CountDepots()); else HDERROR("[%s] failed to collate depot infos", Name()); } PackageManager manager(B_PACKAGE_INSTALLATION_LOCATION_HOME); if (result == B_OK) { result = LocalPkgDataLoadProcessUtils::_InitPackageManager(manager); if (result == B_OK) HDINFO("[%s] did initialize the package manager", Name()); else HDERROR("[%s] failed to initialize the package manager", Name()); } // Collect all of the packages that are known about in the system. if (result == B_OK) { result = LocalPkgDataLoadProcessUtils::_CollateSolverPackages(manager, data); if (result == B_OK) { HDINFO("[%s] did collate %" B_PRIi32 " solver packages", Name(), data.CountSolverPackages()); } else { HDERROR("[%s] failed to collate solver packages", Name()); } } // Collect all of the solver packages into HaikuDepot `PackageInfo` objects for use in the // application. if (result == B_OK) { result = LocalPkgDataLoadProcessUtils::_CollatePackagesData(manager, data); if (result == B_OK) HDINFO("[%s] did collate %" B_PRIi32 " packages", Name(), data.CountPackages()); else HDERROR("[%s] failed to collate packages", Name()); } // Some of the installed packages may not have come from a remote repository. In this case // they will be collated under a fake Depot. if (result == B_OK) { result = LocalPkgDataLoadProcessUtils::_CollateLocalDepotAndPackageData(data); if (result == B_OK) HDINFO("[%s] did collate local depot and package data", Name()); else HDERROR("[%s] failed to collate local depot and package data", Name()); } if (result == B_OK) { result = LocalPkgDataLoadProcessUtils::_EnhanceSystemPackages(data); if (result == B_OK) HDINFO("[%s] did enhance system packages", Name()); else HDERROR("[%s] failed to enhance system packages", Name()); } if (result == B_OK) { result = LocalPkgDataLoadProcessUtils::_PopulateModel(data, fModel, fForce); if (result == B_OK) HDINFO("[%s] did populate model", Name()); else HDERROR("[%s] failed to populate model", Name()); } if (result == B_OK) HDINFO("did refresh the package list"); else HDERROR("failed to refresh the package list"); return result; } /*static*/ status_t LocalPkgDataLoadProcessUtils::_CollateDepotInfos(LocalPkgDataLoadProcessUtilsData& data) { BPackageRoster roster; BStringList repositoryNames; status_t result = roster.GetRepositoryNames(repositoryNames); if (result != B_OK) return result; for (int32 i = repositoryNames.CountStrings() - 1; i >= 0; i--) { const BString& repositoryName = repositoryNames.StringAt(i); DepotInfoBuilder depotInfoBuilder; depotInfoBuilder.WithName(repositoryName); BRepositoryConfig repoConfig; status_t getRepositoryConfigStatus = roster.GetRepositoryConfig(repositoryName, &repoConfig); if (getRepositoryConfigStatus == B_OK) { depotInfoBuilder.WithIdentifier(repoConfig.Identifier()); HDDEBUG("local repository [%s] identifier; [%s]", repositoryName.String(), repoConfig.Identifier().String()); } else { HDINFO("unable to obtain the repository config for local repository '%s'; %s", repositoryName.String(), strerror(getRepositoryConfigStatus)); } data.AddDepot(depotInfoBuilder.BuildRef()); } return result; } /*static*/ status_t LocalPkgDataLoadProcessUtils::_InitPackageManager(PackageManager& manager) { try { manager.Init(PackageManager::B_ADD_INSTALLED_REPOSITORIES | PackageManager::B_ADD_REMOTE_REPOSITORIES); return B_OK; } catch (BException& ex) { BString message(B_TRANSLATE("An error occurred while initializing the package manager: " "%message%")); message.ReplaceFirst("%message%", ex.Message()); _NotifyError(message.String()); return B_ERROR; } } /*static*/ status_t LocalPkgDataLoadProcessUtils::_CollateSolverPackages(PackageManager& manager, LocalPkgDataLoadProcessUtilsData& data) { BObjectList packages; status_t result = manager.Solver()->FindPackages("", BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_NAME | BSolver::B_FIND_IN_SUMMARY | BSolver::B_FIND_IN_DESCRIPTION | BSolver::B_FIND_IN_PROVIDES, packages); if (result != B_OK) { BString message( B_TRANSLATE("An error occurred while obtaining the package list: %message%")); message.ReplaceFirst("%message%", strerror(result)); _NotifyError(message.String()); } else if (packages.IsEmpty()) { HDERROR("no packages were found"); result = B_ERROR; } if (result == B_OK) { for (int32 i = packages.CountItems() - 1; i >= 0; i--) data.AddSolverPackage(packages.ItemAt(i)); } return result; } /*static*/ status_t LocalPkgDataLoadProcessUtils::_CollatePackagesData(PackageManager& manager, LocalPkgDataLoadProcessUtilsData& data) { std::vector::iterator solverPackageIt; status_t result = B_OK; for (solverPackageIt = data.fSolverPackages.begin(); solverPackageIt != data.fSolverPackages.end() && result == B_OK; solverPackageIt++) { const BSolverPackage* solverPackage = *solverPackageIt; result = _CollatePackageData(manager, solverPackage, data); } return result; } /*! This method will collect the data from the `solverPackage` into the data in the supplied `data`. */ /*static*/ status_t LocalPkgDataLoadProcessUtils::_CollatePackageData(PackageManager& manager, const BSolverPackage* solverPackage, LocalPkgDataLoadProcessUtilsData& data) { status_t result = B_OK; const BPackageInfo& solverPackageInfo = solverPackage->Info(); const BString repositoryName = solverPackage->Repository()->Name(); const BString packageName = solverPackageInfo.Name(); PackageCoreInfoBuilder coreInfoBuilder; PackageLocalizedTextBuilder localizedTextBuilder; PackageLocalInfoBuilder localInfoBuilder; PackageClassificationInfoRef classificationInfo; PackageUserRatingInfoRef userRatingInfo; PackageScreenshotInfoBuilder screenshotInfoBuilder; PackageInfoRef preexistingPackageInfo = data.PackageByName(packageName); // If there is an existing package found then build off the data from that package and add to // it; otherwise create new data off the package. if (preexistingPackageInfo.IsSet()) { coreInfoBuilder = PackageCoreInfoBuilder(preexistingPackageInfo->CoreInfo()); localizedTextBuilder = PackageLocalizedTextBuilder(preexistingPackageInfo->LocalizedText()); localInfoBuilder = PackageLocalInfoBuilder(preexistingPackageInfo->LocalInfo()); classificationInfo = PackageClassificationInfoRef(preexistingPackageInfo->PackageClassificationInfo()); userRatingInfo = PackageUserRatingInfoRef(preexistingPackageInfo->UserRatingInfo()); screenshotInfoBuilder = PackageScreenshotInfoBuilder(preexistingPackageInfo->ScreenshotInfo()); // The package list here considers those packages that are installed // in the system as well as those that exist in remote repositories. // It is better if the 'depot name' is from the remote repository // because then it will be possible to perform a rating on it later. BString preexistingPackageDepotName = PackageUtils::DepotName(preexistingPackageInfo); if (preexistingPackageDepotName.IsEmpty() || preexistingPackageDepotName == REPOSITORY_NAME_SYSTEM || preexistingPackageDepotName == REPOSITORY_NAME_INSTALLED) { coreInfoBuilder.WithDepotName(repositoryName); } } else { coreInfoBuilder = PackageCoreInfoBuilder() .WithDepotName(repositoryName) .WithArchitecture(solverPackageInfo.ArchitectureName()) .WithVersion(new PackageVersion(solverPackageInfo.Version())) .WithPublisher(PackageKitUtils::CreatePublisherInfo(solverPackageInfo)); localizedTextBuilder = PackageLocalizedTextBuilder() .WithTitle(solverPackageInfo.Name()) .WithSummary(solverPackageInfo.Summary()) .WithDescription(solverPackageInfo.Description()); // TODO: Retrieve local file size localInfoBuilder = PackageLocalInfoBuilder() .WithFlags(solverPackageInfo.Flags()) .WithFileName(solverPackageInfo.FileName()); } BSolverRepository* solverRepository = solverPackage->Repository(); BPackageManager::RemoteRepository* solverRemoteRepository = dynamic_cast(solverRepository); uint32 solverPackageFlags = solverPackageInfo.Flags(); if (solverRemoteRepository != NULL) { const BString solverRemoteRepositoryName = solverRemoteRepository->Config().Name(); DepotInfoRef depotInfoForSolverRemoteRepository = data.DepotByName(solverRemoteRepositoryName); if (depotInfoForSolverRemoteRepository.IsSet()) { coreInfoBuilder.WithDepotName(solverRemoteRepositoryName); HDTRACE("pkg [%s]; assigned to [%s]", packageName.String(), repositoryName.String()); } else { HDDEBUG("pkg [%s]; repository [%s] not recognized --> ignored", packageName.String(), repositoryName.String()); } data.AddRemotePackageName(packageName); } else { if (LocalPkgDataLoadProcessUtils::_IsSystemRepository(manager, solverRepository)) { localInfoBuilder.AddInstallationLocation(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM); if ((solverPackageFlags & BPackageKit::B_PACKAGE_FLAG_SYSTEM_PACKAGE) == 0) data.AddSystemInstalledPackage(solverPackageInfo); } else if (LocalPkgDataLoadProcessUtils::_IsHomeRepository(manager, solverRepository)) { localInfoBuilder.AddInstallationLocation(B_PACKAGE_INSTALLATION_LOCATION_HOME); } } if ((solverPackageFlags & BPackageKit::B_PACKAGE_FLAG_SYSTEM_PACKAGE) != 0) { HDTRACE("am adding system flagged package [%s]", solverPackageInfo.FileName().String()); data.AddSystemFlaggedPackageFilename(solverPackageInfo.FileName()); } PackageLocalInfoRef localInfo = localInfoBuilder.BuildRef(); PackageLocalizedTextRef localizedText = localizedTextBuilder.BuildRef(); PackageCoreInfoRef coreInfo = coreInfoBuilder.BuildRef(); PackageScreenshotInfoRef screenshotInfo = screenshotInfoBuilder.BuildRef(); PackageInfoRef package = PackageInfoBuilder(packageName) .WithLocalInfo(localInfo) .WithLocalizedText(localizedText) .WithCoreInfo(coreInfo) .WithPackageClassificationInfo(classificationInfo) .WithUserRatingInfo(userRatingInfo) .WithScreenshotInfo(screenshotInfo) .BuildRef(); data.AddPackage(package); return result; } /*! This method will filter out any packages that are not from a repository. It will then be able to identify those that are "local" only. A fake Depot is created for these so that they can be seen. */ /*static*/ status_t LocalPkgDataLoadProcessUtils::_CollateLocalDepotAndPackageData( LocalPkgDataLoadProcessUtilsData& data) { uint32 count = 0; std::map::const_iterator it; for (it = data.fFoundPackages.begin(); it != data.fFoundPackages.end(); it++) { BString packageName = it->first; PackageInfoRef packageInfo = it->second; if (!data.IsRemotePackageName(packageName)) { BString repoName = B_TRANSLATE("Local"); if (count == 0) { data.AddDepot(DepotInfoBuilder() .WithName(repoName) .WithIdentifier(LOCAL_DEPOT_IDENTIFIER) .BuildRef()); } // This one is local and so should be replaced with the special identifier. PackageCoreInfoRef coreInfo = PackageCoreInfoBuilder(packageInfo->CoreInfo()) .WithDepotName(repoName) .BuildRef(); PackageInfoRef replacementPackageInfo = PackageInfoBuilder(packageInfo).WithCoreInfo(coreInfo).BuildRef(); data.AddPackage(replacementPackageInfo); count++; } } return B_OK; } /*! This method will identify those packages that are required for the system to function and mark those on the in-memory models of the packages. */ /*static*/ status_t LocalPkgDataLoadProcessUtils::_EnhanceSystemPackages(LocalPkgDataLoadProcessUtilsData& data) { try { // create the solver BSolver* solver; status_t error = BSolver::Create(solver); if (error != B_OK) throw BFatalErrorException(error, "Failed to create solver."); ObjectDeleter solverDeleter(solver); BPath systemPath; error = find_directory(B_SYSTEM_PACKAGES_DIRECTORY, &systemPath); if (error != B_OK) throw BFatalErrorException(error, "Unable to retrieve system packages directory."); HDDEBUG("will assemble the system packages to enhance"); // add the "installed" repository with the given packages BSolverRepository installedRepository; { BRepositoryBuilder installedRepositoryBuilder(installedRepository, REPOSITORY_NAME_INSTALLED); std::set::iterator it; for (it = data.fSystemFlaggedPackageFilenames.begin(); it != data.fSystemFlaggedPackageFilenames.end(); it++) { BPath packagePath(systemPath); packagePath.Append(*(it)); bool exists = false; if (StorageUtils::ExistsObject(packagePath, &exists, NULL, NULL) != B_OK) throw BFatalErrorException(error, "unable to check package file's existence."); const char* packagePathStr = packagePath.Path(); if (exists) { HDTRACE("adding system flagged package filename [%s]", packagePathStr); installedRepositoryBuilder.AddPackage(packagePathStr); } else { HDINFO("system flagged package filename [%s] is not existing --> ignored", packagePathStr); } } installedRepositoryBuilder.AddToSolver(solver, true); } HDDEBUG("creating a system repository"); // add system repository BSolverRepository systemRepository; { BRepositoryBuilder systemRepositoryBuilder(systemRepository, REPOSITORY_NAME_SYSTEM); std::map::iterator it; for (it = data.fSystemInstalledFilenamesToPackageNames.begin(); it != data.fSystemInstalledFilenamesToPackageNames.end(); it++) { BPath packagePath(systemPath); packagePath.Append(it->first); systemRepositoryBuilder.AddPackage(packagePath.Path()); } systemRepositoryBuilder.AddToSolver(solver, false); } HDDEBUG("verifying system repository"); // solve error = solver->VerifyInstallation(); if (error != B_OK) throw BFatalErrorException(error, "Failed to compute packages to install."); HDDEBUG("getting system repository result"); BSolverResult solverResult; error = solver->GetResult(solverResult); if (error != B_OK) throw BFatalErrorException(error, "Failed to retrieve system package dependency list."); HDDEBUG("processing system repository files"); for (int32 i = 0; const BSolverResultElement* element = solverResult.ElementAt(i); i++) { BSolverPackage* package = element->Package(); if (element->Type() == BSolverResultElement::B_TYPE_INSTALL) { BString packageFilename = package->Info().FileName(); HDTRACE("will process package filename [%s]", packageFilename.String()); PackageInfoRef systemInstalledPackage = data.PackageBySystemInstalledFilename(packageFilename); if (systemInstalledPackage.IsSet()) { PackageLocalInfoRef localInfo = PackageLocalInfoBuilder(systemInstalledPackage->LocalInfo()) .WithSystemDependency(true) .BuildRef(); PackageInfoRef systemInstalledPackageUpdated = PackageInfoBuilder(systemInstalledPackage) .WithLocalInfo(localInfo) .BuildRef(); data.AddPackage(systemInstalledPackageUpdated); } } } } catch (BFatalErrorException& ex) { BString logMessage = _LogMessageFromFatalError(ex); HDERROR(logMessage.String()); return B_ERROR; } catch (BNothingToDoException&) { // do nothing } catch (BException& ex) { HDERROR("Exception occurred while resolving system dependencies: %s", ex.Message().String()); return B_ERROR; } catch (...) { HDERROR("Unknown exception occurred while resolving system dependencies."); return B_ERROR; } return B_OK; } /*static*/ BString LocalPkgDataLoadProcessUtils::_LogMessageFromFatalError(BFatalErrorException& ex) { BString logMessage; logMessage.SetToFormat("a fatal exception has occurred resolving system dependencies: [%s]", strerror(ex.Error())); if (!ex.Details().IsEmpty()) { logMessage.Append(", details: ["); logMessage.Append(ex.Details()); logMessage.Append("]"); } if (ex.HasCommitTransactionFailed()) { logMessage.Append("txn result: ["); logMessage.Append(ex.CommitTransactionResult().FullErrorMessage()); logMessage.Append("]"); } return logMessage; } /*! This method will write all of the assembled packages into the model. It will also load in the Depots as well. */ /*static*/ status_t LocalPkgDataLoadProcessUtils::_PopulateModel(LocalPkgDataLoadProcessUtilsData& data, Model* model, bool force) { // Transfer the packages to a vector data structure to supply to the model. std::vector packages; std::map::iterator packageIt; for (packageIt = data.fFoundPackages.begin(); packageIt != data.fFoundPackages.end(); packageIt++) { packages.push_back(packageIt->second); } if (force) model->Clear(); // first populate the depots into the model. std::map::iterator depotIt; std::vector depots; for (depotIt = data.fDepots.begin(); depotIt != data.fDepots.end(); depotIt++) { const DepotInfoRef depotInfo = depotIt->second; if (!depotInfo->Identifier().IsEmpty()) depots.push_back(depotInfo); } model->SetDepots(depots); uint32 changeMask = PKG_CHANGED_LOCAL_INFO | PKG_CHANGED_CORE_INFO | PKG_CHANGED_LOCALIZED_TEXT; model->AddPackagesWithChange(packages, changeMask); return B_OK; } /*static*/ void LocalPkgDataLoadProcessUtils::_NotifyError(const BString& messageText) { HDERROR("an error has arisen loading data of packages from local : %s", messageText.String()); AppUtils::NotifySimpleError(B_TRANSLATE("Local repository load error"), messageText); } /*static*/ bool LocalPkgDataLoadProcessUtils::_IsHomeRepository(PackageManager& manager, BSolverRepository* solverRepository) { return solverRepository == static_cast(manager.HomeRepository()); } /*static*/ bool LocalPkgDataLoadProcessUtils::_IsSystemRepository(PackageManager& manager, BSolverRepository* solverRepository) { return solverRepository == static_cast(manager.SystemRepository()); } int32 LocalPkgDataLoadProcessUtilsData::CountPackages() const { return static_cast(fFoundPackages.size()); } void LocalPkgDataLoadProcessUtilsData::AddPackage(PackageInfoRef packageInfo) { if (!packageInfo.IsSet()) HDFATAL("attempt to work with unset package info"); const BString packageName = packageInfo->Name(); HDTRACE("did add package [%s]", packageName.String()); fFoundPackages[packageName] = packageInfo; } const PackageInfoRef LocalPkgDataLoadProcessUtilsData::PackageByName(const BString& name) const { if (!name.IsEmpty()) { std::map::const_iterator it = fFoundPackages.find(name); if (it != fFoundPackages.end()) return it->second; } return PackageInfoRef(); } void LocalPkgDataLoadProcessUtilsData::AddDepot(DepotInfoRef depotInfo) { if (!depotInfo.IsSet()) HDFATAL("attempt to work with unset depot info"); fDepots[depotInfo->Name()] = depotInfo; } int32 LocalPkgDataLoadProcessUtilsData::CountSolverPackages() const { return static_cast(fSolverPackages.size()); } void LocalPkgDataLoadProcessUtilsData::AddSolverPackage(const BSolverPackage* solverPackage) { fSolverPackages.push_back(solverPackage); } void LocalPkgDataLoadProcessUtilsData::AddRemotePackageName(const BString& name) { fRemotePackageNames.insert(name); } bool LocalPkgDataLoadProcessUtilsData::IsRemotePackageName(const BString& name) const { return fRemotePackageNames.find(name) != fRemotePackageNames.end(); } void LocalPkgDataLoadProcessUtilsData::AddSystemFlaggedPackageFilename(const BString& filename) { fSystemFlaggedPackageFilenames.insert(filename); } void LocalPkgDataLoadProcessUtilsData::AddSystemInstalledPackage(const BPackageInfo& solverPackageInfo) { const BString packageName = solverPackageInfo.Name(); const BString packageFilename = solverPackageInfo.FileName(); fSystemInstalledFilenamesToPackageNames[packageFilename] = packageName; } const PackageInfoRef LocalPkgDataLoadProcessUtilsData::PackageBySystemInstalledFilename(const BString& packageFilename) { BString packageName; if (packageFilename.IsEmpty()) { std::map::const_iterator it; BString packageName; it = fSystemInstalledFilenamesToPackageNames.find(packageFilename); if (it != fSystemInstalledFilenamesToPackageNames.end()) packageName = it->second; } return PackageByName(packageName); } const DepotInfoRef LocalPkgDataLoadProcessUtilsData::DepotByName(const BString& name) const { if (!name.IsEmpty()) { std::map::const_iterator it = fDepots.find(name); if (it != fDepots.end()) return it->second; } return DepotInfoRef(); } int32 LocalPkgDataLoadProcessUtilsData::CountDepots() const { return static_cast(fDepots.size()); }