X-Git-Url: https://git.hcoop.net/ntk/apt.git/blobdiff_plain/d59725349555939d39af81cf7746069d6aa3536c..6845391844315cde1b95b1c5b6bbe28ee2cdf51b:/apt-pkg/packagemanager.cc diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index cc9ce21c..382ee438 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -13,6 +13,8 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ +#include + #include #include #include @@ -22,21 +24,25 @@ #include #include #include - -#include + +#include #include -#include +#include /*}}}*/ using namespace std; +bool pkgPackageManager::SigINTStop = false; + // PM::PackageManager - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgPackageManager::pkgPackageManager(pkgDepCache *pCache) : Cache(*pCache) +pkgPackageManager::pkgPackageManager(pkgDepCache *pCache) : Cache(*pCache), + List(NULL), Res(Incomplete) { FileNames = new string[Cache.Head().PackageCount]; - List = 0; Debug = _config->FindB("Debug::pkgPackageManager",false); + NoImmConfigure = !_config->FindB("APT::Immediate-Configure",true); + ImmConfigureAll = _config->FindB("APT::Immediate-Configure-All",false); } /*}}}*/ // PM::PackageManager - Destructor /*{{{*/ @@ -57,10 +63,13 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources, if (CreateOrderList() == false) return false; - if (List->OrderUnpack() == false) + bool const ordering = + _config->FindB("PackageManager::UnpackAll",true) ? + List->OrderUnpack() : List->OrderCritical(); + 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(); @@ -77,7 +86,7 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources, // Skip already processed packages if (List->IsNow(Pkg) == false) continue; - + new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache), FileNames[Pkg->ID]); } @@ -96,7 +105,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; @@ -122,7 +131,7 @@ bool pkgPackageManager::FixMissing() /* This adds the immediate flag to the pkg and recursively to the dependendies */ -void pkgPackageManager::ImmediateAdd(PkgIterator I, bool UseInstallVer) +void pkgPackageManager::ImmediateAdd(PkgIterator I, bool UseInstallVer, unsigned const int &Depth) { DepIterator D; @@ -137,15 +146,15 @@ void pkgPackageManager::ImmediateAdd(PkgIterator I, bool UseInstallVer) 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)) { if(Debug) - clog << "ImmediateAdd(): Adding Immediate flag to " << I.Name() << endl; + clog << OutputInDepth(Depth) << "ImmediateAdd(): Adding Immediate flag to " << D.TargetPkg() << " cause of " << D.DepType() << " " << I.Name() << endl; List->Flag(D.TargetPkg(),pkgOrderList::Immediate); - ImmediateAdd(D.TargetPkg(), UseInstallVer); + ImmediateAdd(D.TargetPkg(), UseInstallVer, Depth + 1); } } return; @@ -162,30 +171,32 @@ bool pkgPackageManager::CreateOrderList() delete List; List = new pkgOrderList(&Cache); - - bool NoImmConfigure = !_config->FindB("APT::Immediate-Configure",true); + + 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 || - (I->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important) && - NoImmConfigure == false) + if ((((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential) && + 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 @@ -226,7 +237,7 @@ bool pkgPackageManager::DepAlwaysTrue(DepIterator 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) @@ -237,7 +248,7 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D, continue; // Ignore self conflicts, ignore conflicts from irrelevent versions - if (D.ParentPkg() == Pkg || D.ParentVer() != D.ParentPkg().CurrentVer()) + if (D.IsIgnorable(Pkg) || D.ParentVer() != D.ParentPkg().CurrentVer()) continue; if (Cache.VS().CheckDep(Ver,D->CompareOp,D.TargetVer()) == false) @@ -253,27 +264,41 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D, // 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); if (OList.OrderConfigure() == false) return false; - + + std::string const conf = _config->Find("PackageManager::Configure","all"); + 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); - if (Configure(Pkg) == false) + /* 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 && 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); } @@ -283,108 +308,162 @@ bool pkgPackageManager::ConfigureAll() /*}}}*/ // 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) -{ - pkgOrderList OList(&Cache); - - if (DepAdd(OList,Pkg) == false) - return false; - - if (OList.OrderConfigure() == false) - return false; +/* 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. - // Perform the configuring - for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++) - { - PkgIterator Pkg(Cache,*I); - - if (Configure(Pkg) == false) - return false; - - List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States); + 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 this is true, only check and correct and dependencies 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 Dependencies)"; + clog << endl; } - // Sanity Check - if (List->IsFlag(Pkg,pkgOrderList::Configured) == false) - return _error->Error("Internal error, could not immediate 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; + VerIterator const instVer = Cache[Pkg].InstVerIter(Cache); - // 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. + /* Because of the ordered list, most dependencies 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 dependencies before configuring. */ bool Bad = false; - for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); D.end() == false;) + for (DepIterator D = instVer.DependsList(); + D.end() == false; ) { - if (D->Type != pkgCache::Dep::Depends && D->Type != pkgCache::Dep::PreDepends) - { - D++; - continue; - } + // Compute a single dependency element (glob or) + pkgCache::DepIterator Start; + pkgCache::DepIterator End; + D.GlobOr(Start,End); - // 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 VList = D.AllTargets(); - for (Version **I = VList; *I != 0 && Bad == true; I++) - { + 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 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); - PkgIterator Pkg = Ver.ParentPkg(); + DepPkg = Ver.ParentPkg(); + InstallVer = VerIterator(Cache,Cache[DepPkg].InstallVer); - // See if the current version is ok - if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true && - Pkg.State() == PkgIterator::NeedsNothing) + // 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; - continue; + break; } - // 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) + // 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) { + if (List->IsNow(DepPkg)) { Bad = false; + if (List->IsFlag(Pkg,pkgOrderList::Loop)) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl; + } + else + { + 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 (Bad == true) - { - OList.Flag(Pkg,0,pkgOrderList::Added); - OList.pop_back(); - Depth--; - return false; + + if (Start==End) { + if (Bad && Debug && List->IsFlag(DepPkg,pkgOrderList::Loop) == false) + std::clog << OutputInDepth(Depth) << "Could not satisfy dependencies for " << Pkg.Name() << std::endl; + break; + } else { + Start++; + } } } - Depth--; + 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 (List->IsFlag(Pkg,pkgOrderList::Configured)) + return _error->Error("Internal configure error on '%s'.", Pkg.Name()); + + if (ConfigurePkgs == true && Configure(Pkg) == false) + return false; + + List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States); + + 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)) + { + if (Pkg == P || List->IsFlag(P,pkgOrderList::Configured) == true || + Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer && + (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall)) + continue; + SmartConfigure(P, (Depth +1)); + } + + // Sanity Check + if (List->IsFlag(Pkg,pkgOrderList::Configured) == false) + return _error->Error(_("Could not configure '%s'. "),Pkg.Name()); + return true; } /*}}}*/ @@ -406,7 +485,8 @@ bool pkgPackageManager::EarlyRemove(PkgIterator Pkg) // Essential packages get special treatment bool IsEssential = false; - if ((Pkg->Flags & pkgCache::Flag::Essential) != 0) + if ((Pkg->Flags & pkgCache::Flag::Essential) != 0 || + (Pkg->Flags & pkgCache::Flag::Important) != 0) IsEssential = true; /* Check for packages that are the dependents of essential packages and @@ -414,9 +494,10 @@ bool pkgPackageManager::EarlyRemove(PkgIterator 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) + if ((D.ParentPkg()->Flags & pkgCache::Flag::Essential) != 0 || + (D.ParentPkg()->Flags & pkgCache::Flag::Important) != 0) IsEssential = true; } @@ -446,28 +527,43 @@ bool pkgPackageManager::SmartRemove(PkgIterator Pkg) return true; List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States); + return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge); } /*}}}*/ // 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) { - // Check if it is already unpacked - if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure && - Cache[Pkg].Keep() == true) - { - List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States); - if (List->IsFlag(Pkg,pkgOrderList::Immediate) == true) - if (SmartConfigure(Pkg) == false) - return _error->Error("Internal Error, Could not perform immediate configuration (1) on %s",Pkg.Name()); - return true; + return SmartUnPack(Pkg, true, 0); +} +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; } - /* See if this packages install version has any predependencies - that are not met by 'now' packages. */ - for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); + VerIterator const instVer = Cache[Pkg].InstVerIter(Cache); + + /* 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; ) { // Compute a single dependency element (glob or) @@ -477,6 +573,9 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) while (End->Type == pkgCache::Dep::PreDepends) { + if (Debug) + clog << OutputInDepth(Depth) << "PreDepends order for " << Pkg.Name() << std::endl; + // Look for possible ok targets. SPtrArray VList = Start.AllTargets(); bool Bad = true; @@ -490,6 +589,8 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) Pkg.State() == PkgIterator::NeedsNothing) { Bad = false; + if (Debug) + clog << OutputInDepth(Depth) << "Found ok package " << Pkg.Name() << endl; continue; } } @@ -504,9 +605,25 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) if (Cache[Pkg].InstallVer != *I || (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)) continue; + + if (List->IsFlag(Pkg,pkgOrderList::Configured)) { + Bad = false; + continue; + } - Bad = !SmartConfigure(Pkg); - } + // check if it needs unpack or if if configure is enough + if (!List->IsFlag(Pkg,pkgOrderList::UnPacked)) + { + if (Debug) + clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << Pkg.Name() << endl; + // SmartUnpack with the ImmediateFlag to ensure its really ready + Bad = !SmartUnPack(Pkg, true, Depth + 1); + } else { + 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 next or element until a matching element is found */ @@ -517,9 +634,9 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) 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; } @@ -532,36 +649,174 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) 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 (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 VList = End.AllTargets(); + for (Version **I = VList; *I != 0; I++) + { + VerIterator Ver(Cache,*I); + PkgIterator BrokenPkg = Ver.ParentPkg(); + if (BrokenPkg.CurrentVer() != Ver) { - if (EarlyRemove(Pkg) == false) - return _error->Error("Internal Error, Could not early remove %s",Pkg.Name()); + if (Debug) + std::clog << OutputInDepth(Depth) << " Ignore not-installed version " << Ver.VerStr() << " of " << Pkg.FullName() << " for " << End << std::endl; + continue; + } + + // 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 { + // Found a break, so see if we can unpack the package to avoid it + // but do not set loop if another SmartUnPack already deals with it + VerIterator InstallVer(Cache,Cache[BrokenPkg].InstallVer); + bool circle = false; + for (pkgCache::DepIterator D = InstallVer.DependsList(); D.end() == false; ++D) + { + if (D->Type != pkgCache::Dep::PreDepends) + continue; + SPtrArray VL = D.AllTargets(); + for (Version **I = VL; *I != 0; ++I) + { + VerIterator V(Cache,*I); + PkgIterator P = V.ParentPkg(); + // we are checking for installation as an easy 'protection' against or-groups and (unchosen) providers + if (P->CurrentVer == 0 || P != Pkg || (P.CurrentVer() != V && Cache[P].InstallVer != V)) + continue; + circle = true; + break; + } + if (circle == true) + break; + } + if (circle == true) + { + if (Debug) + cout << OutputInDepth(Depth) << " Avoiding " << End << " avoided as " << BrokenPkg.FullName() << " has a pre-depends on " << Pkg.FullName() << std::endl; + continue; + } + else + { + if (Debug) + { + cout << OutputInDepth(Depth) << " Unpacking " << BrokenPkg.FullName() << " to avoid " << End; + if (PkgLoop == true) + cout << " (Looping)"; + cout << std::endl; + } + if (PkgLoop == false) + List->Flag(Pkg,pkgOrderList::Loop); + SmartUnPack(BrokenPkg, false, Depth + 1); + if (PkgLoop == false) + List->RmFlag(Pkg,pkgOrderList::Loop); + } + } + } else { + // 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 " << End << endl; + SmartRemove(BrokenPkg); + } } } } } - + // Check for reverse conflicts. if (CheckRConflicts(Pkg,Pkg.RevDependsList(), - Cache[Pkg].InstVerIter(Cache).VerStr()) == false) - return false; - - for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList(); - P.end() == false; P++) - CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion()); - - if (Install(Pkg,FileNames[Pkg->ID]) == false) - return false; + instVer.VerStr()) == false) + return false; + for (PrvIterator P = instVer.ProvidesList(); + P.end() == false; ++P) + if (Pkg->Group != P.OwnerPkg()->Group) + CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion()); + + if (PkgLoop) + return true; + List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States); - - // Perform immedate configuration of the package. - if (List->IsFlag(Pkg,pkgOrderList::Immediate) == true) - if (SmartConfigure(Pkg) == false) - return _error->Error("Internal Error, Could not perform immediate configuration (2) on %s",Pkg.Name()); + + if (Immediate == true && (instVer->MultiArch & pkgCache::Version::Same) == 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, 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)) + { + 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, Depth + 1) == false) + return false; + } + } + // packages which are already unpacked don't need to be unpacked again + else if (Pkg.State() != pkgCache::PkgIterator::NeedsConfigure && Install(Pkg,FileNames[Pkg->ID]) == false) + return false; + + 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; } @@ -577,9 +832,12 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() Reset(); if (Debug == true) - clog << "Begining to order" << endl; + clog << "Beginning to order" << endl; - if (List->OrderUnpack(FileNames) == false) + bool const ordering = + _config->FindB("PackageManager::UnpackAll",true) ? + List->OrderUnpack(FileNames) : List->OrderCritical(); + if (ordering == false) { _error->Error("Internal ordering error"); return Failed; @@ -589,15 +847,22 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() 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) @@ -628,17 +893,24 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() 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 if (ConfigureAll() == false) 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) { @@ -646,7 +918,7 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() PkgIterator(Cache,*I).Name()); return Failed; } - } + } return Completed; } @@ -678,4 +950,4 @@ pkgPackageManager::OrderResult pkgPackageManager::DoInstall(int statusFd) return DoInstallPostFork(statusFd); } - /*}}}*/ + /*}}}*/