summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Burrows <dburrows@debian.org>2010-01-15 09:23:23 -0800
committerDaniel Burrows <dburrows@debian.org>2010-01-15 09:23:23 -0800
commitbc83f1bedce4f2961eada5a9f0ecdf9c54e750e9 (patch)
tree5cf6da7a68a50c975b94c7faea2d3c80a55e957c
parenta291752c13aaf5d73a091f2983baf9a961036a16 (diff)
downloadaptitude-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.cc320
-rw-r--r--src/solution_fragment.cc257
-rw-r--r--src/solution_fragment.h13
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,..."
*/