#include <apt-pkg/pkgcache.h>
#include <apt-pkg/cacheiterators.h>
#include <apt-pkg/prettyprinters.h>
+#include <apt-pkg/dpkgpm.h>
#include <string.h>
#include <string>
#include <cstdlib>
#include <iostream>
+#include <utility>
#include <apti18n.h>
/*}}}*/
using namespace std;
+class APT_HIDDEN pkgSimulatePrivate
+{
+public:
+ std::vector<pkgDPkgPM::Item> List;
+};
// Simulate::Simulate - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* The legacy translations here of input Pkg iterators is obsolete,
this is not necessary since the pkgCaches are fully shared now. */
pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
- d(NULL), iPolicy(Cache),
+ d(new pkgSimulatePrivate()), iPolicy(Cache),
Sim(&Cache->GetCache(),&iPolicy),
group(Sim)
{
pkgSimulate::~pkgSimulate()
{
delete[] Flags;
+ delete d;
}
/*}}}*/
// Simulate::Describe - Describe a package /*{{{*/
// Simulate::Install - Simulate unpacking of a package /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
+bool pkgSimulate::Install(PkgIterator iPkg,string File)
+{
+ if (iPkg.end() || File.empty())
+ return false;
+ d->List.emplace_back(pkgDPkgPM::Item::Install, iPkg, File);
+ return true;
+}
+bool pkgSimulate::RealInstall(PkgIterator iPkg,string /*File*/)
{
// Adapt the iterator
PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
install the package.. For some investigations it may be necessary
however. */
bool pkgSimulate::Configure(PkgIterator iPkg)
+{
+ if (iPkg.end())
+ return false;
+ d->List.emplace_back(pkgDPkgPM::Item::Configure, iPkg);
+ return true;
+}
+bool pkgSimulate::RealConfigure(PkgIterator iPkg)
{
// Adapt the iterator
PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
// ---------------------------------------------------------------------
/* */
bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
+{
+ if (iPkg.end())
+ return false;
+ d->List.emplace_back(Purge ? pkgDPkgPM::Item::Purge : pkgDPkgPM::Item::Remove, iPkg);
+ return true;
+}
+bool pkgSimulate::RealRemove(PkgIterator iPkg,bool Purge)
{
// Adapt the iterator
PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
cout << ']' << endl;
}
/*}}}*/
+bool pkgSimulate::Go2(APT::Progress::PackageManager *) /*{{{*/
+{
+ if (pkgDPkgPM::ExpandPendingCalls(d->List, Cache) == false)
+ return false;
+ for (auto && I : d->List)
+ switch (I.Op)
+ {
+ case pkgDPkgPM::Item::Install:
+ if (RealInstall(I.Pkg, I.File) == false)
+ return false;
+ break;
+ case pkgDPkgPM::Item::Configure:
+ if (RealConfigure(I.Pkg) == false)
+ return false;
+ break;
+ case pkgDPkgPM::Item::Remove:
+ if (RealRemove(I.Pkg, false) == false)
+ return false;
+ break;
+ case pkgDPkgPM::Item::Purge:
+ if (RealRemove(I.Pkg, true) == false)
+ return false;
+ break;
+ case pkgDPkgPM::Item::ConfigurePending:
+ case pkgDPkgPM::Item::TriggersPending:
+ case pkgDPkgPM::Item::RemovePending:
+ case pkgDPkgPM::Item::PurgePending:
+ return _error->Error("Internal error, simulation encountered unexpected pending item");
+ }
+ return true;
+}
+ /*}}}*/
// ApplyStatus - Adjust for non-ok packages /*{{{*/
// ---------------------------------------------------------------------
/* We attempt to change the state of the all packages that have failed
#endif
+class pkgSimulatePrivate;
class pkgSimulate : public pkgPackageManager /*{{{*/
{
- void * const d;
+ pkgSimulatePrivate * const d;
protected:
class Policy : public pkgDepCache::Policy
virtual bool Configure(PkgIterator Pkg) APT_OVERRIDE;
virtual bool Remove(PkgIterator Pkg,bool Purge) APT_OVERRIDE;
+ // FIXME: trick to avoid ABI break for virtual reimplementation; fix on next ABI break
+public:
+ APT_HIDDEN bool Go2(APT::Progress::PackageManager * progress);
+
private:
APT_HIDDEN void ShortBreaks();
APT_HIDDEN void Describe(PkgIterator iPkg,std::ostream &out,bool Current,bool Candidate);
+ APT_HIDDEN bool RealInstall(PkgIterator Pkg,std::string File);
+ APT_HIDDEN bool RealConfigure(PkgIterator Pkg);
+ APT_HIDDEN bool RealRemove(PkgIterator Pkg,bool Purge);
public:
* through to human readable (and i10n-able)
* names and calculates a percentage for each step.
*/
-bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
+static bool ItemIsEssential(pkgDPkgPM::Item const &I)
+{
+ static auto const cachegen = _config->Find("pkgCacheGen::Essential");
+ if (cachegen == "none" || cachegen == "native")
+ return true;
+ if (unlikely(I.Pkg.end()))
+ return true;
+ return (I.Pkg->Flags & pkgCache::Flag::Essential) != 0;
+}
+bool pkgDPkgPM::ExpandPendingCalls(std::vector<Item> &List, pkgDepCache &Cache)
{
- // we remove the last configures (and after that removes) from the list here
- // as they will be covered by the pending calls, so explicit calls are busy work
- decltype(List)::const_iterator::difference_type explicitIdx =
- std::distance(List.cbegin(),
- _config->FindB("Dpkg::ExplicitLastConfigure", false) ? List.cend() :
- std::find_if_not(
- std::find_if_not(List.crbegin(), List.crend(), [](Item const &i) { return i.Op == Item::Configure; }),
- List.crend(), [](Item const &i) { return i.Op == Item::Remove || i.Op == Item::Purge; }).base());
-
- // explicitely remove everything for hookscripts and progress building
{
std::unordered_set<decltype(pkgCache::Package::ID)> alreadyRemoved;
for (auto && I : List)
if (I.Op == Item::Remove || I.Op == Item::Purge)
alreadyRemoved.insert(I.Pkg->ID);
- decltype(List) AppendList;
+ std::remove_reference<decltype(List)>::type AppendList;
for (auto Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
if (Cache[Pkg].Delete() && alreadyRemoved.insert(Pkg->ID).second == true)
AppendList.emplace_back(Cache[Pkg].Purge() ? Item::Purge : Item::Remove, Pkg);
std::move(AppendList.begin(), AppendList.end(), std::back_inserter(List));
}
-
- // explicitely configure everything for hookscripts and progress building
{
std::unordered_set<decltype(pkgCache::Package::ID)> alreadyConfigured;
for (auto && I : List)
if (I.Op == Item::Configure)
alreadyConfigured.insert(I.Pkg->ID);
- decltype(List) AppendList;
+ std::remove_reference<decltype(List)>::type AppendList;
for (auto && I : List)
if (I.Op == Item::Install && alreadyConfigured.insert(I.Pkg->ID).second == true)
AppendList.emplace_back(Item::Configure, I.Pkg);
AppendList.emplace_back(Item::Configure, Pkg);
std::move(AppendList.begin(), AppendList.end(), std::back_inserter(List));
}
+ return true;
+}
+bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
+{
+ // we remove the last configures (and after that removes) from the list here
+ // as they will be covered by the pending calls, so explicit calls are busy work
+ decltype(List)::const_iterator::difference_type explicitIdx =
+ std::distance(List.cbegin(),
+ _config->FindB("Dpkg::ExplicitLastConfigure", false) ? List.cend() :
+ std::find_if_not(
+ std::find_if_not(List.crbegin(), List.crend(), [](Item const &i) { return i.Op == Item::Configure; }),
+ List.crend(), [](Item const &i) { return i.Op == Item::Remove || i.Op == Item::Purge; }).base());
- auto const ItemIsEssential = [](pkgDPkgPM::Item const &I) {
- static auto const cachegen = _config->Find("pkgCacheGen::Essential");
- if (cachegen == "none" || cachegen == "native")
- return true;
- if (unlikely(I.Pkg.end()))
- return true;
- return (I.Pkg->Flags & pkgCache::Flag::Essential) != 0;
- };
+ // explicitely remove&configure everything for hookscripts and progress building
+ ExpandPendingCalls(List, Cache);
auto const StripAlreadyDoneFromPending = [&](APT::VersionVector & Pending) {
Pending.erase(std::remove_if(Pending.begin(), Pending.end(), [&](pkgCache::VerIterator const &Ver) {
// progress reporting
unsigned int PackagesDone;
unsigned int PackagesTotal;
-
+
+ public:
struct Item
{
enum Ops {Install, Configure, Remove, Purge, ConfigurePending, TriggersPending,
Item(Ops Op,PkgIterator Pkg,std::string File = "") : Op(Op),
File(File), Pkg(Pkg) {};
Item() {};
-
};
+ protected:
std::vector<Item> List;
// Helpers
virtual bool Remove(PkgIterator Pkg,bool Purge = false) APT_OVERRIDE;
virtual bool Go(APT::Progress::PackageManager *progress) APT_OVERRIDE;
- virtual bool Go(int StatusFd=-1) APT_OVERRIDE;
+ APT_DEPRECATED_MSG("Use overload with explicit progress manager") virtual bool Go(int StatusFd=-1) APT_OVERRIDE;
virtual void Reset() APT_OVERRIDE;
pkgDPkgPM(pkgDepCache *Cache);
virtual ~pkgDPkgPM();
+
+ APT_HIDDEN static bool ExpandPendingCalls(std::vector<Item> &List, pkgDepCache &Cache);
};
void SigINT(int sig);
pkgPackageManager::OrderResult
pkgPackageManager::DoInstallPostFork(APT::Progress::PackageManager *progress)
{
- bool goResult = Go(progress);
+ bool goResult;
+ auto simulation = dynamic_cast<pkgSimulate*>(this);
+ if (simulation == nullptr)
+ goResult = Go(progress);
+ else
+ goResult = simulation->Go2(progress);
if(goResult == false)
return Failed;
virtual bool Configure(PkgIterator /*Pkg*/) {return false;};
virtual bool Remove(PkgIterator /*Pkg*/,bool /*Purge*/=false) {return false;};
virtual bool Go(APT::Progress::PackageManager * /*progress*/) {return true;};
- virtual bool Go(int /*statusFd*/=-1) {return true;};
+ APT_DEPRECATED_MSG("Use overload with explicit progress manager") virtual bool Go(int /*statusFd*/=-1) {return true;};
virtual void Reset() {};