Просмотр исходного кода

implement a more generic ShowList method

apt-get is displaying various lists of package names, which until now it
was building as a string before passing it to ShowList, which inserted
linebreaks at fitting points and showed a title if needed, but it never
really understood what it was working with. With the help of C++11 the
new generic knows not only what it works with, but generates the list on
the fly rather than asking for it and potentially discarding parts of
the input (= the non-default verbose display). It also doubles as a test
for how usable the CacheSets are with C++11.

(Not all callers are adapted yet.)

Git-Dch: Ignore
David Kalnischkies лет назад: 11
Родитель
Сommit
a0c19a217c
58 измененных файлов с 570 добавлено и 341 удалено
  1. 79 20
      apt-pkg/cacheset.h
  2. 31 30
      apt-private/private-cachefile.cc
  3. 39 20
      apt-private/private-cachefile.h
  4. 9 7
      apt-private/private-cacheset.h
  5. 27 42
      apt-private/private-install.cc
  6. 127 136
      apt-private/private-output.cc
  7. 66 1
      apt-private/private-output.h
  8. 1 1
      po/apt-all.pot
  9. 2 2
      po/ar.po
  10. 2 2
      po/ast.po
  11. 2 2
      po/bg.po
  12. 1 1
      po/bs.po
  13. 2 2
      po/ca.po
  14. 2 2
      po/cs.po
  15. 2 2
      po/cy.po
  16. 2 2
      po/da.po
  17. 2 2
      po/de.po
  18. 1 1
      po/dz.po
  19. 2 2
      po/el.po
  20. 2 2
      po/es.po
  21. 2 2
      po/eu.po
  22. 2 2
      po/fi.po
  23. 2 2
      po/fr.po
  24. 2 2
      po/gl.po
  25. 2 2
      po/he.po
  26. 2 2
      po/hu.po
  27. 2 2
      po/it.po
  28. 2 2
      po/ja.po
  29. 2 2
      po/km.po
  30. 2 2
      po/ko.po
  31. 1 1
      po/ku.po
  32. 2 2
      po/lt.po
  33. 1 1
      po/mr.po
  34. 2 2
      po/nb.po
  35. 2 2
      po/ne.po
  36. 2 2
      po/nl.po
  37. 2 2
      po/nn.po
  38. 2 2
      po/pl.po
  39. 2 2
      po/pt.po
  40. 2 2
      po/pt_BR.po
  41. 2 2
      po/ro.po
  42. 2 2
      po/ru.po
  43. 2 2
      po/sk.po
  44. 2 2
      po/sl.po
  45. 2 2
      po/sv.po
  46. 2 2
      po/th.po
  47. 2 2
      po/tl.po
  48. 2 2
      po/tr.po
  49. 2 2
      po/uk.po
  50. 2 2
      po/vi.po
  51. 2 2
      po/zh_CN.po
  52. 2 2
      po/zh_TW.po
  53. 26 0
      test/integration/test-apt-get-autoremove
  54. 9 0
      test/integration/test-bug-596498-trusted-unsigned-repo
  55. 26 0
      test/integration/test-bug-604222-new-and-autoremove
  56. 16 0
      test/integration/test-bug-613420-new-garbage-dependency
  57. 14 0
      test/integration/test-bug-675449-essential-are-protected
  58. 16 0
      test/integration/test-kernel-helper-autoremove

+ 79 - 20
apt-pkg/cacheset.h

@@ -17,6 +17,7 @@
 #include <forward_list>
 #endif
 #include <list>
+#include <deque>
 #include <vector>
 #include <string>
 #include <iterator>
@@ -210,16 +211,15 @@ private:
 	void * const d;
 };									/*}}}*/
 // Iterator templates for our Containers				/*{{{*/
-template<typename Interface, typename Container, typename Master, typename iterator_type, typename container_iterator> class Container_iterator_base :
+template<typename Interface, typename Master, typename iterator_type, typename container_iterator, typename container_value> class Container_iterator_base :
    public std::iterator<typename std::iterator_traits<container_iterator>::iterator_category, container_iterator>,
    public Interface::iterator_base
 {
 protected:
 	container_iterator _iter;
-	inline virtual typename Container::value_type getType(void) const APT_OVERRIDE { return *_iter; }
 public:
 	explicit Container_iterator_base(container_iterator i) : _iter(i) {}
-	inline typename Container::value_type operator*(void) const { return *_iter; }
+	inline container_value operator*(void) const { return this->getType(); }
 	operator container_iterator(void) const { return _iter; }
 	inline iterator_type& operator++() { ++_iter; return static_cast<iterator_type&>(*this); }
 	inline iterator_type operator++(int) { iterator_type tmp(*this); operator++(); return tmp; }
@@ -241,48 +241,56 @@ public:
 	friend Master;
 };
 template<class Interface, class Container, class Master> class Container_const_iterator :
-   public Container_iterator_base<Interface, Container, Master, Container_const_iterator<Interface, Container, Master>, typename Container::const_iterator>
+   public Container_iterator_base<Interface, Master, Container_const_iterator<Interface, Container, Master>, typename Container::const_iterator, typename Container::value_type>
 {
 	typedef Container_const_iterator<Interface, Container, Master> iterator_type;
 	typedef typename Container::const_iterator container_iterator;
 public:
 	explicit Container_const_iterator(container_iterator i) :
-	   Container_iterator_base<Interface, Container, Master, iterator_type, container_iterator>(i) {}
+	   Container_iterator_base<Interface, Master, iterator_type, container_iterator, typename Container::value_type>(i) {}
+
+	inline virtual typename Container::value_type getType(void) const APT_OVERRIDE { return *this->_iter; }
 };
 template<class Interface, class Container, class Master> class Container_iterator :
-   public Container_iterator_base<Interface, Container, Master, Container_iterator<Interface, Container, Master>, typename Container::iterator>
+   public Container_iterator_base<Interface, Master, Container_iterator<Interface, Container, Master>, typename Container::iterator, typename Container::value_type>
 {
 	typedef Container_iterator<Interface, Container, Master> iterator_type;
 	typedef typename Container::iterator container_iterator;
 public:
 	explicit Container_iterator(container_iterator i) :
-	   Container_iterator_base<Interface, Container, Master, iterator_type, container_iterator>(i) {}
+	   Container_iterator_base<Interface, Master, iterator_type, container_iterator, typename Container::value_type>(i) {}
 
 	operator typename Master::const_iterator() { return typename Master::const_iterator(this->_iter); }
 	inline iterator_type& operator=(iterator_type const &i) { this->_iter = i._iter; return static_cast<iterator_type&>(*this); }
 	inline iterator_type& operator=(container_iterator const &i) { this->_iter = i; return static_cast<iterator_type&>(*this); }
+
+	inline virtual typename Container::value_type getType(void) const APT_OVERRIDE { return *this->_iter; }
 };
 template<class Interface, class Container, class Master> class Container_const_reverse_iterator :
-   public Container_iterator_base<Interface, Container, Master, Container_const_reverse_iterator<Interface, Container, Master>, typename Container::const_reverse_iterator>
+   public Container_iterator_base<Interface, Master, Container_const_reverse_iterator<Interface, Container, Master>, typename Container::const_reverse_iterator, typename Container::value_type>
 {
 	typedef Container_const_reverse_iterator<Interface, Container, Master> iterator_type;
 	typedef typename Container::const_reverse_iterator container_iterator;
 public:
 	explicit Container_const_reverse_iterator(container_iterator i) :
-	   Container_iterator_base<Interface, Container, Master, iterator_type, container_iterator>(i) {}
+	   Container_iterator_base<Interface, Master, iterator_type, container_iterator, typename Container::value_type>(i) {}
+
+	inline virtual typename Container::value_type getType(void) const APT_OVERRIDE { return *this->_iter; }
 };
 template<class Interface, class Container, class Master> class Container_reverse_iterator :
-   public Container_iterator_base<Interface, Container, Master, Container_reverse_iterator<Interface, Container, Master>, typename Container::reverse_iterator>
+   public Container_iterator_base<Interface, Master, Container_reverse_iterator<Interface, Container, Master>, typename Container::reverse_iterator, typename Container::value_type>
 {
 	typedef Container_reverse_iterator<Interface, Container, Master> iterator_type;
 	typedef typename Container::reverse_iterator container_iterator;
 public:
 	explicit Container_reverse_iterator(container_iterator i) :
-	   Container_iterator_base<Interface, Container, Master, iterator_type, container_iterator>(i) {}
+	   Container_iterator_base<Interface, Master, iterator_type, container_iterator, typename Container::value_type>(i) {}
 
 	operator typename Master::const_iterator() { return typename Master::const_iterator(this->_iter); }
 	inline iterator_type& operator=(iterator_type const &i) { this->_iter = i._iter; return static_cast<iterator_type&>(*this); }
 	inline iterator_type& operator=(container_iterator const &i) { this->_iter = i; return static_cast<iterator_type&>(*this); }
+
+	inline virtual typename Container::value_type getType(void) const APT_OVERRIDE { return *this->_iter; }
 };
 									/*}}}*/
 class PackageContainerInterface {					/*{{{*/
@@ -583,6 +591,10 @@ template<> template<class Cont> void PackageContainer<std::forward_list<pkgCache
 		_cont.push_front(*p);
 }
 #endif
+template<> template<class Cont> void PackageContainer<std::deque<pkgCache::PkgIterator> >::insert(PackageContainer<Cont> const &pkgcont) {
+	for (typename PackageContainer<Cont>::const_iterator p = pkgcont.begin(); p != pkgcont.end(); ++p)
+		_cont.push_back(*p);
+}
 template<> template<class Cont> void PackageContainer<std::vector<pkgCache::PkgIterator> >::insert(PackageContainer<Cont> const &pkgcont) {
 	for (typename PackageContainer<Cont>::const_iterator p = pkgcont.begin(); p != pkgcont.end(); ++p)
 		_cont.push_back(*p);
@@ -603,6 +615,12 @@ template<> inline bool PackageContainer<std::forward_list<pkgCache::PkgIterator>
 	return true;
 }
 #endif
+template<> inline bool PackageContainer<std::deque<pkgCache::PkgIterator> >::insert(pkgCache::PkgIterator const &P) {
+	if (P.end() == true)
+		return false;
+	_cont.push_back(P);
+	return true;
+}
 template<> inline bool PackageContainer<std::vector<pkgCache::PkgIterator> >::insert(pkgCache::PkgIterator const &P) {
 	if (P.end() == true)
 		return false;
@@ -619,6 +637,10 @@ template<> inline void PackageContainer<std::forward_list<pkgCache::PkgIterator>
 		_cont.push_front(*p);
 }
 #endif
+template<> inline void PackageContainer<std::deque<pkgCache::PkgIterator> >::insert(const_iterator begin, const_iterator end) {
+	for (const_iterator p = begin; p != end; ++p)
+		_cont.push_back(*p);
+}
 template<> inline void PackageContainer<std::vector<pkgCache::PkgIterator> >::insert(const_iterator begin, const_iterator end) {
 	for (const_iterator p = begin; p != end; ++p)
 		_cont.push_back(*p);
@@ -647,6 +669,10 @@ template<> template<class Compare> inline bool PackageContainer<std::forward_lis
 	return true;
 }
 #endif
+template<> template<class Compare> inline bool PackageContainer<std::deque<pkgCache::PkgIterator> >::sort(Compare Comp) {
+	std::sort(_cont.begin(), _cont.end(), Comp);
+	return true;
+}
 									/*}}}*/
 
 // class PackageUniverse - pkgCache as PackageContainerInterface	/*{{{*/
@@ -657,22 +683,35 @@ template<> template<class Compare> inline bool PackageContainer<std::forward_lis
 
     The wrapping is read-only in practice modeled by making erase and co
     private methods. */
-class APT_HIDDEN PackageUniverse : public PackageContainerInterface {
+class APT_PUBLIC PackageUniverse : public PackageContainerInterface {
 	pkgCache * const _cont;
 	void * const d;
 public:
-	typedef pkgCache::PkgIterator iterator;
-	typedef pkgCache::PkgIterator const_iterator;
+	class const_iterator : public APT::Container_iterator_base<APT::PackageContainerInterface, PackageUniverse, PackageUniverse::const_iterator, pkgCache::PkgIterator, pkgCache::PkgIterator>
+	{
+	protected:
+	   inline virtual pkgCache::PkgIterator getType(void) const APT_OVERRIDE
+	   {
+	      return _iter;
+	   }
+	public:
+	   explicit const_iterator(pkgCache::PkgIterator i):
+	      Container_iterator_base<APT::PackageContainerInterface, PackageUniverse, PackageUniverse::const_iterator, pkgCache::PkgIterator, pkgCache::PkgIterator>(i) {}
+
+	};
+	typedef const_iterator iterator;
 
 	APT_PUBLIC bool empty() const APT_OVERRIDE { return false; }
 	APT_PUBLIC size_t size() const APT_OVERRIDE { return _cont->Head().PackageCount; }
 
-	APT_PUBLIC const_iterator begin() const { return _cont->PkgBegin(); }
-	APT_PUBLIC const_iterator end() const { return  _cont->PkgEnd(); }
-	APT_PUBLIC const_iterator cbegin() const { return _cont->PkgBegin(); }
-	APT_PUBLIC const_iterator cend() const { return  _cont->PkgEnd(); }
-	APT_PUBLIC iterator begin() { return _cont->PkgBegin(); }
-	APT_PUBLIC iterator end() { return _cont->PkgEnd(); }
+	APT_PUBLIC const_iterator begin() const { return const_iterator(_cont->PkgBegin()); }
+	APT_PUBLIC const_iterator end() const { return const_iterator(_cont->PkgEnd()); }
+	APT_PUBLIC const_iterator cbegin() const { return const_iterator(_cont->PkgBegin()); }
+	APT_PUBLIC const_iterator cend() const { return const_iterator(_cont->PkgEnd()); }
+	APT_PUBLIC iterator begin() { return iterator(_cont->PkgBegin()); }
+	APT_PUBLIC iterator end() { return iterator(_cont->PkgEnd()); }
+
+	APT_PUBLIC pkgCache * data() const { return _cont; }
 
 	explicit APT_PUBLIC PackageUniverse(pkgCache * const Owner);
 	APT_PUBLIC virtual ~PackageUniverse();
@@ -693,6 +732,7 @@ typedef PackageContainer<std::unordered_set<pkgCache::PkgIterator> > PackageUnor
 typedef PackageContainer<std::forward_list<pkgCache::PkgIterator> > PackageForwardList;
 #endif
 typedef PackageContainer<std::list<pkgCache::PkgIterator> > PackageList;
+typedef PackageContainer<std::deque<pkgCache::PkgIterator> > PackageDeque;
 typedef PackageContainer<std::vector<pkgCache::PkgIterator> > PackageVector;
 
 class VersionContainerInterface {					/*{{{*/
@@ -1059,6 +1099,10 @@ template<> template<class Cont> void VersionContainer<std::forward_list<pkgCache
 		_cont.push_front(*v);
 }
 #endif
+template<> template<class Cont> void VersionContainer<std::deque<pkgCache::VerIterator> >::insert(VersionContainer<Cont> const &vercont) {
+	for (typename VersionContainer<Cont>::const_iterator v = vercont.begin(); v != vercont.end(); ++v)
+		_cont.push_back(*v);
+}
 template<> template<class Cont> void VersionContainer<std::vector<pkgCache::VerIterator> >::insert(VersionContainer<Cont> const &vercont) {
 	for (typename VersionContainer<Cont>::const_iterator v = vercont.begin(); v != vercont.end(); ++v)
 		_cont.push_back(*v);
@@ -1079,6 +1123,12 @@ template<> inline bool VersionContainer<std::forward_list<pkgCache::VerIterator>
 	return true;
 }
 #endif
+template<> inline bool VersionContainer<std::deque<pkgCache::VerIterator> >::insert(pkgCache::VerIterator const &V) {
+	if (V.end() == true)
+		return false;
+	_cont.push_back(V);
+	return true;
+}
 template<> inline bool VersionContainer<std::vector<pkgCache::VerIterator> >::insert(pkgCache::VerIterator const &V) {
 	if (V.end() == true)
 		return false;
@@ -1095,6 +1145,10 @@ template<> inline void VersionContainer<std::forward_list<pkgCache::VerIterator>
 		_cont.push_front(*v);
 }
 #endif
+template<> inline void VersionContainer<std::deque<pkgCache::VerIterator> >::insert(const_iterator begin, const_iterator end) {
+	for (const_iterator v = begin; v != end; ++v)
+		_cont.push_back(*v);
+}
 template<> inline void VersionContainer<std::vector<pkgCache::VerIterator> >::insert(const_iterator begin, const_iterator end) {
 	for (const_iterator v = begin; v != end; ++v)
 		_cont.push_back(*v);
@@ -1123,6 +1177,10 @@ template<> template<class Compare> inline bool VersionContainer<std::forward_lis
 	return true;
 }
 #endif
+template<> template<class Compare> inline bool VersionContainer<std::deque<pkgCache::VerIterator> >::sort(Compare Comp) {
+	std::sort(_cont.begin(), _cont.end(), Comp);
+	return true;
+}
 									/*}}}*/
 
 typedef VersionContainer<std::set<pkgCache::VerIterator> > VersionSet;
@@ -1131,6 +1189,7 @@ typedef VersionContainer<std::unordered_set<pkgCache::VerIterator> > VersionUnor
 typedef VersionContainer<std::forward_list<pkgCache::VerIterator> > VersionForwardList;
 #endif
 typedef VersionContainer<std::list<pkgCache::VerIterator> > VersionList;
+typedef VersionContainer<std::deque<pkgCache::VerIterator> > VersionDeque;
 typedef VersionContainer<std::vector<pkgCache::VerIterator> > VersionVector;
 }
 #endif

+ 31 - 30
apt-private/private-cachefile.cc

@@ -7,7 +7,7 @@
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/pkgcache.h>
-#include <apt-pkg/cacheiterators.h>
+#include <apt-pkg/cacheset.h>
 
 #include <apt-private/private-output.h>
 #include <apt-private/private-cachefile.h>
@@ -21,39 +21,40 @@
 
 using namespace std;
 
-// CacheFile::NameComp - QSort compare by name				/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-pkgCache *CacheFile::SortCache = 0;
-int CacheFile::NameComp(const void *a,const void *b)
+static bool SortPackagesByName(pkgCache * const Owner,
+      map_pointer_t const A, map_pointer_t const B)
 {
-   if (*(pkgCache::Package **)a == 0 || *(pkgCache::Package **)b == 0)
-      return *(pkgCache::Package **)a - *(pkgCache::Package **)b;
-   
-   const pkgCache::Package &A = **(pkgCache::Package **)a;
-   const pkgCache::Package &B = **(pkgCache::Package **)b;
-   const pkgCache::Group * const GA = SortCache->GrpP + A.Group;
-   const pkgCache::Group * const GB = SortCache->GrpP + B.Group;
-
-   return strcmp(SortCache->StrP + GA->Name,SortCache->StrP + GB->Name);
+   if (A == 0)
+      return false;
+   if (B == 0 || A == B)
+      return true;
+   pkgCache::Group const * const GA = Owner->GrpP + A;
+   pkgCache::Group const * const GB = Owner->GrpP + B;
+   return strcmp(Owner->StrP + GA->Name, Owner->StrP + GB->Name) <= 0;
 }
-									/*}}}*/
-// CacheFile::Sort - Sort by name					/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void CacheFile::Sort()
+SortedPackageUniverse::SortedPackageUniverse(CacheFile &Cache) :
+      PackageUniverse{Cache}, List{Cache.UniverseList}
 {
-   delete [] List;
-   List = new pkgCache::Package *[Cache->Head().PackageCount];
-   memset(List,0,sizeof(*List)*Cache->Head().PackageCount);
-   pkgCache::PkgIterator I = Cache->PkgBegin();
-   for (;I.end() != true; ++I)
-      List[I->ID] = I;
-
-   SortCache = *this;
-   qsort(List,Cache->Head().PackageCount,sizeof(*List),NameComp);
 }
-									/*}}}*/
+void SortedPackageUniverse::LazyInit() const
+{
+   if (List.empty() == false)
+      return;
+   pkgCache * const Owner = data();
+   // In Multi-Arch systems Grps are easier to sort than Pkgs
+   std::vector<map_pointer_t> GrpList;
+   List.reserve(Owner->Head().GroupCount);
+   for (pkgCache::GrpIterator I{Owner->GrpBegin()}; I.end() != true; ++I)
+      GrpList.emplace_back(I - Owner->GrpP);
+   std::stable_sort(GrpList.begin(), GrpList.end(), std::bind( &SortPackagesByName, Owner, std::placeholders::_1, std::placeholders::_2 ));
+   List.reserve(Owner->Head().PackageCount);
+   for (auto G : GrpList)
+   {
+      pkgCache::GrpIterator const Grp(*Owner, Owner->GrpP + G);
+      for (pkgCache::PkgIterator P = Grp.PackageList(); P.end() != true; P = Grp.NextPkg(P))
+	 List.emplace_back(P - Owner->PkgP);
+   }
+}
 // CacheFile::CheckDeps - Open the cache file				/*{{{*/
 // ---------------------------------------------------------------------
 /* This routine generates the caches and then opens the dependency cache

+ 39 - 20
apt-private/private-cachefile.h

@@ -7,12 +7,13 @@
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/macros.h>
 #include <apt-pkg/sourcelist.h>
+#include <apt-pkg/cacheset.h>
+
 #include <apti18n.h>
 
-// FIXME: we need to find a way to export this 
+// FIXME: we need to find a way to export this
 class APT_PUBLIC SourceList : public pkgSourceList
 {
-   
  public:
    // Add custom metaIndex (e.g. local files)
    void AddMetaIndex(metaIndex *mi) {
@@ -22,17 +23,11 @@ class APT_PUBLIC SourceList : public pkgSourceList
 };
 
 // class CacheFile - Cover class for some dependency cache functions	/*{{{*/
-// ---------------------------------------------------------------------
-/* */
 class APT_PUBLIC CacheFile : public pkgCacheFile
 {
-   static pkgCache *SortCache;
-   APT_HIDDEN static int NameComp(const void *a,const void *b) APT_PURE;
-
    public:
-   pkgCache::Package **List;
-   
-   void Sort();
+   std::vector<map_pointer_t> UniverseList;
+
    bool CheckDeps(bool AllowBroken = false);
    bool BuildCaches(bool WithLock = true)
    {
@@ -51,14 +46,10 @@ class APT_PUBLIC CacheFile : public pkgCacheFile
          return _error->Error(_("The list of sources could not be read."));
       return true;
    }
-   bool Open(bool WithLock = true) 
+   bool Open(bool WithLock = true)
    {
       OpTextProgress Prog(*_config);
-      if (pkgCacheFile::Open(&Prog,WithLock) == false)
-	 return false;
-      Sort();
-      
-      return true;
+      return pkgCacheFile::Open(&Prog,WithLock);
    };
    bool OpenForInstall()
    {
@@ -67,11 +58,39 @@ class APT_PUBLIC CacheFile : public pkgCacheFile
       else
 	 return Open(true);
    }
-   CacheFile() : List(0) {};
-   ~CacheFile() {
-      delete[] List;
-   }
 };
 									/*}}}*/
 
+class APT_PUBLIC SortedPackageUniverse : public APT::PackageUniverse
+{
+   std::vector<map_pointer_t> &List;
+   void LazyInit() const;
+
+public:
+   SortedPackageUniverse(CacheFile &Cache);
+
+   class const_iterator : public APT::Container_iterator_base<APT::PackageContainerInterface, SortedPackageUniverse, SortedPackageUniverse::const_iterator, std::vector<map_pointer_t>::const_iterator, pkgCache::PkgIterator>
+   {
+      pkgCache * const Cache;
+      protected:
+	 inline virtual pkgCache::PkgIterator getType(void) const APT_OVERRIDE
+	 {
+	    if (*_iter == 0) return pkgCache::PkgIterator(*Cache);
+	    return pkgCache::PkgIterator(*Cache, Cache->PkgP + *_iter);
+	 }
+      public:
+	 explicit const_iterator(pkgCache * const Owner, std::vector<map_pointer_t>::const_iterator i):
+	    Container_iterator_base<APT::PackageContainerInterface, SortedPackageUniverse, SortedPackageUniverse::const_iterator, std::vector<map_pointer_t>::const_iterator, pkgCache::PkgIterator>(i), Cache(Owner) {}
+
+   };
+   typedef const_iterator iterator;
+
+   APT_PUBLIC const_iterator begin() const { LazyInit(); return const_iterator(data(), List.begin()); }
+   APT_PUBLIC const_iterator end() const { LazyInit(); return const_iterator(data(), List.end()); }
+   APT_PUBLIC const_iterator cbegin() const { LazyInit(); return const_iterator(data(), List.begin()); }
+   APT_PUBLIC const_iterator cend() const { LazyInit(); return const_iterator(data(), List.end()); }
+   APT_PUBLIC iterator begin() { LazyInit(); return iterator(data(), List.begin()); }
+   APT_PUBLIC iterator end() { LazyInit(); return iterator(data(), List.end()); }
+};
+
 #endif

+ 9 - 7
apt-private/private-cacheset.h

@@ -12,6 +12,8 @@
 #include <apt-pkg/cacheiterators.h>
 #include <apt-pkg/macros.h>
 
+#include <apt-private/private-output.h>
+
 #include <algorithm>
 #include <vector>
 #include <string.h>
@@ -21,8 +23,6 @@
 #include <string>
 #include <utility>
 
-#include "private-output.h"
-
 #include <apti18n.h>
 
 class OpProgress;
@@ -174,17 +174,19 @@ public:
 				std::string VersionsList;
 				SPtrArray<bool> Seen = new bool[Cache.GetPkgCache()->Head().PackageCount];
 				memset(Seen,0,Cache.GetPkgCache()->Head().PackageCount*sizeof(*Seen));
+				APT::PackageList pkglist;
 				for (pkgCache::DepIterator Dep = Pkg.RevDependsList();
 				     Dep.end() == false; ++Dep) {
 					if (Dep->Type != pkgCache::Dep::Replaces)
 						continue;
-					if (Seen[Dep.ParentPkg()->ID] == true)
+					pkgCache::PkgIterator const DP = Dep.ParentPkg();
+					if (Seen[DP->ID] == true)
 						continue;
-					Seen[Dep.ParentPkg()->ID] = true;
-					List += Dep.ParentPkg().FullName(true) + " ";
-					//VersionsList += std::string(Dep.ParentPkg().CurVersion) + "\n"; ???
+					Seen[DP->ID] = true;
+					pkglist.insert(DP);
 				}
-				ShowList(c1out,_("However the following packages replace it:"),List,VersionsList);
+				ShowList(c1out, _("However the following packages replace it:"), pkglist,
+				      &AlwaysTrue, &PrettyFullName, &EmptyString);
 			}
 			c1out << std::endl;
 		}

+ 27 - 42
apt-private/private-install.cc

@@ -374,11 +374,10 @@ static bool DoAutomaticRemove(CacheFile &Cache)
 
    unsigned long autoRemoveCount = 0;
    APT::PackageSet tooMuch;
-   APT::PackageList autoRemoveList;
+   SortedPackageUniverse Universe(Cache);
    // look over the cache to see what can be removed
-   for (unsigned J = 0; J < Cache->Head().PackageCount; ++J)
+   for (auto const &Pkg: Universe)
    {
-      pkgCache::PkgIterator Pkg(Cache,Cache.List[J]);
       if (Cache[Pkg].Garbage)
       {
 	 if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install())
@@ -395,8 +394,6 @@ static bool DoAutomaticRemove(CacheFile &Cache)
 	 }
 	 else
 	 {
-	    if (hideAutoRemove == false && Cache[Pkg].Delete() == false)
-	       autoRemoveList.insert(Pkg);
 	    // if the package is a new install and already garbage we don't need to
 	    // install it in the first place, so nuke it instead of show it
 	    if (Cache[Pkg].Install() == true && Pkg.CurrentVer() == 0)
@@ -456,18 +453,6 @@ static bool DoAutomaticRemove(CacheFile &Cache)
       } while (Changed == true);
    }
 
-   std::string autoremovelist, autoremoveversions;
-   if (smallList == false && autoRemoveCount != 0)
-   {
-      for (APT::PackageList::const_iterator Pkg = autoRemoveList.begin(); Pkg != autoRemoveList.end(); ++Pkg)
-      {
-	 if (Cache[Pkg].Garbage == false)
-	    continue;
-	 autoremovelist += Pkg.FullName(true) + " ";
-	 autoremoveversions += std::string(Cache[Pkg].CandVersion) + "\n";
-      }
-   }
-
    // Now see if we had destroyed anything (if we had done anything)
    if (Cache->BrokenCount() != 0)
    {
@@ -482,12 +467,17 @@ static bool DoAutomaticRemove(CacheFile &Cache)
    }
 
    // if we don't remove them, we should show them!
-   if (doAutoRemove == false && (autoremovelist.empty() == false || autoRemoveCount != 0))
+   if (doAutoRemove == false && autoRemoveCount != 0)
    {
       if (smallList == false)
+      {
+	 SortedPackageUniverse Universe(Cache);
 	 ShowList(c1out, P_("The following package was automatically installed and is no longer required:",
 	          "The following packages were automatically installed and are no longer required:",
-	          autoRemoveCount), autoremovelist, autoremoveversions);
+	          autoRemoveCount), Universe,
+	       [&Cache](pkgCache::PkgIterator const &Pkg) { return (*Cache)[Pkg].Garbage == true && (*Cache)[Pkg].Delete() == false; },
+	       &PrettyFullName, CandidateVersion(&Cache));
+      }
       else
 	 ioprintf(c1out, P_("%lu package was automatically installed and is no longer required.\n",
 	          "%lu packages were automatically installed and are no longer required.\n", autoRemoveCount), autoRemoveCount);
@@ -651,6 +641,18 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache,
 // DoInstall - Install packages from the command line			/*{{{*/
 // ---------------------------------------------------------------------
 /* Install named packages */
+struct PkgIsExtraInstalled {
+   pkgCacheFile * const Cache;
+   APT::VersionSet const * const verset;
+   PkgIsExtraInstalled(pkgCacheFile * const Cache, APT::VersionSet const * const Container) : Cache(Cache), verset(Container) {}
+   bool operator() (pkgCache::PkgIterator const Pkg)
+   {
+        if ((*Cache)[Pkg].Install() == false)
+           return false;
+        pkgCache::VerIterator const Cand = (*Cache)[Pkg].CandidateVerIter(*Cache);
+        return verset->find(Cand) == verset->end();
+   }
+};
 bool DoInstall(CommandLine &CmdL)
 {
    CacheFile Cache;
@@ -689,35 +691,18 @@ bool DoInstall(CommandLine &CmdL)
 
    /* Print out a list of packages that are going to be installed extra
       to what the user asked */
+   SortedPackageUniverse Universe(Cache);
    if (Cache->InstCount() != verset[MOD_INSTALL].size())
-   {
-      std::string List;
-      std::string VersionsList;
-      for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-      {
-	 pkgCache::PkgIterator I(Cache,Cache.List[J]);
-	 if ((*Cache)[I].Install() == false)
-	    continue;
-	 pkgCache::VerIterator Cand = Cache[I].CandidateVerIter(Cache);
-
-	 if (verset[MOD_INSTALL].find(Cand) != verset[MOD_INSTALL].end())
-	    continue;
-
-	 List += I.FullName(true) + " ";
-	 VersionsList += std::string(Cache[I].CandVersion) + "\n";
-      }
-      
-      ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList);
-   }
+      ShowList(c1out, _("The following extra packages will be installed:"), Universe,
+	    PkgIsExtraInstalled(&Cache, &verset[MOD_INSTALL]),
+	    &PrettyFullName, CandidateVersion(&Cache));
 
    /* Print out a list of suggested and recommended packages */
    {
       std::string SuggestsList, RecommendsList;
       std::string SuggestsVersions, RecommendsVersions;
-      for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
+      for (auto const &Pkg: Universe)
       {
-	 pkgCache::PkgIterator Pkg(Cache,Cache.List[J]);
-
 	 /* Just look at the ones we want to install */
 	 if ((*Cache)[Pkg].Install() == false)
 	   continue;
@@ -738,7 +723,6 @@ bool DoInstall(CommandLine &CmdL)
 	    for(;;)
 	    {
 	       /* Skip if package is  installed already, or is about to be */
-               std::string target = Start.TargetPkg().FullName(true) + " ";
 	       pkgCache::PkgIterator const TarPkg = Start.TargetPkg();
 	       if (TarPkg->SelectedState == pkgCache::State::Install ||
 		   TarPkg->SelectedState == pkgCache::State::Hold ||
@@ -749,6 +733,7 @@ bool DoInstall(CommandLine &CmdL)
 	       }
 
 	       /* Skip if we already saw it */
+               std::string target = Start.TargetPkg().FullName(true) + " ";
 	       if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1)
 	       {
 		  foundInstalledInOrGroup=true;

+ 127 - 136
apt-private/private-output.cc

@@ -25,6 +25,8 @@
 #include <signal.h>
 #include <sys/ioctl.h>
 
+#include <sstream>
+
 #include <apti18n.h>
 									/*}}}*/
 
@@ -491,11 +493,9 @@ void ShowBroken(ostream &out, CacheFile &Cache, bool const Now)
       return;
 
    out << _("The following packages have unmet dependencies:") << endl;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator const I(Cache,Cache.List[J]);
-      ShowBrokenPackage(out, &Cache, I, Now);
-   }
+   SortedPackageUniverse Universe(Cache);
+   for (auto const &Pkg: Universe)
+      ShowBrokenPackage(out, &Cache, Pkg, Now);
 }
 void ShowBroken(ostream &out, pkgCacheFile &Cache, bool const Now)
 {
@@ -503,98 +503,64 @@ void ShowBroken(ostream &out, pkgCacheFile &Cache, bool const Now)
       return;
 
    out << _("The following packages have unmet dependencies:") << endl;
-   for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
+   APT::PackageUniverse Universe(Cache);
+   for (auto const &Pkg: Universe)
       ShowBrokenPackage(out, &Cache, Pkg, Now);
 }
 									/*}}}*/
 // ShowNew - Show packages to newly install				/*{{{*/
-// ---------------------------------------------------------------------
-/* */
 void ShowNew(ostream &out,CacheFile &Cache)
 {
-   /* Print out a list of packages that are going to be installed extra
-      to what the user asked */
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      if (Cache[I].NewInstall() == true) {
-         List += I.FullName(true) + " ";
-         VersionsList += string(Cache[I].CandVersion) + "\n";
-      }
-   }
-   
-   ShowList(out,_("The following NEW packages will be installed:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   ShowList(out,_("The following NEW packages will be installed:"), Universe,
+	 [&Cache](pkgCache::PkgIterator const &Pkg) { return Cache[Pkg].NewInstall(); },
+	 &PrettyFullName,
+	 CandidateVersion(&Cache));
 }
 									/*}}}*/
 // ShowDel - Show packages to delete					/*{{{*/
-// ---------------------------------------------------------------------
-/* */
 void ShowDel(ostream &out,CacheFile &Cache)
 {
-   /* Print out a list of packages that are going to be removed extra
-      to what the user asked */
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      if (Cache[I].Delete() == true)
-      {
-	 if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
-	    List += I.FullName(true) + "* ";
-	 else
-	    List += I.FullName(true) + " ";
-     
-     VersionsList += string(Cache[I].CandVersion)+ "\n";
-      }
-   }
-   
-   ShowList(out,_("The following packages will be REMOVED:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   ShowList(out,_("The following packages will be REMOVED:"), Universe,
+	 [&Cache](pkgCache::PkgIterator const &Pkg) { return Cache[Pkg].Delete(); },
+	 [&Cache](pkgCache::PkgIterator const &Pkg)
+	 {
+	    std::string str = PrettyFullName(Pkg);
+	    if (((*Cache)[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
+	       str.append("*");
+	    return str;
+	 },
+	 CandidateVersion(&Cache));
 }
 									/*}}}*/
 // ShowKept - Show kept packages					/*{{{*/
-// ---------------------------------------------------------------------
-/* */
 void ShowKept(ostream &out,CacheFile &Cache)
 {
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {	 
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      
-      // Not interesting
-      if (Cache[I].Upgrade() == true || Cache[I].Upgradable() == false ||
-	  I->CurrentVer == 0 || Cache[I].Delete() == true)
-	 continue;
-      
-      List += I.FullName(true) + " ";
-      VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
-   }
-   ShowList(out,_("The following packages have been kept back:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   ShowList(out,_("The following packages have been kept back:"), Universe,
+	 [&Cache](pkgCache::PkgIterator const &Pkg)
+	 {
+	    return Cache[Pkg].Upgrade() == false &&
+		   Cache[Pkg].Upgradable() == true &&
+		   Pkg->CurrentVer != 0 &&
+		   Cache[Pkg].Delete() == false;
+	 },
+	 &PrettyFullName,
+	 CurrentToCandidateVersion(&Cache));
 }
 									/*}}}*/
 // ShowUpgraded - Show upgraded packages				/*{{{*/
-// ---------------------------------------------------------------------
-/* */
 void ShowUpgraded(ostream &out,CacheFile &Cache)
 {
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      
-      // Not interesting
-      if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
-	 continue;
-
-      List += I.FullName(true) + " ";
-      VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
-   }
-   ShowList(out,_("The following packages will be upgraded:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   ShowList(out,_("The following packages will be upgraded:"), Universe,
+	 [&Cache](pkgCache::PkgIterator const &Pkg)
+	 {
+	    return Cache[Pkg].Upgrade() == true && Cache[Pkg].NewInstall() == false;
+	 },
+	 &PrettyFullName,
+	 CurrentToCandidateVersion(&Cache));
 }
 									/*}}}*/
 // ShowDowngraded - Show downgraded packages				/*{{{*/
@@ -602,74 +568,73 @@ void ShowUpgraded(ostream &out,CacheFile &Cache)
 /* */
 bool ShowDowngraded(ostream &out,CacheFile &Cache)
 {
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      
-      // Not interesting
-      if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true)
-	 continue;
-
-      List += I.FullName(true) + " ";
-      VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
-   }
-   return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   return ShowList(out,_("The following packages will be DOWNGRADED:"), Universe,
+	 [&Cache](pkgCache::PkgIterator const &Pkg)
+	 {
+	    return Cache[Pkg].Downgrade() == true && Cache[Pkg].NewInstall() == false;
+	 },
+	 &PrettyFullName,
+	 CurrentToCandidateVersion(&Cache));
 }
 									/*}}}*/
 // ShowHold - Show held but changed packages				/*{{{*/
-// ---------------------------------------------------------------------
-/* */
 bool ShowHold(ostream &out,CacheFile &Cache)
 {
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() &&
-          I->SelectedState == pkgCache::State::Hold) {
-         List += I.FullName(true) + " ";
-		 VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
-      }
-   }
-
-   return ShowList(out,_("The following held packages will be changed:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   return ShowList(out,_("The following held packages will be changed:"), Universe,
+	 [&Cache](pkgCache::PkgIterator const &Pkg)
+	 {
+	    return Pkg->SelectedState == pkgCache::State::Hold &&
+		   Cache[Pkg].InstallVer != (pkgCache::Version *)Pkg.CurrentVer();
+	 },
+	 &PrettyFullName,
+	 CurrentToCandidateVersion(&Cache));
 }
 									/*}}}*/
 // ShowEssential - Show an essential package warning			/*{{{*/
 // ---------------------------------------------------------------------
 /* This prints out a warning message that is not to be ignored. It shows
-   all essential packages and their dependents that are to be removed. 
+   all essential packages and their dependents that are to be removed.
    It is insanely risky to remove the dependents of an essential package! */
+struct APT_HIDDEN PrettyFullNameWithDue {
+   std::map<unsigned long long, pkgCache::PkgIterator> due;
+   PrettyFullNameWithDue() {}
+   std::string operator() (pkgCache::PkgIterator const &Pkg)
+   {
+      std::string const A = PrettyFullName(Pkg);
+      std::map<unsigned long long, pkgCache::PkgIterator>::const_iterator d = due.find(Pkg->ID);
+      if (d == due.end())
+        return A;
+
+      std::string const B = PrettyFullName(d->second);
+      std::ostringstream outstr;
+      ioprintf(outstr, _("%s (due to %s)"), A.c_str(), B.c_str());
+      return outstr.str();
+   }
+};
 bool ShowEssential(ostream &out,CacheFile &Cache)
 {
-   string List;
-   string VersionsList;
-   bool *Added = new bool[Cache->Head().PackageCount];
-   for (unsigned int I = 0; I != Cache->Head().PackageCount; I++)
-      Added[I] = false;
-   
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
+   std::vector<bool> Added(Cache->Head().PackageCount, false);
+   APT::PackageDeque pkglist;
+   PrettyFullNameWithDue withdue;
+
+   SortedPackageUniverse Universe(Cache);
+   for (pkgCache::PkgIterator const &I: Universe)
    {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if ((I->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
 	  (I->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important)
 	 continue;
-      
+
       // The essential package is being removed
-      if (Cache[I].Delete() == true)
+      if (Cache[I].Delete() == false)
+	 continue;
+
+      if (Added[I->ID] == false)
       {
-	 if (Added[I->ID] == false)
-	 {
-	    Added[I->ID] = true;
-	    List += I.FullName(true) + " ";
-        //VersionsList += string(Cache[I].CurVersion) + "\n"; ???
-	 }
+	 Added[I->ID] = true;
+	 pkglist.insert(I);
       }
-      else
-	 continue;
 
       if (I->CurrentVer == 0)
 	 continue;
@@ -681,27 +646,23 @@ bool ShowEssential(ostream &out,CacheFile &Cache)
 	 if (D->Type != pkgCache::Dep::PreDepends &&
 	     D->Type != pkgCache::Dep::Depends)
 	    continue;
-	 
+
 	 pkgCache::PkgIterator P = D.SmartTargetPkg();
 	 if (Cache[P].Delete() == true)
 	 {
 	    if (Added[P->ID] == true)
 	       continue;
 	    Added[P->ID] = true;
-	    
-	    char S[300];
-	    snprintf(S,sizeof(S),_("%s (due to %s) "),P.FullName(true).c_str(),I.FullName(true).c_str());
-	    List += S;
-        //VersionsList += "\n"; ???
-	 }	 
-      }      
+
+	    pkglist.insert(P);
+	    withdue.due[P->ID] = I;
+	 }
+      }
    }
-   
-   delete [] Added;
    return ShowList(out,_("WARNING: The following essential packages will be removed.\n"
-			 "This should NOT be done unless you know exactly what you are doing!"),List,VersionsList);
+			 "This should NOT be done unless you know exactly what you are doing!"),
+	 pkglist, &AlwaysTrue, withdue, &EmptyString);
 }
-
 									/*}}}*/
 // Stats - Show some statistics						/*{{{*/
 // ---------------------------------------------------------------------
@@ -829,3 +790,33 @@ bool AnalPrompt(const char *Text)
    return false;
 }
 									/*}}}*/
+
+std::string PrettyFullName(pkgCache::PkgIterator const &Pkg)
+{
+   return Pkg.FullName(true);
+}
+std::string CandidateVersion(pkgCacheFile * const Cache, pkgCache::PkgIterator const &Pkg)
+{
+   return (*Cache)[Pkg].CandVersion;
+}
+std::function<std::string(pkgCache::PkgIterator const &)> CandidateVersion(pkgCacheFile * const Cache)
+{
+   return std::bind(static_cast<std::string(*)(pkgCacheFile * const, pkgCache::PkgIterator const&)>(&CandidateVersion), Cache, std::placeholders::_1);
+}
+std::string CurrentToCandidateVersion(pkgCacheFile * const Cache, pkgCache::PkgIterator const &Pkg)
+{
+   return std::string((*Cache)[Pkg].CurVersion) + " => " + (*Cache)[Pkg].CandVersion;
+}
+std::function<std::string(pkgCache::PkgIterator const &)> CurrentToCandidateVersion(pkgCacheFile * const Cache)
+{
+   return std::bind(static_cast<std::string(*)(pkgCacheFile * const, pkgCache::PkgIterator const&)>(&CurrentToCandidateVersion), Cache, std::placeholders::_1);
+}
+bool AlwaysTrue(pkgCache::PkgIterator const &)
+{
+      return true;
+}
+std::string EmptyString(pkgCache::PkgIterator const &)
+{
+   return std::string();
+}
+

+ 66 - 1
apt-private/private-output.h

@@ -1,9 +1,11 @@
 #ifndef APT_PRIVATE_OUTPUT_H
 #define APT_PRIVATE_OUTPUT_H
 
+#include <apt-pkg/configuration.h>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/macros.h>
 
+#include <functional>
 #include <fstream>
 #include <string>
 #include <iostream>
@@ -32,8 +34,63 @@ void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records,
 APT_PUBLIC void ShowBroken(std::ostream &out, CacheFile &Cache, bool const Now);
 APT_PUBLIC void ShowBroken(std::ostream &out, pkgCacheFile &Cache, bool const Now);
 
-APT_PUBLIC bool ShowList(std::ostream &out, std::string Title, std::string List,
+template<class Container> APT_PUBLIC bool ShowList(std::ostream &out, std::string const &Title,
+      Container const &cont,
+      std::function<bool(pkgCache::PkgIterator const &)> Predicate,
+      std::function<std::string(pkgCache::PkgIterator const &)> PkgDisplay,
+      std::function<std::string(pkgCache::PkgIterator const &)> VerboseDisplay)
+{
+   size_t const ScreenWidth = (::ScreenWidth > 3) ? ::ScreenWidth - 3 : 0;
+   int ScreenUsed = 0;
+   bool const ShowVersions = _config->FindB("APT::Get::Show-Versions", false);
+   bool printedTitle = false;
+
+   for (auto const &Pkg: cont)
+   {
+      if (Predicate(Pkg) == false)
+	 continue;
+
+      if (printedTitle == false)
+      {
+	 out << Title;
+	 printedTitle = true;
+      }
+
+      if (ShowVersions == true)
+      {
+	 out << std::endl << "   " << PkgDisplay(Pkg);
+	 std::string const verbose = VerboseDisplay(Pkg);
+	 if (verbose.empty() == false)
+	    out << " (" << verbose << ")";
+      }
+      else
+      {
+	 std::string const PkgName = PkgDisplay(Pkg);
+	 if (ScreenUsed == 0 || (ScreenUsed + PkgName.length()) >= ScreenWidth)
+	 {
+	    out << std::endl << "  ";
+	    ScreenUsed = 0;
+	 }
+	 else if (ScreenUsed != 0)
+	 {
+	    out << " ";
+	    ++ScreenUsed;
+	 }
+	 out << PkgName;
+	 ScreenUsed += PkgName.length();
+      }
+   }
+
+   if (printedTitle == true)
+   {
+      out << std::endl;
+      return false;
+   }
+   return true;
+}
+APT_DEPRECATED APT_PUBLIC bool ShowList(std::ostream &out, std::string Title, std::string List,
               std::string VersionsList);
+
 void ShowNew(std::ostream &out,CacheFile &Cache);
 void ShowDel(std::ostream &out,CacheFile &Cache);
 void ShowKept(std::ostream &out,CacheFile &Cache);
@@ -49,4 +106,12 @@ void Stats(std::ostream &out, pkgDepCache &Dep);
 bool YnPrompt(bool Default=true);
 bool AnalPrompt(const char *Text);
 
+APT_PUBLIC std::string PrettyFullName(pkgCache::PkgIterator const &Pkg);
+APT_PUBLIC std::string CandidateVersion(pkgCacheFile * const Cache, pkgCache::PkgIterator const &Pkg);
+APT_PUBLIC std::function<std::string(pkgCache::PkgIterator const &)> CandidateVersion(pkgCacheFile * const Cache);
+APT_PUBLIC std::string CurrentToCandidateVersion(pkgCacheFile * const Cache, pkgCache::PkgIterator const &Pkg);
+APT_PUBLIC std::function<std::string(pkgCache::PkgIterator const &)> CurrentToCandidateVersion(pkgCacheFile * const Cache);
+APT_PUBLIC std::string EmptyString(pkgCache::PkgIterator const &);
+APT_PUBLIC bool AlwaysTrue(pkgCache::PkgIterator const &);
+
 #endif

+ 1 - 1
po/apt-all.pot

@@ -1135,7 +1135,7 @@ msgstr ""
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
+msgid "%s (due to %s)"
 msgstr ""
 
 #: apt-private/private-output.cc:696

+ 2 - 2
po/ar.po

@@ -1151,8 +1151,8 @@ msgstr "سيتم تغيير الحزم المبقاة التالية:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (بسبب %s) "
+msgid "%s (due to %s)"
+msgstr "%s (بسبب %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/ast.po

@@ -1261,8 +1261,8 @@ msgstr "Van camudase los siguientes paquetes reteníos:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (por %s) "
+msgid "%s (due to %s)"
+msgstr "%s (por %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/bg.po

@@ -1294,8 +1294,8 @@ msgstr "Следните задържани пакети ще бъдат про
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (поради %s) "
+msgid "%s (due to %s)"
+msgstr "%s (поради %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 1 - 1
po/bs.po

@@ -1159,7 +1159,7 @@ msgstr ""
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
+msgid "%s (due to %s)"
 msgstr ""
 
 #: apt-private/private-output.cc:696

+ 2 - 2
po/ca.po

@@ -1276,8 +1276,8 @@ msgstr "Es canviaran els paquets retinguts següents:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (per %s) "
+msgid "%s (due to %s)"
+msgstr "%s (per %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/cs.po

@@ -1301,8 +1301,8 @@ msgstr "Následující podržené balíky budou změněny:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (kvůli %s) "
+msgid "%s (due to %s)"
+msgstr "%s (kvůli %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/cy.po

@@ -1288,8 +1288,8 @@ msgstr "Caiff y pecynnau wedi eu dal canlynol eu newid:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (oherwydd %s) "
+msgid "%s (due to %s)"
+msgstr "%s (oherwydd %s)"
 
 #: apt-private/private-output.cc:696
 #, fuzzy

+ 2 - 2
po/da.po

@@ -1319,8 +1319,8 @@ msgstr "Følgende tilbageholdte pakker vil blive ændret:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (grundet %s) "
+msgid "%s (due to %s)"
+msgstr "%s (grundet %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/de.po

@@ -1364,8 +1364,8 @@ msgstr "Die folgenden zurückgehaltenen Pakete werden verändert:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (wegen %s) "
+msgid "%s (due to %s)"
+msgstr "%s (wegen %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 1 - 1
po/dz.po

@@ -1256,7 +1256,7 @@ msgstr "འོག་གི་འཆང་ཡོད་པའི་ཐུམ་ས
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
+msgid "%s (due to %s)"
 msgstr "%s( %s་གིས་སྦེ)"
 
 #: apt-private/private-output.cc:696

+ 2 - 2
po/el.po

@@ -1272,8 +1272,8 @@ msgstr "Τα ακόλουθα κρατημένα πακέτα θα αλλαχθ
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (λόγω του %s) "
+msgid "%s (due to %s)"
+msgstr "%s (λόγω του %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/es.po

@@ -1388,8 +1388,8 @@ msgstr "Se cambiarán los siguientes paquetes retenidos:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (por %s) "
+msgid "%s (due to %s)"
+msgstr "%s (por %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/eu.po

@@ -1257,8 +1257,8 @@ msgstr "Ondorengo pakete atxikiak aldatu egingo dira:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (arrazoia: %s) "
+msgid "%s (due to %s)"
+msgstr "%s (arrazoia: %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/fi.po

@@ -1248,8 +1248,8 @@ msgstr "Seuraavat pysytetyt paketit muutetaan:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (syynä %s) "
+msgid "%s (due to %s)"
+msgstr "%s (syynä %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/fr.po

@@ -1328,8 +1328,8 @@ msgstr "Les paquets retenus suivants seront changés :"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (en raison de %s) "
+msgid "%s (due to %s)"
+msgstr "%s (en raison de %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/gl.po

@@ -1275,8 +1275,8 @@ msgstr "Vanse modificar os paquetes retidos seguintes:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (por mor de %s) "
+msgid "%s (due to %s)"
+msgstr "%s (por mor de %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/he.po

@@ -610,8 +610,8 @@ msgstr "החבילות המחוזקות הבאות ישונו:"
 
 #: cmdline/apt-get.cc:545
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (בגלל %s) "
+msgid "%s (due to %s)"
+msgstr "%s (בגלל %s)"
 
 #: cmdline/apt-get.cc:553
 #, fuzzy

+ 2 - 2
po/hu.po

@@ -1291,8 +1291,8 @@ msgstr "Az alábbi visszafogott csomagokat cserélem:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (%s miatt) "
+msgid "%s (due to %s)"
+msgstr "%s (%s miatt)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/it.po

@@ -1323,8 +1323,8 @@ msgstr "I seguenti pacchetti bloccati saranno cambiati:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (a causa di %s) "
+msgid "%s (due to %s)"
+msgstr "%s (a causa di %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/ja.po

@@ -1324,8 +1324,8 @@ msgstr "以下の変更禁止パッケージは変更されます:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (%s のため) "
+msgid "%s (due to %s)"
+msgstr "%s (%s のため)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/km.po

@@ -1242,8 +1242,8 @@ msgstr "កញ្ចប់​រង់ចាំ​ខាងក្រោម​ន
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (ដោយ​សារតែ​ %s) "
+msgid "%s (due to %s)"
+msgstr "%s (ដោយ​សារតែ​ %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/ko.po

@@ -1250,8 +1250,8 @@ msgstr "고정되었던 다음 패키지를 바꿀 것입니다:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (%s때문에) "
+msgid "%s (due to %s)"
+msgstr "%s (%s때문에)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 1 - 1
po/ku.po

@@ -1162,7 +1162,7 @@ msgstr ""
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
+msgid "%s (due to %s)"
 msgstr "%s (ji ber %s)"
 
 #: apt-private/private-output.cc:696

+ 2 - 2
po/lt.po

@@ -1166,8 +1166,8 @@ msgstr "Bus pakeisti šie sulaikyti paketai:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (dėl %s) "
+msgid "%s (due to %s)"
+msgstr "%s (dėl %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 1 - 1
po/mr.po

@@ -1240,7 +1240,7 @@ msgstr "पुढिल ठेवलेली पॅकेजेस बदलत
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
+msgid "%s (due to %s)"
 msgstr "%s (च्या मुळे %s)"
 
 #: apt-private/private-output.cc:696

+ 2 - 2
po/nb.po

@@ -1258,8 +1258,8 @@ msgstr "Følgende pakker vil bli endret:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (pga. %s) "
+msgid "%s (due to %s)"
+msgstr "%s (pga. %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/ne.po

@@ -1240,8 +1240,8 @@ msgstr "निम्न भइरहेको प्याकेजहरू प
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (%s कारणले) "
+msgid "%s (due to %s)"
+msgstr "%s (%s कारणले)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/nl.po

@@ -1337,8 +1337,8 @@ msgstr "De volgende vastgehouden pakketten zullen gewijzigd worden:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (vanwege %s) "
+msgid "%s (due to %s)"
+msgstr "%s (vanwege %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/nn.po

@@ -1251,8 +1251,8 @@ msgstr "Dei f
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (fordi %s) "
+msgid "%s (due to %s)"
+msgstr "%s (fordi %s)"
 
 #: apt-private/private-output.cc:696
 #, fuzzy

+ 2 - 2
po/pl.po

@@ -1302,8 +1302,8 @@ msgstr "Zostaną zmienione następujące zatrzymane pakiety:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (z powodu %s) "
+msgid "%s (due to %s)"
+msgstr "%s (z powodu %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/pt.po

@@ -1291,8 +1291,8 @@ msgstr "Os seguintes pacotes mantidos serão mudados:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (devido a %s) "
+msgid "%s (due to %s)"
+msgstr "%s (devido a %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/pt_BR.po

@@ -1264,8 +1264,8 @@ msgstr "Os seguintes pacotes mantidos serão mudados:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (por causa de %s) "
+msgid "%s (due to %s)"
+msgstr "%s (por causa de %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/ro.po

@@ -1267,8 +1267,8 @@ msgstr "Următoarele pachete ținute vor fi schimbate:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (datorită %s) "
+msgid "%s (due to %s)"
+msgstr "%s (datorită %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/ru.po

@@ -1614,8 +1614,8 @@ msgstr ""
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (вследствие %s) "
+msgid "%s (due to %s)"
+msgstr "%s (вследствие %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/sk.po

@@ -1280,8 +1280,8 @@ msgstr "Nasledovné pridržané balíky sa zmenia:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (kvôli %s) "
+msgid "%s (due to %s)"
+msgstr "%s (kvôli %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/sl.po

@@ -1277,8 +1277,8 @@ msgstr "Naslednji zadržani paketi bodo spremenjeni:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (zaradi %s) "
+msgid "%s (due to %s)"
+msgstr "%s (zaradi %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/sv.po

@@ -1266,8 +1266,8 @@ msgstr "Följande tillbakahållna paket kommer att ändras:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (på grund av %s) "
+msgid "%s (due to %s)"
+msgstr "%s (på grund av %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/th.po

@@ -1287,8 +1287,8 @@ msgstr "จะเปลี่ยนแปลงรายการคงรุ่
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (เนื่องจาก %s) "
+msgid "%s (due to %s)"
+msgstr "%s (เนื่องจาก %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/tl.po

@@ -1258,8 +1258,8 @@ msgstr "Ang susunod na mga hinawakang mga pakete ay babaguhin:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (dahil sa %s) "
+msgid "%s (due to %s)"
+msgstr "%s (dahil sa %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/tr.po

@@ -1315,8 +1315,8 @@ msgstr "Aşağıdaki eski sürümlerinde tutulan paketler değiştirilecek:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (%s nedeniyle) "
+msgid "%s (due to %s)"
+msgstr "%s (%s nedeniyle)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/uk.po

@@ -1298,8 +1298,8 @@ msgstr "Пакунки, які мали б залишитися без змін,
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (внаслідок %s) "
+msgid "%s (due to %s)"
+msgstr "%s (внаслідок %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/vi.po

@@ -1334,8 +1334,8 @@ msgstr "Những gói giữ lại sau đây sẽ bị THAY ĐỔI:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (bởi vì %s) "
+msgid "%s (due to %s)"
+msgstr "%s (bởi vì %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/zh_CN.po

@@ -1289,8 +1289,8 @@ msgstr "下列被要求保持版本不变的软件包将被改变:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s (是由于 %s) "
+msgid "%s (due to %s)"
+msgstr "%s (是由于 %s)"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 2 - 2
po/zh_TW.po

@@ -1236,8 +1236,8 @@ msgstr "下列被保留 (hold) 的套件將會被更改:"
 
 #: apt-private/private-output.cc:688
 #, c-format
-msgid "%s (due to %s) "
-msgstr "%s(因為 %s"
+msgid "%s (due to %s)"
+msgstr "%s(因為 %s"
 
 #: apt-private/private-output.cc:696
 msgid ""

+ 26 - 0
test/integration/test-apt-get-autoremove

@@ -27,6 +27,19 @@ The following packages will be REMOVED:
   po-debconf
 0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
 Remv po-debconf [1.0.16]' aptget autoremove -s
+testequal "Reading package lists...
+Building dependency tree...
+Reading state information...
+The following package was automatically installed and is no longer required:
+  po-debconf
+Use 'apt-get autoremove' to remove it.
+0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -s
+testequal "Reading package lists...
+Building dependency tree...
+Reading state information...
+1 package was automatically installed and is no longer required.
+Use 'apt-get autoremove' to remove it.
+0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -s -o APT::Get::HideAutoRemove=small
 testdpkginstalled 'po-debconf'
 
 echo 'APT::NeverAutoRemove { "^po-debconf$"; };' > rootdir/etc/apt/apt.conf.d/00autoremove
@@ -63,6 +76,19 @@ The following packages will be REMOVED:
 0 upgraded, 0 newly installed, 2 to remove and 0 not upgraded.
 Remv debhelper [8.0.0]
 Remv po-debconf [1.0.16]' aptget autoremove -s
+testequal "Reading package lists...
+Building dependency tree...
+Reading state information...
+The following packages were automatically installed and are no longer required:
+  debhelper po-debconf
+Use 'apt-get autoremove' to remove them.
+0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -s
+testequal "Reading package lists...
+Building dependency tree...
+Reading state information...
+2 packages were automatically installed and are no longer required.
+Use 'apt-get autoremove' to remove them.
+0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -s -o APT::Get::HideAutoRemove=small
 
 testsuccess aptmark hold debhelper
 testsuccessequal 'Reading package lists...

+ 9 - 0
test/integration/test-bug-596498-trusted-unsigned-repo

@@ -37,6 +37,15 @@ WARNING: The following packages cannot be authenticated!
 Install these packages without verification? [y/N] N
 E: Some packages could not be authenticated" aptget install cool --assume-no -d
 
+configarchitecture 'amd64' 'i386'
+testequal "$(echo "$PKGTEXT" | sed 's#cool$#cool:i386#g')
+WARNING: The following packages cannot be authenticated!
+  cool:i386
+Authentication warning overridden.
+$DOWNLOG
+Download complete and in download only mode" aptget install cool:i386 --assume-no -d --allow-unauthenticated
+configarchitecture 'i386'
+
 find aptarchive/ \( -name 'Release.gpg' -o -name 'InRelease' \) -delete
 sed -i -e 's#\(deb\(-src\)\?\) \[trusted=no\] #\1 #' $DEBFILE
 aptgetupdate

+ 26 - 0
test/integration/test-bug-604222-new-and-autoremove

@@ -23,6 +23,17 @@ The following NEW packages will be installed:
 Inst libavcodec52 (4:0.5.2-6 localhost [i386])
 Conf libavcodec52 (4:0.5.2-6 localhost [i386])" aptget install libavcodec52 -s
 
+testsuccessequal "Reading package lists...
+Building dependency tree...
+Reading state information...
+1 package was automatically installed and is no longer required.
+Use 'apt-get autoremove' to remove it.
+The following NEW packages will be installed:
+  libavcodec52
+0 upgraded, 1 newly installed, 0 to remove and 1 not upgraded.
+Inst libavcodec52 (4:0.5.2-6 localhost [i386])
+Conf libavcodec52 (4:0.5.2-6 localhost [i386])" aptget install libavcodec52 -s -o APT::Get::HideAutoRemove=small
+
 testfailureequal "Reading package lists...
 Building dependency tree...
 Reading state information...
@@ -39,6 +50,21 @@ The following packages will be upgraded:
 Need to get 0 B/19.4 MB of archives.
 After this operation, 17.3 MB of additional disk space will be used.
 E: Trivial Only specified but this is not a trivial operation." aptget install dummy-archive --trivial-only
+testequal "Reading package lists...
+Building dependency tree...
+Reading state information...
+1 package was automatically installed and is no longer required.
+Use 'apt-get autoremove' to remove it.
+The following extra packages will be installed:
+  libavcodec52 libopenal-dev libvtk5.4
+The following NEW packages will be installed:
+  dummy-archive libavcodec52 libopenal-dev
+The following packages will be upgraded:
+  libvtk5.4
+1 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
+Need to get 0 B/19.4 MB of archives.
+After this operation, 17.3 MB of additional disk space will be used.
+E: Trivial Only specified but this is not a trivial operation." aptget install dummy-archive --trivial-only -o APT::Get::HideAutoRemove=small
 
 echo -n > rootdir/var/lib/dpkg/status
 rm rootdir/var/lib/apt/extended_states

+ 16 - 0
test/integration/test-bug-613420-new-garbage-dependency

@@ -35,3 +35,19 @@ The following packages will be upgraded:
 1 upgraded, 3 newly installed, 1 to remove and 0 not upgraded.
 After this operation, 126 MB disk space will be freed.
 E: Trivial Only specified but this is not a trivial operation." aptget install libreoffice --trivial-only
+testequal "Reading package lists...
+Building dependency tree...
+Reading state information...
+2 packages were automatically installed and are no longer required.
+Use 'apt-get autoremove' to remove them.
+The following extra packages will be installed:
+  libreoffice-core libreoffice-officebean openoffice.org-officebean
+The following packages will be REMOVED:
+  openoffice.org-core
+The following NEW packages will be installed:
+  libreoffice libreoffice-core libreoffice-officebean
+The following packages will be upgraded:
+  openoffice.org-officebean
+1 upgraded, 3 newly installed, 1 to remove and 0 not upgraded.
+After this operation, 126 MB disk space will be freed.
+E: Trivial Only specified but this is not a trivial operation." aptget install libreoffice --trivial-only -o APT::Get::HideAutoRemove=small

+ 14 - 0
test/integration/test-bug-675449-essential-are-protected

@@ -87,3 +87,17 @@ Inst pkg-none-native [1] (2 unstable [amd64])
 Conf pkg-none-native (2 unstable [amd64])
 Inst pkg-none-new (2 unstable [amd64])
 Conf pkg-none-new (2 unstable [amd64])' aptget dist-upgrade -s
+
+insertinstalledpackage 'foo' 'amd64' '1' 'Depends: libfoo
+Essential: yes'
+insertinstalledpackage 'libfoo' 'amd64' '1'
+testequal 'Reading package lists...
+Building dependency tree...
+The following packages will be REMOVED:
+  foo* libfoo*
+WARNING: The following essential packages will be removed.
+This should NOT be done unless you know exactly what you are doing!
+  foo libfoo (due to foo)
+0 upgraded, 0 newly installed, 2 to remove and 4 not upgraded.
+Purg foo [1]
+Purg libfoo [1]' aptget purge libfoo -s

+ 16 - 0
test/integration/test-kernel-helper-autoremove

@@ -58,6 +58,22 @@ testprotected() {
 testsuccessequal "Reading package lists...
 Building dependency tree...
 Reading state information...
+The following packages were automatically installed and are no longer required:
+   linux-headers-1000000-1-generic (100.0.0-1)
+   linux-image-1.0.0-2-generic (1.0.0-2)
+   linux-image-100.0.0-1-generic (100.0.0-1)
+   $CURRENTKERNEL (1)
+Use 'apt-get autoremove' to remove them.
+0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -sV
+testequal "Reading package lists...
+Building dependency tree...
+Reading state information...
+4 packages were automatically installed and are no longer required.
+Use 'apt-get autoremove' to remove them.
+0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -s -o APT::Get::HideAutoRemove=small
+testequal "Reading package lists...
+Building dependency tree...
+Reading state information...
 The following packages will be REMOVED:
    linux-headers-1000000-1-generic (100.0.0-1)
    linux-image-1.0.0-2-generic (1.0.0-2)