/* 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 "search_extras_handle.hh" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; SearchCommandLineIndexOptions index_options; args::ArgsGroup g_hints; args::StringArg a_name_description_substring_hint; FindCandidatesCommandLine() : search_options(this), match_options(this), index_options(this), g_hints(main_options_section(), "Hints", "Hints allow, but do not require, the search to return a " "reduced set of results"), a_name_description_substring_hint(&g_hints, "name-description-substring", '\0', "Candidates whose name or description does not include the specified string as a substring " "may be omitted") { } }; void print_spec(const PackageDepSpec & spec) { cout << spec << endl; } void no_step(const std::string &) { } void check_candidates( const std::function & yield, const std::function & step, const std::shared_ptr & ids) { for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ; i != i_end ; ++i) { step("Checking candidates"); yield((*i)->uniquely_identifying_spec()); } } } int FindCandidatesCommand::run( const std::shared_ptr & env, const std::shared_ptr > & 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 takes no parameters"); run_hosted(env, cmdline.search_options, cmdline.match_options, cmdline.index_options, cmdline.a_name_description_substring_hint.argument(), &print_spec, &no_step); return EXIT_SUCCESS; } typedef std::set RepositoryNames; typedef std::set CategoryNames; typedef std::set QualifiedPackageNames; void FindCandidatesCommand::run_hosted( const std::shared_ptr & env, const SearchCommandLineCandidateOptions & search_options, const SearchCommandLineMatchOptions &, const SearchCommandLineIndexOptions & index_options, const std::string & name_description_substring_hint, const std::function & yield, const std::function & step) { if (index_options.a_index.specified()) { step("Searching index"); CaveSearchExtrasDB * db(SearchExtrasHandle::get_instance()->open_db_function(stringify(index_options.a_index.argument()).c_str())); std::list specs; SearchExtrasHandle::get_instance()->find_candidates_function(db, specs, search_options.a_all_versions.specified(), search_options.a_visible.specified(), name_description_substring_hint); SearchExtrasHandle::get_instance()->cleanup_db_function(db); for (auto s(specs.begin()), s_end(specs.end()) ; s != s_end ; ++s) { step("Checking indexed candidates"); std::list matches; for (args::StringSetArg::ConstIterator k(search_options.a_matching.begin_args()), k_end(search_options.a_matching.end_args()) ; k != k_end ; ++k) matches.push_back(parse_user_package_dep_spec(*k, env.get(), { updso_allow_wildcards })); if (! matches.empty()) { bool ok(false); for (auto m(matches.begin()), m_end(matches.end()) ; m != m_end ; ++m) if (match_package(*env, *m, **(*env)[selection::RequireExactlyOne(generator::Matches( parse_user_package_dep_spec(*s, env.get(), { }), { }))]->begin(), { })) { ok = true; break; } if (! ok) continue; } yield(parse_user_package_dep_spec(*s, env.get(), { })); } } else if (! search_options.a_matching.specified()) { 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::shared_ptr repo(env->package_database()->fetch_repository(*r)); const std::shared_ptr 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::shared_ptr 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::shared_ptr 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()) { if (search_options.a_visible.specified()) { const auto ids((*env)[selection::AllVersionsUnsorted(generator::Package(*q) | filter::NotMasked())]); check_candidates(yield, step, ids); } else { const auto ids((*env)[selection::AllVersionsUnsorted(generator::Package(*q))]); check_candidates(yield, step, ids); } } else { std::shared_ptr ids; ids = ((*env)[selection::BestVersionOnly(generator::Package(*q) | filter::SupportsAction() | filter::NotMasked())]); if (search_options.a_visible.specified()) { if (ids->empty()) ids = ((*env)[selection::BestVersionOnly(generator::Package(*q) | filter::NotMasked())]); } else { if (ids->empty()) ids = ((*env)[selection::BestVersionOnly(generator::Package(*q) | filter::SupportsAction())]); if (ids->empty()) ids = ((*env)[selection::BestVersionOnly(generator::Package(*q))]); } check_candidates(yield, step, ids); } } } else { step("Searching matches"); std::shared_ptr match_generator; std::shared_ptr mask_filter; if (search_options.a_visible.specified()) mask_filter = std::make_shared(); else mask_filter = std::make_shared(); for (args::StringSetArg::ConstIterator k(search_options.a_matching.begin_args()), k_end(search_options.a_matching.end_args()) ; k != k_end ; ++k) { generator::Matches m(parse_user_package_dep_spec(*k, env.get(), { updso_allow_wildcards }), { }); if (match_generator) match_generator = std::make_shared(*match_generator, m); else match_generator = make_shared_copy(m); } if (search_options.a_all_versions.specified()) { const std::shared_ptr ids((*env)[selection::AllVersionsUnsorted( *match_generator | *mask_filter)]); check_candidates(yield, step, ids); } else { const std::shared_ptr ids((*env)[selection::BestVersionOnly( *match_generator | *mask_filter)]); check_candidates(yield, step, ids); } } } std::shared_ptr FindCandidatesCommand::make_doc_cmdline() { return std::make_shared(); }