aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-03-12 17:28:41 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-03-14 09:52:00 +0000
commit4a96bed078086ca40b2862200e56fbbfcdd676b1 (patch)
treeb60068e52a2277f043b62834a18102fbf65e4f0d
parent2ec7e30829e73ec01109189164d0994e8ccfc996 (diff)
downloadpaludis-4a96bed078086ca40b2862200e56fbbfcdd676b1.tar.gz
paludis-4a96bed078086ca40b2862200e56fbbfcdd676b1.tar.xz
cave match
-rw-r--r--src/clients/cave/Makefile.am1
-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_cmdline.cc23
-rw-r--r--src/clients/cave/cmd_search_cmdline.hh16
-rw-r--r--src/clients/cave/command_factory.cc2
6 files changed, 480 insertions, 0 deletions
diff --git a/src/clients/cave/Makefile.am b/src/clients/cave/Makefile.am
index 0795028..e51f9ab 100644
--- a/src/clients/cave/Makefile.am
+++ b/src/clients/cave/Makefile.am
@@ -94,6 +94,7 @@ libcave_a_SOURCES = \
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 \
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_cmdline.cc b/src/clients/cave/cmd_search_cmdline.cc
index 38f8a4b..e861f53 100644
--- a/src/clients/cave/cmd_search_cmdline.cc
+++ b/src/clients/cave/cmd_search_cmdline.cc
@@ -30,3 +30,26 @@ SearchCommandLineCandidateOptions::SearchCommandLineCandidateOptions(args::ArgsH
{
}
+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
index 17b7399..dda27a1 100644
--- a/src/clients/cave/cmd_search_cmdline.hh
+++ b/src/clients/cave/cmd_search_cmdline.hh
@@ -36,6 +36,22 @@ namespace paludis
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;
+ };
}
}
diff --git a/src/clients/cave/command_factory.cc b/src/clients/cave/command_factory.cc
index 5f8bf93..7b2ed85 100644
--- a/src/clients/cave/command_factory.cc
+++ b/src/clients/cave/command_factory.cc
@@ -34,6 +34,7 @@
#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"
@@ -93,6 +94,7 @@ CommandFactory::CommandFactory() :
_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>)));