aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Fernando J. Pereda <ferdy@ferdyx.org> 2007-10-24 16:41:09 +0000
committerAvatar Fernando J. Pereda <ferdy@ferdyx.org> 2007-10-24 16:41:09 +0000
commit4ba5db599133792b39900301a89d145d5dc48048 (patch)
tree022452c474d5e64760f088262ac7416b1726d179
parent6e0aedd0a44450345364b2acb92f05be2d844b1e (diff)
downloadpaludis-4ba5db599133792b39900301a89d145d5dc48048.tar.gz
paludis-4ba5db599133792b39900301a89d145d5dc48048.tar.xz
Introduce fuzzy finders for packages and repositories.
-rw-r--r--NEWS5
-rw-r--r--paludis/files.m41
-rw-r--r--paludis/fuzzy_finder.cc184
-rw-r--r--paludis/fuzzy_finder.hh96
-rw-r--r--paludis/install_task.cc24
-rw-r--r--paludis/util/damerau_levenshtein.cc87
-rw-r--r--paludis/util/damerau_levenshtein.hh58
-rw-r--r--paludis/util/damerau_levenshtein_TEST.cc60
-rw-r--r--paludis/util/files.m41
-rw-r--r--src/clients/adjutrix/find_reverse_deps.cc21
-rw-r--r--src/clients/adjutrix/what_needs_keywording.cc39
-rw-r--r--src/clients/contrarius/install.cc3
-rw-r--r--src/clients/importare/importare.cc17
-rw-r--r--src/clients/paludis/do_contents.cc21
-rw-r--r--src/clients/paludis/install.cc4
-rw-r--r--src/clients/paludis/paludis.cc17
-rw-r--r--src/clients/paludis/query.cc21
-rw-r--r--src/clients/paludis/uninstall.cc17
-rw-r--r--src/clients/reconcilio/install.cc5
-rw-r--r--src/output/console_install_task.cc47
-rw-r--r--src/output/console_install_task.hh2
21 files changed, 705 insertions, 25 deletions
diff --git a/NEWS b/NEWS
index d821781..40a8382 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,11 @@ News for Paludis
This file lists the major changes between versions. For a more detailed list
of every change, see the ChangeLog.
+trunk/:
+ * If a wrong package or repository name is used in several places, they will
+ give possible suggestions rather than just saying "could not find
+ whatever".
+
0.26.0_alpha1:
* STILL BROKEN, wait for 0.26.0 if you use these: CRAN, Ruby bindings for
dep specs.
diff --git a/paludis/files.m4 b/paludis/files.m4
index bc928f9..274df9e 100644
--- a/paludis/files.m4
+++ b/paludis/files.m4
@@ -25,6 +25,7 @@ add(`environment', `hh', `fwd', `cc')
add(`environment_implementation', `hh', `cc')
add(`environment_maker', `hh', `cc')
add(`find_unused_packages_task', `hh', `cc')
+add(`fuzzy_finder', `hh', `cc')
add(`formatter', `hh', `fwd', `cc')
add(`handled_information', `hh', `fwd', `cc')
add(`hashed_containers', `hh', `cc', `test')
diff --git a/paludis/fuzzy_finder.cc b/paludis/fuzzy_finder.cc
new file mode 100644
index 0000000..899adea
--- /dev/null
+++ b/paludis/fuzzy_finder.cc
@@ -0,0 +1,184 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Fernando J. Pereda
+ *
+ * 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 <paludis/fuzzy_finder.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/util/damerau_levenshtein.hh>
+#include <paludis/package_database.hh>
+#include <paludis/environment.hh>
+#include <paludis/repository.hh>
+#include <paludis/name.hh>
+#include <paludis/util/set.hh>
+#include <libwrapiter/libwrapiter_forward_iterator.hh>
+#include <list>
+#include <set>
+
+#include <cctype>
+
+using namespace paludis;
+
+namespace
+{
+ bool char_0_cost(char c)
+ {
+ return (c == '-' || c == '_');
+ }
+
+ std::string tolower_0_cost(const std::string & s)
+ {
+ std::string res(s);
+ std::string::iterator e(std::remove_if(res.begin(), res.end(), char_0_cost));
+ std::string res2(res.begin(), e);
+ std::transform(res.begin(), e, res2.begin(), ::tolower);
+ return res2;
+ }
+}
+
+namespace paludis
+{
+ template <>
+ struct Implementation<FuzzyCandidatesFinder>
+ {
+ std::list<QualifiedPackageName> candidates;
+ };
+}
+
+FuzzyCandidatesFinder::FuzzyCandidatesFinder(const Environment & e, const std::string & name) :
+ PrivateImplementationPattern<FuzzyCandidatesFinder>(new Implementation<FuzzyCandidatesFinder>)
+{
+ std::string cat;
+ std::string repo;
+ std::string package(name);
+
+ if (std::string::npos != name.find('/'))
+ {
+ PackageDepSpec pds(name, pds_pm_permissive);
+
+ if (pds.package_ptr())
+ {
+ cat = stringify(pds.package_ptr()->category);
+ package = stringify(pds.package_ptr()->package);
+ }
+
+ if (pds.repository_ptr())
+ repo = stringify(*pds.repository_ptr());
+ }
+
+ std::string package_0_cost(tolower_0_cost(package));
+ DamerauLevenshtein distance_calculator(package);
+
+ unsigned threshold(package.length() <= 4 ? 1 : 2);
+
+ QualifiedPackageNameSet potential_candidates;
+
+ for (PackageDatabase::RepositoryConstIterator r(e.package_database()->begin_repositories()),
+ r_end(e.package_database()->end_repositories()) ; r != r_end ; ++r)
+ {
+ if (! repo.empty() && repo != stringify((*r)->name()))
+ continue;
+
+ tr1::shared_ptr<const Repository> rr(e.package_database()->fetch_repository((*r)->name()));
+
+ tr1::shared_ptr<const CategoryNamePartSet> cat_names(rr->category_names());
+ for (CategoryNamePartSet::ConstIterator c(cat_names->begin()), c_end(cat_names->end()) ;
+ c != c_end ; ++c)
+ {
+ if (! cat.empty() && cat != stringify(*c))
+ continue;
+
+ tr1::shared_ptr<const QualifiedPackageNameSet> packages(rr->package_names(*c));
+ for (QualifiedPackageNameSet::ConstIterator p(packages->begin()), p_end(packages->end()) ;
+ p != p_end ; ++p)
+ {
+ if (tolower(stringify(p->package)[0]) != tolower(package[0]))
+ continue;
+ potential_candidates.insert(*p);
+ }
+ }
+ }
+
+ for (QualifiedPackageNameSet::ConstIterator p(potential_candidates.begin()), p_end(potential_candidates.end()) ;
+ p != p_end ; ++p)
+ if (distance_calculator.distance_with(tolower_0_cost(stringify(p->package))) <= threshold)
+ _imp->candidates.push_back(*p);
+}
+
+FuzzyCandidatesFinder::~FuzzyCandidatesFinder()
+{
+}
+
+FuzzyCandidatesFinder::CandidatesConstIterator
+FuzzyCandidatesFinder::begin() const
+{
+ return CandidatesConstIterator(_imp->candidates.begin());
+}
+
+FuzzyCandidatesFinder::CandidatesConstIterator
+FuzzyCandidatesFinder::end() const
+{
+ return CandidatesConstIterator(_imp->candidates.end());
+}
+
+namespace paludis
+{
+ template <>
+ struct Implementation<FuzzyRepositoriesFinder>
+ {
+ std::list<RepositoryName> candidates;
+ };
+}
+
+FuzzyRepositoriesFinder::FuzzyRepositoriesFinder(const Environment & e, const std::string & name) :
+ PrivateImplementationPattern<FuzzyRepositoriesFinder>(new Implementation<FuzzyRepositoriesFinder>)
+{
+ DamerauLevenshtein distance_calculator(tolower_0_cost(name));
+
+ unsigned threshold(name.length() <= 4 ? 1 : 2);
+
+ if (0 != name.compare(0, 2, std::string("x-")))
+ {
+ RepositoryName xname(std::string("x-" + name));
+ if (e.package_database()->has_repository_named(xname))
+ {
+ _imp->candidates.push_back(xname);
+ return;
+ }
+ }
+
+ for (PackageDatabase::RepositoryConstIterator r(e.package_database()->begin_repositories()),
+ r_end(e.package_database()->end_repositories()) ; r != r_end ; ++r)
+ if (distance_calculator.distance_with(tolower_0_cost(stringify((*r)->name()))) <= threshold)
+ _imp->candidates.push_back((*r)->name());
+}
+
+FuzzyRepositoriesFinder::~FuzzyRepositoriesFinder()
+{
+}
+
+FuzzyRepositoriesFinder::RepositoriesConstIterator
+FuzzyRepositoriesFinder::begin() const
+{
+ return RepositoriesConstIterator(_imp->candidates.begin());
+}
+
+FuzzyRepositoriesFinder::RepositoriesConstIterator
+FuzzyRepositoriesFinder::end() const
+{
+ return RepositoriesConstIterator(_imp->candidates.end());
+}
diff --git a/paludis/fuzzy_finder.hh b/paludis/fuzzy_finder.hh
new file mode 100644
index 0000000..c7f1968
--- /dev/null
+++ b/paludis/fuzzy_finder.hh
@@ -0,0 +1,96 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Fernando J. Pereda
+ *
+ * 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_PALUDIS_FUZZY_FINDER_HH
+#define PALUDIS_GUARD_PALUDIS_FUZZY_FINDER_HH 1
+
+#include <paludis/environment-fwd.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <libwrapiter/libwrapiter_forward_iterator.hh>
+#include <paludis/name.hh>
+#include <string>
+
+/** \file
+ * Declarations for paludis::FuzzyCandidatesFinder and paludis::FuzzyRepositoriesFinder
+ *
+ * \ingroup g_package_database
+ */
+
+namespace paludis
+{
+ /**
+ * Object to find package names to a given name
+ *
+ * \ingroup g_package_database
+ */
+ class PALUDIS_VISIBLE FuzzyCandidatesFinder :
+ private PrivateImplementationPattern<FuzzyCandidatesFinder>
+ {
+ public:
+ ///\name Basic Operations
+ ///\{
+
+ FuzzyCandidatesFinder(const Environment & e, const std::string & name);
+ ~FuzzyCandidatesFinder();
+
+ ///\}
+
+ ///\name Iterate over the candidates
+ ///\{
+
+ typedef libwrapiter::ForwardIterator<FuzzyCandidatesFinder, const QualifiedPackageName>
+ CandidatesConstIterator;
+
+ CandidatesConstIterator begin() const;
+ CandidatesConstIterator end() const;
+
+ ///\}
+ };
+
+ /**
+ * Object to find repositories similar to a given name
+ *
+ * \ingroup g_package_database
+ */
+ class PALUDIS_VISIBLE FuzzyRepositoriesFinder :
+ private PrivateImplementationPattern<FuzzyRepositoriesFinder>
+ {
+ public:
+ ///\name Basic Operations
+ ///\{
+
+ FuzzyRepositoriesFinder(const Environment & e, const std::string & name);
+ ~FuzzyRepositoriesFinder();
+
+ ///\}
+
+ ///\name Iterate over the candidates
+ ///\{
+
+ typedef libwrapiter::ForwardIterator<FuzzyRepositoriesFinder, const RepositoryName>
+ RepositoriesConstIterator;
+
+ RepositoriesConstIterator begin() const;
+ RepositoriesConstIterator end() const;
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/paludis/install_task.cc b/paludis/install_task.cc
index a0ea773..777e399 100644
--- a/paludis/install_task.cc
+++ b/paludis/install_task.cc
@@ -191,14 +191,22 @@ InstallTask::add_target(const std::string & target)
}
else
{
- QualifiedPackageName q(_imp->env->package_database()->fetch_unique_qualified_package_name(
- PackageNamePart(target)));
- modified_target = stringify(q);
- tr1::shared_ptr<PackageDepSpec> spec(
- new PackageDepSpec(tr1::shared_ptr<QualifiedPackageName>(new QualifiedPackageName(q))));
- spec->set_tag(tr1::shared_ptr<const DepTag>(new TargetDepTag));
- _imp->targets->add(tr1::shared_ptr<TreeLeaf<SetSpecTree, PackageDepSpec> >(
- new TreeLeaf<SetSpecTree, PackageDepSpec>(spec)));
+ try
+ {
+ QualifiedPackageName q(_imp->env->package_database()->fetch_unique_qualified_package_name(
+ PackageNamePart(target)));
+ modified_target = stringify(q);
+ tr1::shared_ptr<PackageDepSpec> spec(
+ new PackageDepSpec(tr1::shared_ptr<QualifiedPackageName>(new QualifiedPackageName(q))));
+ spec->set_tag(tr1::shared_ptr<const DepTag>(new TargetDepTag));
+ _imp->targets->add(tr1::shared_ptr<TreeLeaf<SetSpecTree, PackageDepSpec> >(
+ new TreeLeaf<SetSpecTree, PackageDepSpec>(spec)));
+ }
+ catch (const NoSuchPackageError & e)
+ {
+ _imp->had_resolution_failures = true;
+ throw;
+ }
}
}
diff --git a/paludis/util/damerau_levenshtein.cc b/paludis/util/damerau_levenshtein.cc
new file mode 100644
index 0000000..965e14e
--- /dev/null
+++ b/paludis/util/damerau_levenshtein.cc
@@ -0,0 +1,87 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Fernando J. Pereda
+ *
+ * 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 <paludis/util/damerau_levenshtein.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/util/tr1_memory.hh>
+#include <vector>
+
+using namespace paludis;
+
+namespace paludis
+{
+ template <>
+ struct Implementation<DamerauLevenshtein>
+ {
+ std::string name;
+ unsigned n;
+ tr1::shared_ptr<std::vector<unsigned> > prevprev;
+ tr1::shared_ptr<std::vector<unsigned> > prev;
+ tr1::shared_ptr<std::vector<unsigned> > current;
+
+ Implementation(const std::string & myname) :
+ name(myname), n(name.length() + 1), prevprev(new std::vector<unsigned>(n)),
+ prev(new std::vector<unsigned>(n)), current(new std::vector<unsigned>(n))
+ {
+ }
+ };
+}
+
+DamerauLevenshtein::DamerauLevenshtein(const std::string & name) :
+ PrivateImplementationPattern<DamerauLevenshtein>(new Implementation<DamerauLevenshtein>(name))
+{
+}
+
+DamerauLevenshtein::~DamerauLevenshtein()
+{
+}
+
+unsigned
+DamerauLevenshtein::distance_with(const std::string & candidate)
+{
+ for (unsigned i(0) ; i < _imp->n ; ++i)
+ (*_imp->prev)[i] = i;
+ _imp->prevprev->assign(0, _imp->n);
+ _imp->current->assign(0, _imp->n);
+
+ size_t m(candidate.length() + 1);
+ for (unsigned i(1) ; i < m ; ++i)
+ {
+ (*_imp->current)[0] = i;
+ for (unsigned j(1) ; j < _imp->n ; ++j)
+ {
+ unsigned cost(candidate[i - 1] == _imp->name[j - 1] ? 0 : 1);
+ (*_imp->current)[j] = std::min(
+ std::min((*_imp->prev)[j] + 1, (*_imp->current)[j - 1] + 1),
+ (*_imp->prev)[j - 1] + cost);
+ if (i > 1 && j > 1
+ && candidate[i - 1] == _imp->name[j - 2]
+ && candidate[i - 2] == _imp->name[j - 1])
+ (*_imp->current)[j] = std::min((*_imp->current)[j], (*_imp->prevprev)[j - 2] + cost);
+ }
+ tr1::shared_ptr<std::vector<unsigned> > aux(_imp->current);
+ tr1::shared_ptr<std::vector<unsigned> > aux2(_imp->prev);
+ _imp->current = _imp->prevprev;
+ _imp->prev = aux;
+ _imp->prevprev = aux2;
+ }
+
+ return (*_imp->prev)[_imp->n - 1];
+}
+
diff --git a/paludis/util/damerau_levenshtein.hh b/paludis/util/damerau_levenshtein.hh
new file mode 100644
index 0000000..e3b64c8
--- /dev/null
+++ b/paludis/util/damerau_levenshtein.hh
@@ -0,0 +1,58 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Fernando J. Pereda
+ *
+ * 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_PALUDIS_DAMERAU_LEVENSHTEIN_HH
+#define PALUDIS_GUARD_PALUDIS_DAMERAU_LEVENSHTEIN_HH 1
+
+#include <paludis/util/private_implementation_pattern.hh>
+#include <string>
+
+/** \file
+ * Declarations for paludis::DamerauLevenshtein
+ *
+ * \ingroup g_utils
+ */
+
+namespace paludis
+{
+ /**
+ * Object to calculate Damerau-Levenshtein distances between two strings.
+ *
+ * \ingroup g_utils
+ */
+ class PALUDIS_VISIBLE DamerauLevenshtein :
+ private PrivateImplementationPattern<DamerauLevenshtein>
+ {
+ public:
+ ///\name Basic Operations
+ ///\{
+
+ DamerauLevenshtein(const std::string & name);
+ ~DamerauLevenshtein();
+
+ /**
+ * Compute the Damerau-Levenshtein to this candidate.
+ */
+ unsigned distance_with(const std::string & candidate);
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/paludis/util/damerau_levenshtein_TEST.cc b/paludis/util/damerau_levenshtein_TEST.cc
new file mode 100644
index 0000000..bd597bd
--- /dev/null
+++ b/paludis/util/damerau_levenshtein_TEST.cc
@@ -0,0 +1,60 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Fernando J. Pereda
+ *
+ * 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 <paludis/util/damerau_levenshtein.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+/** \file
+ * Test cases for damerau_levenshtein.hh
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test DamerauLevenshtain methods
+ */
+ struct DamerauLevenshteinTest : TestCase
+ {
+ DamerauLevenshteinTest() : TestCase("Damerau-Levenshtein distance") {}
+
+ void run()
+ {
+ DamerauLevenshtein dl("foo");
+
+ TEST_CHECK_EQUAL(dl.distance_with("foo"), 0);
+ TEST_CHECK_EQUAL(dl.distance_with("foo1"), 1);
+ TEST_CHECK_EQUAL(dl.distance_with("fo"), 1);
+ TEST_CHECK_EQUAL(dl.distance_with("fao"), 1);
+ TEST_CHECK_EQUAL(dl.distance_with("ofo"), 1);
+ TEST_CHECK_EQUAL(dl.distance_with("fie"), 2);
+ TEST_CHECK_EQUAL(dl.distance_with("ife"), 3);
+ TEST_CHECK_EQUAL(dl.distance_with("bar"), 3);
+ TEST_CHECK_EQUAL(dl.distance_with(""), 3);
+
+ DamerauLevenshtein de("");
+
+ TEST_CHECK_EQUAL(de.distance_with("foo"), 3);
+ TEST_CHECK_EQUAL(de.distance_with(""), 0);
+ }
+ } test_damerau_levenshtein_test;
+}
diff --git a/paludis/util/files.m4 b/paludis/util/files.m4
index 115d5b7..4bb8fec 100644
--- a/paludis/util/files.m4
+++ b/paludis/util/files.m4
@@ -13,6 +13,7 @@ add(`attributes', `hh')
add(`config_file', `hh', `cc', `se', `test', `testscript')
add(`clone', `hh', `impl')
add(`condition_variable', `hh', `cc', `test')
+add(`damerau_levenshtein', `hh', `cc', `test')
add(`destringify', `hh', `cc', `test')
add(`dir_iterator', `hh', `cc', `test', `testscript')
add(`exception', `hh', `cc')
diff --git a/src/clients/adjutrix/find_reverse_deps.cc b/src/clients/adjutrix/find_reverse_deps.cc
index 8cd480f..249a5af 100644
--- a/src/clients/adjutrix/find_reverse_deps.cc
+++ b/src/clients/adjutrix/find_reverse_deps.cc
@@ -31,6 +31,7 @@
#include <paludis/package_id.hh>
#include <paludis/package_database.hh>
#include <paludis/metadata_key.hh>
+#include <paludis/fuzzy_finder.hh>
#include <libwrapiter/libwrapiter_forward_iterator.hh>
#include <libwrapiter/libwrapiter_output_iterator.hh>
@@ -280,6 +281,26 @@ int do_find_reverse_deps(NoConfigEnvironment & env)
cerr << endl;
return 4;
}
+ catch (const NoSuchPackageError & e)
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "Could not find '" << e.name() << "'. Looking for suggestions:" << endl;
+
+ FuzzyCandidatesFinder f(env, e.name());
+
+ if (f.begin() == f.end())
+ cerr << "No suggestions found." << endl;
+ else
+ cerr << "Suggestions:" << endl;
+
+ for (FuzzyCandidatesFinder::CandidatesConstIterator c(f.begin()),
+ c_end(f.end()) ; c != c_end ; ++c)
+ cerr << " * " << colour(cl_package_name, *c) << endl;
+ cerr << endl;
+ return 5;
+ }
tr1::shared_ptr<const PackageIDSequence> entries(env.package_database()->query(
query::Matches(*spec), qo_order_by_version));
diff --git a/src/clients/adjutrix/what_needs_keywording.cc b/src/clients/adjutrix/what_needs_keywording.cc
index 594e130..0d5b63a 100644
--- a/src/clients/adjutrix/what_needs_keywording.cc
+++ b/src/clients/adjutrix/what_needs_keywording.cc
@@ -19,6 +19,7 @@
#include "what_needs_keywording.hh"
#include "command_line.hh"
+#include <output/colour.hh>
#include <paludis/util/tokeniser.hh>
#include <paludis/util/strip.hh>
@@ -32,6 +33,7 @@
#include <paludis/package_id.hh>
#include <paludis/metadata_key.hh>
#include <paludis/mask.hh>
+#include <paludis/fuzzy_finder.hh>
#include <set>
#include <map>
@@ -80,13 +82,36 @@ int do_what_needs_keywording(NoConfigEnvironment & env)
for (CommandLine::ParametersConstIterator p(next(CommandLine::get_instance()->begin_parameters())),
p_end(CommandLine::get_instance()->end_parameters()) ; p != p_end ; ++p)
{
- if (std::string::npos == p->find('/'))
- d.add(PackageDepSpec(
- tr1::shared_ptr<QualifiedPackageName>(new QualifiedPackageName(
- env.package_database()->fetch_unique_qualified_package_name(PackageNamePart(*p))))),
- env.default_destinations());
- else
- d.add(PackageDepSpec(*p, pds_pm_permissive), env.default_destinations());
+ try
+ {
+ if (std::string::npos == p->find('/'))
+ d.add(PackageDepSpec(
+ tr1::shared_ptr<QualifiedPackageName>(new QualifiedPackageName(
+ env.package_database()->fetch_unique_qualified_package_name(PackageNamePart(*p))))),
+ env.default_destinations());
+ else
+ d.add(PackageDepSpec(*p, pds_pm_permissive), env.default_destinations());
+ }
+ catch (const NoSuchPackageError & e)
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "Could not find '" << e.name() << "'. Looking for suggestions:" << endl;
+
+ FuzzyCandidatesFinder f(env, e.name());
+
+ if (f.begin() == f.end())
+ cerr << "No suggestions found." << endl;
+ else
+ cerr << "Suggestions:" << endl;
+
+ for (FuzzyCandidatesFinder::CandidatesConstIterator c(f.begin()),
+ c_end(f.end()) ; c != c_end ; ++c)
+ cerr << " * " << colour(cl_package_name, *c) << endl;
+ cerr << endl;
+ return 5;
+ }
}
cout << std::setw(30) << std::left << "Package";
diff --git a/src/clients/contrarius/install.cc b/src/clients/contrarius/install.cc
index 43de5c6..e1e03cd 100644
--- a/src/clients/contrarius/install.cc
+++ b/src/clients/contrarius/install.cc
@@ -131,7 +131,8 @@ do_install(tr1::shared_ptr<Environment> env, std::string spec_str)
throw DoHelp("bad value for --debug-build");
}
- task.add_target(spec_str);
+ if (! task.try_to_add_target(spec_str))
+ return task.exit_status();
task.execute();
diff --git a/src/clients/importare/importare.cc b/src/clients/importare/importare.cc
index b63c8b5..91ade5b 100644
--- a/src/clients/importare/importare.cc
+++ b/src/clients/importare/importare.cc
@@ -29,6 +29,7 @@
#include <paludis/util/sequence.hh>
#include <paludis/about.hh>
#include <paludis/repository_maker.hh>
+#include <paludis/fuzzy_finder.hh>
#include <libwrapiter/libwrapiter_forward_iterator.hh>
@@ -145,8 +146,20 @@ main(int argc, char *argv[])
cerr << "Unhandled exception:" << endl
<< " * " << e.backtrace("\n * ")
<< e.message() << " (" << e.what() << ")" << endl;
- if (env->package_database()->has_repository_named(RepositoryName("x-" + stringify(e.name()))))
- cerr << "Perhaps you meant 'x-" << e.name() << "'?" << endl;
+ cerr << " * Looking for suggestions:" << endl;
+
+ FuzzyRepositoriesFinder f(*env, stringify(e.name()));
+
+ if (f.begin() == f.end())
+ cerr << "No suggestions found." << endl;
+ else
+ cerr << "Suggestions:" << endl;
+
+ for (FuzzyRepositoriesFinder::RepositoriesConstIterator r(f.begin()), r_end(f.end()) ;
+ r != r_end ; ++r)
+ cerr << " * " << colour(cl_repository_name, *r) << endl;
+ cerr << endl;
+
return EXIT_FAILURE;
}
}
diff --git a/src/clients/paludis/do_contents.cc b/src/clients/paludis/do_contents.cc
index 1651869..51a455f 100644
--- a/src/clients/paludis/do_contents.cc
+++ b/src/clients/paludis/do_contents.cc
@@ -22,6 +22,7 @@
#include "command_line.hh"
#include <paludis/paludis.hh>
#include <paludis/util/visitor-impl.hh>
+#include <paludis/fuzzy_finder.hh>
#include <iostream>
#include <algorithm>
@@ -146,6 +147,26 @@ do_contents(tr1::shared_ptr<Environment> env)
cerr << " * " << e.backtrace("\n * ") << e.message() << endl;
cerr << endl;
}
+ catch (const NoSuchPackageError & e)
+ {
+ return_code |= 1;
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "Could not find '" << e.name() << "'. Looking for suggestions:" << endl;
+
+ FuzzyCandidatesFinder f(*env, e.name());
+
+ if (f.begin() == f.end())
+ cerr << "No suggestions found." << endl;
+ else
+ cerr << "Suggestions:" << endl;
+
+ for (FuzzyCandidatesFinder::CandidatesConstIterator c(f.begin()),
+ c_end(f.end()) ; c != c_end ; ++c)
+ cerr << " * " << colour(cl_package_name, *c) << endl;
+ cerr << endl;
+ }
catch (const PackageDatabaseLookupError & e)
{
return_code |= 1;
diff --git a/src/clients/paludis/install.cc b/src/clients/paludis/install.cc
index 9a07e23..321d60a 100644
--- a/src/clients/paludis/install.cc
+++ b/src/clients/paludis/install.cc
@@ -146,7 +146,9 @@ do_install(tr1::shared_ptr<Environment> env)
cout << "Building target list... " << std::flush;
for (CommandLine::ParametersConstIterator q(CommandLine::get_instance()->begin_parameters()),
q_end(CommandLine::get_instance()->end_parameters()) ; q != q_end ; ++q)
- task.add_target(*q);
+ if (! task.try_to_add_target(*q))
+ return task.exit_status();
+
cout << endl;
task.execute();
diff --git a/src/clients/paludis/paludis.cc b/src/clients/paludis/paludis.cc
index 39dc895..42814e9 100644
--- a/src/clients/paludis/paludis.cc
+++ b/src/clients/paludis/paludis.cc
@@ -39,6 +39,7 @@
#include <paludis/hashed_containers.hh>
#include <paludis/util/util.hh>
#include <paludis/util/log.hh>
+#include <paludis/fuzzy_finder.hh>
#include <libebt/libebt.hh>
#include <libwrapiter/libwrapiter.hh>
@@ -464,8 +465,20 @@ main(int argc, char *argv[])
cerr << "Unhandled exception:" << endl
<< " * " << e.backtrace("\n * ")
<< e.message() << " (" << e.what() << ")" << endl;
- if (env->package_database()->has_repository_named(RepositoryName("x-" + stringify(e.name()))))
- cerr << "Perhaps you meant 'x-" << e.name() << "'?" << endl;
+ cerr << " * Looking for suggestions:" << endl;
+
+ FuzzyRepositoriesFinder f(*env, stringify(e.name()));
+
+ if (f.begin() == f.end())
+ cerr << "No suggestions found." << endl;
+ else
+ cerr << "Suggestions:" << endl;
+
+ for (FuzzyRepositoriesFinder::RepositoriesConstIterator r(f.begin()), r_end(f.end()) ;
+ r != r_end ; ++r)
+ cerr << " * " << colour(cl_repository_name, *r) << endl;
+ cerr << endl;
+
return EXIT_FAILURE;
}
}
diff --git a/src/clients/paludis/query.cc b/src/clients/paludis/query.cc
index 786306f..874d1e9 100644
--- a/src/clients/paludis/query.cc
+++ b/src/clients/paludis/query.cc
@@ -24,6 +24,7 @@
#include <iomanip>
#include <iostream>
#include <paludis/paludis.hh>
+#include <paludis/fuzzy_finder.hh>
#include <paludis/util/visitor-impl.hh>
#include <string>
@@ -178,6 +179,26 @@ int do_query(tr1::shared_ptr<Environment> env)
cerr << " * " << e.backtrace("\n * ") << e.message() << endl;
cerr << endl;
}
+ catch (const NoSuchPackageError & e)
+ {
+ return_code |= 1;
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "Could not find '" << e.name() << "'. Looking for suggestions:" << endl;
+
+ FuzzyCandidatesFinder f(*env, e.name());
+
+ if (f.begin() == f.end())
+ cerr << "No suggestions found." << endl;
+ else
+ cerr << "Suggestions:" << endl;
+
+ for (FuzzyCandidatesFinder::CandidatesConstIterator c(f.begin()),
+ c_end(f.end()) ; c != c_end ; ++c)
+ cerr << " * " << colour(cl_package_name, *c) << endl;
+ cerr << endl;
+ }
catch (const PackageDatabaseLookupError & e)
{
return_code |= 1;
diff --git a/src/clients/paludis/uninstall.cc b/src/clients/paludis/uninstall.cc
index 7ecc43a..912b535 100644
--- a/src/clients/paludis/uninstall.cc
+++ b/src/clients/paludis/uninstall.cc
@@ -26,6 +26,7 @@
#include <paludis/uninstall_list.hh>
#include <paludis/package_database.hh>
#include <paludis/action.hh>
+#include <paludis/fuzzy_finder.hh>
#include <iostream>
#include <limits>
@@ -288,11 +289,23 @@ namespace
}
catch (const NoSuchPackageError & e)
{
+ return_code |= 1;
cout << endl;
cerr << "Query error:" << endl;
cerr << " * " << e.backtrace("\n * ");
- cerr << "No such package '" << e.name() << "'" << endl;
- return 1;
+ cerr << "Could not find '" << e.name() << "'. Looking for suggestions:" << endl;
+
+ FuzzyCandidatesFinder f(*env, e.name());
+
+ if (f.begin() == f.end())
+ cerr << "No suggestions found." << endl;
+ else
+ cerr << "Suggestions:" << endl;
+
+ for (FuzzyCandidatesFinder::CandidatesConstIterator c(f.begin()),
+ c_end(f.end()) ; c != c_end ; ++c)
+ cerr << " * " << colour(cl_package_name, *c) << endl;
+ cerr << endl;
}
return return_code;
diff --git a/src/clients/reconcilio/install.cc b/src/clients/reconcilio/install.cc
index b2a5c48..3748697 100644
--- a/src/clients/reconcilio/install.cc
+++ b/src/clients/reconcilio/install.cc
@@ -120,7 +120,10 @@ do_install(const tr1::shared_ptr<Environment> & env, const tr1::shared_ptr<const
CommandLine::get_instance()->install_args.populate_install_task(env.get(), task);
CommandLine::get_instance()->dl_args.populate_install_task(env.get(), task);
- std::for_each(targets->begin(), targets->end(), tr1::bind(&InstallTask::add_target, tr1::ref(task), _1));
+ for (Sequence<std::string>::ConstIterator t(targets->begin()), t_end(targets->end()) ;
+ t != t_end ; ++t)
+ if (! task.try_to_add_target(*t))
+ return task.exit_status();
std::cout << std::endl;
task.execute();
diff --git a/src/output/console_install_task.cc b/src/output/console_install_task.cc
index 76e17a7..ab0a0ca 100644
--- a/src/output/console_install_task.cc
+++ b/src/output/console_install_task.cc
@@ -42,6 +42,7 @@
#include <paludis/metadata_key.hh>
#include <paludis/mask.hh>
#include <paludis/hook.hh>
+#include <paludis/fuzzy_finder.hh>
#include <libwrapiter/libwrapiter_forward_iterator.hh>
#include <libwrapiter/libwrapiter_output_iterator.hh>
@@ -168,6 +169,38 @@ ConsoleInstallTask::exit_status() const
return return_code;
}
+bool
+ConsoleInstallTask::try_to_add_target(const std::string & s)
+{
+ bool is_ok(true);
+ try
+ {
+ InstallTask::add_target(s);
+ }
+ catch (const NoSuchPackageError & e)
+ {
+ output_stream() << endl;
+ output_stream() << "Query error:" << endl;
+ output_stream() << " * " << e.backtrace("\n * ");
+ output_stream() << "Could not find '" << e.name() << "'. Looking for suggestions:" << endl;
+
+ FuzzyCandidatesFinder f(*environment(), e.name());
+
+ if (f.begin() == f.end())
+ output_stream() << "No suggestions found." << endl;
+ else
+ output_stream() << "Suggestions:" << endl;
+
+ for (FuzzyCandidatesFinder::CandidatesConstIterator c(f.begin()),
+ c_end(f.end()) ; c != c_end ; ++c)
+ output_stream() << " * " << colour(cl_package_name, *c) << endl;
+ output_stream() << endl;
+ is_ok = false;;
+ }
+
+ return is_ok;
+}
+
void
ConsoleInstallTask::on_build_deplist_pre()
{
@@ -1328,7 +1361,19 @@ ConsoleInstallTask::on_no_such_package_error(const NoSuchPackageError & e)
output_stream() << endl;
output_stream() << "Query error:" << endl;
output_stream() << " * " << e.backtrace("\n * ");
- output_stream() << "No such package '" << e.name() << "'" << endl;
+ output_stream() << "Could not find '" << e.name() << "'. Looking for suggestions:" << endl;
+
+ FuzzyCandidatesFinder f(*environment(), e.name());
+
+ if (f.begin() == f.end())
+ output_stream() << "No suggestions found." << endl;
+ else
+ output_stream() << "Suggestions:" << endl;
+
+ for (FuzzyCandidatesFinder::CandidatesConstIterator c(f.begin()),
+ c_end(f.end()) ; c != c_end ; ++c)
+ output_stream() << " * " << colour(cl_package_name, *c) << endl;
+ output_stream() << endl;
}
void
diff --git a/src/output/console_install_task.hh b/src/output/console_install_task.hh
index fd7020f..3d3e867 100644
--- a/src/output/console_install_task.hh
+++ b/src/output/console_install_task.hh
@@ -129,6 +129,8 @@ namespace paludis
virtual void execute();
int exit_status() const;
+ bool try_to_add_target(const std::string &) PALUDIS_ATTRIBUTE((warn_unused_result));
+
virtual std::string make_x_of_y(const int x, const int y, const int s, const int f);
virtual void on_build_deplist_pre();