aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-03-14 10:20:39 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-03-14 10:20:39 +0000
commitff9499df3dbefcfb0073b5585f4598ad1d07b42b (patch)
tree3fe42068f2c410ce27188ddcae5547ebf5656bc0
parent53642f3b30c6f4d9a1817db6be749f3e02b6608b (diff)
parent1e54e142347c54f45cd2a2d17bc0d817895058d2 (diff)
downloadpaludis-ff9499df3dbefcfb0073b5585f4598ad1d07b42b.tar.gz
paludis-ff9499df3dbefcfb0073b5585f4598ad1d07b42b.tar.xz
Merge branch 'cave-search'
-rw-r--r--src/clients/cave/Makefile.am6
-rw-r--r--src/clients/cave/cmd_find_candidates.cc208
-rw-r--r--src/clients/cave/cmd_find_candidates.hh55
-rw-r--r--src/clients/cave/cmd_match.cc385
-rw-r--r--src/clients/cave/cmd_match.hh53
-rw-r--r--src/clients/cave/cmd_search.cc308
-rw-r--r--src/clients/cave/cmd_search.hh45
-rw-r--r--src/clients/cave/cmd_search_cmdline.cc55
-rw-r--r--src/clients/cave/cmd_search_cmdline.hh58
-rw-r--r--src/clients/cave/command_factory.cc6
10 files changed, 1179 insertions, 0 deletions
diff --git a/src/clients/cave/Makefile.am b/src/clients/cave/Makefile.am
index 4a1e303..760f21b 100644
--- a/src/clients/cave/Makefile.am
+++ b/src/clients/cave/Makefile.am
@@ -21,6 +21,7 @@ command_MANS = \
cave-config.1 \
cave-display-resolution.1 \
cave-execute-resolution.1 \
+ cave-find-candidates.1 \
cave-fix-cache.1 \
cave-help.1 \
cave-import.1 \
@@ -40,6 +41,7 @@ command_MANS = \
cave-print-sets.1 \
cave-print-sync-protocols.1 \
cave-resolve.1 \
+ cave-search.1 \
cave-show.1 \
cave-sync.1 \
cave-update-world.1
@@ -88,10 +90,12 @@ libcave_a_SOURCES = \
cmd_config.cc cmd_config.hh \
cmd_display_resolution.cc cmd_display_resolution.hh \
cmd_execute_resolution.cc cmd_execute_resolution.hh \
+ cmd_find_candidates.cc cmd_find_candidates.hh \
cmd_fix_cache.cc cmd_fix_cache.hh \
cmd_help.cc cmd_help.hh \
cmd_import.cc cmd_import.hh \
cmd_info.cc cmd_info.hh \
+ cmd_match.cc cmd_match.hh \
cmd_perform.cc cmd_perform.hh \
cmd_print_categories.cc cmd_print_categories.hh \
cmd_print_commands.cc cmd_print_commands.hh \
@@ -110,6 +114,8 @@ 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_search.cc cmd_search.hh \
+ cmd_search_cmdline.cc cmd_search_cmdline.hh \
cmd_show.cc cmd_show.hh \
cmd_sync.cc cmd_sync.hh \
cmd_update_world.cc cmd_update_world.hh \
diff --git a/src/clients/cave/cmd_find_candidates.cc b/src/clients/cave/cmd_find_candidates.cc
new file mode 100644
index 0000000..840ff2a
--- /dev/null
+++ b/src/clients/cave/cmd_find_candidates.cc
@@ -0,0 +1,208 @@
+/* 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_find_candidates.hh"
+#include <paludis/args/args.hh>
+#include <paludis/args/do_help.hh>
+#include <paludis/name.hh>
+#include <paludis/environment.hh>
+#include <paludis/package_database.hh>
+#include <paludis/repository.hh>
+#include <paludis/util/set.hh>
+#include <paludis/util/wrapped_forward_iterator.hh>
+#include <paludis/util/wrapped_output_iterator.hh>
+#include <paludis/util/make_shared_ptr.hh>
+#include <paludis/util/indirect_iterator-impl.hh>
+#include <paludis/util/simple_visitor_cast.hh>
+#include <paludis/generator.hh>
+#include <paludis/filtered_generator.hh>
+#include <paludis/filter.hh>
+#include <paludis/filter_handler.hh>
+#include <paludis/selection.hh>
+#include <paludis/user_dep_spec.hh>
+#include <paludis/package_id.hh>
+#include <paludis/mask.hh>
+#include <cstdlib>
+#include <iostream>
+#include <algorithm>
+#include <set>
+
+#include "command_command_line.hh"
+
+using namespace paludis;
+using namespace cave;
+using std::cout;
+using std::endl;
+
+namespace
+{
+ struct FindCandidatesCommandLine :
+ CaveCommandCommandLine
+ {
+ virtual std::string app_name() const
+ {
+ return "cave find-candidates";
+ }
+
+ virtual std::string app_synopsis() const
+ {
+ return "Find a list of candidate packages for a search.";
+ }
+
+ virtual std::string app_description() const
+ {
+ return "Finds a list of candidate packages for a search. Used by 'cave search'; not generally called "
+ "directly by end users. Note that this command will often select candidates that do not actually "
+ "match some of the supplied restrictions; use 'cave match' to obtain accurate results.";
+ }
+
+ SearchCommandLineCandidateOptions search_options;
+ SearchCommandLineMatchOptions match_options;
+
+ FindCandidatesCommandLine() :
+ search_options(this),
+ match_options(this)
+ {
+ }
+ };
+
+ void print_spec(const PackageDepSpec & spec)
+ {
+ cout << spec << endl;
+ }
+
+ void no_step(const std::string &)
+ {
+ }
+}
+
+int
+FindCandidatesCommand::run(
+ const std::tr1::shared_ptr<Environment> & env,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ )
+{
+ FindCandidatesCommandLine cmdline;
+ cmdline.run(args, "CAVE", "CAVE_FIND_CANDIDATES_OPTIONS", "CAVE_FIND_CANDIDATES_CMDLINE");
+
+ if (cmdline.a_help.specified())
+ {
+ cout << cmdline;
+ return EXIT_SUCCESS;
+ }
+
+ if (cmdline.begin_parameters() == cmdline.end_parameters())
+ throw args::DoHelp("find-candidates requires at least one parameter");
+
+ const std::tr1::shared_ptr<Set<std::string> > patterns(new Set<std::string>);
+ std::copy(cmdline.begin_parameters(), cmdline.end_parameters(), patterns->inserter());
+
+ run_hosted(env, cmdline.search_options, cmdline.match_options, patterns, &print_spec, &no_step);
+
+ return EXIT_SUCCESS;
+}
+
+typedef std::set<RepositoryName, RepositoryNameComparator> RepositoryNames;
+typedef std::set<CategoryNamePart> CategoryNames;
+typedef std::set<QualifiedPackageName> QualifiedPackageNames;
+
+void
+FindCandidatesCommand::run_hosted(
+ const std::tr1::shared_ptr<Environment> & env,
+ const SearchCommandLineCandidateOptions & search_options,
+ const SearchCommandLineMatchOptions &,
+ const std::tr1::shared_ptr<const Set<std::string> > &,
+ const std::tr1::function<void (const PackageDepSpec &)> & yield,
+ const std::tr1::function<void (const std::string &)> & step)
+{
+ step("Searching repositories");
+
+ RepositoryNames repository_names;
+ for (PackageDatabase::RepositoryConstIterator r(env->package_database()->begin_repositories()),
+ r_end(env->package_database()->end_repositories()) ; r != r_end ; ++r)
+ repository_names.insert((*r)->name());
+
+ step("Searching categories");
+
+ CategoryNames category_names;
+ for (RepositoryNames::const_iterator r(repository_names.begin()), r_end(repository_names.end()) ;
+ r != r_end ; ++r)
+ {
+ const std::tr1::shared_ptr<const Repository> repo(env->package_database()->fetch_repository(*r));
+ const std::tr1::shared_ptr<const CategoryNamePartSet> cats(repo->category_names());
+ std::copy(cats->begin(), cats->end(), std::inserter(category_names, category_names.end()));
+ }
+
+ step("Searching packages");
+
+ QualifiedPackageNames package_names;
+ for (RepositoryNames::const_iterator r(repository_names.begin()), r_end(repository_names.end()) ;
+ r != r_end ; ++r)
+ {
+ const std::tr1::shared_ptr<const Repository> repo(env->package_database()->fetch_repository(*r));
+ for (CategoryNames::const_iterator c(category_names.begin()), c_end(category_names.end()) ;
+ c != c_end ; ++c)
+ {
+ const std::tr1::shared_ptr<const QualifiedPackageNameSet> qpns(repo->package_names(*c));
+ std::copy(qpns->begin(), qpns->end(), std::inserter(package_names, package_names.end()));
+ }
+ }
+
+ step("Searching versions");
+
+ for (QualifiedPackageNames::const_iterator q(package_names.begin()), q_end(package_names.end()) ;
+ q != q_end ; ++q)
+ {
+ if (search_options.a_all_versions.specified())
+ {
+ const std::tr1::shared_ptr<const PackageIDSequence> ids((*env)[selection::AllVersionsUnsorted(
+ generator::Package(*q))]);
+ for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ;
+ i != i_end ; ++i)
+ {
+ step("Checking candidates");
+ yield((*i)->uniquely_identifying_spec());
+ }
+ }
+ else
+ {
+ std::tr1::shared_ptr<const PackageIDSequence> ids;
+
+ ids = ((*env)[selection::BestVersionOnly(generator::Package(*q) | filter::SupportsAction<InstallAction>() | filter::NotMasked())]);
+ if (ids->empty())
+ ids = ((*env)[selection::BestVersionOnly(generator::Package(*q) | filter::SupportsAction<InstallAction>())]);
+ if (ids->empty())
+ ids = ((*env)[selection::BestVersionOnly(generator::Package(*q))]);
+
+ for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ;
+ i != i_end ; ++i)
+ {
+ step("Checking candidates");
+ yield((*i)->uniquely_identifying_spec());
+ }
+ }
+ }
+}
+
+std::tr1::shared_ptr<args::ArgsHandler>
+FindCandidatesCommand::make_doc_cmdline()
+{
+ return make_shared_ptr(new FindCandidatesCommandLine);
+}
+
diff --git a/src/clients/cave/cmd_find_candidates.hh b/src/clients/cave/cmd_find_candidates.hh
new file mode 100644
index 0000000..c03dcce
--- /dev/null
+++ b/src/clients/cave/cmd_find_candidates.hh
@@ -0,0 +1,55 @@
+/* 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_FIND_CANDIDATES_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_FIND_CANDIDATES_HH 1
+
+#include "command.hh"
+#include "cmd_search_cmdline.hh"
+#include <paludis/dep_spec-fwd.hh>
+#include <paludis/util/set-fwd.hh>
+#include <tr1/functional>
+
+namespace paludis
+{
+ namespace cave
+ {
+ class PALUDIS_VISIBLE FindCandidatesCommand :
+ public Command
+ {
+ public:
+ int run(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ );
+
+ void run_hosted(
+ const std::tr1::shared_ptr<Environment> &,
+ const SearchCommandLineCandidateOptions &,
+ const SearchCommandLineMatchOptions &,
+ const std::tr1::shared_ptr<const Set<std::string> > &,
+ const std::tr1::function<void (const PackageDepSpec &)> &,
+ const std::tr1::function<void (const std::string &)> &);
+
+ std::tr1::shared_ptr<args::ArgsHandler> make_doc_cmdline();
+ };
+ }
+}
+
+#endif
diff --git a/src/clients/cave/cmd_match.cc b/src/clients/cave/cmd_match.cc
new file mode 100644
index 0000000..c236a61
--- /dev/null
+++ b/src/clients/cave/cmd_match.cc
@@ -0,0 +1,385 @@
+/* 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_match.hh"
+#include <paludis/args/args.hh>
+#include <paludis/args/do_help.hh>
+#include <paludis/name.hh>
+#include <paludis/environment.hh>
+#include <paludis/package_database.hh>
+#include <paludis/repository.hh>
+#include <paludis/util/set.hh>
+#include <paludis/util/wrapped_forward_iterator.hh>
+#include <paludis/util/wrapped_output_iterator.hh>
+#include <paludis/util/make_shared_ptr.hh>
+#include <paludis/util/indirect_iterator-impl.hh>
+#include <paludis/util/simple_visitor_cast.hh>
+#include <paludis/util/iterator_funcs.hh>
+#include <paludis/generator.hh>
+#include <paludis/filtered_generator.hh>
+#include <paludis/filter.hh>
+#include <paludis/filter_handler.hh>
+#include <paludis/selection.hh>
+#include <paludis/user_dep_spec.hh>
+#include <paludis/package_id.hh>
+#include <paludis/mask.hh>
+#include <paludis/metadata_key.hh>
+#include <cstdlib>
+#include <iostream>
+#include <algorithm>
+#include <list>
+#include <string.h>
+
+#include "command_command_line.hh"
+
+using namespace paludis;
+using namespace cave;
+using std::cout;
+using std::endl;
+
+namespace
+{
+ struct MatchCommandLine :
+ CaveCommandCommandLine
+ {
+ virtual std::string app_name() const
+ {
+ return "cave match";
+ }
+
+ virtual std::string app_synopsis() const
+ {
+ return "Determine whether a particular package version has certain properties";
+ }
+
+ virtual std::string app_description() const
+ {
+ return "Determines whether a particular package version has certain properties. Mostly for "
+ "use by 'cave search'; not generally for use by end users.";
+ }
+
+ SearchCommandLineMatchOptions match_options;
+
+ MatchCommandLine() :
+ match_options(this)
+ {
+ add_usage_line("spec [ pattern ... ]");
+ }
+ };
+
+ bool match_text(const std::string & text, const std::string & pattern)
+ {
+ return 0 != strcasestr(text.c_str(), pattern.c_str());
+ }
+
+ bool match_exact(const std::string & text, const std::string & pattern)
+ {
+ return 0 == strcasecmp(text.c_str(), pattern.c_str());
+ }
+
+ bool match(const std::string & text, const std::string & pattern, const std::string & algorithm)
+ {
+ if (algorithm == "text")
+ return match_text(text, pattern);
+ else if (algorithm == "exact")
+ return match_exact(text, pattern);
+ else
+ throw args::DoHelp("Unknown algoritm '" + algorithm + "'");
+ }
+
+ struct SpecTreeAsString
+ {
+ std::list<std::string> & texts;
+
+ void visit(const GenericSpecTree::NodeType<AllDepSpec>::Type & node)
+ {
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
+ }
+
+ void visit(const GenericSpecTree::NodeType<ConditionalDepSpec>::Type & node)
+ {
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
+ }
+
+ void visit(const GenericSpecTree::NodeType<AnyDepSpec>::Type & node)
+ {
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
+ }
+
+ void visit(const GenericSpecTree::NodeType<SimpleURIDepSpec>::Type & node)
+ {
+ texts.push_back(stringify(*node.spec()));
+ }
+
+ void visit(const GenericSpecTree::NodeType<URILabelsDepSpec>::Type & node)
+ {
+ texts.push_back(stringify(*node.spec()));
+ }
+
+ void visit(const GenericSpecTree::NodeType<PlainTextDepSpec>::Type & node)
+ {
+ texts.push_back(stringify(*node.spec()));
+ }
+
+ void visit(const GenericSpecTree::NodeType<FetchableURIDepSpec>::Type & node)
+ {
+ texts.push_back(stringify(*node.spec()));
+ }
+
+ void visit(const GenericSpecTree::NodeType<PackageDepSpec>::Type & node)
+ {
+ texts.push_back(stringify(*node.spec()));
+ }
+
+ void visit(const GenericSpecTree::NodeType<BlockDepSpec>::Type & node)
+ {
+ texts.push_back(stringify(*node.spec()));
+ }
+
+ void visit(const GenericSpecTree::NodeType<LicenseDepSpec>::Type & node)
+ {
+ texts.push_back(stringify(*node.spec()));
+ }
+
+ void visit(const GenericSpecTree::NodeType<PlainTextLabelDepSpec>::Type & node)
+ {
+ texts.push_back(stringify(*node.spec()));
+ }
+
+ void visit(const GenericSpecTree::NodeType<DependenciesLabelsDepSpec>::Type & node)
+ {
+ texts.push_back(stringify(*node.spec()));
+ }
+
+ void visit(const GenericSpecTree::NodeType<NamedSetDepSpec>::Type & node)
+ {
+ texts.push_back(stringify(*node.spec()));
+ }
+ };
+
+ struct MetadataKeyAsString
+ {
+ std::list<std::string> & texts;
+
+ void visit(const MetadataValueKey<std::string> & k)
+ {
+ texts.push_back(stringify(k.value()));
+ }
+
+ void visit(const MetadataValueKey<FSEntry> & k)
+ {
+ texts.push_back(stringify(k.value()));
+ }
+
+ void visit(const MetadataValueKey<SlotName> & k)
+ {
+ texts.push_back(stringify(k.value()));
+ }
+
+ void visit(const MetadataValueKey<long> & k)
+ {
+ texts.push_back(stringify(k.value()));
+ }
+
+ void visit(const MetadataValueKey<bool> & k)
+ {
+ texts.push_back(stringify(k.value()));
+ }
+
+ void visit(const MetadataValueKey<std::tr1::shared_ptr<const PackageID> > & k)
+ {
+ texts.push_back(stringify(*k.value()));
+ }
+
+ void visit(const MetadataValueKey<std::tr1::shared_ptr<const Choices> > &)
+ {
+ }
+
+ void visit(const MetadataValueKey<std::tr1::shared_ptr<const RepositoryMaskInfo> > &)
+ {
+ }
+
+ void visit(const MetadataValueKey<std::tr1::shared_ptr<const Contents> > &)
+ {
+ }
+
+ void visit(const MetadataTimeKey & k)
+ {
+ texts.push_back(stringify(k.value().seconds()));
+ }
+
+ void visit(const MetadataSectionKey & k)
+ {
+ std::for_each(indirect_iterator(k.begin_metadata()), indirect_iterator(k.end_metadata()),
+ accept_visitor(*this));
+ }
+
+ void visit(const MetadataSpecTreeKey<PlainTextSpecTree> & k)
+ {
+ SpecTreeAsString m = { texts };
+ k.value()->root()->accept(m);
+ }
+
+ void visit(const MetadataSpecTreeKey<DependencySpecTree> & k)
+ {
+ SpecTreeAsString m = { texts };
+ k.value()->root()->accept(m);
+ }
+
+ void visit(const MetadataSpecTreeKey<LicenseSpecTree> & k)
+ {
+ SpecTreeAsString m = { texts };
+ k.value()->root()->accept(m);
+ }
+
+ void visit(const MetadataSpecTreeKey<ProvideSpecTree> & k)
+ {
+ SpecTreeAsString m = { texts };
+ k.value()->root()->accept(m);
+ }
+
+ void visit(const MetadataSpecTreeKey<SimpleURISpecTree> & k)
+ {
+ SpecTreeAsString m = { texts };
+ k.value()->root()->accept(m);
+ }
+
+ void visit(const MetadataSpecTreeKey<FetchableURISpecTree> & k)
+ {
+ SpecTreeAsString m = { texts };
+ k.value()->root()->accept(m);
+ }
+
+ void visit(const MetadataCollectionKey<Sequence<FSEntry> > & k)
+ {
+ std::transform(k.value()->begin(), k.value()->end(), std::back_inserter(texts), &stringify<FSEntry>);
+ }
+
+ void visit(const MetadataCollectionKey<Sequence<std::string> > & k)
+ {
+ std::transform(k.value()->begin(), k.value()->end(), std::back_inserter(texts), &stringify<std::string>);
+ }
+
+ void visit(const MetadataCollectionKey<Set<std::string> > & k)
+ {
+ std::transform(k.value()->begin(), k.value()->end(), std::back_inserter(texts), &stringify<std::string>);
+ }
+
+ void visit(const MetadataCollectionKey<Set<KeywordName> > & k)
+ {
+ std::transform(k.value()->begin(), k.value()->end(), std::back_inserter(texts), &stringify<KeywordName>);
+ }
+
+ void visit(const MetadataCollectionKey<Sequence<std::tr1::shared_ptr<const PackageID> > > & k)
+ {
+ std::transform(indirect_iterator(k.value()->begin()), indirect_iterator(k.value()->end()),
+ std::back_inserter(texts), &stringify<PackageID>);
+ }
+
+ };
+}
+
+int
+MatchCommand::run(
+ const std::tr1::shared_ptr<Environment> & env,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ )
+{
+ MatchCommandLine cmdline;
+ cmdline.run(args, "CAVE", "CAVE_MATCH_OPTIONS", "CAVE_MATCH_CMDLINE");
+
+ if (cmdline.a_help.specified())
+ {
+ cout << cmdline;
+ return EXIT_SUCCESS;
+ }
+
+ if (cmdline.begin_parameters() == cmdline.end_parameters())
+ throw args::DoHelp("match requires at least one parameter");
+
+ PackageDepSpec spec(parse_user_package_dep_spec(*cmdline.begin_parameters(), env.get(), UserPackageDepSpecOptions()));
+
+ const std::tr1::shared_ptr<Set<std::string> > patterns(new Set<std::string>);
+ std::copy(next(cmdline.begin_parameters()), cmdline.end_parameters(), patterns->inserter());
+
+ return run_hosted(env, cmdline.match_options, patterns, spec) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+bool
+MatchCommand::run_hosted(
+ const std::tr1::shared_ptr<Environment> & env,
+ const SearchCommandLineMatchOptions & match_options,
+ const std::tr1::shared_ptr<const Set<std::string> > & patterns,
+ const PackageDepSpec & spec)
+{
+ const std::tr1::shared_ptr<const PackageID> id(*((*env)[selection::RequireExactlyOne(
+ generator::Matches(spec, MatchPackageOptions()))])->begin());
+
+ std::list<std::string> texts;
+
+ bool default_names_and_descriptions((! match_options.a_name.specified()) &&
+ (! match_options.a_description.specified()) && (! match_options.a_key.specified()));
+
+ if (default_names_and_descriptions || match_options.a_name.specified())
+ texts.push_back(stringify(id->name()));
+
+ if (default_names_and_descriptions || match_options.a_description.specified())
+ {
+ if (id->short_description_key())
+ texts.push_back(stringify(id->short_description_key()->value()));
+ if (id->long_description_key())
+ texts.push_back(stringify(id->long_description_key()->value()));
+ }
+
+ for (args::StringSetArg::ConstIterator a(match_options.a_key.begin_args()),
+ a_end(match_options.a_key.end_args()) ;
+ a != a_end ; ++a)
+ {
+ PackageID::MetadataConstIterator i(id->find_metadata(*a));
+ if (i == id->end_metadata())
+ continue;
+
+ MetadataKeyAsString m = { texts };
+ (*i)->accept(m);
+ }
+
+ bool any(false), all(true), none(true);;
+ for (std::list<std::string>::const_iterator t(texts.begin()), t_end(texts.end()) ;
+ t != t_end ; ++t)
+ {
+ bool current(patterns->end() != std::find_if(patterns->begin(), patterns->end(),
+ std::tr1::bind(&match, *t, std::tr1::placeholders::_1, match_options.a_type.argument())));
+
+ if (match_options.a_not.specified())
+ current = ! current;
+
+ any = any || current;
+ all = all && current;
+ none = false;
+ }
+
+ return match_options.a_and.specified() ? all : (any || none);
+}
+
+std::tr1::shared_ptr<args::ArgsHandler>
+MatchCommand::make_doc_cmdline()
+{
+ return make_shared_ptr(new MatchCommandLine);
+}
+
diff --git a/src/clients/cave/cmd_match.hh b/src/clients/cave/cmd_match.hh
new file mode 100644
index 0000000..91079fb
--- /dev/null
+++ b/src/clients/cave/cmd_match.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_CMD_MATCH_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_MATCH_HH 1
+
+#include "command.hh"
+#include "cmd_search_cmdline.hh"
+#include <paludis/dep_spec-fwd.hh>
+#include <paludis/util/set-fwd.hh>
+#include <tr1/functional>
+
+namespace paludis
+{
+ namespace cave
+ {
+ class PALUDIS_VISIBLE MatchCommand :
+ public Command
+ {
+ public:
+ int run(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ );
+
+ bool run_hosted(
+ const std::tr1::shared_ptr<Environment> &,
+ const SearchCommandLineMatchOptions &,
+ const std::tr1::shared_ptr<const Set<std::string> > &,
+ const PackageDepSpec &);
+
+ std::tr1::shared_ptr<args::ArgsHandler> make_doc_cmdline();
+ };
+ }
+}
+
+#endif
diff --git a/src/clients/cave/cmd_search.cc b/src/clients/cave/cmd_search.cc
new file mode 100644
index 0000000..68da483
--- /dev/null
+++ b/src/clients/cave/cmd_search.cc
@@ -0,0 +1,308 @@
+/* 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_search.hh"
+#include "cmd_search_cmdline.hh"
+#include "cmd_find_candidates.hh"
+#include "cmd_match.hh"
+#include "cmd_show.hh"
+#include <paludis/args/args.hh>
+#include <paludis/args/do_help.hh>
+#include <paludis/name.hh>
+#include <paludis/environment.hh>
+#include <paludis/package_database.hh>
+#include <paludis/repository.hh>
+#include <paludis/user_dep_spec.hh>
+#include <paludis/filter.hh>
+#include <paludis/generator.hh>
+#include <paludis/filtered_generator.hh>
+#include <paludis/selection.hh>
+#include <paludis/package_id.hh>
+#include <paludis/metadata_key.hh>
+#include <paludis/util/set.hh>
+#include <paludis/util/wrapped_forward_iterator.hh>
+#include <paludis/util/make_shared_ptr.hh>
+#include <paludis/util/indirect_iterator-impl.hh>
+#include <paludis/util/wrapped_output_iterator.hh>
+#include <paludis/util/mutex.hh>
+#include <paludis/action.hh>
+#include <paludis/mask.hh>
+#include <paludis/choice.hh>
+#include <paludis/notifier_callback.hh>
+#include <cstdlib>
+#include <iostream>
+#include <algorithm>
+#include <set>
+#include <map>
+
+#include "command_command_line.hh"
+
+using namespace paludis;
+using namespace cave;
+using std::cout;
+using std::endl;
+
+namespace
+{
+ struct SearchCommandLine :
+ CaveCommandCommandLine
+ {
+ virtual std::string app_name() const
+ {
+ return "cave search";
+ }
+
+ virtual std::string app_synopsis() const
+ {
+ return "Search for packages with particular characteristics.";
+ }
+
+ virtual std::string app_description() const
+ {
+ return "Searches for packages with particular characteristics.";
+ }
+
+ SearchCommandLineCandidateOptions search_options;
+ SearchCommandLineMatchOptions match_options;
+
+ SearchCommandLine() :
+ search_options(this),
+ match_options(this)
+ {
+ add_usage_line("[ --name | --description | --key HOMEPAGE ] pattern ...");
+ }
+ };
+
+ struct SearchStep
+ {
+ std::string stage;
+
+ SearchStep(const std::string & s) :
+ stage(s)
+ {
+ }
+ };
+
+ void found_match(
+ const std::tr1::shared_ptr<Environment> & env,
+ const std::tr1::shared_ptr<Set<QualifiedPackageName> > & result,
+ const PackageDepSpec & spec)
+ {
+ const std::tr1::shared_ptr<const PackageID> id(*((*env)[selection::RequireExactlyOne(
+ generator::Matches(spec, MatchPackageOptions()))])->begin());
+ result->insert(id->name());
+ }
+
+ void found_candidate(
+ const std::tr1::shared_ptr<Environment> & env,
+ MatchCommand & match_command,
+ const SearchCommandLineMatchOptions & match_options,
+ const PackageDepSpec & spec,
+ const std::tr1::shared_ptr<const Set<std::string> > & patterns,
+ const std::tr1::function<void (const PackageDepSpec &)> & success
+ )
+ {
+ if (match_command.run_hosted(env, match_options, patterns, spec))
+ success(spec);
+ }
+
+ struct DisplayCallback
+ {
+ mutable Mutex mutex;
+ mutable std::map<std::string, int> metadata;
+ mutable int steps;
+ mutable std::string stage;
+ mutable unsigned width;
+
+ bool output;
+
+ DisplayCallback() :
+ steps(0),
+ stage("Searching"),
+ width(stage.length() + 2),
+ output(::isatty(1))
+ {
+ if (output)
+ cout << stage << ": " << std::flush;
+ }
+
+ ~DisplayCallback()
+ {
+ if (output)
+ cout << endl << endl;
+ }
+
+ void update() const
+ {
+ if (! output)
+ return;
+
+ std::string s(stage + ": ");
+ s.append(stringify(steps));
+
+ if (! metadata.empty())
+ {
+ std::multimap<int, std::string> biggest;
+ for (std::map<std::string, int>::const_iterator i(metadata.begin()), i_end(metadata.end()) ;
+ i != i_end ; ++i)
+ biggest.insert(std::make_pair(i->second, i->first));
+
+ int t(0), n(0);
+ std::string ss;
+ for (std::multimap<int, std::string>::const_reverse_iterator i(biggest.rbegin()), i_end(biggest.rend()) ;
+ i != i_end ; ++i)
+ {
+ ++n;
+
+ if (n == 4)
+ ss.append(", ...");
+
+ if (n < 4)
+ {
+ if (! ss.empty())
+ ss.append(", ");
+
+ ss.append(stringify(i->first) + " " + i->second);
+ }
+
+ t += i->first;
+ }
+
+ if (! s.empty())
+ s.append(", ");
+ s.append(stringify(t) + " metadata (" + ss + ") ");
+ }
+
+ std::cout << std::string(width, '\010') << s;
+
+ if (width > s.length())
+ std::cout
+ << std::string(width - s.length(), ' ')
+ << std::string(width - s.length(), '\010');
+
+ width = s.length();
+ std::cout << std::flush;
+ }
+
+ void operator() (const NotifierCallbackEvent & event) const
+ {
+ event.accept(*this);
+ }
+
+ void operator() (const SearchStep & s) const
+ {
+ if (! output)
+ return;
+
+ Lock lock(mutex);
+ ++steps;
+ stage = s.stage;
+ update();
+ }
+
+ void visit(const NotifierCallbackGeneratingMetadataEvent & e) const
+ {
+ if (! output)
+ return;
+
+ Lock lock(mutex);
+ ++metadata.insert(std::make_pair(stringify(e.repository()), 0)).first->second;
+ update();
+ }
+
+ void visit(const NotifierCallbackResolverStepEvent &) const
+ {
+ }
+
+ void visit(const NotifierCallbackResolverStageEvent &) const
+ {
+ }
+ };
+
+ void step(DisplayCallback & display_callback, const std::string & s)
+ {
+ display_callback(SearchStep(s));
+ }
+}
+
+bool
+SearchCommand::important() const
+{
+ return true;
+}
+
+int
+SearchCommand::run(
+ const std::tr1::shared_ptr<Environment> & env,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ )
+{
+ SearchCommandLine cmdline;
+ cmdline.run(args, "CAVE", "CAVE_SEARCH_OPTIONS", "CAVE_SEARCH_CMDLINE");
+
+ if (cmdline.a_help.specified())
+ {
+ cout << cmdline;
+ return EXIT_SUCCESS;
+ }
+
+ if (cmdline.begin_parameters() == cmdline.end_parameters())
+ throw args::DoHelp("search requires at least one parameter");
+
+ const std::tr1::shared_ptr<Sequence<std::string> > show_args(new Sequence<std::string>);
+
+ {
+ DisplayCallback display_callback;
+ ScopedNotifierCallback display_callback_holder(env.get(),
+ NotifierCallbackFunction(std::tr1::cref(display_callback)));
+
+ const std::tr1::shared_ptr<Set<std::string> > patterns(new Set<std::string>);
+ std::copy(cmdline.begin_parameters(), cmdline.end_parameters(), patterns->inserter());
+
+ FindCandidatesCommand find_candidates_command;
+ MatchCommand match_command;
+
+ std::tr1::shared_ptr<Set<QualifiedPackageName> > matches(new Set<QualifiedPackageName>);
+ find_candidates_command.run_hosted(env, cmdline.search_options, cmdline.match_options,
+ patterns, std::tr1::bind(
+ &found_candidate, env, std::tr1::ref(match_command), std::tr1::cref(cmdline.match_options),
+ std::tr1::placeholders::_1, patterns, std::tr1::function<void (const PackageDepSpec &)>(std::tr1::bind(
+ &found_match, env, std::tr1::ref(matches), std::tr1::placeholders::_1
+ ))),
+ std::tr1::bind(&step, std::tr1::ref(display_callback), std::tr1::placeholders::_1)
+ );
+
+ for (Set<QualifiedPackageName>::ConstIterator p(matches->begin()), p_end(matches->end()) ;
+ p != p_end ; ++p)
+ show_args->push_back(stringify(*p));
+ }
+
+ if (show_args->empty())
+ return EXIT_FAILURE;
+
+ ShowCommand show_command;
+ return show_command.run(env, show_args);
+}
+
+std::tr1::shared_ptr<args::ArgsHandler>
+SearchCommand::make_doc_cmdline()
+{
+ return make_shared_ptr(new SearchCommandLine);
+}
+
diff --git a/src/clients/cave/cmd_search.hh b/src/clients/cave/cmd_search.hh
new file mode 100644
index 0000000..4b49061
--- /dev/null
+++ b/src/clients/cave/cmd_search.hh
@@ -0,0 +1,45 @@
+/* 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_SEARCH_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_SEARCH_HH 1
+
+#include "command.hh"
+
+namespace paludis
+{
+ namespace cave
+ {
+ class PALUDIS_VISIBLE SearchCommand :
+ 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/cmd_search_cmdline.cc b/src/clients/cave/cmd_search_cmdline.cc
new file mode 100644
index 0000000..e861f53
--- /dev/null
+++ b/src/clients/cave/cmd_search_cmdline.cc
@@ -0,0 +1,55 @@
+/* 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_search_cmdline.hh"
+
+using namespace paludis;
+using namespace cave;
+
+SearchCommandLineCandidateOptions::SearchCommandLineCandidateOptions(args::ArgsHandler * const h) :
+ ArgsSection(h, "Search Candidate Options"),
+ g_candidate_options(this, "Candidate Options", "Control which packages and versions are selected as "
+ "candidates for matching."),
+ a_all_versions(&g_candidate_options, "all-versions", 'a', "Search in every version of packages", true)
+{
+}
+
+SearchCommandLineMatchOptions::SearchCommandLineMatchOptions(args::ArgsHandler * const h) :
+ ArgsSection(h, "Match Options"),
+ g_pattern_options(this, "Pattern Options", "Alter how patterns are matched."),
+ a_type(&g_pattern_options, "type", 't', "Specify which matching algorithm to use",
+ args::EnumArg::EnumArgOptions
+ ("text", 't', "Match an exact text substring, ignoring case")
+ ("exact", 'x', "Match only an entire exact string, ignoring case"),
+ "text"
+ ),
+ a_and(&g_pattern_options, "and", '&', "If multiple patterns are specified, require that "
+ "all patterns match. Default is to succeed if any pattern matches.", true),
+ a_not(&g_pattern_options, "not", '!', "Invert the results of pattern matches.", true),
+
+ g_search_key_options(this, "Search Key Options", "Alter the keys used for searching. If "
+ "no option in this group is specified, matches are carried out on name and description. Otherwise, "
+ "matches are carried out on all of the specified keys."),
+ a_key(&g_search_key_options, "key", 'k', "Search the named metadata key (e.g. DESCRIPTION). May be specified "
+ "multiple times."),
+ a_name(&g_search_key_options, "name", 'n', "Search package names.", true),
+ a_description(&g_search_key_options, "description", 'd', "Search package descriptions.", true)
+{
+}
+
diff --git a/src/clients/cave/cmd_search_cmdline.hh b/src/clients/cave/cmd_search_cmdline.hh
new file mode 100644
index 0000000..dda27a1
--- /dev/null
+++ b/src/clients/cave/cmd_search_cmdline.hh
@@ -0,0 +1,58 @@
+/* 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_SEARCH_CMDLINE_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_SEARCH_CMDLINE_HH 1
+
+#include "command_command_line.hh"
+#include <paludis/environment-fwd.hh>
+#include <tr1/memory>
+
+namespace paludis
+{
+ namespace cave
+ {
+ struct SearchCommandLineCandidateOptions :
+ args::ArgsSection
+ {
+ SearchCommandLineCandidateOptions(args::ArgsHandler * const);
+
+ args::ArgsGroup g_candidate_options;
+ args::SwitchArg a_all_versions;
+ };
+
+ struct SearchCommandLineMatchOptions :
+ args::ArgsSection
+ {
+ SearchCommandLineMatchOptions(args::ArgsHandler * const);
+
+ args::ArgsGroup g_pattern_options;
+ args::EnumArg a_type;
+ args::SwitchArg a_and;
+ args::SwitchArg a_not;
+
+ args::ArgsGroup g_search_key_options;
+ args::StringSetArg a_key;
+ args::SwitchArg a_name;
+ args::SwitchArg a_description;
+ };
+ }
+}
+
+#endif
diff --git a/src/clients/cave/command_factory.cc b/src/clients/cave/command_factory.cc
index dd30d52..3174465 100644
--- a/src/clients/cave/command_factory.cc
+++ b/src/clients/cave/command_factory.cc
@@ -29,10 +29,12 @@
#include "cmd_config.hh"
#include "cmd_display_resolution.hh"
#include "cmd_execute_resolution.hh"
+#include "cmd_find_candidates.hh"
#include "cmd_fix_cache.hh"
#include "cmd_help.hh"
#include "cmd_import.hh"
#include "cmd_info.hh"
+#include "cmd_match.hh"
#include "cmd_perform.hh"
#include "cmd_print_categories.hh"
#include "cmd_print_commands.hh"
@@ -48,6 +50,7 @@
#include "cmd_print_sets.hh"
#include "cmd_print_sync_protocols.hh"
#include "cmd_resolve.hh"
+#include "cmd_search.hh"
#include "cmd_show.hh"
#include "cmd_sync.hh"
#include "cmd_update_world.hh"
@@ -87,10 +90,12 @@ CommandFactory::CommandFactory() :
_imp->handlers.insert(std::make_pair("config", std::tr1::bind(&make_command<ConfigCommand>)));
_imp->handlers.insert(std::make_pair("display-resolution", std::tr1::bind(&make_command<DisplayResolutionCommand>)));
_imp->handlers.insert(std::make_pair("execute-resolution", std::tr1::bind(&make_command<ExecuteResolutionCommand>)));
+ _imp->handlers.insert(std::make_pair("find-candidates", std::tr1::bind(&make_command<FindCandidatesCommand>)));
_imp->handlers.insert(std::make_pair("fix-cache", std::tr1::bind(&make_command<FixCacheCommand>)));
_imp->handlers.insert(std::make_pair("help", std::tr1::bind(&make_command<HelpCommand>)));
_imp->handlers.insert(std::make_pair("import", std::tr1::bind(&make_command<ImportCommand>)));
_imp->handlers.insert(std::make_pair("info", std::tr1::bind(&make_command<InfoCommand>)));
+ _imp->handlers.insert(std::make_pair("match", std::tr1::bind(&make_command<MatchCommand>)));
_imp->handlers.insert(std::make_pair("perform", std::tr1::bind(&make_command<PerformCommand>)));
_imp->handlers.insert(std::make_pair("print-categories", std::tr1::bind(&make_command<PrintCategoriesCommand>)));
_imp->handlers.insert(std::make_pair("print-commands", std::tr1::bind(&make_command<PrintCommandsCommand>)));
@@ -106,6 +111,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("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>)));
_imp->handlers.insert(std::make_pair("update-world", std::tr1::bind(&make_command<UpdateWorldCommand>)));