]> git.saurik.com Git - apt.git/commitdiff
* Implement EDSP in libapt-pkg so that all front-ends which
authorDavid Kalnischkies <kalnischkies@gmail.com>
Tue, 17 May 2011 15:26:59 +0000 (17:26 +0200)
committerDavid Kalnischkies <kalnischkies@gmail.com>
Tue, 17 May 2011 15:26:59 +0000 (17:26 +0200)
  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

1  2 
apt-pkg/algorithms.cc
apt-pkg/depcache.cc
apt-pkg/pkgcachegen.cc
apt-pkg/policy.cc
cmdline/apt-get.cc
cmdline/makefile
debian/changelog
debian/rules

diff --combined apt-pkg/algorithms.cc
index 2dae4258a964c1935201235e7c3a72c1f26172d4,31c3e9c28633316d7835f7e4743229e4e99a0bf6..6f1f82d501c95af5ce73832021a1a848f6f91352
  #include <apt-pkg/version.h>
  #include <apt-pkg/sptr.h>
  #include <apt-pkg/acquire-item.h>
-     
+ #include <apt-pkg/edsp.h>
  #include <apti18n.h>
  #include <sys/types.h>
  #include <cstdlib>
  #include <algorithm>
  #include <iostream>
+ #include <stdio.h>
                                                                        /*}}}*/
  using namespace std;
  
@@@ -101,7 -104,9 +104,7 @@@ bool pkgSimulate::Install(PkgIterator i
         DepIterator Start;
         DepIterator End;
         D.GlobOr(Start,End);
 -       if (Start->Type == pkgCache::Dep::Conflicts ||
 -           Start->Type == pkgCache::Dep::DpkgBreaks ||
 -           Start->Type == pkgCache::Dep::Obsoletes ||
 +       if (Start.IsNegative() == true ||
             End->Type == pkgCache::Dep::PreDepends)
           {
            if ((Sim[End] & pkgDepCache::DepGInstall) == 0)
@@@ -327,6 -332,12 +330,12 @@@ bool pkgFixBroken(pkgDepCache &Cache
   */
  bool pkgDistUpgrade(pkgDepCache &Cache)
  {
+    std::string const solver = _config->Find("APT::Solver::Name", "internal");
+    if (solver != "internal") {
+       OpTextProgress Prog(*_config);
+       return EDSP::ResolveExternal(solver.c_str(), Cache, false, true, false, &Prog);
+    }
     pkgDepCache::ActionGroup group(Cache);
  
     /* Upgrade all installed packages first without autoinst to help the resolver
     to install packages not marked for install */
  bool pkgAllUpgrade(pkgDepCache &Cache)
  {
+    std::string const solver = _config->Find("APT::Solver::Name", "internal");
+    if (solver != "internal") {
+       OpTextProgress Prog(*_config);
+       return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
+    }
     pkgDepCache::ActionGroup group(Cache);
  
     pkgProblemResolver Fix(&Cache);
@@@ -645,10 -662,12 +660,10 @@@ bool pkgProblemResolver::DoUpgrade(pkgC
        // Compute a single dependency element (glob or)
        pkgCache::DepIterator Start = D;
        pkgCache::DepIterator End = D;
 -      unsigned char State = 0;
        for (bool LastOR = true; D.end() == false && LastOR == true;)
        {
 -       State |= Cache[D];
         LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
 -       D++;
 +       ++D;
         if (LastOR == true)
            End = D;
        }
            {
               /* We let the algorithm deal with conflicts on its next iteration,
                it is much smarter than us */
 -             if (Start->Type == pkgCache::Dep::Conflicts || 
 -                 Start->Type == pkgCache::Dep::DpkgBreaks || 
 -                 Start->Type == pkgCache::Dep::Obsoletes)
 +             if (Start.IsNegative() == true)
                   break;
               
               if (Debug == true)
     return true;
  }
                                                                        /*}}}*/
- // ProblemResolver::Resolve - Run the resolution pass                 /*{{{*/
+ // ProblemResolver::Resolve - calls a resolver to fix the situation   /*{{{*/
+ // ---------------------------------------------------------------------
+ /* */
+ bool pkgProblemResolver::Resolve(bool BrokenFix)
+ {
+    std::string const solver = _config->Find("APT::Solver::Name", "internal");
+    if (solver != "internal") {
+       OpTextProgress Prog(*_config);
+       return EDSP::ResolveExternal(solver.c_str(), Cache, false, false, false, &Prog);
+    }
+    return ResolveInternal(BrokenFix);
+ }
+                                                                       /*}}}*/
+ // ProblemResolver::ResolveInternal - Run the resolution pass         /*{{{*/
  // ---------------------------------------------------------------------
  /* This routines works by calculating a score for each package. The score
     is derived by considering the package's priority and all reverse 
   
     The BrokenFix flag enables a mode where the algorithm tries to 
     upgrade packages to advoid problems. */
- bool pkgProblemResolver::Resolve(bool BrokenFix)
+ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
  {
     pkgDepCache::ActionGroup group(Cache);
  
-    unsigned long Size = Cache.Head().PackageCount;
     // Record which packages are marked for install
     bool Again = false;
     do
        clog << "Starting" << endl;
     
     MakeScores();
-    
+    unsigned long const Size = Cache.Head().PackageCount;
     /* We have to order the packages so that the broken fixing pass 
        operates from highest score to lowest. This prevents problems when
        high score packages cause the removal of lower score packages that
               if a package has a dep on another package that cant be found */
            SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
            if (*VList == 0 && (Flags[I->ID] & Protected) != Protected &&
 -              Start->Type != pkgCache::Dep::Conflicts &&
 -              Start->Type != pkgCache::Dep::DpkgBreaks &&
 -              Start->Type != pkgCache::Dep::Obsoletes &&
 +              Start.IsNegative() == false &&
                Cache[I].NowBroken() == false)
            {          
               if (InOr == true)
                    at is not the currently selected version of the 
                    package, which means it is not necessary to 
                    remove/keep */
 -               if (Cache[Pkg].InstallVer != Ver &&
 -                   (Start->Type == pkgCache::Dep::Conflicts ||
 -                    Start->Type == pkgCache::Dep::DpkgBreaks ||
 -                    Start->Type == pkgCache::Dep::Obsoletes)) 
 +               if (Cache[Pkg].InstallVer != Ver && Start.IsNegative() == true)
                 {
                    if (Debug) 
                       clog << "  Conflicts//Breaks against version " 
                  fiddle with the VList package */
               if (Scores[I->ID] <= Scores[Pkg->ID] ||
                   ((Cache[Start] & pkgDepCache::DepNow) == 0 &&
 -                  End->Type != pkgCache::Dep::Conflicts &&
 -                  End->Type != pkgCache::Dep::DpkgBreaks &&
 -                  End->Type != pkgCache::Dep::Obsoletes))
 +                  End.IsNegative() == false))
               {
                  // Try a little harder to fix protected packages..
                  if ((Flags[I->ID] & Protected) == Protected)
            }
  
            // Hm, nothing can possibly satisify this dep. Nuke it.
 -          if (VList[0] == 0 && 
 -              Start->Type != pkgCache::Dep::Conflicts &&
 -              Start->Type != pkgCache::Dep::DpkgBreaks &&
 -              Start->Type != pkgCache::Dep::Obsoletes &&
 +          if (VList[0] == 0 &&
 +              Start.IsNegative() == false &&
                (Flags[I->ID] & Protected) != Protected)
            {
               bool Installed = Cache[I].Install();
               Change = true;
               if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
               {
 -                if (J->Dep->Type == pkgCache::Dep::Conflicts || 
 -                    J->Dep->Type == pkgCache::Dep::DpkgBreaks ||
 -                    J->Dep->Type == pkgCache::Dep::Obsoletes)
 +                if (J->Dep.IsNegative() == true)
                  {
                     if (Debug == true)
                        clog << "  Fixing " << I.FullName(false) << " via remove of " << J->Pkg.FullName(false) << endl;
     in that it does not install or remove any packages. It is assumed that the
     system was non-broken previously. */
  bool pkgProblemResolver::ResolveByKeep()
+ {
+    std::string const solver = _config->Find("APT::Solver::Name", "internal");
+    if (solver != "internal") {
+       OpTextProgress Prog(*_config);
+       return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
+    }
+    return ResolveByKeepInternal();
+ }
+                                                                       /*}}}*/
+ // ProblemResolver::ResolveByKeepInternal - Resolve problems using keep       /*{{{*/
+ // ---------------------------------------------------------------------
+ /* This is the work horse of the soft upgrade routine. It is very gental
+    in that it does not install or remove any packages. It is assumed that the
+    system was non-broken previously. */
+ bool pkgProblemResolver::ResolveByKeepInternal()
  {
     pkgDepCache::ActionGroup group(Cache);
  
diff --combined apt-pkg/depcache.cc
index e9fa097aaf11e8aa32fdfc274059daf46c9a9eea,31410e2a69202596cd09021219e3fc5a589d6865..5cb68804dd46bc8efd515f1c8ed141331c39b200
@@@ -70,7 -70,7 +70,7 @@@ void pkgDepCache::ActionGroup::release(
            cache.MarkAndSweep();
        }
  
 -      released = false;
 +      released = true;
      }
  }
  
@@@ -339,7 -339,8 +339,7 @@@ bool pkgDepCache::CheckDep(DepIterator 
     /* Check simple depends. A depends -should- never self match but 
        we allow it anyhow because dpkg does. Technically it is a packaging
        bug. Conflicts may never self match */
 -   if (Dep.TargetPkg() != Dep.ParentPkg() ||
 -       (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes))
 +   if (Dep.TargetPkg() != Dep.ParentPkg() || Dep.IsNegative() == false)
     {
        PkgIterator Pkg = Dep.TargetPkg();
        // Check the base package
     {
        /* Provides may never be applied against the same package (or group)
           if it is a conflicts. See the comment above. */
 -      if (P.OwnerPkg()->Group == Pkg->Group &&
 -        (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks))
 +      if (P.OwnerPkg()->Group == Pkg->Group && Dep.IsNegative() == true)
         continue;
        
        // Check if the provides is a hit
@@@ -547,8 -549,8 +547,8 @@@ void pkgDepCache::AddStates(const PkgIt
     // Not installed
     if (Pkg->CurrentVer == 0)
     {
 -      if (State.Mode == ModeDelete && 
 -        (State.iFlags | Purge) == Purge && Pkg.Purge() == false)
 +      if (State.Mode == ModeDelete &&
 +        (State.iFlags & Purge) == Purge && Pkg.Purge() == false)
         iDelCount += Add;
        
        if (State.Mode == ModeInstall)
@@@ -592,7 -594,9 +592,7 @@@ void pkgDepCache::BuildGroupOrs(VerIter
  
        /* Invert for Conflicts. We have to do this twice to get the
           right sense for a conflicts group */
 -      if (D->Type == Dep::Conflicts ||
 -        D->Type == Dep::DpkgBreaks ||
 -        D->Type == Dep::Obsoletes)
 +      if (D.IsNegative() == true)
         State = ~State;
        
        // Add to the group if we are within an or..
         Group = 0;
        
        // Invert for Conflicts
 -      if (D->Type == Dep::Conflicts ||
 -        D->Type == Dep::DpkgBreaks ||
 -        D->Type == Dep::Obsoletes)
 +      if (D.IsNegative() == true)
         State = ~State;
     }   
  }
@@@ -736,7 -742,9 +736,7 @@@ void pkgDepCache::Update(OpProgress *Pr
               Group = 0;
  
            // Invert for Conflicts
 -          if (D->Type == Dep::Conflicts ||
 -              D->Type == Dep::DpkgBreaks ||
 -              D->Type == Dep::Obsoletes)
 +          if (D.IsNegative() == true)
               State = ~State;
         }
        }
@@@ -766,7 -774,9 +766,7 @@@ void pkgDepCache::Update(DepIterator D
        State = DependencyState(D);
      
        // Invert for Conflicts
 -      if (D->Type == Dep::Conflicts ||
 -        D->Type == Dep::DpkgBreaks ||
 -        D->Type == Dep::Obsoletes)
 +      if (D.IsNegative() == true)
         State = ~State;
  
        RemoveStates(D.ParentPkg());
@@@ -1046,7 -1056,7 +1046,7 @@@ void pkgDepCache::MarkInstall(PkgIterat
     Update(Pkg);
     AddSizes(Pkg);
  
-    if (AutoInst == false)
+    if (AutoInst == false || _config->Find("APT::Solver::Name", "internal") != "internal")
        return;
  
     if (DebugMarker == true)
        */
        if (IsImportantDep(Start) == false)
         continue;
 -      
 +
 +      /* If we are in an or group locate the first or that can 
 +         succeed. We have already cached this.. */
 +      for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; --Ors)
 +       ++Start;
 +      if (Ors == 1 && (DepState[Start->ID] &DepCVer) != DepCVer && Start.IsNegative() == false)
 +      {
 +       if(DebugAutoInstall == true)
 +          std::clog << OutputInDepth(Depth) << Start << " can't be satisfied!" << std::endl;
 +       if (Start.IsCritical() == false)
 +          continue;
 +       // if the dependency was critical, we can't install it, so remove it again
 +       MarkDelete(Pkg,false,Depth + 1, false);
 +       return;
 +      }
 +
        /* Check if any ImportantDep() (but not Critical) were added
         * since we installed the package.  Also check for deps that
         * were satisfied in the past: for instance, if a version
         * package should follow that Recommends rather than causing the
         * dependency to be removed. (bug #470115)
         */
 -      bool isNewImportantDep = false;
 -      bool isPreviouslySatisfiedImportantDep = false;
 -      if(!ForceImportantDeps && !Start.IsCritical())
 +      if (Pkg->CurrentVer != 0 && ForceImportantDeps == false && Start.IsCritical() == false)
        {
 -       bool found=false;
 -       VerIterator instVer = Pkg.CurrentVer();
 -       if(!instVer.end())
 +       bool isNewImportantDep = true;
 +       bool isPreviouslySatisfiedImportantDep = false;
 +       for (DepIterator D = Pkg.CurrentVer().DependsList(); D.end() != true; ++D)
         {
 -         for (DepIterator D = instVer.DependsList(); D.end() != true; D++)
 -           {
 -             //FIXME: deal better with or-groups(?)
 -             if(IsImportantDep(D) && !D.IsCritical() &&
 -                Start.TargetPkg() == D.TargetPkg())
 -               {
 -                 if(!isPreviouslySatisfiedImportantDep)
 -                   {
 -                     DepIterator D2 = D;
 -                     while((D2->CompareOp & Dep::Or) != 0)
 -                       ++D2;
 -
 -                     isPreviouslySatisfiedImportantDep =
 -                       (((*this)[D2] & DepGNow) != 0);
 -                   }
 -
 -                 found=true;
 -               }
 -           }
 -          // this is a new dep if it was not found to be already
 -          // a important dep of the installed pacakge
 -          isNewImportantDep = !found;
 +          //FIXME: Should we handle or-group better here?
 +          // We do not check if the package we look for is part of the same or-group
 +          // we might find while searching, but could that really be a problem?
 +          if (D.IsCritical() == true || IsImportantDep(D) == false ||
 +              Start.TargetPkg() != D.TargetPkg())
 +             continue;
 +
 +          isNewImportantDep = false;
 +
 +          while ((D->CompareOp & Dep::Or) != 0)
 +             ++D;
 +
 +          isPreviouslySatisfiedImportantDep = (((*this)[D] & DepGNow) != 0);
 +          if (isPreviouslySatisfiedImportantDep == true)
 +             break;
 +       }
 +
 +       if(isNewImportantDep == true)
 +       {
 +          if (DebugAutoInstall == true)
 +             std::clog << OutputInDepth(Depth) << "new important dependency: "
 +                       << Start.TargetPkg().FullName() << std::endl;
 +       }
 +       else if(isPreviouslySatisfiedImportantDep == true)
 +       {
 +          if (DebugAutoInstall == true)
 +             std::clog << OutputInDepth(Depth) << "previously satisfied important dependency on "
 +                       << Start.TargetPkg().FullName() << std::endl;
 +       }
 +       else
 +       {
 +          if (DebugAutoInstall == true)
 +             std::clog << OutputInDepth(Depth) << "ignore old unsatisfied important dependency on "
 +                       << Start.TargetPkg().FullName() << std::endl;
 +          continue;
         }
        }
 -      if(isNewImportantDep)
 -       if(DebugAutoInstall == true)
 -          std::clog << OutputInDepth(Depth) << "new important dependency: "
 -                    << Start.TargetPkg().Name() << std::endl;
 -      if(isPreviouslySatisfiedImportantDep)
 -      if(DebugAutoInstall == true)
 -        std::clog << OutputInDepth(Depth) << "previously satisfied important dependency on "
 -                  << Start.TargetPkg().Name() << std::endl;
 -
 -      // skip important deps if the package is already installed
 -      if (Pkg->CurrentVer != 0 && Start.IsCritical() == false 
 -        && !isNewImportantDep && !isPreviouslySatisfiedImportantDep
 -        && !ForceImportantDeps)
 -       continue;
 -      
 -      /* If we are in an or group locate the first or that can 
 -         succeed. We have already cached this.. */
 -      for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; Ors--)
 -       Start++;
  
        /* This bit is for processing the possibilty of an install/upgrade
           fixing the problem */
        /* For conflicts we just de-install the package and mark as auto,
           Conflicts may not have or groups.  For dpkg's Breaks we try to
           upgrade the package. */
 -      if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes ||
 -        Start->Type == Dep::DpkgBreaks)
 +      if (Start.IsNegative() == true)
        {
         for (Version **I = List; *I != 0; I++)
         {
@@@ -1574,6 -1578,12 +1574,12 @@@ bool pkgDepCache::Policy::IsImportantDe
     return false;
  }
                                                                        /*}}}*/
+ // Policy::GetPriority - Get the priority of the package pin          /*{{{*/
+ signed short pkgDepCache::Policy::GetPriority(pkgCache::PkgIterator const &Pkg)
+ { return 0; };
+ signed short pkgDepCache::Policy::GetPriority(pkgCache::PkgFileIterator const &File)
+ { return 0; };
+                                                                       /*}}}*/
  pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc()             /*{{{*/
  {
    DefaultRootSetFunc *f = new DefaultRootSetFunc;
@@@ -1599,6 -1609,9 +1605,9 @@@ bool pkgDepCache::MarkFollowsSuggests(
  // pkgDepCache::MarkRequired - the main mark algorithm                        /*{{{*/
  bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
  {
+    if (_config->Find("APT::Solver::Name", "internal") != "internal")
+       return true;
     bool follow_recommends;
     bool follow_suggests;
     bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
diff --combined apt-pkg/pkgcachegen.cc
index 9820fde81996c413494970f74f4eb57834b8cba9,46dd220073fc6015f50b3420f3f511fd39a7f5ca..8e088ba68d1baaa037528bcb333e267d4722d824
@@@ -479,8 -479,7 +479,8 @@@ bool pkgCacheGenerator::NewPackage(pkgC
     // Set the name, arch and the ID
     Pkg->Name = Grp->Name;
     Pkg->Group = Grp.Index();
 -   map_ptrloc const idxArch = WriteUniqString((Arch == "all") ? _config->Find("APT::Architecture") : Arch.c_str());
 +   // all is mapped to the native architecture
 +   map_ptrloc const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : WriteUniqString(Arch.c_str());
     if (unlikely(idxArch == 0))
        return false;
     Pkg->Arch = idxArch;
@@@ -642,7 -641,7 +642,7 @@@ bool pkgCacheGenerator::FinishCache(OpP
               bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
               for (vector<string>::const_iterator A = archs.begin(); A != archs.end(); ++A)
               {
-                 if (*A == Arch)
+                 if (Arch == 0 || *A == Arch)
                     continue;
                  /* We allow only one installed arch at the time
                     per group, therefore each group member conflicts
@@@ -784,7 -783,7 +784,7 @@@ bool pkgCacheGenerator::ListParser::New
  
     // We do not add self referencing provides
     if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() ||
 -      (PkgArch == "all" && _config->Find("APT::Architecture") == Ver.ParentPkg().Arch())))
 +      (PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0)))
        return true;
     
     // Get a structure
diff --combined apt-pkg/policy.cc
index 2cc2e5e39cfc23d911650c0c4208892e630c0b72,4e4077feb3a5dafcda09003ccb00ca0f3e790f66..4fc272a747a3356f836176c7295b28891c87d9b6
@@@ -216,22 -216,10 +216,22 @@@ void pkgPolicy::CreatePin(pkgVersionMat
        P->Data = Data;
        return;
     }
 +   
 +   // Allow pinning by wildcards
 +   // TODO: Maybe we should always prefer specific pins over non-
 +   // specific ones.
 +   if (Name[0] == '/' || Name.find_first_of("*[?") != string::npos)
 +   {
 +      pkgVersionMatch match(Data, Type);
 +      for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() != true; ++G)
 +       if (match.ExpressionMatches(Name, G.Name()))
 +          CreatePin(Type, G.Name(), Data, Priority);
 +      return;
 +   }
  
     // Get a spot to put the pin
     pkgCache::GrpIterator Grp = Cache->FindGrp(Name);
 -   for (pkgCache::PkgIterator Pkg = Grp.FindPkg("any");
 +   for (pkgCache::PkgIterator Pkg = Grp.PackageList();
        Pkg.end() != true; Pkg = Grp.NextPkg(Pkg))
     {
        Pin *P = 0;
@@@ -281,6 -269,10 +281,10 @@@ signed short pkgPolicy::GetPriority(pkg
     }
     
     return 0;
+ }
+ signed short pkgPolicy::GetPriority(pkgCache::PkgFileIterator const &File)
+ {
+    return PFPriority[File->ID];
  }
                                                                        /*}}}*/
  // PreferenceSection class - Overriding the default TrimRecord method /*{{{*/
diff --combined cmdline/apt-get.cc
index 845c92026b66602e3f9799e0b634451d23f823f8,2312f5a101736f51eb9243f5d9ff3efe7b31a91d..fdb1033a159d4c2e0a0a42fd108c28d3438827b9
@@@ -1887,7 -1887,7 +1887,7 @@@ bool DoInstall(CommandLine &CmdL
         // Call the scored problem resolver
         Fix->InstallProtect();
         if (Fix->Resolve(true) == false)
-           _error->Discard();
+           ; //FIXME: is there a valid reason for?  _error->Discard();
         delete Fix;
        }
  
  
     return InstallPackages(Cache,false);   
  }
 -
 -/* mark packages as automatically/manually installed. */
 +                                                                      /*}}}*/
 +/* mark packages as automatically/manually installed.                 {{{*/
  bool DoMarkAuto(CommandLine &CmdL)
  {
     bool Action = true;
           AutoMarkChanged++;
        }
     }
 +
 +   _error->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead."));
 +
     if (AutoMarkChanged && ! _config->FindB("APT::Get::Simulate",false))
        return Cache->writeStateFile(NULL);
     return false;
@@@ -2389,10 -2386,8 +2389,10 @@@ bool DoSource(CommandLine &CmdL
        string Src;
        pkgSrcRecords::Parser *Last = FindSrc(*I,Recs,SrcRecs,Src,*Cache);
        
 -      if (Last == 0)
 +      if (Last == 0) {
 +       delete[] Dsc;
         return _error->Error(_("Unable to find a source package for %s"),Src.c_str());
 +      }
        
        string srec = Last->AsStr();
        string::size_type pos = srec.find("\nVcs-");
  
        // Back track
        vector<pkgSrcRecords::File> Lst;
 -      if (Last->Files(Lst) == false)
 +      if (Last->Files(Lst) == false) {
 +       delete[] Dsc;
         return false;
 +      }
  
        // Load them into the fetcher
        for (vector<pkgSrcRecords::File>::const_iterator I = Lst.begin();
     struct statvfs Buf;
     string OutputDir = ".";
     if (statvfs(OutputDir.c_str(),&Buf) != 0) {
 +      delete[] Dsc;
        if (errno == EOVERFLOW)
         return _error->WarningE("statvfs",_("Couldn't determine free space in %s"),
                                OutputDir.c_str());
  #if HAVE_STRUCT_STATFS_F_TYPE
             || unsigned(Stat.f_type) != RAMFS_MAGIC
  #endif
 -           ) 
 +           )  {
 +       delete[] Dsc;
            return _error->Error(_("You don't have enough free space in %s"),
                OutputDir.c_str());
 -      }
 +       }
 +     }
     
     // Number of bytes
     if (DebBytes != FetchBytes)
     
     // Run it
     if (Fetcher.Run() == pkgAcquire::Failed)
 +   {
 +      delete[] Dsc;
        return false;
 +   }
  
     // Print error messages
     bool Failed = false;
        Failed = true;
     }
     if (Failed == true)
 +   {
 +      delete[] Dsc;
        return _error->Error(_("Failed to fetch some archives."));
 -   
 +   }
 +
     if (_config->FindB("APT::Get::Download-only",false) == true)
     {
        c1out << _("Download complete and in download only mode") << endl;
  bool DoBuildDep(CommandLine &CmdL)
  {
     CacheFile Cache;
 +
 +   _config->Set("APT::Install-Recommends", false);
 +   
     if (Cache.Open(true) == false)
        return false;
  
@@@ -3187,6 -3168,8 +3187,6 @@@ bool ShowHelp(CommandLine &CmdL
        "   clean - Erase downloaded archive files\n"
        "   autoclean - Erase old downloaded archive files\n"
        "   check - Verify that there are no broken dependencies\n"
 -      "   markauto - Mark the given packages as automatically installed\n"
 -      "   unmarkauto - Mark the given packages as manually installed\n"
        "   changelog - Download and display the changelog for the given package\n"
        "   download - Download the binary package into the current directory\n"
        "\n"
@@@ -3270,6 -3253,7 +3270,7 @@@ int main(int argc,const char *argv[]
        {0,"install-recommends","APT::Install-Recommends",CommandLine::Boolean},
        {0,"install-suggests","APT::Install-Suggests",CommandLine::Boolean},
        {0,"fix-policy","APT::Get::Fix-Policy-Broken",0},
+       {0,"solver","APT::Solver::Name",CommandLine::HasArg},
        {'c',"config-file",0,CommandLine::ConfigFile},
        {'o',"option",0,CommandLine::ArbItem},
        {0,0,0,0}};
diff --combined cmdline/makefile
index e867dae73654fb573bdcaabc09ddf2fe5795261e,aea5d1db55257028aaa1b20af44caadbf32b2f3a..6d988a8f587f365355440619da2ad86a89e1fbc4
@@@ -54,14 -54,27 +54,28 @@@ TARGET=progra
  include $(COPY_H)
  
  # The apt-mark program
 -SOURCE=apt-mark
 -TO=$(BIN)
 -TARGET=program
 -include $(COPY_H)
 +PROGRAM=apt-mark
 +SLIBS = -lapt-pkg $(INTLLIBS)
 +LIB_MAKES = apt-pkg/makefile
 +SOURCE = apt-mark.cc
 +include $(PROGRAM_H)
  
  # The apt-report-mirror-failure program
  #SOURCE=apt-report-mirror-failure
  #TO=$(BIN)
  #TARGET=program
  #include $(COPY_H)
+ # The internal solver acting as an external
+ PROGRAM=apt-internal-solver
+ SLIBS = -lapt-pkg $(INTLLIBS)
+ LIB_MAKES = apt-pkg/makefile
+ SOURCE = apt-internal-solver.cc
+ include $(PROGRAM_H)
+ # The internal solver acting as an external
+ PROGRAM=apt-dump-solver
+ SLIBS = -lapt-pkg $(INTLLIBS)
+ LIB_MAKES = apt-pkg/makefile
+ SOURCE = apt-dump-solver.cc
+ include $(PROGRAM_H)
diff --combined debian/changelog
index b64594c2ca57909f43589510be90876fd35c9eae,e669077fed84726e8603ba63eacd450df3f4fd37..16827ff8d765f2598abfa03beca84518bfff1f0c
 -apt (0.8.13.1) UNRELEASED; urgency=low
++apt (0.8.15) UNRELEASED; urgency=low
++
++  [ David Kalnischkies ]
++  * 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
++
++ -- David Kalnischkies <kalnischkies@gmail.com>  Tue, 17 May 2011 17:19:48 +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:
 +    - Only try to rename existing Release files (Closes: #622912)
 +
 + -- Julian Andres Klode <jak@debian.org>  Sat, 16 Apr 2011 14:36:10 +0200
 +
 +apt (0.8.14) unstable; urgency=low
 +
 +  [ Julian Andres Klode ]
 +  * apt-pkg/indexcopy.cc:
 +    - Use RealFileExists() instead of FileExists(), allows amongst other
 +      things a directory named Sources to exist on a CD-ROM (LP: #750694).
 +  * apt-pkg/acquire-item.cc:
 +    - Use Release files even if they cannot be verified (LP: #704595)
 +  * cmdline/apt-get.cc:
 +    - Do not install recommends for build-dep (Closes: #454479) (LP: #245273)
 +  * apt-pkg/deb/deblistparser.cc:
 +    - Handle no space before "[" in build-dependencies (LP: #72344)
 +  * apt-pkg/policy.cc:
 +    - Allow pinning by glob() expressions, and regular expressions
 +      surrounded by slashes (the "/" character) (LP: #399474)
 +      (Closes: #121132)
 +  * debian/control:
 +    - Set Standards-Version to 3.9.2
 +  
 +  [ Michael Vogt ]
 +  * mirror method:
 +    - do not crash if the mirror file fails to download
 +  * apt-pkg/aptconfiguration.cc:
 +    - fix comparing for a empty string
 +  * debian/apt.cron.daily:
 +    - run unattended-upgrades even if there was a error during
 +      the apt-get update (LP: #676295)
 +
 +  [ David Kalnischkies ]
 +  * apt-pkg/pkgcache.cc:
 +    - use the native Architecture stored in the cache header instead of
 +      loading it from configuration as suggested by Julian Andres Klode
 +
 + -- Julian Andres Klode <jak@debian.org>  Fri, 15 Apr 2011 14:28:15 +0200
 +
 +apt (0.8.13.2) unstable; urgency=low
  
    [ David Kalnischkies ]
    * apt-pkg/deb/dpkgpm.cc:
    * apt-pkg/deb/deblistparser.cc:
      - create foo:any provides for all architectures for an allowed package
  
 - -- David Kalnischkies <kalnischkies@gmail.com>  Tue, 29 Mar 2011 13:12:45 +0200
 + -- Michael Vogt <mvo@debian.org>  Tue, 05 Apr 2011 09:40:28 +0200
 +
 +apt (0.8.13.1) unstable; urgency=low
 +
 +  * apt-pkg/acquire-item.cc: Use stat buffer if stat was
 +    successful, not if it failed (Closes: #620546)
 +
 + -- Julian Andres Klode <jak@debian.org>  Sat, 02 Apr 2011 20:55:35 +0200
  
  apt (0.8.13) unstable; urgency=low
  
diff --combined debian/rules
index 0544b2b8e1c92cdea83e2715c28c7ed2c61a929d,c83796e03f327f53082ca18a30ca8a8de72f7cb6..6c58d82bb191d394766502c9b54e7313a0ab19e3
@@@ -62,7 -62,7 +62,7 @@@ configure.in
  endif
  
  # APT Programs in apt-utils
- APT_UTILS=ftparchive sortpkgs extracttemplates
+ APT_UTILS=ftparchive sortpkgs extracttemplates internal-solver
  
  # Uncomment this to turn on verbose mode.
  #export DH_VERBOSE=1
@@@ -120,9 -120,6 +120,9 @@@ libapt-pkg-doc: build-do
  #
  # libapt-pkg-doc install
  #
 +      # remove doxygen's embedded jquery as we don't use it anyway (#622147)
 +      rm -f $(BLD)/doc/doxygen/html/jquery.js
 +
        dh_installdocs -p$@ $(BLD)/docs/design* \
                            $(BLD)/docs/dpkg-tech* \
                            $(BLD)/docs/files* \
@@@ -185,7 -182,7 +185,7 @@@ apt: build build-do
        dh_install -p$@ --sourcedir=$(BLD)
  
        # Remove the bits that are in apt-utils
-       rm $(addprefix debian/$@/usr/bin/apt-,$(APT_UTILS))
+       rm $(addprefix debian/$@/usr/bin/apt-,$(APT_UTILS) dump-solver)
  
        # https has its own package
        rm debian/$@/usr/lib/apt/methods/https
@@@ -239,8 -236,10 +239,10 @@@ apt-utils: buil
        dh_installdirs -p$@
  
        cp $(addprefix $(BLD)/bin/apt-,$(APT_UTILS)) debian/$@/usr/bin/
+       cp $(BLD)/bin/apt-dump-solver debian/$@/usr/lib/apt/solvers/dump
  
        dh_install -p$@ --sourcedir=$(BLD)
+       dh_link -p$@
        dh_installdocs -p$@
        dh_installexamples -p$@