/* vim: set sw=4 sts=4 et foldmethod=syntax : *//* * Copyright (c) 2005, 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org> * * This file is part of the Paludis package manager. Paludis is free software; * you can redistribute it and/or modify it under the terms of the GNU General * Public License version 2, as published by the Free Software Foundation. * * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */#include<paludis/dep_atom.hh>#include<paludis/dep_atom_flattener.hh>#include<paludis/dep_list/dep_list.hh>#include<paludis/dep_list/exceptions.hh>#include<paludis/match_package.hh>#include<paludis/hashed_containers.hh>#include<paludis/util/collection_concrete.hh>#include<paludis/util/iterator.hh>#include<paludis/util/join.hh>#include<paludis/util/log.hh>#include<paludis/util/save.hh>#include<paludis/util/stringify.hh>#include<paludis/util/tokeniser.hh>#include<algorithm>#include<functional>#include<vector>#include<set>usingnamespacepaludis;#include<paludis/dep_list/dep_list-sr.cc>DepListOptions::DepListOptions():reinstall(dl_reinstall_never),reinstall_scm(dl_reinstall_scm_never),target_type(dl_target_package),upgrade(dl_upgrade_always),downgrade(dl_downgrade_as_needed),new_slots(dl_new_slots_always),fall_back(dl_fall_back_as_needed_except_targets),installed_deps_pre(dl_deps_discard),installed_deps_runtime(dl_deps_try_post),installed_deps_post(dl_deps_try_post),uninstalled_deps_pre(dl_deps_pre),uninstalled_deps_runtime(dl_deps_pre_or_post),uninstalled_deps_post(dl_deps_post),uninstalled_deps_suggested(dl_deps_try_post),suggested(dl_suggested_show),circular(dl_circular_error),use(dl_use_deps_standard),blocks(dl_blocks_accumulate),dependency_tags(false){/* when changing the above, also see src/paludis/command_line.cc. */}namespacepaludis{typedefstd::list<DepListEntry>MergeList;typedefMakeHashedMultiMap<QualifiedPackageName,MergeList::iterator>::TypeMergeListIndex;template<>structImplementation<DepList>:InternalCounted<Implementation<DepList>>{constEnvironment*constenv;CountedPtr<DepListOptions,count_policy::ExternalCountTag>opts;MergeListmerge_list;MergeList::const_iteratorcurrent_merge_list_entry;MergeList::iteratormerge_list_insert_position;longmerge_list_generation;MergeListIndexmerge_list_index;DepAtom::ConstPointercurrent_top_level_target;boolthrow_on_blocker;constPackageDatabaseEntry*current_pde()const{if(current_merge_list_entry!=merge_list.end())return&current_merge_list_entry->package;return0;}Implementation(constEnvironment*conste,constDepListOptions&o):env(e),opts(newDepListOptions(o)),current_merge_list_entry(merge_list.end()),merge_list_insert_position(merge_list.end()),merge_list_generation(0),current_top_level_target(0),throw_on_blocker(o.blocks==dl_blocks_error){}};}namespace{structGenerationGreaterThan{longg;GenerationGreaterThan(longgg):g(gg){}template<typenameT_>booloperator()(constT_&e)const{returne.generation>g;}};structRemoveTagsWithGenerationGreaterThan{longg;RemoveTagsWithGenerationGreaterThan(longgg):g(gg){}voidoperator()(DepListEntry&e)const{/* see EffSTL 9 for why this is so painful */if(e.tags->empty())return;DepListEntryTags::Pointert(newDepListEntryTags::Concrete);GenerationGreaterThanpred(g);for(DepListEntryTags::Iteratori(e.tags->begin()),i_end(e.tags->end());i!=i_end;++i)if(!pred(*i))t->insert(*i);std::swap(e.tags,t);}};classDepListTransaction{protected:MergeList&_list;MergeListIndex&_index;long&_generation;int_initial_generation;bool_committed;public:DepListTransaction(MergeList&l,MergeListIndex&i,long&g):_list(l),_index(i),_generation(g),_initial_generation(g),_committed(false){++_generation;}voidcommit(){_committed=true;}~DepListTransaction(){if(_committed)return;/* See EffSTL 9 */GenerationGreaterThanpred(_initial_generation);for(MergeList::iteratori(_list.begin());i!=_list.end();){if(!pred(*i))++i;else{for(std::pair<MergeListIndex::iterator,MergeListIndex::iterator>p(_index.equal_range(i->package.name));p.first!=p.second;)if(p.first->second==i)_index.erase(p.first++);else++p.first;_list.erase(i++);}}std::for_each(_list.begin(),_list.end(),RemoveTagsWithGenerationGreaterThan(_initial_generation));}};structMatchDepListEntryAgainstPackageDepAtom{constEnvironment*constenv;constPackageDepAtom*consta;MatchDepListEntryAgainstPackageDepAtom(constEnvironment*constee,constPackageDepAtom*constaa):env(ee),a(aa){}booloperator()(conststd::pair<constQualifiedPackageName,MergeList::const_iterator>&e){switch(e.second->kind){casedlk_virtual:casedlk_package:casedlk_provided:casedlk_already_installed:casedlk_subpackage:returnmatch_package(env,a,e.second->package);casedlk_block:casedlk_masked:casedlk_suggested:returnfalse;caselast_dlk:;}throwInternalError(PALUDIS_HERE,"Bad e.second->kind");}};structIsViableAnyDepAtomChild{constEnvironment*constenv;constPackageDatabaseEntry*constpde;IsViableAnyDepAtomChild(constEnvironment*conste,constPackageDatabaseEntry*constp):env(e),pde(p){}booloperator()(PackageDepAtom::ConstPointeratom){constUseDepAtom*constu(atom->as_use_dep_atom());if(0!=u)returnenv->query_use(u->flag(),pde)^u->inverse();elsereturntrue;}};structIsInterestingPDADepAtomChild{constEnvironment*constenv;IsInterestingPDADepAtomChild(constEnvironment*conste):env(e){}booloperator()(PackageDepAtom::ConstPointeratom){constPackageDepAtom*constu(atom->as_package_dep_atom());if(0!=u){return!env->package_database()->query(PackageDepAtom(u->package()),is_installed_only,qo_whatever)->empty();}elsereturnfalse;}};}structDepList::QueryVisitor:DepAtomVisitorTypes::ConstVisitor{boolresult;constDepList*constd;QueryVisitor(constDepList*constdd):result(true),d(dd){}voidvisit(constPlainTextDepAtom*const)PALUDIS_ATTRIBUTE((noreturn));voidvisit(constPackageDepAtom*const);voidvisit(constUseDepAtom*const);voidvisit(constAnyDepAtom*const);voidvisit(constBlockDepAtom*const);voidvisit(constAllDepAtom*const);};voidDepList::QueryVisitor::visit(constPlainTextDepAtom*const){throwInternalError(PALUDIS_HERE,"Got PlainTextDepAtom?");}voidDepList::QueryVisitor::visit(constPackageDepAtom*consta){/* a pda matches either if we're already installed, or if we will be installed * by the time the current point in the dep list is reached. */if(!d->_imp->env->package_database()->query(*a,is_installed_only,qo_whatever)->empty())result=true;else{std::pair<MergeListIndex::const_iterator,MergeListIndex::const_iterator>p(d->_imp->merge_list_index.equal_range(a->package()));if(p.second!=std::find_if(p.first,p.second,MatchDepListEntryAgainstPackageDepAtom(d->_imp->env,a)))result=true;elseresult=false;}}voidDepList::QueryVisitor::visit(constUseDepAtom*consta){/* for use? ( ) dep atoms, return true if we're not enabled, so that * weird || ( ) cases work. */if(d->_imp->env->query_use(a->flag(),d->_imp->current_pde())^a->inverse()){result=true;for(CompositeDepAtom::Iteratorc(a->begin()),c_end(a->end());c!=c_end;++c){(*c)->accept(this);if(!result)return;}}elseresult=true;}voidDepList::QueryVisitor::visit(constAnyDepAtom*consta){/* empty || ( ) must resolve to true */std::list<DepAtom::ConstPointer>viable_children;std::copy(a->begin(),a->end(),filter_inserter(std::back_inserter(viable_children),IsViableAnyDepAtomChild(d->_imp->env,d->_imp->current_pde())));result=true;for(std::list<DepAtom::ConstPointer>::const_iteratorc(viable_children.begin()),c_end(viable_children.end());c!=c_end;++c){(*c)->accept(this);if(result)return;}}voidDepList::QueryVisitor::visit(constBlockDepAtom*consta){a->blocked_atom()->accept(this);result=!result;}voidDepList::QueryVisitor::visit(constAllDepAtom*consta){for(CompositeDepAtom::Iteratorc(a->begin()),c_end(a->end());c!=c_end;++c){(*c)->accept(this);if(!result)return;}}structDepList::AddVisitor:DepAtomVisitorTypes::ConstVisitor,DepAtomVisitorTypes::ConstVisitor::VisitChildren<AddVisitor,AllDepAtom>{DepList*constd;AddVisitor(DepList*constdd):d(dd){}voidvisit(constPlainTextDepAtom*const)PALUDIS_ATTRIBUTE((noreturn));voidvisit(constPackageDepAtom*const);voidvisit(constUseDepAtom*const);voidvisit(constAnyDepAtom*const);voidvisit(constBlockDepAtom*const);usingDepAtomVisitorTypes::ConstVisitor::VisitChildren<AddVisitor,AllDepAtom>::visit;};voidDepList::AddVisitor::visit(constPlainTextDepAtom*const){throwInternalError(PALUDIS_HERE,"Got PlainTextDepAtom?");}voidDepList::AddVisitor::visit(constPackageDepAtom*consta){Contextcontext("When adding PackageDepAtom '"+stringify(*a)+"':");/* find already installed things */PackageDatabaseEntryCollection::ConstPointeralready_installed(d->_imp->env->package_database()->query(*a,is_installed_only,qo_order_by_version));/* are we already on the merge list? */std::pair<MergeListIndex::iterator,MergeListIndex::iterator>q(d->_imp->merge_list_index.equal_range(a->package()));MergeListIndex::iteratorqq(std::find_if(q.first,q.second,MatchDepListEntryAgainstPackageDepAtom(d->_imp->env,a)));MergeList::iteratorexisting_merge_list_entry(qq==q.second?d->_imp->merge_list.end():qq->second);if(existing_merge_list_entry!=d->_imp->merge_list.end()){/* tag it */if(a->tag())existing_merge_list_entry->tags->insert(DepTagEntry::create().tag(a->tag()).generation(d->_imp->merge_list_generation));if(d->_imp->opts->dependency_tags&&d->_imp->current_pde())existing_merge_list_entry->tags->insert(DepTagEntry::create().tag(DepTag::Pointer(newDependencyDepTag(*d->_imp->current_pde()))).generation(d->_imp->merge_list_generation));/* have our deps been merged already, or is this a circular dep? */if(dle_no_deps==existing_merge_list_entry->state){/* is a sufficiently good version installed? */if(!already_installed->empty())return;if(d->_imp->opts->circular==dl_circular_discard){Log::get_instance()->message(ll_qa,lc_context,"Dropping circular dependency on '"+stringify(existing_merge_list_entry->package)+"'");return;}elseif(d->_imp->opts->circular==dl_circular_discard_silently)return;throwCircularDependencyError("Atom '"+stringify(*a)+"' matched by merge list entry '"+stringify(existing_merge_list_entry->package)+"', which does not yet have its ""dependencies installed");}elsereturn;}/* find installable candidates, and find the best visible candidate */constPackageDatabaseEntry*best_visible_candidate(0);PackageDatabaseEntryCollection::ConstPointerinstallable_candidates(d->_imp->env->package_database()->query(*a,is_installable_only,qo_order_by_version));for(PackageDatabaseEntryCollection::ReverseIteratorp(installable_candidates->rbegin()),p_end(installable_candidates->rend());p!=p_end;++p)if(!d->_imp->env->mask_reasons(*p).any()){best_visible_candidate=&*p;break;}/* are we allowed to override mask reasons? */if(!best_visible_candidate&&d->_imp->opts->override_masks.any()){DepListOverrideMasknext(static_cast<DepListOverrideMask>(0));DepListOverrideMasksmasks_to_override;do{while(next!=last_dl_override){if(masks_to_override.test(next))next=static_cast<DepListOverrideMask>(static_cast<int>(next)+1);elseif(d->_imp->opts->override_masks.test(next)){masks_to_override.set(next);break;}elsenext=static_cast<DepListOverrideMask>(static_cast<int>(next)+1);}if(next==last_dl_override)break;MaskReasonsmask_mask;if(masks_to_override.test(dl_override_repository_masks))mask_mask.set(mr_repository_mask);if(masks_to_override.test(dl_override_profile_masks))mask_mask.set(mr_profile_mask);if(masks_to_override.test(dl_override_licenses))mask_mask.set(mr_license);mask_mask.set(mr_by_association);mask_mask.flip();booloverride_tilde_keywords(masks_to_override.test(dl_override_tilde_keywords));booloverride_unkeyworded(masks_to_override.test(dl_override_unkeyworded));for(PackageDatabaseEntryCollection::ReverseIteratorp(installable_candidates->rbegin()),p_end(installable_candidates->rend());p!=p_end;++p){if(!(d->_imp->env->mask_reasons(*p,override_tilde_keywords,override_unkeyworded)&mask_mask).any()){d->add_error_package(*p,dlk_masked);best_visible_candidate=&*p;break;}}}while(!best_visible_candidate);}/* no installable candidates. if we're already installed, that's ok (except for top level * package targets), otherwise error. */if(!best_visible_candidate){boolcan_fall_back;do{switch(d->_imp->opts->fall_back){casedl_fall_back_never:can_fall_back=false;continue;casedl_fall_back_as_needed_except_targets:if(!d->_imp->current_pde())can_fall_back=false;elseif(already_installed->empty())can_fall_back=true;elsecan_fall_back=!d->is_top_level_target(*already_installed->last());continue;casedl_fall_back_as_needed:can_fall_back=true;continue;caselast_dl_fall_back:;}throwInternalError(PALUDIS_HERE,"Bad fall_back value '"+stringify(d->_imp->opts->fall_back)+"'");}while(false);if(already_installed->empty()||!can_fall_back){if(!a->use_requirements_ptr())throwAllMaskedError(stringify(*a));PackageDatabaseEntryCollection::ConstPointermatch_except_reqs(d->_imp->env->package_database()->query(*a->without_use_requirements(),is_any,qo_whatever));for(PackageDatabaseEntryCollection::Iteratori(match_except_reqs->begin()),i_end(match_except_reqs->end());i!=i_end;++i)if(!(d->_imp->env->mask_reasons(*i).any()))throwUseRequirementsNotMetError(stringify(*a));throwAllMaskedError(stringify(*a));}else{Log::get_instance()->message(ll_warning,lc_context,"No visible packages matching '"+stringify(*a)+"', falling back to installed package '"+stringify(*already_installed->last())+"'");d->add_already_installed_package(*already_installed->last(),a->tag());return;}}SlotNameslot(d->_imp->env->package_database()->fetch_repository(best_visible_candidate->repository)->version_metadata(best_visible_candidate->name,best_visible_candidate->version)->slot);PackageDatabaseEntryCollection::Pointeralready_installed_in_same_slot(newPackageDatabaseEntryCollection::Concrete);for(PackageDatabaseEntryCollection::Iteratoraa(already_installed->begin()),aa_end(already_installed->end());aa!=aa_end;++aa)if(d->_imp->env->package_database()->fetch_repository(aa->repository)->version_metadata(aa->name,aa->version)->slot==slot)already_installed_in_same_slot->push_back(*aa);/* no need to sort already_installed_in_same_slot here, although if the above is * changed then check that this still holds... *//* we have an already installed version. do we want to use it? */if(!already_installed_in_same_slot->empty()){if(d->prefer_installed_over_uninstalled(*already_installed_in_same_slot->last(),*best_visible_candidate)){Log::get_instance()->message(ll_debug,lc_context,"Taking installed package '"+stringify(*already_installed_in_same_slot->last())+"' over '"+stringify(*best_visible_candidate)+"'");d->add_already_installed_package(*already_installed_in_same_slot->last(),a->tag());return;}elseLog::get_instance()->message(ll_debug,lc_context,"Not taking installed package '"+stringify(*already_installed_in_same_slot->last())+"' over '"+stringify(*best_visible_candidate)+"'");}elseif((!already_installed->empty())&&(dl_new_slots_as_needed==d->_imp->opts->new_slots)){/* we have an already installed, but not in the same slot, and our options * allow us to take this. */if(d->prefer_installed_over_uninstalled(*already_installed->last(),*best_visible_candidate)){Log::get_instance()->message(ll_debug,lc_context,"Taking installed package '"+stringify(*already_installed->last())+"' over '"+stringify(*best_visible_candidate)+"' (in different slot)");d->add_already_installed_package(*already_installed->last(),a->tag());return;}elseLog::get_instance()->message(ll_debug,lc_context,"Not taking installed package '"+stringify(*already_installed->last())+"' over '"+stringify(*best_visible_candidate)+"' (in different slot)");}elseLog::get_instance()->message(ll_debug,lc_context,"No installed packages in SLOT '"+stringify(slot)+"', taking uninstalled package '"+stringify(*best_visible_candidate)+"'");/* if this is a downgrade, make sure that that's ok */switch(d->_imp->opts->downgrade){casedl_downgrade_as_needed:break;casedl_downgrade_error:casedl_downgrade_warning:{PackageDatabaseEntryCollection::Pointerare_we_downgrading(d->_imp->env->package_database()->query(PackageDepAtom(stringify(a->package())+":"+stringify(slot)),is_installed_only,qo_order_by_version));if(are_we_downgrading->empty())break;if(are_we_downgrading->last()->version<=best_visible_candidate->version)break;if(d->_imp->opts->downgrade==dl_downgrade_error)throwDowngradeNotAllowedError(stringify(*best_visible_candidate),stringify(*are_we_downgrading->last()));Log::get_instance()->message(ll_warning,lc_context,"Downgrade to '"+stringify(*best_visible_candidate)+"' from '"+stringify(*are_we_downgrading->last())+"' forced");}break;caselast_dl_downgrade:;}d->add_package(*best_visible_candidate,a->tag());}voidDepList::AddVisitor::visit(constUseDepAtom*consta){if(d->_imp->opts->use==dl_use_deps_standard){if(d->_imp->env->query_use(a->flag(),d->_imp->current_pde())^a->inverse())std::for_each(a->begin(),a->end(),accept_visitor(this));}else{RepositoryUseInterface*u;if((!d->_imp->current_pde())||(!((u=d->_imp->env->package_database()->fetch_repository(d->_imp->current_pde()->repository)->use_interface))))std::for_each(a->begin(),a->end(),accept_visitor(this));elseif(a->inverse()){if(!u->query_use_force(a->flag(),d->_imp->current_pde()))std::for_each(a->begin(),a->end(),accept_visitor(this));}else{if(!u->query_use_mask(a->flag(),d->_imp->current_pde()))std::for_each(a->begin(),a->end(),accept_visitor(this));}}}voidDepList::AddVisitor::visit(constAnyDepAtom*consta){/* annoying requirement: || ( foo? ( ... ) ) resolves to empty if !foo. */std::list<DepAtom::ConstPointer>viable_children;std::copy(a->begin(),a->end(),filter_inserter(std::back_inserter(viable_children),IsViableAnyDepAtomChild(d->_imp->env,d->_imp->current_pde())));if(viable_children.empty())return;/* see if any of our children is already installed. if any is, add it so that * any upgrades kick in */for(std::list<DepAtom::ConstPointer>::const_iteratorc(viable_children.begin()),c_end(viable_children.end());c!=c_end;++c){if(d->already_installed(*c)){d->add(*c);return;}}/* if we have something like || ( a >=b-2 ) and b-1 is installed, try to go for * the b-2 bit first */std::list<DepAtom::ConstPointer>pda_children;std::copy(viable_children.begin(),viable_children.end(),filter_inserter(std::back_inserter(pda_children),IsInterestingPDADepAtomChild(d->_imp->env)));for(std::list<DepAtom::ConstPointer>::const_iteratorc(pda_children.begin()),c_end(pda_children.end());c!=c_end;++c){try{Save<bool>save_t(&d->_imp->throw_on_blocker,true);Save<DepListOverrideMasks>save_o(&d->_imp->opts->override_masks,DepListOverrideMasks());d->add(*c);return;}catch(constDepListError&){}}/* install first available viable option */for(std::list<DepAtom::ConstPointer>::const_iteratorc(viable_children.begin()),c_end(viable_children.end());c!=c_end;++c){try{Save<bool>save_t(&d->_imp->throw_on_blocker,true);Save<DepListOverrideMasks>save_o(&d->_imp->opts->override_masks,DepListOverrideMasks());d->add(*c);return;}catch(constDepListError&){}}Log::get_instance()->message(ll_debug,lc_context,"No resolvable item in || ( ) block. Using ""first item for error message");{Contextblock_context("Inside || ( ) block with other options:");d->add(*viable_children.begin());}}voidDepList::AddVisitor::visit(constBlockDepAtom*consta){if(!d->already_installed(a->blocked_atom()))return;Contextcontext("When checking BlockDepAtom '!"+stringify(*a->blocked_atom())+"':");/* special case: the provider of virtual/blah can DEPEND upon !virtual/blah. *//* special case: foo/bar can DEPEND upon !foo/bar. */if(d->_imp->current_pde()){if(d->_imp->current_pde()->name==a->blocked_atom()->package()){Log::get_instance()->message(ll_debug,lc_context,"Ignoring self block '"+stringify(*a->blocked_atom())+"' for package '"+stringify(*d->_imp->current_pde())+"'");return;}VersionMetadata::ConstPointermetadata(d->_imp->env->package_database()->fetch_repository(d->_imp->current_pde()->repository)->version_metadata(d->_imp->current_pde()->name,d->_imp->current_pde()->version));if(metadata->get_ebuild_interface()){boolskip(false);DepAtomFlattenerf(d->_imp->env,d->_imp->current_pde(),metadata->get_ebuild_interface()->provide());for(DepAtomFlattener::Iteratori(f.begin()),i_end(f.end());i!=i_end&&!skip;++i)if((*i)->text()==stringify(a->blocked_atom()->package()))skip=true;if(skip){Log::get_instance()->message(ll_debug,lc_context,"Ignoring self block (via PROVIDE) '"+stringify(*a->blocked_atom())+"' for package '"+stringify(*d->_imp->current_pde())+"'");return;}}}switch(d->_imp->opts->blocks){casedl_blocks_error:throwBlockError(stringify(*a->blocked_atom()));casedl_blocks_accumulate:if(d->_imp->throw_on_blocker)throwBlockError(stringify(*a->blocked_atom()));else{PackageDatabaseEntryCollection::ConstPointerm(d->_imp->env->package_database()->query(*a->blocked_atom(),is_installed_only,qo_order_by_version));if(m->empty()){/* this happens if we match an already on the list package, so always * throw */throwBlockError(stringify(*a->blocked_atom()));}elsefor(PackageDatabaseEntryCollection::Iteratorp(m->begin()),p_end(m->end());p!=p_end;++p)d->add_error_package(*p,dlk_block);}break;casedl_blocks_discard:Log::get_instance()->message(ll_warning,lc_context,"Discarding block '!"+stringify(*a->blocked_atom())+"'");break;caselast_dl_blocks:;}}structDepList::ShowSuggestVisitor:DepAtomVisitorTypes::ConstVisitor,DepAtomVisitorTypes::ConstVisitor::VisitChildren<ShowSuggestVisitor,AllDepAtom>,DepAtomVisitorTypes::ConstVisitor::VisitChildren<ShowSuggestVisitor,AnyDepAtom>{DepList*constd;ShowSuggestVisitor(DepList*constdd):d(dd){}voidvisit(constPlainTextDepAtom*const)PALUDIS_ATTRIBUTE((noreturn));voidvisit(constPackageDepAtom*const);voidvisit(constUseDepAtom*const);voidvisit(constBlockDepAtom*const);usingDepAtomVisitorTypes::ConstVisitor::VisitChildren<ShowSuggestVisitor,AllDepAtom>::visit;usingDepAtomVisitorTypes::ConstVisitor::VisitChildren<ShowSuggestVisitor,AnyDepAtom>::visit;};voidDepList::ShowSuggestVisitor::visit(constPlainTextDepAtom*const){throwInternalError(PALUDIS_HERE,"Got PlainTextDepAtom?");}voidDepList::ShowSuggestVisitor::visit(constUseDepAtom*consta){if(d->_imp->env->query_use(a->flag(),d->_imp->current_pde())^a->inverse())std::for_each(a->begin(),a->end(),accept_visitor(this));}voidDepList::ShowSuggestVisitor::visit(constBlockDepAtom*const){}voidDepList::ShowSuggestVisitor::visit(constPackageDepAtom*consta){Contextcontext("When adding suggested dep '"+stringify(*a)+"':");PackageDatabaseEntryCollection::ConstPointermatches(d->_imp->env->package_database()->query(*a,is_installable_only,qo_order_by_version));if(matches->empty()){Log::get_instance()->message(ll_warning,lc_context,"Nothing found for '"+stringify(*a)+"'");return;}for(PackageDatabaseEntryCollection::Iteratorm(matches->begin()),m_end(matches->end());m!=m_end;++m){if(d->_imp->env->mask_reasons(*m).any())continue;d->add_suggested_package(*m);return;}Log::get_instance()->message(ll_warning,lc_context,"Nothing visible found for '"+stringify(*a)+"'");}DepList::DepList(constEnvironment*conste,constDepListOptions&o):PrivateImplementationPattern<DepList>(newImplementation<DepList>(e,o)){}DepList::~DepList(){}CountedPtr<DepListOptions,count_policy::ExternalCountTag>DepList::options(){return_imp->opts;}voidDepList::clear(){DepListOptionso(*options());_imp.assign(newImplementation<DepList>(_imp->env,o));}voidDepList::add_in_role(DepAtom::ConstPointeratom,conststd::string&role){Contextcontext("When adding "+role+":");add(atom);}voidDepList::add(DepAtom::ConstPointeratom){DepListTransactiontransaction(_imp->merge_list,_imp->merge_list_index,_imp->merge_list_generation);Save<DepAtom::ConstPointer>save_current_top_level_target(&_imp->current_top_level_target,_imp->current_top_level_target?_imp->current_top_level_target:atom);AddVisitorvisitor(this);atom->accept(&visitor);transaction.commit();}voidDepList::add_package(constPackageDatabaseEntry&p,DepTag::ConstPointertag){Contextcontext("When adding package '"+stringify(p)+"':");Save<MergeList::iterator>save_merge_list_insert_position(&_imp->merge_list_insert_position);VersionMetadata::ConstPointermetadata(_imp->env->package_database()->fetch_repository(p.repository)->version_metadata(p.name,p.version));/* create our merge list entry. insert pre deps before ourself in the list. insert * post deps after ourself, and after any provides. */MergeList::iteratorour_merge_entry_position(_imp->merge_list.insert(_imp->merge_list_insert_position,DepListEntry::create().package(p).metadata(metadata).generation(_imp->merge_list_generation).state(dle_no_deps).tags(DepListEntryTags::Pointer(newDepListEntryTags::Concrete)).destinations(RepositoryNameCollection::Pointer(newRepositoryNameCollection::Concrete)).kind(metadata->get_virtual_interface()?dlk_virtual:dlk_package))),our_merge_entry_post_position(our_merge_entry_position);_imp->merge_list_index.insert(std::make_pair(p.name,our_merge_entry_position));if(tag)our_merge_entry_position->tags->insert(DepTagEntry::create().generation(_imp->merge_list_generation).tag(tag));if(_imp->opts->dependency_tags&&_imp->current_pde())our_merge_entry_position->tags->insert(DepTagEntry::create().tag(DepTag::Pointer(newDependencyDepTag(*_imp->current_pde()))).generation(_imp->merge_list_generation));Save<MergeList::const_iterator>save_current_merge_list_entry(&_imp->current_merge_list_entry,our_merge_entry_position);_imp->merge_list_insert_position=our_merge_entry_position;/* add provides */if(metadata->get_ebuild_interface()){DepAtomFlattenerf(_imp->env,_imp->current_pde(),metadata->get_ebuild_interface()->provide());for(DepAtomFlattener::Iteratori(f.begin()),i_end(f.end());i!=i_end;++i){PackageDepAtom::Pointerpp(newPackageDepAtom("="+(*i)->text()+"-"+stringify(p.version)));std::pair<MergeListIndex::iterator,MergeListIndex::iterator>z(_imp->merge_list_index.equal_range(pp->package()));MergeListIndex::iteratorzz(std::find_if(z.first,z.second,MatchDepListEntryAgainstPackageDepAtom(_imp->env,pp.raw_pointer())));if(z.first!=z.second)continue;VersionMetadata::ConstPointerm(0);if(_imp->env->package_database()->fetch_repository(RepositoryName("virtuals"))->has_version(QualifiedPackageName((*i)->text()),p.version))m=_imp->env->package_database()->fetch_repository(RepositoryName("virtuals"))->version_metadata(QualifiedPackageName((*i)->text()),p.version);else{VersionMetadata::Pointermm(0);mm.assign(newVersionMetadata::Virtual(metadata->deps.parser,PackageDatabaseEntry(p.name,p.version,RepositoryName("virtuals"))));mm->slot=metadata->slot;m=mm;}our_merge_entry_post_position=_imp->merge_list.insert(next(our_merge_entry_post_position),DepListEntry(DepListEntry::create().package(PackageDatabaseEntry((*i)->text(),p.version,RepositoryName("virtuals"))).metadata(m).generation(_imp->merge_list_generation).state(dle_has_all_deps).tags(DepListEntryTags::Pointer(newDepListEntryTags::Concrete)).destinations(RepositoryNameCollection::Pointer(newRepositoryNameCollection::Concrete)).kind(dlk_provided)));_imp->merge_list_index.insert(std::make_pair((*i)->text(),our_merge_entry_post_position));}}/* add suggests */if(_imp->opts->suggested==dl_suggested_show){Contextc("When showing suggestions:");Save<MergeList::iterator>suggest_save_merge_list_insert_position(&_imp->merge_list_insert_position,next(our_merge_entry_position));ShowSuggestVisitorvisitor(this);metadata->deps.suggested_depend()->accept(&visitor);}/* add pre dependencies */add_predeps(metadata->deps.build_depend(),_imp->opts->uninstalled_deps_pre,"build");add_predeps(metadata->deps.run_depend(),_imp->opts->uninstalled_deps_runtime,"run");add_predeps(metadata->deps.post_depend(),_imp->opts->uninstalled_deps_post,"post");if(_imp->opts->suggested==dl_suggested_install)add_predeps(metadata->deps.suggested_depend(),_imp->opts->uninstalled_deps_suggested,"suggest");our_merge_entry_position->state=dle_has_pre_deps;_imp->merge_list_insert_position=next(our_merge_entry_post_position);/* add post dependencies */add_postdeps(metadata->deps.build_depend(),_imp->opts->uninstalled_deps_pre,"build");add_postdeps(metadata->deps.run_depend(),_imp->opts->uninstalled_deps_runtime,"run");add_postdeps(metadata->deps.post_depend(),_imp->opts->uninstalled_deps_post,"post");if(_imp->opts->suggested==dl_suggested_install)add_postdeps(metadata->deps.suggested_depend(),_imp->opts->uninstalled_deps_suggested,"suggest");our_merge_entry_position->state=dle_has_all_deps;}voidDepList::add_error_package(constPackageDatabaseEntry&p,constDepListEntryKindkind){std::pair<MergeListIndex::iterator,MergeListIndex::const_iterator>pp(_imp->merge_list_index.equal_range(p.name));for(;pp.first!=pp.second;++pp.first){if(pp.first->second->kind==kind&&pp.first->second->package==p){if(_imp->current_pde())pp.first->second->tags->insert(DepTagEntry::create().tag(DepTag::Pointer(newDependencyDepTag(*_imp->current_pde()))).generation(_imp->merge_list_generation));return;}}MergeList::iteratorour_merge_entry_position(_imp->merge_list.insert(_imp->merge_list.begin(),DepListEntry::create().package(p).metadata(_imp->env->package_database()->fetch_repository(p.repository)->version_metadata(p.name,p.version)).generation(_imp->merge_list_generation).state(dle_has_all_deps).tags(DepListEntryTags::Pointer(newDepListEntryTags::Concrete)).destinations(RepositoryNameCollection::Pointer(newRepositoryNameCollection::Concrete)).kind(kind)));if(_imp->current_pde())our_merge_entry_position->tags->insert(DepTagEntry::create().tag(DepTag::Pointer(newDependencyDepTag(*_imp->current_pde()))).generation(_imp->merge_list_generation));_imp->merge_list_index.insert(std::make_pair(p.name,our_merge_entry_position));}voidDepList::add_suggested_package(constPackageDatabaseEntry&p){std::pair<MergeListIndex::iterator,MergeListIndex::const_iterator>pp(_imp->merge_list_index.equal_range(p.name));for(;pp.first!=pp.second;++pp.first){if((pp.first->second->kind==dlk_suggested||pp.first->second->kind==dlk_already_installed||pp.first->second->kind==dlk_package||pp.first->second->kind==dlk_provided||pp.first->second->kind==dlk_subpackage)&&pp.first->second->package==p)return;}MergeList::iteratorour_merge_entry_position(_imp->merge_list.insert(_imp->merge_list_insert_position,DepListEntry::create().package(p).metadata(_imp->env->package_database()->fetch_repository(p.repository)->version_metadata(p.name,p.version)).generation(_imp->merge_list_generation).state(dle_has_all_deps).tags(DepListEntryTags::Pointer(newDepListEntryTags::Concrete)).destinations(RepositoryNameCollection::Pointer(newRepositoryNameCollection::Concrete)).kind(dlk_suggested)));if(_imp->current_pde())our_merge_entry_position->tags->insert(DepTagEntry::create().tag(DepTag::Pointer(newDependencyDepTag(*_imp->current_pde()))).generation(_imp->merge_list_generation));_imp->merge_list_index.insert(std::make_pair(p.name,our_merge_entry_position));}voidDepList::add_predeps(DepAtom::ConstPointerd,constDepListDepsOptionopt,conststd::string&s){if(dl_deps_pre==opt||dl_deps_pre_or_post==opt){try{add_in_role(d,s+" dependencies as pre dependencies");}catch(constDepListError&e){if(dl_deps_pre==opt)throw;elseLog::get_instance()->message(ll_warning,lc_context,"Dropping "+s+" dependencies to ""post dependencies because of exception '"+e.message()+"' ("+e.what()+")");}}}voidDepList::add_postdeps(DepAtom::ConstPointerd,constDepListDepsOptionopt,conststd::string&s){if(dl_deps_pre_or_post==opt||dl_deps_post==opt||dl_deps_try_post==opt){try{try{add_in_role(d,s+" dependencies as post dependencies");}catch(constCircularDependencyError&){Save<DepListCircularOption>save_circular(&_imp->opts->circular,_imp->opts->circular==dl_circular_discard_silently?dl_circular_discard_silently:dl_circular_discard);Save<MergeList::iterator>save_merge_list_insert_position(&_imp->merge_list_insert_position,_imp->merge_list.end());add_in_role(d,s+" dependencies as post dependencies with cycle breaking");}}catch(constDepListError&e){if(dl_deps_try_post!=opt)throw;elseLog::get_instance()->message(ll_warning,lc_context,"Ignoring "+s+" dependencies due to exception '"+e.message()+"' ("+e.what()+")");}}}voidDepList::add_already_installed_package(constPackageDatabaseEntry&p,DepTag::ConstPointertag){Contextcontext("When adding installed package '"+stringify(p)+"':");Save<MergeList::iterator>save_merge_list_insert_position(&_imp->merge_list_insert_position);VersionMetadata::ConstPointermetadata(_imp->env->package_database()->fetch_repository(p.repository)->version_metadata(p.name,p.version));MergeList::iteratorour_merge_entry(_imp->merge_list.insert(_imp->merge_list_insert_position,DepListEntry::create().package(p).metadata(metadata).generation(_imp->merge_list_generation).tags(DepListEntryTags::Pointer(newDepListEntryTags::Concrete)).state(dle_has_pre_deps).destinations(RepositoryNameCollection::Pointer(newRepositoryNameCollection::Concrete)).kind(dlk_already_installed)));_imp->merge_list_index.insert(std::make_pair(p.name,our_merge_entry));if(tag)our_merge_entry->tags->insert(DepTagEntry::create().generation(_imp->merge_list_generation).tag(tag));if(_imp->opts->dependency_tags&&_imp->current_pde())our_merge_entry->tags->insert(DepTagEntry::create().tag(DepTag::Pointer(newDependencyDepTag(*_imp->current_pde()))).generation(_imp->merge_list_generation));Save<MergeList::const_iterator>save_current_merge_list_entry(&_imp->current_merge_list_entry,our_merge_entry);add_predeps(metadata->deps.build_depend(),_imp->opts->installed_deps_pre,"build");add_predeps(metadata->deps.run_depend(),_imp->opts->installed_deps_runtime,"run");add_predeps(metadata->deps.post_depend(),_imp->opts->installed_deps_post,"post");our_merge_entry->state=dle_has_pre_deps;_imp->merge_list_insert_position=next(our_merge_entry);add_postdeps(metadata->deps.build_depend(),_imp->opts->installed_deps_pre,"build");add_postdeps(metadata->deps.run_depend(),_imp->opts->installed_deps_runtime,"run");add_postdeps(metadata->deps.post_depend(),_imp->opts->installed_deps_post,"post");}namespace{boolis_scm(constQualifiedPackageName&n){std::stringpkg(stringify(n.package));switch(pkg.length()){case0:case1:case2:case3:returnfalse;default:if(0==pkg.compare(pkg.length()-5,5,"-live"))returntrue;case4:if(0==pkg.compare(pkg.length()-4,4,"-cvs"))returntrue;if(0==pkg.compare(pkg.length()-4,4,"-svn"))returntrue;returnfalse;}}}boolDepList::prefer_installed_over_uninstalled(constPackageDatabaseEntry&installed,constPackageDatabaseEntry&uninstalled){do{switch(_imp->opts->target_type){casedl_target_package:if(!_imp->current_pde())returnfalse;if(is_top_level_target(uninstalled))returnfalse;continue;casedl_target_set:continue;caselast_dl_target:;}throwInternalError(PALUDIS_HERE,"Bad target_type value '"+stringify(_imp->opts->target_type)+"'");}while(false);if(dl_reinstall_always==_imp->opts->reinstall)returnfalse;if(dl_upgrade_as_needed==_imp->opts->upgrade)returntrue;if(dl_reinstall_scm_never!=_imp->opts->reinstall_scm)if(uninstalled.version==installed.version&&(installed.version.is_scm()||is_scm(installed.name))){statictime_tcurrent_time(time(0));/* static to avoid weirdness */time_tinstalled_time(_imp->env->package_database()->fetch_repository(installed.repository)->installed_interface->installed_time(installed.name,installed.version));do{switch(_imp->opts->reinstall_scm){casedl_reinstall_scm_always:returnfalse;casedl_reinstall_scm_daily:if(current_time-installed_time>(24*60*60))returnfalse;continue;casedl_reinstall_scm_weekly:if(current_time-installed_time>(24*60*60*7))returnfalse;continue;casedl_reinstall_scm_never:;/* nothing */caselast_dl_reinstall_scm:;}throwInternalError(PALUDIS_HERE,"Bad value for opts->reinstall_scm");}while(false);}/* use != rather than > to correctly force a downgrade when packages are * removed. */if(uninstalled.version!=installed.version)returnfalse;if(dl_reinstall_if_use_changed==_imp->opts->reinstall){constEbuildVersionMetadata*constevm_i(_imp->env->package_database()->fetch_repository(installed.repository)->version_metadata(installed.name,installed.version)->get_ebuild_interface());constEbuildVersionMetadata*constevm_u(_imp->env->package_database()->fetch_repository(uninstalled.repository)->version_metadata(uninstalled.name,uninstalled.version)->get_ebuild_interface());std::set<std::string>use_i,use_u,use_common;if(evm_i)WhitespaceTokeniser::get_instance()->tokenise(evm_i->iuse,std::inserter(use_i,use_i.end()));if(evm_u)WhitespaceTokeniser::get_instance()->tokenise(evm_u->iuse,std::inserter(use_u,use_u.end()));std::set_intersection(use_i.begin(),use_i.end(),use_u.begin(),use_u.end(),std::inserter(use_common,use_common.end()));for(std::set<std::string>::const_iteratorf(use_common.begin()),f_end(use_common.end());f!=f_end;++f)if(_imp->env->query_use(UseFlagName(*f),&installed)!=_imp->env->query_use(UseFlagName(*f),&uninstalled))returnfalse;}returntrue;}boolDepList::already_installed(DepAtom::ConstPointeratom)const{returnalready_installed(atom.raw_pointer());}boolDepList::already_installed(constDepAtom*constatom)const{QueryVisitorvisitor(this);atom->accept(&visitor);returnvisitor.result;}DepList::IteratorDepList::begin()const{returnIterator(_imp->merge_list.begin());}DepList::IteratorDepList::end()const{returnIterator(_imp->merge_list.end());}namespace{structIsTopLevelTarget:DepAtomVisitorTypes::ConstVisitor,std::unary_function<PackageDatabaseEntry,bool>{constEnvironment*constenv;DepAtom::ConstPointertarget;constPackageDatabaseEntry*dbe;boolmatched;IsTopLevelTarget(constEnvironment*conste,DepAtom::ConstPointert):env(e),target(t),matched(false){}booloperator()(constPackageDatabaseEntry&e){dbe=&e;matched=false;target->accept(this);returnmatched;}voidvisit(constAllDepAtom*consta){if(matched)return;std::for_each(a->begin(),a->end(),accept_visitor(this));}voidvisit(constPackageDepAtom*consta){if(matched)return;if(match_package(env,a,*dbe))matched=true;}voidvisit(constUseDepAtom*constu){if(matched)return;std::for_each(u->begin(),u->end(),accept_visitor(this));}voidvisit(constAnyDepAtom*consta){if(matched)return;std::for_each(a->begin(),a->end(),accept_visitor(this));}voidvisit(constBlockDepAtom*const){}voidvisit(constPlainTextDepAtom*const)PALUDIS_ATTRIBUTE((noreturn)){throwInternalError(PALUDIS_HERE,"Got PlainTextDepAtom?");}};}boolDepList::is_top_level_target(constPackageDatabaseEntry&e)const{if(!_imp->current_top_level_target)throwInternalError(PALUDIS_HERE,"current_top_level_target not set?");IsTopLevelTargett(_imp->env,_imp->current_top_level_target);returnt(e);}namespace{structIsError{booloperator()(constDepListEntry&e)const{switch(e.kind){casedlk_virtual:casedlk_package:casedlk_provided:casedlk_already_installed:casedlk_subpackage:casedlk_suggested:returnfalse;casedlk_block:casedlk_masked:returntrue;caselast_dlk:;}throwInternalError(PALUDIS_HERE,"Bad e.kind");}};}boolDepList::has_errors()const{returnend()!=std::find_if(begin(),end(),IsError());}