diff options
author | Daniel Burrows <dburrows@debian.org> | 2010-01-15 09:23:23 -0800 |
---|---|---|
committer | Daniel Burrows <dburrows@debian.org> | 2010-01-15 09:23:23 -0800 |
commit | bc83f1bedce4f2961eada5a9f0ecdf9c54e750e9 (patch) | |
tree | 5cf6da7a68a50c975b94c7faea2d3c80a55e957c | |
parent | a291752c13aaf5d73a091f2983baf9a961036a16 (diff) | |
download | aptitude-bc83f1bedce4f2961eada5a9f0ecdf9c54e750e9.tar.gz |
Add integer IDs for solution entries that can be used to quickly reject/accept members of the solution.
-rw-r--r-- | src/cmdline/cmdline_resolver.cc | 320 | ||||
-rw-r--r-- | src/solution_fragment.cc | 257 | ||||
-rw-r--r-- | src/solution_fragment.h | 13 |
3 files changed, 442 insertions, 148 deletions
diff --git a/src/cmdline/cmdline_resolver.cc b/src/cmdline/cmdline_resolver.cc index 5e5cdcac..80d43cf6 100644 --- a/src/cmdline/cmdline_resolver.cc +++ b/src/cmdline/cmdline_resolver.cc @@ -1,6 +1,6 @@ // cmdline_resolver.cc // -// Copyright (C) 2005-2009 Daniel Burrows +// Copyright (C) 2005-2010 Daniel Burrows // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -30,6 +30,7 @@ #include <aptitude.h> #include <solution_fragment.h> +#include <boost/lexical_cast.hpp> #include <boost/make_shared.hpp> #include <boost/ref.hpp> @@ -65,8 +66,13 @@ namespace cw = cwidget; /** Generate a cw::fragment describing a solution as an ordered sequence * of actions. + * + * \param ids If not NULL, updated with a mapping from the string + * keys identifying choices in the solution to the associated + * choices. */ -static cw::fragment *solution_story(const aptitude_solution &s) +static cw::fragment *solution_story(const aptitude_solution &s, + std::map<std::string, choice> *ids) { std::vector<choice> choices; for(choice_set::const_iterator it = s.get_choices().begin(); @@ -84,7 +90,33 @@ static cw::fragment *solution_story(const aptitude_solution &s) dep_text(i->get_dep().get_dep()).c_str(), indentbox(0, 4, choice_fragment(*i)))); - return cw::sequence_fragment(fragments); + if(ids == NULL) + return cw::sequence_fragment(fragments); + else + { + std::vector<cw::fragment *> id_fragments; + + for(std::vector<choice>::size_type i = 0; i < choices.size(); ++i) + { + std::string key = boost::lexical_cast<std::string>(i + 1); + id_fragments.push_back(cw::fragf("%s)", key.c_str())); + (*ids)[key] = choices[i]; + } + + + std::vector<cw::fragment_column_entry> columns; + columns.push_back(cw::fragment_column_entry(false, true, + 1, cw::fragment_column_entry::top, + id_fragments)); + columns.push_back(cw::fragment_column_entry(false, false, + 1, cw::fragment_column_entry::top, + NULL)); + columns.push_back(cw::fragment_column_entry(false, true, + 1, cw::fragment_column_entry::top, + fragments)); + + return cw::fragment_columns(columns); + } } void cmdline_dump_resolver() @@ -174,8 +206,8 @@ static void resolver_help(ostream &out) "o: %F" "e: %F" "x: %F" - "r pkg ver ...: %F%n" - "a pkg ver ...: %F%n" + "r (ID|pkg ver) ...: %F%n" + "a (ID|pkg ver) ...: %F%n" "<ACTION> pkg... : %F%n" "%F" "%F" @@ -202,9 +234,9 @@ static void resolver_help(ostream &out) flowindentbox(0, 3, cw::fragf(_("abort automatic dependency resolution; resolve dependencies by hand instead"))), flowindentbox(0, 15, - cw::fragf(_("reject the given package versions; don't display any solutions in which they occur. Enter UNINST instead of a version to reject removing the package."))), + cw::fragf(_("reject the given package versions; don't display any solutions in which they occur. Enter UNINST instead of a version to reject removing the package. ID is the integer printed to the left of the action."))), flowindentbox(0, 15, - cw::fragf(_("accept the given package versions; display only solutions in which they occur. Enter UNINST instead of a version to accept removing the package."))), + cw::fragf(_("accept the given package versions; display only solutions in which they occur. Enter UNINST instead of a version to accept removing the package. ID is the integer printed to the left of the action."))), flowindentbox(0, 3, cw::fragf(_("adjust the state of the listed packages, where ACTION is one of:"))), flowindentbox(0, 4, @@ -260,6 +292,7 @@ static pkgCache::VerIterator choose_version(const vector<pkgCache::VerIterator> } static void reject_or_mandate_version(const string &s, + const std::map<std::string, choice> &ids, bool is_reject) { istringstream in(s); @@ -280,101 +313,187 @@ static void reject_or_mandate_version(const string &s, { in >> pkgname >> ws; - if(in.eof()) - { - cerr << ssprintf(_("Expected a version or \"%s\" after \"%s\""), "UNINST", pkgname.c_str()) << endl; - return; - } - - in >> vername >> ws; - - pkgCache::PkgIterator pkg((*apt_cache_file)->FindPkg(pkgname)); + choice c; // Initialized below. - if(pkg.end()) - { - cerr << ssprintf(_("No such package \"%s\""), pkgname.c_str()) << endl; - continue; - } - - aptitude_universe::version ver = - aptitude_universe::version::make_removal(pkg, - *apt_cache_file); - if(stringcasecmp(vername, "UNINST") != 0) + std::map<std::string, choice>::const_iterator found = + ids.find(pkgname); + if(found != ids.end()) + c = found->second; + else { - vector<pkgCache::VerIterator> found; - for(pkgCache::VerIterator vi = pkg.VersionList(); !vi.end(); ++vi) - if(vi.VerStr() == vername) - found.push_back(vi); - - if(found.empty()) + if(in.eof()) { - cerr << ssprintf(_("%s has no version named \"%s\""), - pkgname.c_str(), vername.c_str()) << endl; - continue; + cerr << ssprintf(_("Expected a version or \"%s\" after \"%s\""), "UNINST", pkgname.c_str()) << endl; + return; } - ver = aptitude_universe::version::make_install(choose_version(found), - *apt_cache_file); + in >> vername >> ws; - eassert(!ver.get_ver().end()); - eassert(ver.get_pkg() == ver.get_ver().ParentPkg()); - } + pkgCache::PkgIterator pkg((*apt_cache_file)->FindPkg(pkgname)); - if(is_reject) - { - if(resman->is_rejected(ver)) + if(pkg.end()) { - if(ver.get_ver().end()) - cout << ssprintf(_("Allowing the removal of %s"), - pkgname.c_str()) << endl; - else - cout << ssprintf(_("Allowing the installation of %s version %s (%s)"), - pkg.Name(), - ver.get_ver().VerStr(), - archives_text(ver.get_ver()).c_str()) << endl; - - resman->unreject_version(ver); + cerr << ssprintf(_("No such package \"%s\""), pkgname.c_str()) << endl; + continue; } - else + + aptitude_universe::version ver = + aptitude_universe::version::make_removal(pkg, + *apt_cache_file); + if(stringcasecmp(vername, "UNINST") != 0) { - if(ver.get_ver().end()) - cout << ssprintf(_("Rejecting the removal of %s"), - pkgname.c_str()) << endl; - else - cout << ssprintf(_("Rejecting the installation of %s version %s (%s)"), - pkg.Name(), - ver.get_ver().VerStr(), - archives_text(ver.get_ver()).c_str()) << endl; - - resman->reject_version(ver); + vector<pkgCache::VerIterator> found; + for(pkgCache::VerIterator vi = pkg.VersionList(); !vi.end(); ++vi) + if(vi.VerStr() == vername) + found.push_back(vi); + + if(found.empty()) + { + cerr << ssprintf(_("%s has no version named \"%s\""), + pkgname.c_str(), vername.c_str()) << endl; + continue; + } + + ver = aptitude_universe::version::make_install(choose_version(found), + *apt_cache_file); + + eassert(!ver.get_ver().end()); + eassert(ver.get_pkg() == ver.get_ver().ParentPkg()); } } - else + + switch(c.get_type()) { - if(resman->is_mandatory(ver)) - { - if(ver.get_ver().end()) - cout << ssprintf(_("No longer requiring the removal of %s"), - pkgname.c_str()) << endl; - else - cout << ssprintf(_("No longer requiring the installation of %s version %s (%s)"), - pkg.Name(), ver.get_ver().VerStr(), - archives_text(ver.get_ver()).c_str()) << endl; - - resman->unmandate_version(ver); - } - else - { - if(ver.get_ver().end()) - cout << ssprintf(_("Requiring the removal of %s"), - pkgname.c_str()) << endl; - else - cout << ssprintf(_("Requiring the installation of %s version %s (%s)"), - pkg.Name(), ver.get_ver().VerStr(), - archives_text(ver.get_ver()).c_str()) << endl; - - resman->mandate_version(ver); - } + case choice::install_version: + { + aptitude_resolver_version ver(c.get_ver()); + pkgCache::PkgIterator pkg(ver.get_pkg()); + if(is_reject) + { + if(resman->is_rejected(ver)) + { + if(ver.get_ver().end()) + cout << ssprintf(_("Allowing the removal of %s"), + pkg.Name()) << endl; + else + cout << ssprintf(_("Allowing the installation of %s version %s (%s)"), + pkg.Name(), + ver.get_ver().VerStr(), + archives_text(ver.get_ver()).c_str()) << endl; + + resman->unreject_version(ver); + } + else + { + if(ver.get_ver().end()) + cout << ssprintf(_("Rejecting the removal of %s"), + pkg.Name()) << endl; + else + cout << ssprintf(_("Rejecting the installation of %s version %s (%s)"), + pkg.Name(), + ver.get_ver().VerStr(), + archives_text(ver.get_ver()).c_str()) << endl; + + resman->reject_version(ver); + } + } + else + { + if(resman->is_mandatory(ver)) + { + if(ver.get_ver().end()) + cout << ssprintf(_("No longer requiring the removal of %s"), + pkg.Name()) << endl; + else + cout << ssprintf(_("No longer requiring the installation of %s version %s (%s)"), + pkg.Name(), ver.get_ver().VerStr(), + archives_text(ver.get_ver()).c_str()) << endl; + + resman->unmandate_version(ver); + } + else + { + if(ver.get_ver().end()) + cout << ssprintf(_("Requiring the removal of %s"), + pkg.Name()) << endl; + else + cout << ssprintf(_("Requiring the installation of %s version %s (%s)"), + pkg.Name(), ver.get_ver().VerStr(), + archives_text(ver.get_ver()).c_str()) << endl; + + resman->mandate_version(ver); + } + } + } + break; + + case choice::break_soft_dep: + { + aptitude_resolver_dep d(c.get_dep()); + + pkgCache::DepIterator start, end; + surrounding_or(d.get_dep(), start, end, d.get_dep().Cache()); + std::ostringstream dep_rendering_stream; + + if(start.end()) // Sanity-check. + dep_rendering_stream << "(??\?)"; + else + { + dep_rendering_stream << start.ParentPkg().Name() + << " " + << start.ParentVer().VerStr() + << " " + << start.DepType() + << " "; + bool first = true; + + while(!start.end() && start != end) + { + if(first) + first = false; + else + dep_rendering_stream << " | "; + + dep_rendering_stream << start.TargetPkg().Name() + << " " + << start.TargetVer(); + + ++start; + } + std::string dep_rendering = dep_rendering_stream.str(); + + if(is_reject) + { + if(resman->is_hardened(d)) + { + cout << ssprintf(_("Allowing this recommendation to be ignored: %s"), + dep_rendering.c_str()) << endl; + resman->unharden_dep(d); + } + else + { + cout << ssprintf(_("Always obeying this recommendation: %s"), + dep_rendering.c_str()) << endl; + resman->harden_dep(d); + } + } + else + { + if(resman->is_approved_broken(d)) + { + cout << ssprintf(_("No longer ignoring this recommendation: %s"), + dep_rendering.c_str()) << endl; + resman->unapprove_broken_dep(d); + } + else + { + cout << ssprintf(_("Ignoring this recommendation: %s"), + dep_rendering.c_str()) << endl; + resman->approve_broken_dep(d); + } + } + } + } } } } @@ -619,6 +738,13 @@ cmdline_resolve_deps(pkgset &to_install, force_no_change); aptitude_solution lastsol; + // Stores the string IDs that can be used for accept/reject + // commands. Filled in when the solution is being rendered + // (since the IDs are integers counting from the first entry in + // the displayed lists). + std::map<std::string, choice> ids; + + // The inner loop tries to generate solutions until some // packages are modified by the user (then the new set of broken // packages, if any, is displayed and we start over) @@ -635,11 +761,12 @@ cmdline_resolve_deps(pkgset &to_install, if(sol != lastsol) { + ids.clear(); cw::fragment *f=cw::sequence_fragment(flowbox(cwidget::text_fragment(_("The following actions will resolve these dependencies:"))), cwidget::newline_fragment(), story_is_default - ? solution_story(sol) - : solution_fragment(sol), + ? solution_story(sol, &ids) + : solution_fragment_with_ids(sol, ids), NULL); update_screen_width(); @@ -687,9 +814,10 @@ cmdline_resolve_deps(pkgset &to_install, case 'O': { story_is_default = !story_is_default; + ids.clear(); cw::fragment *f = story_is_default - ? solution_story(sol) - : solution_fragment(sol); + ? solution_story(sol, &ids) + : solution_fragment_with_ids(sol, ids); update_screen_width(); cout << f->layout(screen_width, screen_width, cwidget::style()) << endl; @@ -700,10 +828,10 @@ cmdline_resolve_deps(pkgset &to_install, ui_solution_screen(); break; case 'R': - reject_or_mandate_version(string(response, 1), true); + reject_or_mandate_version(string(response, 1), ids, true); break; case 'A': - reject_or_mandate_version(string(response, 1), false); + reject_or_mandate_version(string(response, 1), ids, false); break; case '.': resman->select_next_solution(); @@ -858,7 +986,7 @@ namespace aptitude // The previous line will say "resolving dependencies..."; // separate the solution from this message.. std::cout << std::endl; - std::auto_ptr<cw::fragment> story(solution_story(solution)); + std::auto_ptr<cw::fragment> story(solution_story(solution, NULL)); std::cout << story->layout(screen_width, screen_width, cwidget::style()); } } diff --git a/src/solution_fragment.cc b/src/solution_fragment.cc index 02684cec..5e1673b3 100644 --- a/src/solution_fragment.cc +++ b/src/solution_fragment.cc @@ -1,7 +1,7 @@ // solution_fragment.cc // // -// Copyright (C) 2005, 2007, 2009 Daniel Burrows +// Copyright (C) 2005, 2007, 2009-2010 Daniel Burrows // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -28,10 +28,13 @@ #include <generic/util/util.h> +#include <boost/lexical_cast.hpp> + #include <cwidget/fragment.h> #include <cwidget/generic/util/transcode.h> #include <algorithm> +#include <functional> #include <vector> typedef generic_solution<aptitude_universe> aptitude_solution; @@ -166,16 +169,105 @@ cw::fragment *choice_fragment(const choice &c) } } +namespace +{ + // Used to centralize the logic to generate an ID map and column if + // requested (otherwise it does nothing). + class ids_column_generator + { + int next_id; + std::vector<cw::fragment *> id_fragments; + std::map<std::string, choice> *ids_out; + + public: + ids_column_generator(int first_id, std::map<std::string, choice> *_ids_out) + : next_id(first_id), + ids_out(_ids_out) + { + } -cw::fragment *solution_fragment(const aptitude_solution &sol) + ~ids_column_generator() + { + for(std::vector<cw::fragment *>::const_iterator it = + id_fragments.begin(); + it != id_fragments.end(); ++it) + delete *it; + } + + /** \brief If ID generation is enabled, create an ID for the given + * choice, adding it to both the output map and the in-order + * list of IDs. + */ + void append_id(const choice &c) + { + if(ids_out != NULL) + { + std::string key = boost::lexical_cast<std::string>(next_id); + id_fragments.push_back(cw::fragf("%s)", key.c_str())); + (*ids_out)[key] = c; + + ++next_id; + } + } + + /** \brief Append a newline to the IDs column, normally to match a + * newline in the matching fragments column. + */ + void append_newline() + { + if(ids_out != NULL) + id_fragments.push_back(cw::newline_fragment()); + } + + /** \brief Append a fragment for each row in the ID listing + * column to the given vector. + * + * After this function completes, its caller is responsible for + * deleting the fragments. + */ + void release_ids_column(std::vector<cw::fragment *> &fragments) + { + for(std::vector<cw::fragment *>::const_iterator it = id_fragments.begin(); + it != id_fragments.end(); ++it) + fragments.push_back(*it); + + id_fragments.clear(); + } + }; + + class pkg_name_pair_lt + { + pkg_name_lt base; + public: + bool operator()(const std::pair<pkgCache::PkgIterator, choice> &p1, + const std::pair<pkgCache::PkgIterator, choice> &p2) const + { + return base(p1.first, p2.first); + } + }; + + class ver_name_pair_lt + { + ver_name_lt base; + public: + bool operator()(const std::pair<pkgCache::VerIterator, choice> &p1, + const std::pair<pkgCache::VerIterator, choice> &p2) const + { + return base(p1.first, p2.first); + } + }; +} + +cw::fragment *solution_fragment_with_ids(const aptitude_solution &sol, + std::map<std::string, choice> *ids) { // Bin packages according to what will happen to them. - vector<pkgCache::PkgIterator> remove_packages; - vector<pkgCache::PkgIterator> keep_packages; - vector<pkgCache::VerIterator> install_packages; - vector<pkgCache::VerIterator> downgrade_packages; - vector<pkgCache::VerIterator> upgrade_packages; - vector<pkgCache::DepIterator> unresolved; + vector<std::pair<pkgCache::PkgIterator, choice> > remove_packages; + vector<std::pair<pkgCache::PkgIterator, choice> > keep_packages; + vector<std::pair<pkgCache::VerIterator, choice> > install_packages; + vector<std::pair<pkgCache::VerIterator, choice> > downgrade_packages; + vector<std::pair<pkgCache::VerIterator, choice> > upgrade_packages; + vector<std::pair<pkgCache::DepIterator, choice> > unresolved; for(choice_set::const_iterator i = sol.get_choices().begin(); i != sol.get_choices().end(); ++i) @@ -191,14 +283,14 @@ cw::fragment *solution_fragment(const aptitude_solution &sol) if(curver.end()) { if(newver.end()) - keep_packages.push_back(pkg); + keep_packages.push_back(std::make_pair(pkg, *i)); else - install_packages.push_back(newver); + install_packages.push_back(std::make_pair(newver, *i)); } else if(newver.end()) - remove_packages.push_back(pkg); + remove_packages.push_back(std::make_pair(pkg, *i)); else if(newver == curver) - keep_packages.push_back(pkg); + keep_packages.push_back(std::make_pair(pkg, *i)); else { int cmp=_system->VS->CmpVersion(curver.VerStr(), @@ -213,116 +305,179 @@ cw::fragment *solution_fragment(const aptitude_solution &sol) /** \todo indicate "sidegrades" separately? */ if(cmp<=0) - upgrade_packages.push_back(newver); + upgrade_packages.push_back(std::make_pair(newver, *i)); else if(cmp>0) - downgrade_packages.push_back(newver); + downgrade_packages.push_back(std::make_pair(newver, *i)); } } break; case choice::break_soft_dep: - unresolved.push_back(i->get_dep().get_dep()); + unresolved.push_back(std::make_pair(i->get_dep().get_dep(), *i)); break; } } sort(remove_packages.begin(), remove_packages.end(), - pkg_name_lt()); + pkg_name_pair_lt()); sort(keep_packages.begin(), keep_packages.end(), - pkg_name_lt()); + pkg_name_pair_lt()); sort(install_packages.begin(), install_packages.end(), - ver_name_lt()); + ver_name_pair_lt()); sort(downgrade_packages.begin(), downgrade_packages.end(), - ver_name_lt()); + ver_name_pair_lt()); sort(upgrade_packages.begin(), upgrade_packages.end(), - ver_name_lt()); + ver_name_pair_lt()); // \todo Sort the unresolved list in some readable fashion. vector<cw::fragment *> fragments; + ids_column_generator ids_column(1, ids); if(!remove_packages.empty()) { + ids_column.append_newline(); fragments.push_back(cw::fragf(_("%BRemove%b the following packages:%n"))); - for(vector<pkgCache::PkgIterator>::const_iterator i=remove_packages.begin(); + for(std::vector<std::pair<pkgCache::PkgIterator, choice> >::const_iterator i=remove_packages.begin(); i!=remove_packages.end(); ++i) - fragments.push_back(cw::fragf(" %s%n", i->Name())); + { + ids_column.append_id(i->second); + fragments.push_back(cw::fragf(" %s%n", i->first.Name())); + } + ids_column.append_newline(); fragments.push_back(cw::newline_fragment()); } if(!install_packages.empty()) { + ids_column.append_newline(); fragments.push_back(cw::fragf(_("%BInstall%b the following packages:%n"))); - for(vector<pkgCache::VerIterator>::const_iterator i=install_packages.begin(); + for(std::vector<std::pair<pkgCache::VerIterator, choice> >::const_iterator i=install_packages.begin(); i!=install_packages.end(); ++i) - fragments.push_back(cw::fragf(" %s [%s (%s)]%n", - i->ParentPkg().Name(), - i->VerStr(), - archives_text(*i).c_str())); + { + ids_column.append_id(i->second); + fragments.push_back(cw::fragf(" %s [%s (%s)]%n", + i->first.ParentPkg().Name(), + i->first.VerStr(), + archives_text(i->first).c_str())); + } + ids_column.append_newline(); fragments.push_back(cw::newline_fragment()); } if(!keep_packages.empty()) { + ids_column.append_newline(); fragments.push_back(cw::fragf(_("%BKeep%b the following packages at their current version:%n"))); - for(vector<pkgCache::PkgIterator>::const_iterator i=keep_packages.begin(); + for(std::vector<std::pair<pkgCache::PkgIterator, choice> >::const_iterator i=keep_packages.begin(); i!=keep_packages.end(); ++i) { - if(i->CurrentVer().end()) + ids_column.append_id(i->second); + + if(i->first.CurrentVer().end()) fragments.push_back(cw::fragf(" %s [%s]%n", - i->Name(), - _("Not Installed"))); + i->first.Name(), + _("Not Installed"))); else fragments.push_back(cw::fragf(" %s [%s (%s)]%n", - i->Name(), - i->CurrentVer().VerStr(), - archives_text(i->CurrentVer()).c_str())); + i->first.Name(), + i->first.CurrentVer().VerStr(), + archives_text(i->first.CurrentVer()).c_str())); } + ids_column.append_newline(); fragments.push_back(cw::newline_fragment()); } if(!upgrade_packages.empty()) { + ids_column.append_newline(); fragments.push_back(cw::fragf(_("%BUpgrade%b the following packages:%n"))); - for(vector<pkgCache::VerIterator>::const_iterator i=upgrade_packages.begin(); + for(std::vector<std::pair<pkgCache::VerIterator, choice> >::const_iterator i=upgrade_packages.begin(); i!=upgrade_packages.end(); ++i) - fragments.push_back(cw::fragf(" %s [%s (%s) -> %s (%s)]%n", - i->ParentPkg().Name(), - i->ParentPkg().CurrentVer().VerStr(), - archives_text(i->ParentPkg().CurrentVer()).c_str(), - i->VerStr(), - archives_text(*i).c_str())); + { + ids_column.append_id(i->second); + fragments.push_back(cw::fragf(" %s [%s (%s) -> %s (%s)]%n", + i->first.ParentPkg().Name(), + i->first.ParentPkg().CurrentVer().VerStr(), + archives_text(i->first.ParentPkg().CurrentVer()).c_str(), + i->first.VerStr(), + archives_text(i->first).c_str())); + } + ids_column.append_newline(); fragments.push_back(cw::newline_fragment()); } if(!downgrade_packages.empty()) { + ids_column.append_newline(); fragments.push_back(cw::fragf(_("%BDowngrade%b the following packages:%n"))); - for(vector<pkgCache::VerIterator>::const_iterator i=downgrade_packages.begin(); + for(std::vector<std::pair<pkgCache::VerIterator, choice> >::const_iterator i=downgrade_packages.begin(); i!=downgrade_packages.end(); ++i) - fragments.push_back(cw::fragf(" %s [%s (%s) -> %s (%s)]%n", - i->ParentPkg().Name(), - i->ParentPkg().CurrentVer().VerStr(), - archives_text(i->ParentPkg().CurrentVer()).c_str(), - i->VerStr(), - archives_text(*i).c_str())); + { + ids_column.append_id(i->second); + + fragments.push_back(cw::fragf(" %s [%s (%s) -> %s (%s)]%n", + i->first.ParentPkg().Name(), + i->first.ParentPkg().CurrentVer().VerStr(), + archives_text(i->first.ParentPkg().CurrentVer()).c_str(), + i->first.VerStr(), + archives_text(i->first).c_str())); + } + ids_column.append_newline(); fragments.push_back(cw::newline_fragment()); } if(!unresolved.empty()) { + ids_column.append_newline(); fragments.push_back(cw::fragf(_("Leave the following dependencies unresolved:%n"))); - for(std::vector<pkgCache::DepIterator>::const_iterator i = unresolved.begin(); + for(std::vector<std::pair<pkgCache::DepIterator, choice> >::const_iterator i = unresolved.begin(); i != unresolved.end(); ++i) - fragments.push_back(cw::fragf("%ls%n", dep_text(*i).c_str())); + { + ids_column.append_id(i->second); + fragments.push_back(cw::fragf(" %ls%n", dep_text(i->first).c_str())); + } } + ids_column.append_newline(); fragments.push_back(cw::fragf(_("Tier: %s"), aptitude_universe::get_tier_name(sol.get_tier()).c_str())); - return flowbox(cw::sequence_fragment(fragments)); + if(ids == NULL) + return flowbox(cw::sequence_fragment(fragments)); + else + { + std::vector<cw::fragment_column_entry> columns; + + std::vector<cw::fragment *> ids_column_fragments; + ids_column.release_ids_column(ids_column_fragments); + + columns.push_back(cw::fragment_column_entry(false, true, + 1, cw::fragment_column_entry::top, + ids_column_fragments)); + columns.push_back(cw::fragment_column_entry(false, false, + 1, cw::fragment_column_entry::top, + NULL)); + columns.push_back(cw::fragment_column_entry(false, true, + 1, cw::fragment_column_entry::top, + fragments)); + + return cw::fragment_columns(columns); + } +} + +cw::fragment *solution_fragment_with_ids(const aptitude_solution &sol, + std::map<std::string, choice> &ids) + +{ + return solution_fragment_with_ids(sol, &ids); +} + +cw::fragment *solution_fragment(const aptitude_solution &sol) +{ + return solution_fragment_with_ids(sol, NULL); } diff --git a/src/solution_fragment.h b/src/solution_fragment.h index 73816aad..1dd1a7eb 100644 --- a/src/solution_fragment.h +++ b/src/solution_fragment.h @@ -1,6 +1,6 @@ // solution_fragment.h -*-c++-*- // -// Copyright (C) 2005, 2009 Daniel Burrows +// Copyright (C) 2005, 2009-2010 Daniel Burrows // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -43,6 +43,17 @@ class aptitude_universe; cwidget::fragment *solution_fragment(const generic_solution<aptitude_universe> &solution); +/** \return a fragment describing the given solution. + * + * \param solution The solution to render. + * \param ids A map in which bindings from string values to the + * choices in the solution will be stored; the strings + * can be used later on to act on entries in the + * solution. + */ +cwidget::fragment *solution_fragment_with_ids(const generic_solution<aptitude_universe> &solution, + std::map<std::string, generic_choice<aptitude_universe> > &ids); + /** \return a list of the archives to which a version * belongs in the form "archive1,archive2,..." */ |