aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-06-19 16:00:07 +0100
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-06-19 16:00:07 +0100
commitf76c8165fab809f06991acd55bb8eab97fd2c41d (patch)
treebda184e8cc9568f1decac1d7e5569bd55d55d770
parent40d750718c8e6f0d50496ddbff67d1eed1981f87 (diff)
downloadpaludis-f76c8165fab809f06991acd55bb8eab97fd2c41d.tar.gz
paludis-f76c8165fab809f06991acd55bb8eab97fd2c41d.tar.xz
cave resume
Fixes: ticket:842
-rw-r--r--src/clients/cave/Makefile.am5
-rw-r--r--src/clients/cave/cmd_execute_resolution.cc166
-rw-r--r--src/clients/cave/cmd_resolve_cmdline.cc3
-rw-r--r--src/clients/cave/cmd_resolve_cmdline.hh1
-rw-r--r--src/clients/cave/cmd_resume.cc280
-rw-r--r--src/clients/cave/cmd_resume.hh46
-rw-r--r--src/clients/cave/command_factory.cc2
-rw-r--r--src/clients/cave/resume_data.cc66
-rw-r--r--src/clients/cave/resume_data.hh53
9 files changed, 608 insertions, 14 deletions
diff --git a/src/clients/cave/Makefile.am b/src/clients/cave/Makefile.am
index cf66170..cda7484 100644
--- a/src/clients/cave/Makefile.am
+++ b/src/clients/cave/Makefile.am
@@ -43,6 +43,7 @@ command_MANS = \
cave-print-sets.1 \
cave-print-sync-protocols.1 \
cave-resolve.1 \
+ cave-resume.1 \
cave-search.1 \
cave-show.1 \
cave-sync.1 \
@@ -118,6 +119,7 @@ libcave_a_SOURCES = \
cmd_resolve_cmdline.cc cmd_resolve_cmdline.hh \
cmd_resolve_display_callback.cc cmd_resolve_display_callback.hh \
cmd_resolve_dump.cc cmd_resolve_dump.hh \
+ cmd_resume.cc cmd_resume.hh \
cmd_search.cc cmd_search.hh \
cmd_search_cmdline.cc cmd_search_cmdline.hh \
cmd_show.cc cmd_show.hh \
@@ -131,7 +133,8 @@ libcave_a_SOURCES = \
formats.cc formats.hh \
select_format_for_spec.cc select_format_for_spec.hh \
match_qpns.cc match_qpns.hh \
- resolve_common.cc resolve_common.hh
+ resolve_common.cc resolve_common.hh \
+ resume_data.cc resume_data.hh
# cmd_executables.cc \
# cmd_owner.cc \
diff --git a/src/clients/cave/cmd_execute_resolution.cc b/src/clients/cave/cmd_execute_resolution.cc
index eebf62d..58d8fbf 100644
--- a/src/clients/cave/cmd_execute_resolution.cc
+++ b/src/clients/cave/cmd_execute_resolution.cc
@@ -24,10 +24,12 @@
#include "command_command_line.hh"
#include "formats.hh"
#include "colour_formatter.hh"
+#include "resume_data.hh"
#include <paludis/args/do_help.hh>
#include <paludis/args/escape.hh>
#include <paludis/util/make_shared_ptr.hh>
#include <paludis/util/safe_ifstream.hh>
+#include <paludis/util/safe_ofstream.hh>
#include <paludis/util/system.hh>
#include <paludis/util/destringify.hh>
#include <paludis/util/stringify.hh>
@@ -41,6 +43,7 @@
#include <paludis/util/hashes.hh>
#include <paludis/util/type_list.hh>
#include <paludis/util/indirect_iterator-impl.hh>
+#include <paludis/util/wrapped_output_iterator.hh>
#include <paludis/resolver/resolutions_by_resolvent.hh>
#include <paludis/resolver/reason.hh>
#include <paludis/resolver/sanitised_dependencies.hh>
@@ -115,7 +118,7 @@ namespace
virtual std::string app_synopsis() const
{
- return "Executes a dependency resolution created using 'cave execute'.";
+ return "Executes a dependency resolution created using 'cave resolve'.";
}
virtual std::string app_description() const
@@ -623,13 +626,12 @@ namespace
{
const std::tr1::shared_ptr<Environment> env;
const ExecuteResolutionCommandLine & cmdline;
- int & x;
- const int y;
+ const int x, y;
ExecuteOneVisitor(
const std::tr1::shared_ptr<Environment> & e,
const ExecuteResolutionCommandLine & c,
- int & xx, int yy) :
+ int xx, int yy) :
env(e),
cmdline(c),
x(xx),
@@ -639,8 +641,6 @@ namespace
int visit(InstallJob & install_item)
{
- ++x;
-
const std::tr1::shared_ptr<JobActiveState> active_state(new JobActiveState);
install_item.set_state(active_state);
@@ -664,8 +664,6 @@ namespace
int visit(UninstallJob & uninstall_item)
{
- ++x;
-
const std::tr1::shared_ptr<JobActiveState> active_state(new JobActiveState);
uninstall_item.set_state(active_state);
@@ -684,8 +682,6 @@ namespace
int visit(FetchJob & fetch_item)
{
- ++x;
-
const std::tr1::shared_ptr<JobActiveState> active_state(new JobActiveState);
fetch_item.set_state(active_state);
@@ -729,6 +725,75 @@ namespace
}
};
+ struct ExistingStateVisitor
+ {
+ bool done;
+ bool failed;
+ bool skipped;
+
+ ExistingStateVisitor() :
+ done(false),
+ failed(false),
+ skipped(false)
+ {
+ }
+
+ void visit(const JobPendingState &)
+ {
+ }
+
+ void visit(const JobActiveState &)
+ {
+ }
+
+ void visit(const JobFailedState &)
+ {
+ done = true;
+ failed = true;
+ }
+
+ void visit(const JobSkippedState &)
+ {
+ done = true;
+ skipped = true;
+ }
+
+ void visit(const JobSucceededState &)
+ {
+ done = true;
+ }
+ };
+
+ void already_done_action(
+ const std::string & state,
+ const std::string & name,
+ const int x, const int y)
+ {
+ cout << endl;
+ cout << c::bold_green() << x << " of " << y << ": Already " << state << " for "
+ << name << "..." << c::normal() << endl;
+ cout << endl;
+ }
+
+ struct JobAsStringVisitor
+ {
+ std::string visit(const InstallJob & j) const
+ {
+ return "install " + stringify(*j.origin_id());
+ }
+
+ std::string visit(const FetchJob & j) const
+ {
+ return "fetch " + stringify(*j.origin_id());
+ }
+
+ std::string visit(const UninstallJob & j) const
+ {
+ return "uninstall " + join(indirect_iterator(j.ids_to_remove()->begin()),
+ indirect_iterator(j.ids_to_remove()->end()), ", ");
+ }
+ };
+
int execute_executions(
const std::tr1::shared_ptr<Environment> & env,
const std::tr1::shared_ptr<JobLists> & lists,
@@ -760,9 +825,35 @@ namespace
c_end(lists->execute_job_list()->end()) ;
c != c_end ; ++c)
{
+ ++x;
+
bool want(true);
+ ExistingStateVisitor initial_state;
- if (0 != retcode)
+ if ((*c)->state())
+ {
+ (*c)->state()->accept(initial_state);
+
+ if (initial_state.failed)
+ {
+ retcode = 1;
+ want = false;
+ already_done_action("failed", (*c)->accept_returning<std::string>(JobAsStringVisitor()), x, y);
+ }
+ else if (initial_state.skipped)
+ {
+ retcode = 1;
+ want = false;
+ already_done_action("skipped", (*c)->accept_returning<std::string>(JobAsStringVisitor()), x, y);
+ }
+ else if (initial_state.done)
+ {
+ want = false;
+ already_done_action("succeeded", (*c)->accept_returning<std::string>(JobAsStringVisitor()), x, y);
+ }
+ }
+
+ if ((0 != retcode) && want)
{
if (last_jri == require_if)
want = false;
@@ -785,7 +876,7 @@ namespace
ExecuteOneVisitor execute(env, cmdline, x, y);
retcode |= (*c)->accept_returning<int>(execute);
}
- else
+ else if (! initial_state.done)
(*c)->set_state(make_shared_ptr(new JobSkippedState));
}
@@ -805,7 +896,8 @@ namespace
for (JobList<ExecuteJob>::ConstIterator c(lists->execute_job_list()->begin()),
c_end(lists->execute_job_list()->end()) ;
c != c_end ; ++c)
- (*c)->set_state(make_shared_ptr(new JobPendingState));
+ if (! (*c)->state())
+ (*c)->set_state(make_shared_ptr(new JobPendingState));
int retcode(0);
@@ -917,6 +1009,48 @@ namespace
}
}
+ struct NotASuccess
+ {
+ bool operator() (const std::tr1::shared_ptr<const ExecuteJob> & job) const
+ {
+ return (! job->state()) || ! simple_visitor_cast<const JobSucceededState>(*job->state());
+ }
+ };
+
+ void write_resume_file(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<JobLists> & lists,
+ const ExecuteResolutionCommandLine & cmdline)
+ {
+ if (! cmdline.execution_options.a_resume_file.specified())
+ return;
+
+ FSEntry resume_file(cmdline.execution_options.a_resume_file.argument());
+ bool success(lists->execute_job_list()->end() == std::find_if(lists->execute_job_list()->begin(),
+ lists->execute_job_list()->end(), NotASuccess()));
+ if (success)
+ {
+ cout << endl << "Erasing resume file " << resume_file << "..." << endl;
+ resume_file.unlink();
+ }
+ else
+ {
+ std::tr1::shared_ptr<Sequence<std::string> > targets(new Sequence<std::string>);
+ std::copy(cmdline.begin_parameters(), cmdline.end_parameters(), targets->back_inserter());
+
+ ResumeData resume_data(make_named_values<ResumeData>(
+ n::job_lists() = lists,
+ n::target_set() = cmdline.a_set.specified(),
+ n::targets() = targets
+ ));
+
+ cout << endl << "Writing resume information to " << resume_file << "..." << endl;
+ SafeOFStream stream(resume_file);
+ Serialiser ser(stream);
+ resume_data.serialise(ser);
+ }
+ }
+
int execute_resolution(
const std::tr1::shared_ptr<Environment> & env,
const std::tr1::shared_ptr<JobLists> & lists,
@@ -936,6 +1070,9 @@ namespace
}
catch (...)
{
+ if ((! cmdline.a_pretend.specified()) || (0 == retcode))
+ write_resume_file(env, lists, cmdline);
+
if (! cmdline.a_pretend.specified())
display_summary(lists, 0 != retcode);
@@ -948,6 +1085,9 @@ namespace
throw;
}
+ if ((! cmdline.a_pretend.specified()) || (0 == retcode))
+ write_resume_file(env, lists, cmdline);
+
if (! cmdline.a_pretend.specified())
display_summary(lists, 0 != retcode);
diff --git a/src/clients/cave/cmd_resolve_cmdline.cc b/src/clients/cave/cmd_resolve_cmdline.cc
index 91ecb95..a942c05 100644
--- a/src/clients/cave/cmd_resolve_cmdline.cc
+++ b/src/clients/cave/cmd_resolve_cmdline.cc
@@ -288,6 +288,9 @@ ResolveCommandLineExecutionOptions::ResolveCommandLineExecutionOptions(args::Arg
("if-independent", 'i', "If remaining packages do not depend upon any failing package")
("always", 'a', "Always (dangerous)"),
"never"),
+ a_resume_file(&g_failure_options, "resume-file", '\0',
+ "Write resume information to the specified file. If a build fails, or if '--execute' is not "
+ "specified, then 'cave resume' can resume execution from this file."),
g_phase_options(this, "Phase Options", "Options controlling which phases to execute. No sanity checking "
"is done, allowing you to shoot as many feet off as you desire. Phase names do not have the "
diff --git a/src/clients/cave/cmd_resolve_cmdline.hh b/src/clients/cave/cmd_resolve_cmdline.hh
index 9c3d4f8..ef3e4a3 100644
--- a/src/clients/cave/cmd_resolve_cmdline.hh
+++ b/src/clients/cave/cmd_resolve_cmdline.hh
@@ -120,6 +120,7 @@ namespace paludis
args::ArgsGroup g_failure_options;
args::EnumArg a_continue_on_failure;
+ args::StringArg a_resume_file;
args::ArgsGroup g_phase_options;
args::StringSetArg a_skip_phase;
diff --git a/src/clients/cave/cmd_resume.cc b/src/clients/cave/cmd_resume.cc
new file mode 100644
index 0000000..fb65d77
--- /dev/null
+++ b/src/clients/cave/cmd_resume.cc
@@ -0,0 +1,280 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2010 Ciaran McCreesh
+ *
+ * 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 "cmd_resume.hh"
+#include "cmd_resolve_cmdline.hh"
+#include "cmd_execute_resolution.hh"
+#include "exceptions.hh"
+#include "command_command_line.hh"
+#include "formats.hh"
+#include "colour_formatter.hh"
+#include "resume_data.hh"
+#include <paludis/args/do_help.hh>
+#include <paludis/args/escape.hh>
+#include <paludis/util/make_shared_ptr.hh>
+#include <paludis/util/safe_ifstream.hh>
+#include <paludis/util/safe_ofstream.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/destringify.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/join.hh>
+#include <paludis/util/make_named_values.hh>
+#include <paludis/util/make_shared_copy.hh>
+#include <paludis/util/wrapped_forward_iterator.hh>
+#include <paludis/util/wrapped_output_iterator.hh>
+#include <paludis/util/string_list_stream.hh>
+#include <paludis/resolver/job_lists.hh>
+#include <paludis/resolver/job.hh>
+#include <paludis/resolver/job_list.hh>
+#include <paludis/resolver/job_state.hh>
+#include <paludis/environment.hh>
+#include <paludis/serialise.hh>
+
+#include <iostream>
+#include <cstdlib>
+#include <algorithm>
+
+using namespace paludis;
+using namespace cave;
+using namespace paludis::resolver;
+
+using std::cout;
+using std::endl;
+
+namespace
+{
+ struct ResumeCommandLine :
+ CaveCommandCommandLine
+ {
+ args::ArgsGroup g_retry_options;
+ args::SwitchArg a_retry_failed;
+ args::SwitchArg a_retry_skipped;
+ args::SwitchArg a_skip_failed;
+
+ ResolveCommandLineExecutionOptions execution_options;
+ ResolveCommandLineProgramOptions program_options;
+
+ ResumeCommandLine() :
+ g_retry_options(main_options_section(), "Retry Options", "Retry options. By default, 'cave resume' will "
+ "treat packages that were already skipped or already failed as skipped or failed, respectively."),
+ a_retry_failed(&g_retry_options, "retry-failed", 'f', "Retry any job that has already failed", true),
+ a_retry_skipped(&g_retry_options, "retry-skipped", 's', "Retry any job that has already been skipped. Note that "
+ "the job will just be skipped again unless circumstances have changed.", true),
+ a_skip_failed(&g_retry_options, "skip-failed", 'F', "Skip any job that has already failed", true),
+ execution_options(this),
+ program_options(this)
+ {
+ add_usage_line("--resume-file state [ --retry-failed ] [ --retry-skipped ]");
+ }
+
+ virtual std::string app_name() const
+ {
+ return "cave resume";
+ }
+
+ virtual std::string app_synopsis() const
+ {
+ return "Resume a failed resolution from 'cave resolve'";
+ }
+
+ virtual std::string app_description() const
+ {
+ return "Resumes a failed resultion from 'cave resolve'. To enable resumes, use "
+ "'cave resolve --resume-file state' --execute, and then if errors occur, use "
+ "'cave resume --resume-file state [ --retry-failed ] [ --retry-skipped ]' to "
+ "try again.";
+ }
+ };
+
+ int perform_resolution(
+ const std::tr1::shared_ptr<Environment> & env,
+ const std::tr1::shared_ptr<ResumeData> & data,
+ const ResolveCommandLineExecutionOptions & execution_options,
+ const ResolveCommandLineProgramOptions & program_options)
+ {
+ Context context("When performing chosen resolution:");
+
+ std::tr1::shared_ptr<Sequence<std::string> > args(new Sequence<std::string>);
+
+ for (args::ArgsSection::GroupsConstIterator g(program_options.begin()), g_end(program_options.end()) ;
+ g != g_end ; ++g)
+ {
+ for (args::ArgsGroup::ConstIterator o(g->begin()), o_end(g->end()) ;
+ o != o_end ; ++o)
+ if ((*o)->specified())
+ {
+ const std::tr1::shared_ptr<const Sequence<std::string> > f((*o)->forwardable_args());
+ std::copy(f->begin(), f->end(), args->back_inserter());
+ }
+ }
+
+ for (args::ArgsSection::GroupsConstIterator g(execution_options.begin()), g_end(execution_options.end()) ;
+ g != g_end ; ++g)
+ {
+ for (args::ArgsGroup::ConstIterator o(g->begin()), o_end(g->end()) ;
+ o != o_end ; ++o)
+ if ((*o)->specified())
+ {
+ const std::tr1::shared_ptr<const Sequence<std::string> > f((*o)->forwardable_args());
+ std::copy(f->begin(), f->end(), args->back_inserter());
+ }
+ }
+
+ for (Sequence<std::string>::ConstIterator p(data->targets()->begin()),
+ p_end(data->targets()->end()) ;
+ p != p_end ; ++p)
+ args->push_back(*p);
+
+ if (data->target_set())
+ args->push_back("--set");
+
+ if (program_options.a_execute_resolution_program.specified())
+ {
+ StringListStream ser_stream;
+ Serialiser ser(ser_stream);
+ data->job_lists()->serialise(ser);
+ ser_stream.nothing_more_to_write();
+
+ std::string command;
+ if (program_options.a_execute_resolution_program.specified())
+ command = program_options.a_execute_resolution_program.argument();
+ else
+ command = "$CAVE execute-resolution";
+
+ for (Sequence<std::string>::ConstIterator a(args->begin()), a_end(args->end()) ;
+ a != a_end ; ++a)
+ command = command + " " + args::escape(*a);
+
+ paludis::Command cmd(command);
+ cmd
+ .with_input_stream(&ser_stream, -1, "PALUDIS_SERIALISED_RESOLUTION_FD");
+
+ become_command(cmd);
+ }
+ else
+ return ExecuteResolutionCommand().run(env, args, data->job_lists());
+ }
+
+ struct StateVisitor
+ {
+ bool is_active;
+ bool is_failed;
+ bool is_skipped;
+
+ StateVisitor() :
+ is_active(false),
+ is_failed(false),
+ is_skipped(false)
+ {
+ }
+
+ void visit(const JobPendingState &)
+ {
+ }
+
+ void visit(const JobSkippedState &)
+ {
+ is_skipped = true;
+ }
+
+ void visit(const JobFailedState &)
+ {
+ is_failed = true;
+ }
+
+ void visit(const JobActiveState &)
+ {
+ is_active = true;
+ }
+
+ void visit(const JobSucceededState &)
+ {
+ }
+ };
+
+ void fix_lists(
+ const std::tr1::shared_ptr<Environment> &,
+ const ResumeCommandLine & cmdline,
+ const std::tr1::shared_ptr<JobLists> & lists)
+ {
+ for (JobList<ExecuteJob>::ConstIterator c(lists->execute_job_list()->begin()),
+ c_end(lists->execute_job_list()->end()) ;
+ c != c_end ; ++c)
+ {
+ StateVisitor s;
+ if ((*c)->state())
+ (*c)->state()->accept(s);
+
+ if (s.is_active)
+ (*c)->set_state(make_shared_ptr(new JobPendingState));
+ else if (cmdline.a_retry_failed.specified() && s.is_failed)
+ (*c)->set_state(make_shared_ptr(new JobPendingState));
+ else if (cmdline.a_skip_failed.specified() && s.is_failed)
+ (*c)->set_state(make_shared_ptr(new JobSkippedState));
+ else if (cmdline.a_retry_skipped.specified() && s.is_skipped)
+ (*c)->set_state(make_shared_ptr(new JobPendingState));
+ }
+ }
+}
+
+bool
+ResumeCommand::important() const
+{
+ return true;
+}
+
+int
+ResumeCommand::run(
+ const std::tr1::shared_ptr<Environment> & env,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ )
+{
+ ResumeCommandLine cmdline;
+ cmdline.run(args, "CAVE", "CAVE_RESUME_OPTIONS", "CAVE_RESUME_CMDLINE");
+
+ if (cmdline.a_help.specified())
+ {
+ cout << cmdline;
+ return EXIT_SUCCESS;
+ }
+
+ if (! cmdline.execution_options.a_resume_file.specified())
+ throw args::DoHelp("--" + cmdline.execution_options.a_resume_file.long_name() + " must be specified");
+
+ std::tr1::shared_ptr<ResumeData> data;
+ {
+ FSEntry f(cmdline.execution_options.a_resume_file.argument());
+ if (! f.exists())
+ throw args::DoHelp("Resume file '" + stringify(f) + "' does not exist");
+ SafeIFStream deser_stream(f);
+ Deserialiser deserialiser(env.get(), deser_stream);
+ Deserialisation deserialisation("ResumeData", deserialiser);
+ data = ResumeData::deserialise(deserialisation);
+ }
+
+ fix_lists(env, cmdline, data->job_lists());
+ return perform_resolution(env, data, cmdline.execution_options, cmdline.program_options);
+}
+
+std::tr1::shared_ptr<args::ArgsHandler>
+ResumeCommand::make_doc_cmdline()
+{
+ return make_shared_ptr(new ResumeCommandLine);
+}
+
diff --git a/src/clients/cave/cmd_resume.hh b/src/clients/cave/cmd_resume.hh
new file mode 100644
index 0000000..9752940
--- /dev/null
+++ b/src/clients/cave/cmd_resume.hh
@@ -0,0 +1,46 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2010 Ciaran McCreesh
+ *
+ * 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
+ */
+
+#ifndef PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESUME_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESUME_HH 1
+
+#include "command.hh"
+#include <paludis/resolver/job_lists-fwd.hh>
+
+namespace paludis
+{
+ namespace cave
+ {
+ class PALUDIS_VISIBLE ResumeCommand :
+ public Command
+ {
+ public:
+ bool important() const;
+
+ int run(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ );
+
+ std::tr1::shared_ptr<args::ArgsHandler> make_doc_cmdline();
+ };
+ }
+}
+
+#endif
diff --git a/src/clients/cave/command_factory.cc b/src/clients/cave/command_factory.cc
index 20a8b7b..6d0a525 100644
--- a/src/clients/cave/command_factory.cc
+++ b/src/clients/cave/command_factory.cc
@@ -52,6 +52,7 @@
#include "cmd_print_sets.hh"
#include "cmd_print_sync_protocols.hh"
#include "cmd_resolve.hh"
+#include "cmd_resume.hh"
#include "cmd_search.hh"
#include "cmd_show.hh"
#include "cmd_sync.hh"
@@ -115,6 +116,7 @@ CommandFactory::CommandFactory() :
_imp->handlers.insert(std::make_pair("print-sets", std::tr1::bind(&make_command<PrintSetsCommand>)));
_imp->handlers.insert(std::make_pair("print-sync-protocols", std::tr1::bind(&make_command<PrintSyncProtocolsCommand>)));
_imp->handlers.insert(std::make_pair("resolve", std::tr1::bind(&make_command<ResolveCommand>)));
+ _imp->handlers.insert(std::make_pair("resume", std::tr1::bind(&make_command<ResumeCommand>)));
_imp->handlers.insert(std::make_pair("search", std::tr1::bind(&make_command<SearchCommand>)));
_imp->handlers.insert(std::make_pair("show", std::tr1::bind(&make_command<ShowCommand>)));
_imp->handlers.insert(std::make_pair("sync", std::tr1::bind(&make_command<SyncCommand>)));
diff --git a/src/clients/cave/resume_data.cc b/src/clients/cave/resume_data.cc
new file mode 100644
index 0000000..1609c8b
--- /dev/null
+++ b/src/clients/cave/resume_data.cc
@@ -0,0 +1,66 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2010 Ciaran McCreesh
+ *
+ * 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 "resume_data.hh"
+#include <paludis/args/do_help.hh>
+#include <paludis/util/sequence.hh>
+#include <paludis/util/make_named_values.hh>
+#include <paludis/util/make_shared_copy.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/wrapped_forward_iterator.hh>
+#include <paludis/resolver/job_lists.hh>
+#include <paludis/serialise-impl.hh>
+#include <paludis/about.hh>
+
+using namespace paludis;
+using namespace paludis::resolver;
+using namespace cave;
+
+const std::tr1::shared_ptr<ResumeData>
+ResumeData::deserialise(Deserialisation & d)
+{
+ if (d.class_name() != "ResumeData@" + stringify(PALUDIS_VERSION))
+ throw args::DoHelp("Resume file was created using a different version of Paludis, and cannot be used");
+
+ Deserialisator v(d, "ResumeData@" + stringify(PALUDIS_VERSION));
+
+ std::tr1::shared_ptr<Sequence<std::string> > targets(new Sequence<std::string>);
+ {
+ Deserialisator vv(*v.find_remove_member("targets"), "c");
+ for (int n(1), n_end(vv.member<int>("count") + 1) ; n != n_end ; ++n)
+ targets->push_back(vv.member<std::string>(stringify(n)));
+ }
+
+ return make_shared_copy(make_named_values<ResumeData>(
+ n::job_lists() = v.member<std::tr1::shared_ptr<JobLists> >("job_lists"),
+ n::target_set() = v.member<bool>("target_set"),
+ n::targets() = targets
+ ));
+}
+
+void
+ResumeData::serialise(Serialiser & s) const
+{
+ s.object("ResumeData@" + stringify(PALUDIS_VERSION))
+ .member(SerialiserFlags<serialise::might_be_null>(), "job_lists", job_lists())
+ .member(SerialiserFlags<>(), "target_set", target_set())
+ .member(SerialiserFlags<serialise::might_be_null, serialise::container>(), "targets", targets())
+ ;
+}
+
diff --git a/src/clients/cave/resume_data.hh b/src/clients/cave/resume_data.hh
new file mode 100644
index 0000000..fcf3cf2
--- /dev/null
+++ b/src/clients/cave/resume_data.hh
@@ -0,0 +1,53 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2010 Ciaran McCreesh
+ *
+ * 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
+ */
+
+#ifndef PALUDIS_GUARD_SRC_CLIENTS_CAVE_RESUME_DATA_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_RESUME_DATA_HH 1
+
+#include <paludis/util/named_value.hh>
+#include <paludis/util/sequence-fwd.hh>
+#include <paludis/resolver/job_lists-fwd.hh>
+#include <paludis/serialise-fwd.hh>
+#include <tr1/memory>
+
+namespace paludis
+{
+ namespace n
+ {
+ typedef Name<struct job_lists_name> job_lists;
+ typedef Name<struct target_set_name> target_set;
+ typedef Name<struct targets_name> targets;
+ }
+
+ namespace cave
+ {
+ struct ResumeData
+ {
+ NamedValue<n::job_lists, std::tr1::shared_ptr<resolver::JobLists> > job_lists;
+ NamedValue<n::target_set, bool> target_set;
+ NamedValue<n::targets, std::tr1::shared_ptr<Sequence<std::string> > > targets;
+
+ void serialise(Serialiser &) const;
+ static const std::tr1::shared_ptr<ResumeData> deserialise(
+ Deserialisation & d) PALUDIS_ATTRIBUTE((warn_unused_result));
+ };
+ }
+}
+
+#endif