enable APT in unpack/configure ordering to handle loops as well
authorDavid Kalnischkies <kalnischkies@gmail.com>
Wed, 14 Sep 2011 18:22:31 +0000 (20:22 +0200)
committerDavid Kalnischkies <kalnischkies@gmail.com>
Wed, 14 Sep 2011 18:22:31 +0000 (20:22 +0200)
as tight dependencies between immediate packages better
enabling also the possibility to mark all packages as immediate
(at least Closes: #353290, #540227, #559733, #621836, #639290)

1  2 
apt-pkg/deb/dpkgpm.cc
apt-pkg/deb/dpkgpm.h
apt-pkg/orderlist.cc
apt-pkg/orderlist.h
apt-pkg/packagemanager.cc
debian/changelog
test/integration/test-bug-618288-multiarch-same-lockstep

diff --combined apt-pkg/deb/dpkgpm.cc
index 2c34465c092fee4a1241b62649d3443a6760bd00,57361ccdc3e2d93f8e797488a91f64037463cbf4..0cc21f322003d35413e7ec8fa530511a72e3133a
@@@ -8,8 -8,6 +8,8 @@@
     ##################################################################### */
                                                                        /*}}}*/
  // Includes                                                           /*{{{*/
 +#include <config.h>
 +
  #include <apt-pkg/dpkgpm.h>
  #include <apt-pkg/error.h>
  #include <apt-pkg/configuration.h>
@@@ -18,6 -16,7 +18,7 @@@
  #include <apt-pkg/strutl.h>
  #include <apt-pkg/fileutl.h>
  #include <apt-pkg/cachefile.h>
+ #include <apt-pkg/packagemanager.h>
  
  #include <unistd.h>
  #include <stdlib.h>
  #include <sys/ioctl.h>
  #include <pty.h>
  
 -#include <config.h>
  #include <apti18n.h>
                                                                        /*}}}*/
  
  using namespace std;
  
 +class pkgDPkgPMPrivate 
 +{
 +public:
 +   pkgDPkgPMPrivate() : dpkgbuf_pos(0), term_out(NULL), history_out(NULL)
 +   {
 +   }
 +   bool stdin_is_dev_null;
 +   // the buffer we use for the dpkg status-fd reading
 +   char dpkgbuf[1024];
 +   int dpkgbuf_pos;
 +   FILE *term_out;
 +   FILE *history_out;
 +   string dpkg_error;
 +};
 +
  namespace
  {
    // Maps the dpkg "processing" info to human readable names.  Entry 0
@@@ -126,9 -111,9 +127,9 @@@ ionice(int PID
  // ---------------------------------------------------------------------
  /* */
  pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache) 
 -   : pkgPackageManager(Cache), dpkgbuf_pos(0),
 -     term_out(NULL), history_out(NULL), PackagesDone(0), PackagesTotal(0)
 +   : pkgPackageManager(Cache), PackagesDone(0), PackagesTotal(0)
  {
 +   d = new pkgDPkgPMPrivate();
  }
                                                                        /*}}}*/
  // DPkgPM::pkgDPkgPM - Destructor                                     /*{{{*/
  /* */
  pkgDPkgPM::~pkgDPkgPM()
  {
 +   delete d;
  }
                                                                        /*}}}*/
  // DPkgPM::Install - Install a package                                        /*{{{*/
@@@ -230,7 -214,7 +231,7 @@@ bool pkgDPkgPM::SendV2Pkgs(FILE *F
     fprintf(F,"\n");
   
     // Write out the package actions in order.
 -   for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
 +   for (vector<Item>::iterator I = List.begin(); I != List.end(); ++I)
     {
        if(I->Pkg.end() == true)
         continue;
@@@ -352,7 -336,7 +353,7 @@@ bool pkgDPkgPM::RunScriptsWithPkgs(cons
        // Feed it the filenames.
        if (Version <= 1)
        {
 -       for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
 +       for (vector<Item>::iterator I = List.begin(); I != List.end(); ++I)
         {
            // Only deal with packages to be installed from .deb
            if (I->Op != Item::Install)
@@@ -393,7 -377,7 +394,7 @@@ void pkgDPkgPM::DoStdin(int master
     if (len)
        write(master, input_buf, len);
     else
 -      stdin_is_dev_null = true;
 +      d->stdin_is_dev_null = true;
  }
                                                                        /*}}}*/
  // DPkgPM::DoTerminalPty - Read the terminal pty and write log                /*{{{*/
@@@ -418,8 -402,8 +419,8 @@@ void pkgDPkgPM::DoTerminalPty(int maste
     if(len <= 0) 
        return;
     write(1, term_buf, len);
 -   if(term_out)
 -      fwrite(term_buf, len, sizeof(char), term_out);
 +   if(d->term_out)
 +      fwrite(term_buf, len, sizeof(char), d->term_out);
  }
                                                                        /*}}}*/
  // DPkgPM::ProcessDpkgStatusBuf                                               /*{{{*/
@@@ -623,14 -607,14 +624,14 @@@ void pkgDPkgPM::DoDpkgStatusFd(int stat
     char *p, *q;
     int len;
  
 -   len=read(statusfd, &dpkgbuf[dpkgbuf_pos], sizeof(dpkgbuf)-dpkgbuf_pos);
 -   dpkgbuf_pos += len;
 +   len=read(statusfd, &d->dpkgbuf[d->dpkgbuf_pos], sizeof(d->dpkgbuf)-d->dpkgbuf_pos);
 +   d->dpkgbuf_pos += len;
     if(len <= 0)
        return;
  
     // process line by line if we have a buffer
 -   p = q = dpkgbuf;
 -   while((q=(char*)memchr(p, '\n', dpkgbuf+dpkgbuf_pos-p)) != NULL)
 +   p = q = d->dpkgbuf;
 +   while((q=(char*)memchr(p, '\n', d->dpkgbuf+d->dpkgbuf_pos-p)) != NULL)
     {
        *q = 0;
        ProcessDpkgStatusLine(OutStatusFd, p);
     }
  
     // now move the unprocessed bits (after the final \n that is now a 0x0) 
 -   // to the start and update dpkgbuf_pos
 -   p = (char*)memrchr(dpkgbuf, 0, dpkgbuf_pos);
 +   // to the start and update d->dpkgbuf_pos
 +   p = (char*)memrchr(d->dpkgbuf, 0, d->dpkgbuf_pos);
     if(p == NULL)
        return;
  
     p++;
  
     // move the unprocessed tail to the start and update pos
 -   memmove(dpkgbuf, p, p-dpkgbuf);
 -   dpkgbuf_pos = dpkgbuf+dpkgbuf_pos-p;
 +   memmove(d->dpkgbuf, p, p-d->dpkgbuf);
 +   d->dpkgbuf_pos = d->dpkgbuf+d->dpkgbuf_pos-p;
  }
                                                                        /*}}}*/
  // DPkgPM::WriteHistoryTag                                            /*{{{*/
@@@ -660,7 -644,7 +661,7 @@@ void pkgDPkgPM::WriteHistoryTag(string 
     // poor mans rstrip(", ")
     if (value[length-2] == ',' && value[length-1] == ' ')
        value.erase(length - 2, 2);
 -   fprintf(history_out, "%s: %s\n", tag.c_str(), value.c_str());
 +   fprintf(d->history_out, "%s: %s\n", tag.c_str(), value.c_str());
  }                                                                     /*}}}*/
  // DPkgPM::OpenLog                                                    /*{{{*/
  bool pkgDPkgPM::OpenLog()
                                   _config->Find("Dir::Log::Terminal"));
     if (!logfile_name.empty())
     {
 -      term_out = fopen(logfile_name.c_str(),"a");
 -      if (term_out == NULL)
 +      d->term_out = fopen(logfile_name.c_str(),"a");
 +      if (d->term_out == NULL)
         return _error->WarningE("OpenLog", _("Could not open file '%s'"), logfile_name.c_str());
 -      setvbuf(term_out, NULL, _IONBF, 0);
 -      SetCloseExec(fileno(term_out), true);
 +      setvbuf(d->term_out, NULL, _IONBF, 0);
 +      SetCloseExec(fileno(d->term_out), true);
        struct passwd *pw;
        struct group *gr;
        pw = getpwnam("root");
        if (pw != NULL && gr != NULL)
          chown(logfile_name.c_str(), pw->pw_uid, gr->gr_gid);
        chmod(logfile_name.c_str(), 0644);
 -      fprintf(term_out, "\nLog started: %s\n", timestr);
 +      fprintf(d->term_out, "\nLog started: %s\n", timestr);
     }
  
     // write your history
                                   _config->Find("Dir::Log::History"));
     if (!history_name.empty())
     {
 -      history_out = fopen(history_name.c_str(),"a");
 -      if (history_out == NULL)
 +      d->history_out = fopen(history_name.c_str(),"a");
 +      if (d->history_out == NULL)
         return _error->WarningE("OpenLog", _("Could not open file '%s'"), history_name.c_str());
        chmod(history_name.c_str(), 0644);
 -      fprintf(history_out, "\nStart-Date: %s\n", timestr);
 +      fprintf(d->history_out, "\nStart-Date: %s\n", timestr);
        string remove, purge, install, reinstall, upgrade, downgrade;
 -      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
 +      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
        {
         enum { CANDIDATE, CANDIDATE_AUTO, CURRENT_CANDIDATE, CURRENT } infostring;
         string *line = NULL;
        WriteHistoryTag("Downgrade",downgrade);
        WriteHistoryTag("Remove",remove);
        WriteHistoryTag("Purge",purge);
 -      fflush(history_out);
 +      fflush(d->history_out);
     }
     
     return true;
@@@ -760,16 -744,16 +761,16 @@@ bool pkgDPkgPM::CloseLog(
     struct tm *tmp = localtime(&t);
     strftime(timestr, sizeof(timestr), "%F  %T", tmp);
  
 -   if(term_out)
 +   if(d->term_out)
     {
 -      fprintf(term_out, "Log ended: ");
 -      fprintf(term_out, "%s", timestr);
 -      fprintf(term_out, "\n");
 -      fclose(term_out);
 +      fprintf(d->term_out, "Log ended: ");
 +      fprintf(d->term_out, "%s", timestr);
 +      fprintf(d->term_out, "\n");
 +      fclose(d->term_out);
     }
 -   term_out = NULL;
 +   d->term_out = NULL;
  
 -   if(history_out)
 +   if(d->history_out)
     {
        if (disappearedPkgs.empty() == false)
        {
         }
         WriteHistoryTag("Disappeared", disappear);
        }
 -      if (dpkg_error.empty() == false)
 -       fprintf(history_out, "Error: %s\n", dpkg_error.c_str());
 -      fprintf(history_out, "End-Date: %s\n", timestr);
 -      fclose(history_out);
 +      if (d->dpkg_error.empty() == false)
 +       fprintf(d->history_out, "Error: %s\n", d->dpkg_error.c_str());
 +      fprintf(d->history_out, "End-Date: %s\n", timestr);
 +      fclose(d->history_out);
     }
 -   history_out = NULL;
 +   d->history_out = NULL;
  
     return true;
  }
@@@ -885,21 -869,21 +886,21 @@@ bool pkgDPkgPM::Go(int OutStatusFd
     // that will be [installed|configured|removed|purged] and add
     // them to the PackageOps map (the dpkg states it goes through)
     // and the PackageOpsTranslations (human readable strings)
 -   for (vector<Item>::const_iterator I = List.begin(); I != List.end();I++)
 +   for (vector<Item>::const_iterator I = List.begin(); I != List.end(); ++I)
     {
        if((*I).Pkg.end() == true)
         continue;
  
        string const name = (*I).Pkg.Name();
        PackageOpsDone[name] = 0;
 -      for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL;  i++) 
 +      for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; ++i)
        {
         PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]);
         PackagesTotal++;
        }
     }
  
 -   stdin_is_dev_null = false;
 +   d->stdin_is_dev_null = false;
  
     // create log
     OpenLog();
        // Do all actions with the same Op in one run
        vector<Item>::const_iterator J = I;
        if (TriggersPending == true)
 -       for (; J != List.end(); J++)
 +       for (; J != List.end(); ++J)
         {
            if (J->Op == I->Op)
               continue;
            break;
         }
        else
 -       for (; J != List.end() && J->Op == I->Op; J++)
 +       for (; J != List.end() && J->Op == I->Op; ++J)
            /* nothing */;
  
        // Generate the argument list
        // the argument list is split in a way that A depends on B
        // and they are in the same "--configure A B" run
        // - with the split they may now be configured in different
-       //   runs 
+       //   runs, using Immediate-Configure-All can help prevent this.
        if (J - I > (signed)MaxArgs)
         J = I + MaxArgs;
        
        snprintf(status_fd_buf,sizeof(status_fd_buf),"%i", fd[1]);
        Args[n++] = status_fd_buf;
        Size += strlen(Args[n-1]);
+       
+       unsigned long const Op = I->Op;
  
        switch (I->Op)
        {
        // Write in the file or package names
        if (I->Op == Item::Install)
        {
 -       for (;I != J && Size < MaxArgBytes; I++)
 +       for (;I != J && Size < MaxArgBytes; ++I)
         {
            if (I->File[0] != '/')
               return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
        {
         string const nativeArch = _config->Find("APT::Architecture");
         unsigned long const oldSize = I->Op == Item::Configure ? Size : 0;
 -       for (;I != J && Size < MaxArgBytes; I++)
 +       for (;I != J && Size < MaxArgBytes; ++I)
         {
            if((*I).Pkg.end() == true)
               continue;
         it to all processes in the group. Since dpkg ignores the signal 
         it doesn't die but we do! So we must also ignore it */
        sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN);
-       sighandler_t old_SIGINT = signal(SIGINT,SIG_IGN);
+       sighandler_t old_SIGINT = signal(SIGINT,SigINT);
+       
+       // Check here for any SIGINT
+       if (pkgPackageManager::SigINTStop && (Op == Item::Remove || Op == Item::Purge || Op == Item::Install)) 
+          break;
+       
+       
        // ignore SIGHUP as well (debian #463030)
        sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN);
  
            const char *s = _("Can not write log, openpty() "
                              "failed (/dev/pts not mounted?)\n");
            fprintf(stderr, "%s",s);
 -            if(term_out)
 -              fprintf(term_out, "%s",s);
 +            if(d->term_out)
 +              fprintf(d->term_out, "%s",s);
            master = slave = -1;
         }  else {
            struct termios rtt;
            sigprocmask(SIG_SETMASK, &original_sigmask, 0);
         }
        }
         // Fork dpkg
        pid_t Child;
        _config->Set("APT::Keep-Fds::",fd[1]);
            // Restore sig int/quit
            signal(SIGQUIT,old_SIGQUIT);
            signal(SIGINT,old_SIGINT);
            signal(SIGHUP,old_SIGHUP);
            return _error->Errno("waitpid","Couldn't wait for subprocess");
         }
  
         // wait for input or output here
         FD_ZERO(&rfds);
 -       if (master >= 0 && !stdin_is_dev_null)
 +       if (master >= 0 && !d->stdin_is_dev_null)
            FD_SET(0, &rfds); 
         FD_SET(_dpkgin, &rfds);
         if(master >= 0)
        // Restore sig int/quit
        signal(SIGQUIT,old_SIGQUIT);
        signal(SIGINT,old_SIGINT);
+       
        signal(SIGHUP,old_SIGHUP);
  
        if(master >= 0) 
            RunScripts("DPkg::Post-Invoke");
  
         if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV) 
 -          strprintf(dpkg_error, "Sub-process %s received a segmentation fault.",Args[0]);
 +          strprintf(d->dpkg_error, "Sub-process %s received a segmentation fault.",Args[0]);
         else if (WIFEXITED(Status) != 0)
 -          strprintf(dpkg_error, "Sub-process %s returned an error code (%u)",Args[0],WEXITSTATUS(Status));
 +          strprintf(d->dpkg_error, "Sub-process %s returned an error code (%u)",Args[0],WEXITSTATUS(Status));
         else 
 -          strprintf(dpkg_error, "Sub-process %s exited unexpectedly",Args[0]);
 +          strprintf(d->dpkg_error, "Sub-process %s exited unexpectedly",Args[0]);
  
 -       if(dpkg_error.size() > 0)
 -          _error->Error("%s", dpkg_error.c_str());
 +       if(d->dpkg_error.size() > 0)
 +          _error->Error("%s", d->dpkg_error.c_str());
  
         if(stopOnError) 
         {
        }      
     }
     CloseLog();
+    
+    if (pkgPackageManager::SigINTStop)
+        _error->Warning(_("Operation was interrupted before it could finish"));
  
     if (RunScripts("DPkg::Post-Invoke") == false)
        return false;
     Cache.writeStateFile(NULL);
     return true;
  }
+ void SigINT(int sig) {
+    if (_config->FindB("APT::Immediate-Configure-All",false)) 
+       pkgPackageManager::SigINTStop = true;
+ } 
                                                                        /*}}}*/
  // pkgDpkgPM::Reset - Dump the contents of the command list           /*{{{*/
  // ---------------------------------------------------------------------
@@@ -1455,8 -1455,8 +1472,8 @@@ void pkgDPkgPM::WriteApportReport(cons
     fprintf(report, "ErrorMessage:\n %s\n", errormsg);
  
     // ensure that the log is flushed
 -   if(term_out)
 -      fflush(term_out);
 +   if(d->term_out)
 +      fflush(d->term_out);
  
     // attach terminal log it if we have it
     string logfile_name = _config->FindFile("Dir::Log::Terminal");
     // log the ordering 
     const char *ops_str[] = {"Install", "Configure","Remove","Purge"};
     fprintf(report, "AptOrdering:\n");
 -   for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
 +   for (vector<Item>::iterator I = List.begin(); I != List.end(); ++I)
        fprintf(report, " %s: %s\n", (*I).Pkg.Name(), ops_str[(*I).Op]);
  
     // attach dmesg log (to learn about segfaults)
diff --combined apt-pkg/deb/dpkgpm.h
index ddf9485c746d2d9f9a0f949a815d07a1b46fa72e,fb92c58ea98258fa84186773c696cbdf39e9d75b..3f95c51dc9cd37f72806c21708f99b97ec87bc1d
  using std::vector;
  using std::map;
  
 +class pkgDPkgPMPrivate;
  
  class pkgDPkgPM : public pkgPackageManager
  {
     private:
 -
 -   bool stdin_is_dev_null;
 -
 -   // the buffer we use for the dpkg status-fd reading
 -   char dpkgbuf[1024];
 -   int dpkgbuf_pos;
 -   FILE *term_out;
 -   FILE *history_out;
 -   string dpkg_error;
 +   pkgDPkgPMPrivate *d;
  
     /** \brief record the disappear action and handle accordingly
  
     virtual ~pkgDPkgPM();
  };
  
+ void SigINT(int sig);
  #endif
diff --combined apt-pkg/orderlist.cc
index 80d7b6619a56fa0c2c1910b71f2bdb97a8f3ee14,1e412ead52bbb4a0beb1884974346ba8f91b6a37..0ac9a83e3b14c1971e7dc863022d00279ad2d042
@@@ -63,8 -63,6 +63,8 @@@
     ##################################################################### */
                                                                        /*}}}*/
  // Include Files                                                      /*{{{*/
 +#include<config.h>
 +
  #include <apt-pkg/orderlist.h>
  #include <apt-pkg/depcache.h>
  #include <apt-pkg/error.h>
@@@ -147,14 -145,14 +147,14 @@@ bool pkgOrderList::DoRun(
     Depth = 0;
     WipeFlags(Added | AddPending | Loop | InList);
  
 -   for (iterator I = List; I != End; I++)
 +   for (iterator I = List; I != End; ++I)
        Flag(*I,InList);
  
     // Rebuild the main list into the temp list.
     iterator OldEnd = End;
     End = NList;
 -   for (iterator I = List; I != OldEnd; I++)
 -      if (VisitNode(PkgIterator(Cache,*I)) == false)
 +   for (iterator I = List; I != OldEnd; ++I)
 +      if (VisitNode(PkgIterator(Cache,*I), "DoRun") == false)
        {
         End = OldEnd;
         return false;
@@@ -199,7 -197,7 +199,7 @@@ bool pkgOrderList::OrderCritical(
     {
        clog << "** Critical Unpack ordering done" << endl;
  
 -      for (iterator I = List; I != End; I++)
 +      for (iterator I = List; I != End; ++I)
        {
         PkgIterator P(Cache,*I);
         if (IsNow(P) == true)
@@@ -224,7 -222,7 +224,7 @@@ bool pkgOrderList::OrderUnpack(string *
        WipeFlags(After);
  
        // Set the inlist flag
 -      for (iterator I = List; I != End; I++)
 +      for (iterator I = List; I != End; ++I)
        {
         PkgIterator P(Cache,*I);
         if (IsMissing(P) == true && IsNow(P) == true)
     {
        clog << "** Unpack ordering done" << endl;
  
 -      for (iterator I = List; I != End; I++)
 +      for (iterator I = List; I != End; ++I)
        {
         PkgIterator P(Cache,*I);
         if (IsNow(P) == true)
@@@ -325,7 -323,7 +325,7 @@@ int pkgOrderList::Score(PkgIterator Pkg
        Score += ScoreImmediate;
  
     for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList();
 -      D.end() == false; D++)
 +      D.end() == false; ++D)
        if (D->Type == pkgCache::Dep::PreDepends)
        {
         Score += ScorePreDepends;
@@@ -490,76 -488,40 +490,76 @@@ bool pkgOrderList::VisitRProvides(DepFu
        return true;
     
     bool Res = true;
 -   for (PrvIterator P = Ver.ProvidesList(); P.end() == false; P++)
 +   for (PrvIterator P = Ver.ProvidesList(); P.end() == false; ++P)
        Res &= (this->*F)(P.ParentPkg().RevDependsList());
     return Res;
  }
                                                                        /*}}}*/
  // OrderList::VisitProvides - Visit all of the providing packages     /*{{{*/
  // ---------------------------------------------------------------------
 -/* This routine calls visit on all providing packages. */
 +/* This routine calls visit on all providing packages.
 +
 +   If the dependency is negative it first visits packages which are
 +   intended to be removed and after that all other packages.
 +   It does so to avoid situations in which this package is used to
 +   satisfy a (or-group/provides) dependency of another package which
 +   could have been satisfied also by upgrading another package -
 +   otherwise we have more broken packages dpkg needs to auto-
 +   deconfigure and in very complicated situations it even decides
 +   against it! */
  bool pkgOrderList::VisitProvides(DepIterator D,bool Critical)
 -{   
 +{
     SPtrArray<Version *> List = D.AllTargets();
 -   for (Version **I = List; *I != 0; I++)
 +   for (Version **I = List; *I != 0; ++I)
     {
        VerIterator Ver(Cache,*I);
        PkgIterator Pkg = Ver.ParentPkg();
  
 +      if (D.IsNegative() == true && Cache[Pkg].Delete() == false)
 +       continue;
 +
        if (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)
         continue;
 -      
 +
        if (D.IsNegative() == false &&
          Cache[Pkg].InstallVer != *I)
         continue;
 -      
 +
        if (D.IsNegative() == true &&
          (Version *)Pkg.CurrentVer() != *I)
         continue;
 -      
 +
 +      // Skip over missing files
 +      if (Critical == false && IsMissing(D.ParentPkg()) == true)
 +       continue;
 +
 +      if (VisitNode(Pkg, "Provides-1") == false)
 +       return false;
 +   }
 +   if (D.IsNegative() == false)
 +      return true;
 +   for (Version **I = List; *I != 0; ++I)
 +   {
 +      VerIterator Ver(Cache,*I);
 +      PkgIterator Pkg = Ver.ParentPkg();
 +
 +      if (Cache[Pkg].Delete() == true)
 +       continue;
 +
 +      if (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)
 +       continue;
 +
 +      if ((Version *)Pkg.CurrentVer() != *I)
 +       continue;
 +
        // Skip over missing files
        if (Critical == false && IsMissing(D.ParentPkg()) == true)
         continue;
  
 -      if (VisitNode(Pkg) == false)
 +      if (VisitNode(Pkg, "Provides-2") == false)
         return false;
     }
 +
     return true;
  }
                                                                        /*}}}*/
  /* This is the core ordering routine. It calls the set dependency
     consideration functions which then potentialy call this again. Finite
     depth is achived through the colouring mechinism. */
 -bool pkgOrderList::VisitNode(PkgIterator Pkg)
 +bool pkgOrderList::VisitNode(PkgIterator Pkg, char const* from)
  {
     // Looping or irrelevent.
     // This should probably trancend not installed packages
     if (Debug == true)
     {
        for (int j = 0; j != Depth; j++) clog << ' ';
 -      clog << "Visit " << Pkg.FullName() << endl;
 +      clog << "Visit " << Pkg.FullName() << " from " << from << endl;
     }
     
     Depth++;
     Loops are preprocessed and logged. */
  bool pkgOrderList::DepUnPackCrit(DepIterator D)
  {
 -   for (; D.end() == false; D++)
 +   for (; D.end() == false; ++D)
     {
        if (D.Reverse() == true)
        {
         if (CheckDep(D) == true)
            continue;
  
 -       if (VisitNode(D.ParentPkg()) == false)
 +       if (VisitNode(D.ParentPkg(), "UnPackCrit") == false)
            return false;
        }
        else
@@@ -731,7 -693,7 +731,7 @@@ bool pkgOrderList::DepUnPackPreD(DepIte
     if (D.Reverse() == true)
        return DepUnPackCrit(D);
     
 -   for (; D.end() == false; D++)
 +   for (; D.end() == false; ++D)
     {
        if (D.IsCritical() == false)
         continue;
@@@ -774,7 -736,7 +774,7 @@@ bool pkgOrderList::DepUnPackPre(DepIter
     if (D.Reverse() == true)
        return true;
     
 -   for (; D.end() == false; D++)
 +   for (; D.end() == false; ++D)
     {
        /* Only consider the PreDepends or Depends. Depends are only
                 considered at the lowest depth or in the case of immediate
  bool pkgOrderList::DepUnPackDep(DepIterator D)
  {
     
 -   for (; D.end() == false; D++)
 +   for (; D.end() == false; ++D)
        if (D.IsCritical() == true)
        {
         if (D.Reverse() == true)
            if (IsMissing(D.ParentPkg()) == true)
               continue;
            
 -          if (VisitNode(D.ParentPkg()) == false)
 +          if (VisitNode(D.ParentPkg(), "UnPackDep-Parent") == false)
               return false;
         }
         else
               if (CheckDep(D) == true)
                 continue;
  
 -             if (VisitNode(D.TargetPkg()) == false)
 +             if (VisitNode(D.TargetPkg(), "UnPackDep-Target") == false)
                 return false;
            }
         }
@@@ -884,7 -846,7 +884,7 @@@ bool pkgOrderList::DepConfigure(DepIter
     if (D.Reverse() == true)
        return true;
     
 -   for (; D.end() == false; D++)
 +   for (; D.end() == false; ++D)
        if (D->Type == pkgCache::Dep::Depends)
         if (VisitProvides(D,false) == false)
            return false;
@@@ -906,7 -868,7 +906,7 @@@ bool pkgOrderList::DepRemove(DepIterato
  {
     if (D.Reverse() == false)
        return true;
 -   for (; D.end() == false; D++)
 +   for (; D.end() == false; ++D)
        if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
        {
         // Duplication elimination, consider the current version only
                        if (IsFlag(P, InList) == true &&
                            IsFlag(P, AddPending) == false &&
                            Cache[P].InstallVer != 0 &&
 -                          VisitNode(P) == true)
 +                          VisitNode(P, "Remove-P") == true)
                        {
                           Flag(P, Immediate);
                           tryFixDeps = false;
                  if (IsFlag(F.TargetPkg(), InList) == true &&
                      IsFlag(F.TargetPkg(), AddPending) == false &&
                      Cache[F.TargetPkg()].InstallVer != 0 &&
 -                    VisitNode(F.TargetPkg()) == true)
 +                    VisitNode(F.TargetPkg(), "Remove-Target") == true)
                  {
                     Flag(F.TargetPkg(), Immediate);
                     tryFixDeps = false;
                        if (IsFlag(Prv.OwnerPkg(), InList) == true &&
                            IsFlag(Prv.OwnerPkg(), AddPending) == false &&
                            Cache[Prv.OwnerPkg()].InstallVer != 0 &&
 -                          VisitNode(Prv.OwnerPkg()) == true)
 +                          VisitNode(Prv.OwnerPkg(), "Remove-Owner") == true)
                        {
                           Flag(Prv.OwnerPkg(), Immediate);
                           tryFixDeps = false;
         if (IsMissing(D.ParentPkg()) == true)
            continue;
         
 -       if (VisitNode(D.ParentPkg()) == false)
 +       if (VisitNode(D.ParentPkg(), "Remove-Parent") == false)
            return false;
        }
     
@@@ -1059,8 -1021,10 +1059,10 @@@ bool pkgOrderList::AddLoop(DepIterator 
     Loops[LoopCount++] = D;
     
     // Mark the packages as being part of a loop.
-    Flag(D.TargetPkg(),Loop);
-    Flag(D.ParentPkg(),Loop);
+    //Flag(D.TargetPkg(),Loop);
+    //Flag(D.ParentPkg(),Loop);
+    /* This is currently disabled because the Loop flag is being used for
+       loop management in the package manager. Check the orderlist.h file for more info */
     return true;
  }
                                                                        /*}}}*/
@@@ -1111,7 -1075,7 +1113,7 @@@ bool pkgOrderList::CheckDep(DepIterato
           just needs one */
        if (D.IsNegative() == false)
        {
-        // ignore provides by older versions of this package
+                // ignore provides by older versions of this package
         if (((D.Reverse() == false && Pkg == D.ParentPkg()) ||
              (D.Reverse() == true && Pkg == D.TargetPkg())) &&
             Cache[Pkg].InstallVer != *I)
diff --combined apt-pkg/orderlist.h
index 264f7ba03814e7f1cf1ba92a7cfbc9d8f23fbffd,4e5ea16542e3186cee5b690fee3dd9202a08e227..9588d30a57a58be117559899af3b874c7b8626d4
@@@ -18,7 -18,6 +18,7 @@@
  
  
  #include <apt-pkg/pkgcache.h>
 +#include <apt-pkg/macros.h>
  
  class pkgDepCache;
  class pkgOrderList : protected pkgCache::Namespace
@@@ -46,8 -45,7 +46,8 @@@
     bool Debug;
     
     // Main visit function
 -   bool VisitNode(PkgIterator Pkg);
 +   __deprecated bool VisitNode(PkgIterator Pkg) { return VisitNode(Pkg, "UNKNOWN"); };
 +   bool VisitNode(PkgIterator Pkg, char const* from);
     bool VisitDeps(DepFunc F,PkgIterator Pkg);
     bool VisitRDeps(DepFunc F,PkgIterator Pkg);
     bool VisitRProvides(DepFunc F,VerIterator Ver);
  
     typedef Package **iterator;
     
-    // State flags
+    /* State flags
+       The Loop flag can be set on a package that is currently being processed by either SmartConfigure or
+       SmartUnPack. This allows the package manager to tell when a loop has been formed as it will try to 
+       SmartUnPack or SmartConfigure a package with the Loop flag set. It will then either stop (as it knows
+       that the operation is unnecessary as its already in process), or in the case of the conflicts resolution
+       in SmartUnPack, use EarlyRemove to resolve the situation.  */
     enum Flags {Added = (1 << 0), AddPending = (1 << 1),
                 Immediate = (1 << 2), Loop = (1 << 3),
                 UnPacked = (1 << 4), Configured = (1 << 5),
@@@ -91,6 -94,9 +96,9 @@@
     void Flag(PkgIterator Pkg,unsigned long State, unsigned long F) {Flags[Pkg->ID] = (Flags[Pkg->ID] & (~F)) | State;};
     inline void Flag(PkgIterator Pkg,unsigned long F) {Flags[Pkg->ID] |= F;};
     inline void Flag(Package *Pkg,unsigned long F) {Flags[Pkg->ID] |= F;};
+    // RmFlag removes a flag from a package 
+    inline void RmFlag(Package *Pkg,unsigned long F) {Flags[Pkg->ID] &= ~F;};
+    // IsNow will return true if the Pkg has been not been either configured or unpacked
     inline bool IsNow(PkgIterator Pkg) {return (Flags[Pkg->ID] & (States & (~Removed))) == 0;};
     bool IsMissing(PkgIterator Pkg);
     void WipeFlags(unsigned long F);
index c41a1f1eec62442bd0ab50ac53a39f93abb65826,b5d353602c13776c19dc6aa8710ad20d7535025c..3cd9f6f0009bb3c9996ae9b7c473440d129de0b4
@@@ -13,8 -13,6 +13,8 @@@
     ##################################################################### */
                                                                        /*}}}*/
  // Include Files                                                      /*{{{*/
 +#include<config.h>
 +
  #include <apt-pkg/packagemanager.h>
  #include <apt-pkg/orderlist.h>
  #include <apt-pkg/depcache.h>
  #include <apt-pkg/algorithms.h>
  #include <apt-pkg/configuration.h>
  #include <apt-pkg/sptr.h>
 -    
 -#include <apti18n.h>    
 +
 +#include <apti18n.h>
  #include <iostream>
 -#include <fcntl.h> 
 +#include <fcntl.h>
                                                                        /*}}}*/
  using namespace std;
  
+ bool pkgPackageManager::SigINTStop = false;
  // PM::PackageManager - Constructor                                   /*{{{*/
  // ---------------------------------------------------------------------
  /* */
@@@ -65,7 -65,7 +67,7 @@@ bool pkgPackageManager::GetArchives(pkg
     if (ordering == false)
        return _error->Error("Internal ordering error");
  
 -   for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
 +   for (pkgOrderList::iterator I = List->begin(); I != List->end(); ++I)
     {
        PkgIterator Pkg(Cache,*I);
        FileNames[Pkg->ID] = string();
@@@ -101,7 -101,7 +103,7 @@@ bool pkgPackageManager::FixMissing(
     List->SetFileList(FileNames);
  
     bool Bad = false;
 -   for (PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
 +   for (PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
     {
        if (List->IsMissing(I) == false)
         continue;
@@@ -142,7 -142,7 +144,7 @@@ void pkgPackageManager::ImmediateAdd(Pk
        D = I.CurrentVer().DependsList(); 
     }
  
 -   for ( /* nothing */  ; D.end() == false; D++)
 +   for ( /* nothing */  ; D.end() == false; ++D)
        if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
        {
         if(!List->IsFlag(D.TargetPkg(), pkgOrderList::Immediate))
@@@ -168,29 -168,35 +170,35 @@@ bool pkgPackageManager::CreateOrderList
     delete List;
     List = new pkgOrderList(&Cache);
     
-    static bool const NoImmConfigure = !_config->FindB("APT::Immediate-Configure",true);
+    NoImmConfigure = !_config->FindB("APT::Immediate-Configure",true);
+    ImmConfigureAll = _config->FindB("APT::Immediate-Configure-All",false);
+    
+    if (Debug && ImmConfigureAll) 
+       clog << "CreateOrderList(): Adding Immediate flag for all packages because of APT::Immediate-Configure-All" << endl;
     
     // Generate the list of affected packages and sort it
 -   for (PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
 +   for (PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
     {
        // Ignore no-version packages
        if (I->VersionList == 0)
         continue;
        
        // Mark the package and its dependends for immediate configuration
-       if (((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential ||
+       if ((((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential ||
           (I->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important) &&
-         NoImmConfigure == false)
+         NoImmConfigure == false) || ImmConfigureAll)
        {
-        if(Debug)
+        if(Debug && !ImmConfigureAll)
            clog << "CreateOrderList(): Adding Immediate flag for " << I.Name() << endl;
         List->Flag(I,pkgOrderList::Immediate);
-        // Look for other install packages to make immediate configurea
-        ImmediateAdd(I, true);
         
-        // And again with the current version.
-        ImmediateAdd(I, false);
+        if (!ImmConfigureAll) {
+           // Look for other install packages to make immediate configurea
+           ImmediateAdd(I, true);
+         
+           // And again with the current version.
+           ImmediateAdd(I, false);
+        }
        }
        
        // Not interesting
@@@ -231,7 -237,7 +239,7 @@@ bool pkgPackageManager::DepAlwaysTrue(D
  bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D,
                                        const char *Ver)
  {
 -   for (;D.end() == false; D++)
 +   for (;D.end() == false; ++D)
     {
        if (D->Type != pkgCache::Dep::Conflicts &&
          D->Type != pkgCache::Dep::Obsoletes)
  // PM::ConfigureAll - Run the all out configuration                   /*{{{*/
  // ---------------------------------------------------------------------
  /* This configures every package. It is assumed they are all unpacked and
-    that the final configuration is valid. */
+    that the final configuration is valid. This is also used to catch packages
+    that have not been configured when using ImmConfigureAll */
  bool pkgPackageManager::ConfigureAll()
  {
     pkgOrderList OList(&Cache);
     
     // Populate the order list
 -   for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
 +   for (pkgOrderList::iterator I = List->begin(); I != List->end(); ++I)
        if (List->IsFlag(pkgCache::PkgIterator(Cache,*I),
                       pkgOrderList::UnPacked) == true)
         OList.push_back(*I);
     bool const ConfigurePkgs = (conf == "all");
  
     // Perform the configuring
 -   for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
 +   for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); ++I)
     {
        PkgIterator Pkg(Cache,*I);
+       
+       /* Check if the package has been configured, this can happen if SmartConfigure
+          calls its self */ 
+       if (List->IsFlag(Pkg,pkgOrderList::Configured)) continue;
  
-       if (ConfigurePkgs == true && Configure(Pkg) == false)
+       if (ConfigurePkgs == true && SmartConfigure(Pkg, 0) == false) {
+          if (ImmConfigureAll)
+             _error->Error(_("Could not perform immediate configuration on '%s'. "
+                       "Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.Name(),1);
+          else
+             _error->Error("Internal error, packages left unconfigured. %s",Pkg.Name());
         return false;
+       }
        
        List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
     }
                                                                        /*}}}*/
  // PM::SmartConfigure - Perform immediate configuration of the pkg    /*{{{*/
  // ---------------------------------------------------------------------
- /* This routine scheduals the configuration of the given package and all
-    of it's dependents. */
- bool pkgPackageManager::SmartConfigure(PkgIterator Pkg)
+ /* This function tries to put the system in a state where Pkg can be configured.
+    This involves checking each of Pkg's dependanies and unpacking and 
+    configuring packages where needed. 
+    
+    Note on failure: This method can fail, without causing any problems. 
+    This can happen when using Immediate-Configure-All, SmartUnPack may call
+    SmartConfigure, it may fail because of a complex dependancy situation, but
+    a error will only be reported if ConfigureAll fails. This is why some of the
+    messages this function reports on failure (return false;) as just warnings
+    only shown when debuging*/
+ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
  {
-    if (Debug == true)
-       clog << "SmartConfigure " << Pkg.Name() << endl;
+    // If this is true, only check and correct and dependancies without the Loop flag
+    bool PkgLoop = List->IsFlag(Pkg,pkgOrderList::Loop);
+    if (Debug) {
+       VerIterator InstallVer = VerIterator(Cache,Cache[Pkg].InstallVer);
+       clog << OutputInDepth(Depth) << "SmartConfigure " << Pkg.Name() << " (" << InstallVer.VerStr() << ")";
+       if (PkgLoop)
+         clog << " (Only Correct Dependancies)";
+       clog << endl;
+    }
  
-    pkgOrderList OList(&Cache);
+    VerIterator const instVer = Cache[Pkg].InstVerIter(Cache);
+       
+    /* Because of the ordered list, most dependancies should be unpacked, 
+       however if there is a loop (A depends on B, B depends on A) this will not 
+       be the case, so check for dependancies before configuring. */
+    bool Bad = false;
+    for (DepIterator D = instVer.DependsList();
+       D.end() == false; )
+    {
+       // Compute a single dependency element (glob or)
+       pkgCache::DepIterator Start;
+       pkgCache::DepIterator End;
+       D.GlobOr(Start,End);
+       
+       if (End->Type == pkgCache::Dep::Depends) 
+           Bad = true;
+       // Check for dependanices that have not been unpacked, probably due to loops.
+       while (End->Type == pkgCache::Dep::Depends) {
+          PkgIterator DepPkg;
+          VerIterator InstallVer;
+          SPtrArray<Version *> VList = Start.AllTargets();
+          
+          // Check through each version of each package that could satisfy this dependancy
+        for (Version **I = VList; *I != 0; I++) {
+           VerIterator Ver(Cache,*I);
+           DepPkg = Ver.ParentPkg();
+           InstallVer = VerIterator(Cache,Cache[DepPkg].InstallVer);
  
-    if (DepAdd(OList,Pkg) == false)
+           // Check if the current version of the package is avalible and will satisfy this dependancy
+           if (DepPkg.CurrentVer() == Ver && List->IsNow(DepPkg) == true && 
+               !List->IsFlag(DepPkg,pkgOrderList::Removed) && DepPkg.State() == PkgIterator::NeedsNothing)
+           {
+              Bad = false;
+              break;
+           }
+           
+           // Check if the version that is going to be installed will satisfy the dependancy
+           if (Cache[DepPkg].InstallVer == *I) {
+              if (List->IsFlag(DepPkg,pkgOrderList::UnPacked)) {
+                 if (List->IsFlag(DepPkg,pkgOrderList::Loop) && PkgLoop) {
+                   // This dependancy has already been dealt with by another SmartConfigure on Pkg
+                   Bad = false;
+                   break;
+                   } else if (List->IsFlag(Pkg,pkgOrderList::Loop)) {
+                   /* Check for a loop to prevent one forming
+                      If A depends on B and B depends on A, SmartConfigure will
+                      just hop between them if this is not checked. Dont remove the 
+                      loop flag after finishing however as loop is already set.
+                      This means that there is another SmartConfigure call for this 
+                      package and it will remove the loop flag */
+                    Bad = !SmartConfigure(DepPkg, Depth + 1);
+                 } else {
+                   /* Check for a loop to prevent one forming
+                      If A depends on B and B depends on A, SmartConfigure will
+                      just hop between them if this is not checked */
+                   List->Flag(Pkg,pkgOrderList::Loop);
+                   Bad = !SmartConfigure(DepPkg, Depth + 1);
+                   List->RmFlag(Pkg,pkgOrderList::Loop);
+                 }
+                 // If SmartConfigure was succesfull, Bad is false, so break
+                 if (!Bad) break;
+              } else if (List->IsFlag(DepPkg,pkgOrderList::Configured)) {
+                 Bad = false;
+                 break;
+              }
+           }
+        }
+        
+        /* If the dependany is still not satisfied, try, if possible, unpacking a package to satisfy it */
+        if (InstallVer != 0 && Bad) {
+           Bad = false;
+           if (List->IsNow(DepPkg) && !List->IsFlag(DepPkg,pkgOrderList::Loop)) {
+              List->Flag(Pkg,pkgOrderList::Loop);
+              if (Debug) 
+                 cout << OutputInDepth(Depth) << "Unpacking " << DepPkg.Name() << " to avoid loop" << endl;
+              SmartUnPack(DepPkg, true, Depth + 1);
+              List->RmFlag(Pkg,pkgOrderList::Loop);
+           }
+        }
+        
+        if (Start==End) {
+           if (Bad && Debug) {
+              if (!List->IsFlag(DepPkg,pkgOrderList::Loop)) {
+                   _error->Warning("Could not satisfy dependancies for %s",Pkg.Name());
+                } 
+           }
+           break;
+        } else {
+             Start++;
+          }
+       }
+    }
+    
+    if (Bad) {
+       if (Debug)
+          _error->Warning(_("Could not configure '%s'. "),Pkg.Name());
        return false;
+    }
+    
+    if (PkgLoop) return true;
  
     static std::string const conf = _config->Find("PackageManager::Configure","all");
     static bool const ConfigurePkgs = (conf == "all" || conf == "smart");
  
-    if (ConfigurePkgs == true)
-       if (OList.OrderConfigure() == false)
-        return false;
+    if (List->IsFlag(Pkg,pkgOrderList::Configured)) 
+       return _error->Error("Internal configure error on '%s'. ",Pkg.Name(),1);
  
-    // Perform the configuring
-    for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); ++I)
-    {
-       PkgIterator Pkg(Cache,*I);
-       
-       if (ConfigurePkgs == true && Configure(Pkg) == false)
-        return false;
-       
-       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
-    }
+    if (ConfigurePkgs == true && Configure(Pkg) == false)
+       return false;
 -      
++
+    List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
  
 -   if (Cache[Pkg].InstVerIter(Cache)->MultiArch == pkgCache::Version::Same)
 +   if ((Cache[Pkg].InstVerIter(Cache)->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
        for (PkgIterator P = Pkg.Group().PackageList();
           P.end() == false; P = Pkg.Group().NextPkg(P))
        {
             Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
              (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
            continue;
-        SmartConfigure(P);
+        SmartConfigure(P, (Depth +1));
        }
  
     // Sanity Check
     if (List->IsFlag(Pkg,pkgOrderList::Configured) == false)
-       return _error->Error(_("Could not perform immediate configuration on '%s'. "
-                       "Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.Name(),1);
+       return _error->Error(_("Could not configure '%s'. "),Pkg.Name());
  
     return true;
  }
                                                                        /*}}}*/
- // PM::DepAdd - Add all dependents to the oder list                   /*{{{*/
- // ---------------------------------------------------------------------
- /* This recursively adds all dependents to the order list */
- bool pkgPackageManager::DepAdd(pkgOrderList &OList,PkgIterator Pkg,int Depth)
- {
-    if (OList.IsFlag(Pkg,pkgOrderList::Added) == true)
-       return true;
-    if (List->IsFlag(Pkg,pkgOrderList::Configured) == true)
-       return true;
-    if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == false)
-       return false;
-    if (Debug) 
-       std::clog << OutputInDepth(Depth) << "DepAdd: " << Pkg.Name() << std::endl;
-       
-    // Put the package on the list
-    OList.push_back(Pkg);
-    OList.Flag(Pkg,pkgOrderList::Added);
-    Depth++;
-    // Check the dependencies to see if they are all satisfied.
-    bool Bad = false;
-    for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); D.end() == false;)
-    {
-       if (D->Type != pkgCache::Dep::Depends && D->Type != pkgCache::Dep::PreDepends)
-       {
-        ++D;
-        continue;
-       }
-       
-       // Grok or groups
-       Bad = true;
-       for (bool LastOR = true; D.end() == false && LastOR == true; ++D)
-       {
-        LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
-        
-        if (Bad == false)
-           continue;
-        SPtrArray<Version *> VList = D.AllTargets();
-        for (Version **I = VList; *I != 0 && Bad == true; ++I)
-        {
-           VerIterator Ver(Cache,*I);
-           PkgIterator Pkg = Ver.ParentPkg();
-           // See if the current version is ok
-           if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true && 
-               Pkg.State() == PkgIterator::NeedsNothing)
-           {
-              Bad = false;
-              continue;
-           }
-           
-           // Not the install version 
-           if (Cache[Pkg].InstallVer != *I || 
-               (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing))
-              continue;
-           
-           if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == true)
-              Bad = !DepAdd(OList,Pkg,Depth);
-           if (List->IsFlag(Pkg,pkgOrderList::Configured) == true)
-              Bad = false;
-        }
-       }
-       
-       if (Bad == true)
-       {
-        if (Debug) 
-           std::clog << OutputInDepth(Depth) << "DepAdd FAILS on: " << Pkg.Name() << std::endl;
-        OList.Flag(Pkg,0,pkgOrderList::Added);
-        OList.pop_back();
-        Depth--;
-        return false;
-       }
-    }
-    
-    Depth--;
-    return true;
- }
-                                                                       /*}}}*/
  // PM::EarlyRemove - Perform removal of packages before their time    /*{{{*/
  // ---------------------------------------------------------------------
  /* This is called to deal with conflicts arising from unpacking */
@@@ -446,7 -488,7 +490,7 @@@ bool pkgPackageManager::EarlyRemove(Pkg
     if (Pkg->CurrentVer != 0)
     {
        for (DepIterator D = Pkg.RevDependsList(); D.end() == false &&
 -         IsEssential == false; D++)
 +         IsEssential == false; ++D)
         if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
            if ((D.ParentPkg()->Flags & pkgCache::Flag::Essential) != 0)
               IsEssential = true;
@@@ -485,30 -527,44 +529,44 @@@ bool pkgPackageManager::SmartRemove(Pkg
                                                                        /*}}}*/
  // PM::SmartUnPack - Install helper                                   /*{{{*/
  // ---------------------------------------------------------------------
- /* This performs the task of handling pre-depends. */
+ /* This puts the system in a state where it can Unpack Pkg, if Pkg is allready
+    unpacked, or when it has been unpacked, if Immediate==true it configures it. */
  bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
  {
-    return SmartUnPack(Pkg, true);
+    return SmartUnPack(Pkg, true, 0);
  }
- bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate)
+ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int const Depth)
  {
+    bool PkgLoop = List->IsFlag(Pkg,pkgOrderList::Loop);
+    if (Debug) {
+       clog << OutputInDepth(Depth) << "SmartUnPack " << Pkg.Name();
+       VerIterator InstallVer = VerIterator(Cache,Cache[Pkg].InstallVer);
+       if (Pkg.CurrentVer() == 0)
+         cout << " (install version " << InstallVer.VerStr() << ")";
+       else
+         cout << " (replace version " << Pkg.CurrentVer().VerStr() << " with " << InstallVer.VerStr() << ")";
+       if (PkgLoop)
+         cout << " (Only Perform PreUnpack Checks)";
+       cout << endl;
+    }
     // Check if it is already unpacked
     if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
         Cache[Pkg].Keep() == true)
     {
-       List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
-       if (Immediate == true &&
-         List->IsFlag(Pkg,pkgOrderList::Immediate) == true)
-        if (SmartConfigure(Pkg) == false)
-           return _error->Error(_("Could not perform immediate configuration on already unpacked '%s'. "
-                       "Please see man 5 apt.conf under APT::Immediate-Configure for details."),Pkg.Name());
-       return true;
+       cout << OutputInDepth(Depth) << "SmartUnPack called on Package " << Pkg.Name() << " but its unpacked" << endl;
+       return false;
     }
+  
     VerIterator const instVer = Cache[Pkg].InstVerIter(Cache);
  
-    /* See if this packages install version has any predependencies
-       that are not met by 'now' packages. */
+    /* PreUnpack Checks: This loop checks and attempts to rectify and problems that would prevent the package being unpacked.
+       It addresses: PreDepends, Conflicts, Obsoletes and Breaks (DpkgBreaks). Any resolutions that do not require it should 
+       avoid configuration (calling SmartUnpack with Immediate=true), this is because when unpacking some packages with
+       complex dependancy structures, trying to configure some packages while breaking the loops can complicate things . 
+       This will be either dealt with if the package is configured as a dependency of Pkg (if and when Pkg is configured), 
+       or by the ConfigureAll call at the end of the for loop in OrderInstall. */
     for (DepIterator D = instVer.DependsList();
        D.end() == false; )
     {
        
        while (End->Type == pkgCache::Dep::PreDepends)
        {
-        if (Debug == true)
-           clog << "PreDepends order for " << Pkg.Name() << std::endl;
+        if (Debug)
+           clog << OutputInDepth(Depth) << "PreDepends order for " << Pkg.Name() << std::endl;
  
         // Look for possible ok targets.
         SPtrArray<Version *> VList = Start.AllTargets();
                Pkg.State() == PkgIterator::NeedsNothing)
            {
               Bad = false;
-              if (Debug == true)
-                 clog << "Found ok package " << Pkg.Name() << endl;
+              if (Debug)
+                 clog << OutputInDepth(Depth) << "Found ok package " << Pkg.Name() << endl;
               continue;
            }
         }
            if (Cache[Pkg].InstallVer != *I || 
                (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing))
               continue;
+              
+           if (List->IsFlag(Pkg,pkgOrderList::Configured)) {
+              Bad = false;
+              continue;
+           }
  
-           if (Debug == true)
-              clog << "Trying to SmartConfigure " << Pkg.Name() << endl;
-           Bad = !SmartConfigure(Pkg);
+           if (Debug)
+              clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << Pkg.Name() << endl;
+           Bad = !SmartConfigure(Pkg, Depth + 1);
         }
  
         /* If this or element did not match then continue on to the
               return _error->Error("Couldn't configure pre-depend %s for %s, "
                                    "probably a dependency cycle.",
                                    End.TargetPkg().Name(),Pkg.Name());
 -          Start++;
 +          ++Start;
         }
-        else
+        else 
            break;
        }
        
         for (Version **I = VList; *I != 0; I++)
         {
            VerIterator Ver(Cache,*I);
-           PkgIterator Pkg = Ver.ParentPkg();
+           PkgIterator ConflictPkg = Ver.ParentPkg();
+           VerIterator InstallVer(Cache,Cache[ConflictPkg].InstallVer);
            
            // See if the current version is conflicting
-           if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true)
-           {
-              if (EarlyRemove(Pkg) == false)
-                 return _error->Error("Internal Error, Could not early remove %s",Pkg.Name());
+           if (ConflictPkg.CurrentVer() == Ver && List->IsNow(ConflictPkg))
+           { 
+              cout << OutputInDepth(Depth) << Pkg.Name() << " conflicts with " << ConflictPkg.Name() << endl;
+              /* If a loop is not present or has not yet been detected, attempt to unpack packages 
+                 to resolve this conflict. If there is a loop present, remove packages to resolve this conflict */
+              if (!List->IsFlag(ConflictPkg,pkgOrderList::Loop)) {
+                 if (Cache[ConflictPkg].Keep() == 0 && Cache[ConflictPkg].InstallVer != 0) {
+                     if (Debug)
+                         cout << OutputInDepth(Depth) << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.Name() << " to prevent conflict" << endl;
+                       List->Flag(Pkg,pkgOrderList::Loop);
+                     SmartUnPack(ConflictPkg,false, Depth + 1);
+                     // Remove loop to allow it to be used later if needed
+                     List->RmFlag(Pkg,pkgOrderList::Loop);
+                   } else {
+                       if (EarlyRemove(ConflictPkg) == false)
+                          return _error->Error("Internal Error, Could not early remove %s",ConflictPkg.Name());
+                   }
+              } else {
+                 if (!List->IsFlag(ConflictPkg,pkgOrderList::Removed)) {
+                     if (Debug)
+                          cout << OutputInDepth(Depth) << "Because of conficts knot, removing " << ConflictPkg.Name() << " to conflict violation" << endl;
+                     if (EarlyRemove(ConflictPkg) == false)
+                           return _error->Error("Internal Error, Could not early remove %s",ConflictPkg.Name());
+                 }
+              }
+           }
+        }
+       }
+       
+       // Check for breaks
+       if (End->Type == pkgCache::Dep::DpkgBreaks) {
+          SPtrArray<Version *> VList = End.AllTargets();
+        for (Version **I = VList; *I != 0; I++)
+        {
+           VerIterator Ver(Cache,*I);
+           PkgIterator BrokenPkg = Ver.ParentPkg();
+           VerIterator InstallVer(Cache,Cache[BrokenPkg].InstallVer);
+           
+           // Check if it needs to be unpacked
+           if (List->IsFlag(BrokenPkg,pkgOrderList::InList) && Cache[BrokenPkg].Delete() == false && 
+               List->IsNow(BrokenPkg)) {
+             if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) && PkgLoop) {
+               // This dependancy has already been dealt with by another SmartUnPack on Pkg
+               break;
+             } else if (List->IsFlag(Pkg,pkgOrderList::Loop)) {
+               /* Found a break, so unpack the package, but dont remove loop as already set.
+                  This means that there is another SmartUnPack call for this 
+                  package and it will remove the loop flag. */
+               if (Debug) 
+                 cout << OutputInDepth(Depth) << "  Unpacking " << BrokenPkg.Name() << " to avoid break" << endl;
+                   
+               SmartUnPack(BrokenPkg, false, Depth + 1);
+             } else {
+                 List->Flag(Pkg,pkgOrderList::Loop);
+               // Found a break, so unpack the package
+               if (Debug) 
+                 cout << OutputInDepth(Depth) << "  Unpacking " << BrokenPkg.Name() << " to avoid break" << endl;
+                
+               SmartUnPack(BrokenPkg, false, Depth + 1);
+               List->RmFlag(Pkg,pkgOrderList::Loop);
+             }
+           }
+           
+           // Check if a package needs to be removed
+           if (Cache[BrokenPkg].Delete() == true && !List->IsFlag(BrokenPkg,pkgOrderList::Configured)) {
+             if (Debug) 
+                cout << OutputInDepth(Depth) << "  Removing " << BrokenPkg.Name() << " to avoid break" << endl;
+             SmartRemove(BrokenPkg);
            }
         }
        }
     }
+    
     // Check for reverse conflicts.
     if (CheckRConflicts(Pkg,Pkg.RevDependsList(),
                   instVer.VerStr()) == false)
-       return false;
+                         return false;
     
     for (PrvIterator P = instVer.ProvidesList();
 -        P.end() == false; P++)
 -        CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
 +      P.end() == false; ++P)
 +      if (Pkg->Group != P.OwnerPkg()->Group)
 +       CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
  
 -   if (PkgLoop) return true;
++   if (PkgLoop)
++      return true;
     List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
  
 -   if (instVer->MultiArch == pkgCache::Version::Same)
 +   if (Immediate == true && instVer->MultiArch == pkgCache::Version::Same)
 +   {
 +      /* Do lockstep M-A:same unpacking in two phases:
 +       First unpack all installed architectures, then the not installed.
 +       This way we avoid that M-A: enabled packages are installed before
 +       their older non-M-A enabled packages are replaced by newer versions */
 +      bool const installed = Pkg->CurrentVer != 0;
 +      if (installed == true && Install(Pkg,FileNames[Pkg->ID]) == false)
 +       return false;
 +      for (PkgIterator P = Pkg.Group().PackageList();
 +         P.end() == false; P = Pkg.Group().NextPkg(P))
 +      {
 +       if (P->CurrentVer == 0 || P == Pkg || List->IsFlag(P,pkgOrderList::UnPacked) == true ||
 +           Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
 +            (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
 +          continue;
-        if (SmartUnPack(P, false) == false)
++       if (SmartUnPack(P, false, Depth + 1) == false)
 +          return false;
 +      }
 +      if (installed == false && Install(Pkg,FileNames[Pkg->ID]) == false)
 +       return false;
        for (PkgIterator P = Pkg.Group().PackageList();
 -         P.end() == false; P = Pkg.Group().NextPkg(P))
 +         P.end() == false; P = Pkg.Group().NextPkg(P))
        {
 -         if (Pkg == P || List->IsFlag(P,pkgOrderList::UnPacked) == true ||
 -             Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
 -              (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
 -         continue;
 -         SmartUnPack(P, false, Depth + 1);
 +       if (P->CurrentVer != 0 || P == Pkg || List->IsFlag(P,pkgOrderList::UnPacked) == true ||
 +           Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
 +            (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
 +          continue;
-        if (SmartUnPack(P, false) == false)
++       if (SmartUnPack(P, false, Depth + 1) == false)
 +          return false;
        }
 -
 -   if(Install(Pkg,FileNames[Pkg->ID]) == false)
 +   }
 +   else if (Install(Pkg,FileNames[Pkg->ID]) == false)
        return false;
  
-    // Perform immedate configuration of the package.
-    if (Immediate == true &&
-        List->IsFlag(Pkg,pkgOrderList::Immediate) == true)
-       if (SmartConfigure(Pkg) == false)
-        return _error->Error(_("Could not perform immediate configuration on '%s'. "
-                       "Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.Name(),2);
+    if (Immediate == true) {
+       // Perform immedate configuration of the package. 
+          if (SmartConfigure(Pkg, Depth + 1) == false)
+             _error->Warning(_("Could not perform immediate configuration on '%s'. "
+                "Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.Name(),2);
+    }
     
     return true;
  }
@@@ -676,15 -782,22 +807,22 @@@ pkgPackageManager::OrderResult pkgPacka
        clog << "Done ordering" << endl;
  
     bool DoneSomething = false;
 -   for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
 +   for (pkgOrderList::iterator I = List->begin(); I != List->end(); ++I)
     {
        PkgIterator Pkg(Cache,*I);
+       
        if (List->IsNow(Pkg) == false)
        {
-        if (Debug == true)
-           clog << "Skipping already done " << Pkg.Name() << endl;
+          if (!List->IsFlag(Pkg,pkgOrderList::Configured) && !NoImmConfigure) {
+             if (SmartConfigure(Pkg, 0) == false && Debug)
+                _error->Warning("Internal Error, Could not configure %s",Pkg.Name());
+             // FIXME: The above warning message might need changing
+          } else {
+           if (Debug == true)
+              clog << "Skipping already done " << Pkg.Name() << endl;
+        }
         continue;
+        
        }
        
        if (List->IsMissing(Pkg) == true)
            return Failed;
        }
        else
-        if (SmartUnPack(Pkg) == false)
+        if (SmartUnPack(Pkg,List->IsFlag(Pkg,pkgOrderList::Immediate),0) == false)
            return Failed;
        DoneSomething = true;
+       
+       if (ImmConfigureAll) {
+          /* ConfigureAll here to pick up and packages left unconfigured becuase they were unpacked in the 
+             "PreUnpack Checks" section */
+          if (!ConfigureAll())
+             return Failed; 
+       }
     }
  
     // Final run through the configure phase
        return Failed;
  
     // Sanity check
 -   for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
 +   for (pkgOrderList::iterator I = List->begin(); I != List->end(); ++I)
     {
        if (List->IsFlag(*I,pkgOrderList::Configured) == false)
        {
                       PkgIterator(Cache,*I).Name());
         return Failed;
        }
-    }   
+    }
         
     return Completed;
  }
@@@ -765,4 -885,4 +910,4 @@@ pkgPackageManager::OrderResult pkgPacka
     
     return DoInstallPostFork(statusFd);
  }
-                                                                       /*}}}*/
+                                                                       /*}}}*/       
diff --combined debian/changelog
index 62bbdcdd807da34c4eb948d5f11aa9d3b2a52ed0,87d25e78ffdac0406c547b23928284ca2798bb53..444a99ba72187273b9a56ece9310b0f7031aaaba
 +apt (0.8.16~exp6) experimental; urgency=low
 +
++  [ Christopher Baines ]
++  * enable APT in unpack/configure ordering to handle loops as well
++    as tight dependencies between immediate packages better
++    enabling also the possibility to mark all packages as immediate
++    (at least Closes: #353290, #540227, #559733, #621836, #639290)
++
 +  [ David Kalnischkies ]
 +  * [abi-break] Support large files in the complete toolset. Indexes of this
 +    size are pretty unlikely for now, but we need it for deb
 +    packages which could become bigger than 4GB now (LP: #815895)
 +  * merged the debian-sid branch
 +  
 +  [ Michael Vogt ]
 +  * bump ABI version
 +
 + -- Michael Vogt <mvo@debian.org>  Wed, 14 Sep 2011 13:26:23 +0200
 +
 +apt (0.8.16~exp5) experimental; urgency=low
 +
 +  * merged the latest debian-sid fixes
 +  * apt-pkg/makefile:
 +    - install sha256.h compat header
 +  * apt-pkg/pkgcachegen.{cc,h}:
 +    - use ref-to-ptr semantic in NewDepends() to ensure that the   
 +      libapt does not segfault if the cache is remapped in between
 +      (LP: #812862)
 +    - fix crash when P.Arch() was used but the cache got remapped
 +  * apt-pkg/acquire-item.{cc,h}:
 +    - do not check for a "Package" tag in optional index targets
 +      like the translations index
 +  * apt-pkg/acquire.cc:
 +    - fix potential divide-by-zero
 +  * methods/mirror.cc:
 +    - include the architecture(s) in the query string as well so 
 +      that the server can make better decisions
 +
 + -- Michael Vogt <mvo@debian.org>  Mon, 15 Aug 2011 14:52:54 +0200
 +
 +apt (0.8.16~exp4) experimental; urgency=low
 +
 +  [ Julian Andres Klode ]
 +  * apt-pkg/pkgcache.h:
 +    - [ABI break] Add pkgCache::Header::CacheFileSize, storing the cache size
 +  * apt-pkg/pkgcachegen.cc:
 +    - Write the file size to the cache
 +  * apt-pkg/pkgcache.cc:
 +    - Check that cache is at least CacheFileSize bytes large (LP: #16467)
 +  
 +  [ Michael Vogt ]
 +  * merged latest fixes from debian-sid
 +  * apt-pkg/cdrom.{cc,h}:
 +    - cleanup old ABI break avoidance hacks
 +  * [ABI break] apt-pkg/acquire-item.{cc,h}:
 +    - cleanup around OptionalIndexTarget and SubIndexTarget
 +  * [ABI break] merged patch from Jonathan Thomas to have a new
 +    RecordField() function in the pkgRecorder parser. Many thanks
 +    Thomas
 +  * [ABI break] merge patch from Jonathan Thomas to speed up the
 +    depcache by caching the install-recommends and install-suggests
 +    values
 +  * apt-pkg/contrib/fileutl.{cc,h}:
 +    - add GetModificationTime() helper
 +  * apt-pkg/pkgcachegen.cc:
 +    - regenerate the cache if the sources.list changes to ensure
 +      that changes in the ordering there will be honored by apt
 +  * apt-pkg/sourcelist.{cc,h}:
 +    - add pkgSourceList::GetLastModifiedTime() helper
 +
 + -- Michael Vogt <mvo@debian.org>  Thu, 28 Jul 2011 16:57:08 +0200
 +
 +apt (0.8.16~exp3) experimental; urgency=low
 +
 +  [ David Kalnischkies ]
 +  * apt-pkg/pkgcache.h:
 +    - readd All{Foreign,Allowed} as suggested by Julian to
 +      remain strictly API compatible
 +  * apt-pkg/acquire*.{cc,h}:
 +    - try even harder to support really big files in the fetcher by
 +      converting (hopefully) everything to 'long long' (Closes: #632271)
 +  * ftparchive/writer.cc:
 +    - generate all checksums in one run over the file for Release
 +  * cmdline/apt-get.cc:
 +    - add an --assume-no option for testing to say 'no' to everything
 +  * apt-pkg/deb/debmetaindex.cc:
 +    - add trusted=yes option to mark unsigned (local) repository as trusted
 +      based on a patch from Ansgar Burchardt, thanks a lot! (Closes: #596498)
 +
 +  [ Michael Vogt ]
 +  * merge fixes from the debian/unstable upload
 +  * merge lp:~mvo/apt/sha512-template to get fixes for the 
 +    sha1/md5 verifiation (closes: #632520)
 +
 + -- Michael Vogt <mvo@debian.org>  Fri, 15 Jul 2011 09:56:17 +0200
 +
 +apt (0.8.16~exp2) experimental; urgency=low
 +
 +  [ David Kalnischkies ]
 +  * [ABI-Break] Implement EDSP in libapt-pkg so that all front-ends which
 +    use the internal resolver can now be used also with external
 +    ones as the usage is hidden in between the old API
 +  * provide two edsp solvers in apt-utils:
 +    - 'dump' to quickly output a complete scenario and
 +    - 'apt' to use the internal as an external resolver
 +  * apt-pkg/pkgcache.h:
 +    - clean up mess with the "all" handling in MultiArch to
 +      fix LP: #733741 cleanly for everyone now
 +  * apt-pkg/depcache.cc:
 +    - use a boolean instead of an int for Add/Remove in AddStates
 +      similar to how it works with AddSizes
 +    - let the Mark methods return if their marking was successful
 +    - if a Breaks can't be upgraded, remove it. If it or a Conflict
 +      can't be removed the installation of the breaker fails.
 +  * cmdline/apt-get.cc:
 +    - do not discard the error messages from the resolver and instead
 +      only show the general 'Broken packages' message if nothing else
 +
 +  [ Stefano Zacchiroli ]
 +  * doc/external-dependency-solver-protocol.txt:
 +    - describe EDSP and the configuration interface around it
 +  
 +  [ Michael Vogt ]
 +  * [ABI-Break] merge lp:~mvo/apt/sha512-template to add support for sha512
 +  * [ABI-Break] merge lp:~mvo/apt/dpointer to support easier extending
 +    without breaking the ABI
 +  * increase ABI version and update package names
 +
 + -- Michael Vogt <mvo@debian.org>  Wed, 29 Jun 2011 13:57:28 +0200
 +
 +apt (0.8.16~exp1) experimental; urgency=low
 +
 +  * merged with the debian/unstable upload
 +
 + -- Michael Vogt <mvo@debian.org>  Wed, 29 Jun 2011 12:40:31 +0200
 +
 +apt (0.8.15.7) unstable; urgency=low
 +
 +  [ David Kalnischkies ]
 +  * apt-pkg/packagemanager.cc, apt-pkg/pkgcache.cc:
 +    - ignore "self"-conflicts for all architectures of a package
 +      instead of just for the architecture of the package look at
 +      in the ordering of installations, too (LP: #802901)
 +    - M-A:same lockstep unpack should operate on installed
 +      packages first (LP: #835625)
 +  * test/*
 +    - reorganize the various testcases and helper we have and
 +      integrate them better into the buildsystem
 +    - run the test/libapt testcases at package build-time
 +  * debian/apt.symbols:
 +    - add the newly added symbols since 0.8.15.3
 +  * cmdline/apt-get.cc:
 +    - remove the binary caches in 'apt-get clean' as it is the first
 +      thing recommend by many supporters in case of APT segfaults
 +    - remove the caches in 'apt-get update', too, as they will be
 +      invalid in most cases anyway
 +  * apt-pkg/acquire-item.cc:
 +    - if no Release.gpg file is found try to verify with hashes,
 +      but do not fail if a hash can't be found
 +  * apt-pkg/acquire.cc:
 +    - non-existing directories are by definition clean
 +  * cmdline/apt-key:
 +    - if command is 'add' do not error out if the specified
 +      keyring doesn't exist, it will be created by gpg
 +  * apt-pkg/orderlist.cc:
 +    - prefer visiting packages marked for deletion in VisitProvides
 +      if we are operating on a negative dependency so that we can
 +      deal early with the fallout of this remove
 +  * apt-pkg/indexrecords.cc:
 +    - fix Acquire::Max-ValidTime option by interpreting it really
 +      as seconds as specified in the manpage and not as days
 +    - add an Acquire::Min-ValidTime option (Closes: #640122)
 +  * doc/apt.conf.5.xml:
 +    - reword Acquire::Max-ValidTime documentation to make clear
 +      that it doesn't provide the new Min-ValidTime functionality
 +
 + -- Michael Vogt <mvo@debian.org>  Mon, 12 Sep 2011 16:38:46 +0200
 +
 +apt (0.8.15.6) unstable; urgency=low
 +
 +  [ Michael Vogt ]
 +  * apt-pkg/contrib/fileutl.{cc,h}:
 +    - add GetModificationTime() helper
 +  * apt-pkg/pkgcachegen.cc:
 +    - regenerate the cache if the sources.list changes to ensure
 +      that changes in the ordering there will be honored by apt
 +  * apt-pkg/sourcelist.{cc,h}:
 +    - add pkgSourceList::GetLastModifiedTime() helper
 +  * apt-pkg/pkgcachegen.{cc,h}:
 +    - use ref-to-ptr semantic in NewDepends() to ensure that the   
 +      libapt does not segfault if the cache is remapped in between
 +      (LP: #812862)
 +    - fix crash when P.Arch() was used but the cache got remapped
 +  * test/integration/test-hashsum-verification:
 +    - add regression test for hashsum verification
 +  * apt-pkg/acquire-item.cc:
 +    - if no Release.gpg file is found, still load the hashes for
 +      verification (closes: #636314) and add test
 +  
 +  [ David Kalnischkies ]
 +  * lots of cppcheck fixes
 +
 + -- Michael Vogt <mvo@debian.org>  Mon, 15 Aug 2011 09:20:35 +0200
 +
 +apt (0.8.15.5) unstable; urgency=low
 +
 +  [ David Kalnischkies ]
 +  * apt-pkg/deb/deblistparser.cc:
 +    - do not assume that the last char on a line is a \n (Closes: #633350)
 +
 + -- Michael Vogt <mvo@debian.org>  Thu, 28 Jul 2011 16:49:15 +0200
 +
 +apt (0.8.15.4) unstable; urgency=low
 +
 +  [ David Miller ]
 +  * apt-pkg/contrib/sha1.cc:
 +    - fix illegally casts of on-stack buffer to a type requiring more
 +      alignment than it has resulting in segfaults on sparc (Closes: #634696)
 +
 +  [ Michael Vogt ]
 +  * apt-pkg/contrib/cdromutl.cc:
 +    - fix escape problem when looking for the mounted devices
 +  * apt-pkg/contrib/strutl.{h,cc}, test/libapt/strutil_test.cc:
 +    - add new DeEscapeString() similar to DeQuoteString but
 +      unescape character escapes like \0XX and \xXX (plus added
 +      test)
 +  * refresh po/*
 +  
 + -- Michael Vogt <mvo@debian.org>  Tue, 26 Jul 2011 12:12:27 +0200
 +
 +apt (0.8.15.3) unstable; urgency=low
 +
 +  [ Michael Vogt ]
 +  * apt-pkg/acquire-item.cc:
 +    - improve error message for a expired Release file
 +  * apt-pkg/algorithms.cc:
 +    - Hold back packages that would enter "policy-broken" state on upgrade
 +      when doing a "apt-get upgrade"
 +  * cmdline/apt-get.cc:
 +    - fix missing download progress in apt-get download
 +
 +  [ David Kalnischkies ]
 +  * apt-pkg/pkgcachegen.cc:
 +    - fallback to memory if file is not writeable even if access()
 +      told us the opposite before (e.g. in fakeroot 1.16) (Closes: #630591)
 +  * doc/sources.list.5.xml:
 +    - document available [options] for sources.list entries (Closes: 632441)
 +  * doc/apt.conf.5.xml:
 +    - document APT::Architectures list (Closes: #612102)
 +  * cmdline/apt-get.cc:
 +    - restore all important dependencies for garbage packages (LP: #806274)
 +    - do not require unused partial dirs in 'source' (Closes: #633510)
 +    - buildconflicts effect all architectures
 +    - implement MultiarchCross for build-dep and source (Closes: #632221)
 +  * apt-pkg/init.cc:
 +    - use CndSet in pkgInitConfig (Closes: #629617)
 +  * apt-pkg/depcache.cc:
 +    - change default of APT::AutoRemove::SuggestsImportant to true
 +  * cmdline/apt-key:
 +    - use a tmpfile instead of /etc/apt/secring.gpg (Closes: #632596)
 +  * debian/apt.postinst:
 +    - remove /etc/apt/secring.gpg if it is an empty file
 +  * doc/apt-cache.8.xml:
 +    - apply madison typofix from John Feuerstein, thanks! (Closes: #633455)
 +  * apt-pkg/policy.cc:
 +    - emit an error on unknown APT::Default-Release value (Closes: #407511)
 +  * apt-pkg/aptconfiguration.cc:
 +    - ensure that native architecture is if not specified otherwise the
 +      first architecture in the Architectures vector
 +  * apt-pkg/deb/deblistparser.cc:
 +    - Strip only :any and :native if MultiArch should be stripped as it is
 +      save to ignore them in non-MultiArch contexts but if the dependency
 +      is a specific architecture (and not the native) do not strip
 +
 + -- Michael Vogt <mvo@debian.org>  Mon, 25 Jul 2011 15:04:43 +0200
 +
 +apt (0.8.15.2) unstable; urgency=high
 +
 +  * fix from David Kalnischkies for the InRelease gpg verification 
 +    code (LP: #784473)
 +
 + -- Michael Vogt <mvo@debian.org>  Tue, 12 Jul 2011 11:54:47 +0200
 +
  apt (0.8.15.1) unstable; urgency=low
  
    [ David Kalnischkies ]
@@@ -407,185 -130,6 +413,185 @@@ apt (0.8.15) unstable; urgency=lo
  
   -- Michael Vogt <mvo@debian.org>  Tue, 28 Jun 2011 18:00:48 +0200
  
 +apt (0.8.15~exp3) experimental; urgency=low
 +
 +  * debian/control:
 +    - add Breaks: 0.8.15~exp3) for libapt-pkg4.10 and 
 +     libapt-inst1.2 (thanks to Jonathan Nieder, closes: #630214)
 +    - use depends for the ${shlibs:Depends} to make the breaks work
 +
 + -- Michael Vogt <mvo@debian.org>  Fri, 17 Jun 2011 21:51:41 +0200
 +
 +apt (0.8.15~exp2) experimental; urgency=low
 +
 +  * debian/control:
 +    - fix incorrect Replaces (closes: #630204) for libapt-inst1.2
 +
 + -- Michael Vogt <mvo@debian.org>  Wed, 15 Jun 2011 16:51:14 +0200
 +
 +apt (0.8.15~exp1) experimental; urgency=low
 +
 +  [ Julian Andres Klode ]
 +  * apt-pkg/depcache.cc:
 +    - Really release action groups only once (Closes: #622744)
 +    - Make purge work again for config-files (LP: #244598) (Closes: #150831)
 +  * apt-pkg/acquire-item.cc:
 +    - Reject files known to be invalid (LP: #346386) (Closes: #627642)
 +  * debian/apt.cron.daily:
 +    - Check power after wait, patch by manuel-soto (LP: #705269)
 +  * debian/control:
 +    - Move ${shlibs:Depends} to Pre-Depends, as we do not want APT
 +      unpacked if a library is too old and thus break upgrades
 +  * doc/apt-key.8.xml:
 +    - Document apt-key net-update (LP: #192810)
 +
 +  [ Christian Perrier ]
 +  * Galician translation update (Miguel Anxo Bouzada). Closes: #626505
 +  * Italian translation update (Milo Casagrande). Closes: #627834
 +  * German documentation translation update (Chris Leick). Closes: #629949
 +
 +  [ David Kalnischkies ]
 +  * fix a bunch of cppcheck warnings/errors based on a patch by
 +    Niels Thykier, thanks! (Closes: #622805)
 +  * apt-pkg/depcache.cc:
 +    - really include 'rc' packages in the delete count by fixing a
 +      typo which exists since 1999 in the source… (LP: #761175)
 +    - if critical or-group can't be satisfied, exit directly.
 +  * apt-pkg/acquire-method.cc:
 +    - write directly to stdout instead of creating the message in
 +      memory first before writing to avoid hitting limits
 +    - fix order of CurrentURI and UsedMirror in Status() and Log()
 +  * apt-pkg/orderlist.cc:
 +    - let VisitRProvides report if the calls were successful
 +  * apt-pkg/deb/dpkgpm.cc:
 +    - replace obsolete usleep with nanosleep
 +  * debian/apt{,-utils}.symbols:
 +    - update both experimental symbol-files to reflect 0.8.14 state
 +  * debian/rules:
 +    - remove unused embedded jquery by doxygen from libapt-pkg-doc
 +  * cmdline/apt-mark.cc:
 +    - reimplement apt-mark in c++
 +    - provide a 'showmanual' command (Closes: #582791)
 +    - provide a 'dpkg --set-selections' wrapper to set/release holds
 +  * cmdline/apt-get.cc:
 +    - deprecate mostly undocumented 'markauto' in favor of 'apt-mark'
 +  * cmdline/apt-cache.cc:
 +    - deprecate mostly undocumented 'showauto' in favor of 'apt-mark'
 +  * apt-pkg/pkgcache.cc:
 +    - really ignore :arch in FindPkg() in non-multiarch environment
 +  * doc/po/de.po:
 +    - undo the translation of the command 'dump' in manpage of apt-config
 +      as report by Burghard Grossmann on debian-l10n-german, thanks!
 +  * apt-pkg/deb/debmetaindex.cc:
 +    - do not download TranslationIndex if no Translation-* will be
 +      downloaded later on anyway (Closes: #624218)
 +  * test/versions.lst:
 +    - disable obscure version number tests with versions dpkg doesn't
 +      allow any more as they don't start with a number
 +  * apt-pkg/acquire-worker.cc:
 +    - print filename in the unmatching size warning (Closes: #623137)
 +  * apt-pkg/acquire-item.cc:
 +    - apply fix for poorly worded 'locate file' error message from
 +      Ben Finney, thanks! (Closes: #623171)
 +  * methods/http.cc:
 +    - add config option to ignore a closed stdin to be able to easily
 +      use the method as a simple standalone downloader
 +    - Location header in redirects should be absolute URI, but some
 +      servers just send an absolute path so still deal with it properly
 +    - dequote URL taken from Location in redirects as we will otherwise
 +      quote an already quoted string in the request later (Closes: #602412)
 +  * apt-pkg/contrib/netrc.cc:
 +    - replace non-posix gnu-extension strdupa with strdup
 +  * apt-pkg/packagemanager.cc:
 +    - ensure for Multi-Arch:same packages that they are unpacked in
 +      lock step even in immediate configuration (Closes: #618288)
 +
 +  [ Michael Vogt ]
 +  * methods/mirror.cc:
 +    - ignore lines starting with "#" in the mirror file
 +    - ignore non http urls in the mirrors
 +    - append the dist (e.g. sid, wheezy) as a query string when
 +      asking for a suitable mirror 
 +  * debian/control:
 +    - add libapt-pkg4.10 and libapt-inst1.2 library packages
 +
 + -- Michael Vogt <mvo@debian.org>  Fri, 10 Jun 2011 15:32:07 +0200
 +
 +apt (0.8.14.2) UNRELEASED; urgency=low
 +
 +  [ Julian Andres Klode ]
 +  * apt-pkg/depcache.cc:
 +    - Really release action groups only once (Closes: #622744)
 +    - Make purge work again for config-files (LP: #244598) (Closes: #150831)
 +  * debian/apt.cron.daily:
 +    - Check power after wait, patch by manuel-soto (LP: #705269)
 +  * debian/control:
 +    - Move ${shlibs:Depends} to Pre-Depends, as we do not want APT
 +      unpacked if a library is too old and thus break upgrades
 +  * doc/apt-key.8.xml:
 +    - Document apt-key net-update (LP: #192810)
 +
 +  [ Christian Perrier ]
 +  * Galician translation update (Miguel Anxo Bouzada). Closes: #626505
 +
 +  [ David Kalnischkies ]
 +  * fix a bunch of cppcheck warnings/errors based on a patch by
 +    Niels Thykier, thanks! (Closes: #622805)
 +  * apt-pkg/depcache.cc:
 +    - really include 'rc' packages in the delete count by fixing a
 +      typo which exists since 1999 in the source… (LP: #761175)
 +    - if critical or-group can't be satisfied, exit directly.
 +  * apt-pkg/acquire-method.cc:
 +    - write directly to stdout instead of creating the message in
 +      memory first before writing to avoid hitting limits
 +    - fix order of CurrentURI and UsedMirror in Status() and Log()
 +  * apt-pkg/orderlist.cc:
 +    - let VisitRProvides report if the calls were successful
 +  * apt-pkg/deb/dpkgpm.cc:
 +    - replace obsolete usleep with nanosleep
 +  * debian/apt{,-utils}.symbols:
 +    - update both experimental symbol-files to reflect 0.8.14 state
 +  * debian/rules:
 +    - remove unused embedded jquery by doxygen from libapt-pkg-doc
 +  * cmdline/apt-mark.cc:
 +    - reimplement apt-mark in c++
 +    - provide a 'showmanual' command (Closes: #582791)
 +    - provide a 'dpkg --set-selections' wrapper to set/release holds
 +  * cmdline/apt-get.cc:
 +    - deprecate mostly undocumented 'markauto' in favor of 'apt-mark'
 +  * cmdline/apt-cache.cc:
 +    - deprecate mostly undocumented 'showauto' in favor of 'apt-mark'
 +  * apt-pkg/pkgcache.cc:
 +    - really ignore :arch in FindPkg() in non-multiarch environment
 +  * doc/po/de.po:
 +    - undo the translation of the command 'dump' in manpage of apt-config
 +      as report by Burghard Grossmann on debian-l10n-german, thanks!
 +  * apt-pkg/deb/debmetaindex.cc:
 +    - do not download TranslationIndex if no Translation-* will be
 +      downloaded later on anyway (Closes: #624218)
 +  * test/versions.lst:
 +    - disable obscure version number tests with versions dpkg doesn't
 +      allow any more as they don't start with a number
 +  * apt-pkg/acquire-worker.cc:
 +    - print filename in the unmatching size warning (Closes: #623137)
 +  * apt-pkg/acquire-item.cc:
 +    - apply fix for poorly worded 'locate file' error message from
 +      Ben Finney, thanks! (Closes: #623171)
 +  * methods/http.cc:
 +    - add config option to ignore a closed stdin to be able to easily
 +      use the method as a simple standalone downloader
 +    - Location header in redirects should be absolute URI, but some
 +      servers just send an absolute path so still deal with it properly
 +    - dequote URL taken from Location in redirects as we will otherwise
 +      quote an already quoted string in the request later (Closes: #602412)
 +  * apt-pkg/contrib/netrc.cc:
 +    - replace non-posix gnu-extension strdupa with strdup
 +  * apt-pkg/packagemanager.cc:
 +    - ensure for Multi-Arch:same packages that they are unpacked in
 +      lock step even in immediate configuration (Closes: #618288)
 +
 + -- Michael Vogt <mvo@debian.org>  Mon, 16 May 2011 14:57:52 +0200
 +
  apt (0.8.14.1) unstable; urgency=low
  
    * apt-pkg/acquire-item.cc:
index a05f03df4c39b76d8915aafa0adf2dfd792cb881,7e384e428c2b055e67b7dd25a4dc39e4d23e71fe..7333054cc11b47da54da8833793b413b390cc33d
@@@ -17,16 -17,16 +17,29 @@@ buildsimplenativepackage 'apt2' 'amd64
  
  setupaptarchive
  
--testequal 'Reading package lists...
++# order in switch libsame:{amd64,i386} are unpacked is irrelevant, as both are installed - but we need to do it together
++testequalor2 'Reading package lists...
 +Building dependency tree...
 +The following packages will be upgraded:
 +  apt:i386 apt2 libsame libsame:i386
 +4 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
 +Inst libsame:i386 [1] (2 unstable [i386]) [libsame:amd64 on libsame:i386] [libsame:i386 on libsame:amd64] [libsame:amd64 apt:i386 ]
 +Inst libsame [1] (2 unstable [amd64]) [apt2:amd64 apt:i386 ]
 +Conf libsame:i386 (2 unstable [i386]) [apt2:amd64 apt:i386 ]
 +Conf libsame (2 unstable [amd64]) [apt2:amd64 apt:i386 ]
 +Inst apt2 [1] (2 unstable [amd64]) [apt:i386 ]
 +Conf apt2 (2 unstable [amd64]) [apt:i386 ]
 +Inst apt:i386 [1] (2 unstable [i386])
++Conf apt:i386 (2 unstable [i386])' 'Reading package lists...
+ Building dependency tree...
+ The following packages will be upgraded:
+   apt:i386 apt2 libsame libsame:i386
+ 4 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
+ Inst libsame [1] (2 unstable [amd64]) [libsame:amd64 on libsame:i386] [libsame:i386 on libsame:amd64] [libsame:i386 apt2:amd64 ]
+ Inst libsame:i386 [1] (2 unstable [i386]) [apt2:amd64 apt:i386 ]
+ Conf libsame:i386 (2 unstable [i386]) [apt2:amd64 apt:i386 ]
+ Conf libsame (2 unstable [amd64]) [apt2:amd64 apt:i386 ]
+ Inst apt2 [1] (2 unstable [amd64]) [apt:i386 ]
+ Conf apt2 (2 unstable [amd64]) [apt:i386 ]
+ Inst apt:i386 [1] (2 unstable [i386])
  Conf apt:i386 (2 unstable [i386])' aptget dist-upgrade -s