summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2019-11-25 09:59:38 +0000
committerJulian Andres Klode <jak@debian.org>2019-11-25 09:59:38 +0000
commitf95e6c8032a47dc776ed9d2080c3468cf051dd57 (patch)
tree13cc2899b6497f463d401091a9a6b8a603d9d3f3
parent4afb07258fad5f9026ad25f579a871093a312ac5 (diff)
parent19033186919b9c6d31ca3aabaacfb069a4b64f88 (diff)
Merge branch 'search-in-all-translations' into 'master'
Search in all available description translations See merge request apt-team/apt!79
-rw-r--r--apt-pkg/cacheiterators.h1
-rw-r--r--apt-pkg/pkgcache.cc48
-rw-r--r--apt-private/private-search.cc121
-rwxr-xr-xtest/integration/test-bug-490000-search-in-all-translations107
4 files changed, 228 insertions, 49 deletions
diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h
index fbd4bcb8d..5c3ad9bbb 100644
--- a/apt-pkg/cacheiterators.h
+++ b/apt-pkg/cacheiterators.h
@@ -220,6 +220,7 @@ class pkgCache::VerIterator : public Iterator<Version, VerIterator> {
inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);}
inline DescIterator DescriptionList() const;
+ DescIterator TranslatedDescriptionForLanguage(APT::StringView lang) const;
DescIterator TranslatedDescription() const;
inline DepIterator DependsList() const;
inline PrvIterator ProvidesList() const;
diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc
index ba9a39f13..160c58273 100644
--- a/apt-pkg/pkgcache.cc
+++ b/apt-pkg/pkgcache.cc
@@ -992,6 +992,23 @@ string pkgCache::PkgFileIterator::RelStr() /*{{{*/
return Res;
}
/*}}}*/
+// VerIterator::TranslatedDescriptionForLanguage - Return a DescIter for language/*{{{*/
+// ---------------------------------------------------------------------
+/* return a DescIter for the specified language
+ */
+pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescriptionForLanguage(StringView lang) const
+{
+ for (pkgCache::DescIterator Desc = DescriptionList(); Desc.end() == false; ++Desc)
+ if (lang == Desc.LanguageCode())
+ return Desc;
+
+ if (lang == "en")
+ return TranslatedDescriptionForLanguage("");
+
+ return DescIterator();
+}
+
+ /*}}}*/
// VerIterator::TranslatedDescription - Return the a DescIter for locale/*{{{*/
// ---------------------------------------------------------------------
/* return a DescIter for the current locale or the default if none is
@@ -1003,30 +1020,15 @@ pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const
for (std::vector<string>::const_iterator l = lang.begin();
l != lang.end(); ++l)
{
- pkgCache::DescIterator Desc = DescriptionList();
- for (; Desc.end() == false; ++Desc)
- if (*l == Desc.LanguageCode())
- break;
- if (Desc.end() == true)
- {
- if (*l == "en")
- {
- Desc = DescriptionList();
- for (; Desc.end() == false; ++Desc)
- if (strcmp(Desc.LanguageCode(), "") == 0)
- break;
- if (Desc.end() == true)
- continue;
- }
- else
- continue;
- }
- return Desc;
+ pkgCache::DescIterator Desc = TranslatedDescriptionForLanguage(*l);
+ if (Desc.IsGood())
+ return Desc;
}
- for (pkgCache::DescIterator Desc = DescriptionList();
- Desc.end() == false; ++Desc)
- if (strcmp(Desc.LanguageCode(), "") == 0)
- return Desc;
+
+ pkgCache::DescIterator Desc = TranslatedDescriptionForLanguage("");
+ if (Desc.IsGood())
+ return Desc;
+
return DescriptionList();
}
diff --git a/apt-private/private-search.cc b/apt-private/private-search.cc
index de1b19758..b3f9469ac 100644
--- a/apt-private/private-search.cc
+++ b/apt-private/private-search.cc
@@ -1,6 +1,7 @@
// Includes /*{{{*/
#include <config.h>
+#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/cachefile.h>
#include <apt-pkg/cacheset.h>
#include <apt-pkg/cmndline.h>
@@ -24,11 +25,30 @@
#include <sstream>
#include <string>
#include <utility>
+#include <vector>
#include <string.h>
#include <apti18n.h>
/*}}}*/
+static std::vector<pkgCache::DescIterator> const TranslatedDescriptionsList(pkgCache::VerIterator const &V) /*{{{*/
+{
+ std::vector<pkgCache::DescIterator> Descriptions;
+
+ for (std::string const &lang: APT::Configuration::getLanguages())
+ {
+ pkgCache::DescIterator Desc = V.TranslatedDescriptionForLanguage(lang);
+ if (Desc.IsGood())
+ Descriptions.push_back(Desc);
+ }
+
+ if (Descriptions.empty())
+ Descriptions.push_back(V.TranslatedDescription());
+
+ return Descriptions;
+}
+
+ /*}}}*/
static bool FullTextSearch(CommandLine &CmdL) /*{{{*/
{
@@ -94,27 +114,49 @@ static bool FullTextSearch(CommandLine &CmdL) /*{{{*/
if (PkgsDone[P->ID] == true)
continue;
- char const * const PkgName = P.Name();
- pkgCache::DescIterator Desc = V.TranslatedDescription();
- std::string LongDesc = "";
- if (Desc.end() == false)
+ std::vector<std::string> PkgDescriptions;
+ if (not NamesOnly)
{
- pkgRecords::Parser &parser = records.Lookup(Desc.FileList());
- LongDesc = parser.LongDesc();
+ for (auto &Desc: TranslatedDescriptionsList(V))
+ {
+ pkgRecords::Parser &parser = records.Lookup(Desc.FileList());
+ PkgDescriptions.push_back(parser.LongDesc());
+ }
}
bool all_found = true;
+
+ char const * const PkgName = P.Name();
+ std::vector<bool> SkipDescription(PkgDescriptions.size(), false);
for (std::vector<regex_t>::const_iterator pattern = Patterns.begin();
- pattern != Patterns.end(); ++pattern)
+ pattern != Patterns.end(); ++pattern)
{
- if (regexec(&(*pattern), PkgName, 0, 0, 0) == 0)
- continue;
- else if (NamesOnly == false && regexec(&(*pattern), LongDesc.c_str(), 0, 0, 0) == 0)
- continue;
- // search patterns are AND, so one failing fails all
- all_found = false;
- break;
+ if (regexec(&(*pattern), PkgName, 0, 0, 0) == 0)
+ continue;
+ else if (not NamesOnly)
+ {
+ bool found = false;
+
+ for (std::vector<std::string>::size_type i = 0; i < PkgDescriptions.size(); ++i)
+ {
+ if (not SkipDescription[i])
+ {
+ if (regexec(&(*pattern), PkgDescriptions[i].c_str(), 0, 0, 0) == 0)
+ found = true;
+ else
+ SkipDescription[i] = true;
+ }
+ }
+
+ if (found)
+ continue;
+ }
+
+ // search patterns are AND, so one failing fails all
+ all_found = false;
+ break;
}
+
if (all_found == true)
{
PkgsDone[P->ID] = true;
@@ -290,19 +332,43 @@ static bool Search(CommandLine &CmdL)
// Iterate over all the version records and check them
for (ExDescFile *J = DFList; J->Df != 0; ++J)
{
- pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(*Cache,J->Df));
size_t const PatternOffset = J->ID * NumPatterns;
-
- if (NamesOnly == false)
+ if (not NamesOnly)
{
- std::string const LongDesc = P.LongDesc();
- for (unsigned I = 0; I < NumPatterns; ++I)
- {
- if (PatternMatch[PatternOffset + I] == true)
- continue;
- else if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0)
- PatternMatch[PatternOffset + I] = true;
- }
+ std::vector<std::string> PkgDescriptions;
+ for (auto &Desc: TranslatedDescriptionsList(J->V))
+ {
+ pkgRecords::Parser &parser = Recs.Lookup(Desc.FileList());
+ PkgDescriptions.push_back(parser.LongDesc());
+ }
+
+ std::vector<bool> SkipDescription(PkgDescriptions.size(), false);
+ for (unsigned I = 0; I < NumPatterns; ++I)
+ {
+ if (PatternMatch[PatternOffset + I])
+ continue;
+ else
+ {
+ bool found = false;
+
+ for (std::vector<std::string>::size_type k = 0; k < PkgDescriptions.size(); ++k)
+ {
+ if (not SkipDescription[k])
+ {
+ if (regexec(&Patterns[I], PkgDescriptions[k].c_str(), 0, 0, 0) == 0)
+ {
+ found = true;
+ PatternMatch[PatternOffset + I] = true;
+ }
+ else
+ SkipDescription[k] = true;
+ }
+ }
+
+ if (not found)
+ break;
+ }
+ }
}
bool matchedAll = true;
@@ -325,7 +391,10 @@ static bool Search(CommandLine &CmdL)
DisplayRecordV1(CacheFile, Recs, J->V, Vf, Start, Length, std::cout);
}
else
- printf("%s - %s\n",P.Name().c_str(),P.ShortDesc().c_str());
+ {
+ pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(*Cache, J->Df));
+ printf("%s - %s\n", P.Name().c_str(), P.ShortDesc().c_str());
+ }
}
}
diff --git a/test/integration/test-bug-490000-search-in-all-translations b/test/integration/test-bug-490000-search-in-all-translations
new file mode 100755
index 000000000..3a034bc49
--- /dev/null
+++ b/test/integration/test-bug-490000-search-in-all-translations
@@ -0,0 +1,107 @@
+#!/bin/sh
+
+set -e
+
+TESTDIR="$(readlink -f "$(dirname "$0")")"
+. "${TESTDIR}/framework"
+
+setupenvironment
+
+ARCH='amd64'
+DIST='unstable'
+
+PKG_NAME='foo'
+PKG_VERSION='1.0'
+
+SHORT_DESCRIPTION_EN='have you fooed today?'
+LONG_DESCRIPTION_EN="${SHORT_DESCRIPTION_EN}
+ Where there's foo, there's fire."
+
+SHORT_DESCRIPTION_ZZ='bar alter ego'
+LONG_DESCRIPTION_ZZ="${SHORT_DESCRIPTION_ZZ}
+ He who foos last foos best."
+
+configure_languages()
+{
+ {
+ echo '#clear Acquire::Languages;'
+ echo 'Acquire::Languages {'
+ for language in "$@"
+ do
+ echo " \"${language}\";"
+ done
+ echo '};'
+ } > rootdir/etc/apt/apt.conf.d/languages.conf
+}
+
+new_translation_record()
+{
+ echo "Package: ${1:?Package name expected}"
+ echo "Description-md5: ${2:?Description-md5 expected}"
+ echo "Description-${3:?Language code expected}: ${4:?Package description expected}"
+ echo
+}
+
+str_md5sum()
+{
+ echo -n "${1:?String expected}" | md5sum | cut -d ' ' -f 1
+}
+
+configarchitecture "${ARCH}"
+
+insertpackage "${DIST}" "${PKG_NAME}" "${ARCH}" "${PKG_VERSION}" '' '' "${LONG_DESCRIPTION_EN}"
+# English translation was already added by insertpackage above
+new_translation_record "${PKG_NAME}" "$(str_md5sum "${LONG_DESCRIPTION_EN}")" 'zz' "${LONG_DESCRIPTION_ZZ}" > "aptarchive/dists/${DIST}/main/i18n/Translation-zz"
+
+configure_languages en zz
+setupaptarchive
+
+# ===========================
+#
+# Tests
+#
+# ===========================
+
+# ----------[ apt ]----------
+
+# Test that all translations are searched, but the short
+# description is in the first configured language
+
+configure_languages en zz
+testequal "${PKG_NAME}/${DIST} ${PKG_VERSION} ${ARCH}
+ ${SHORT_DESCRIPTION_EN}
+" apt -qq search alter ego
+
+configure_languages zz en
+testequal "${PKG_NAME}/${DIST} ${PKG_VERSION} ${ARCH}
+ ${SHORT_DESCRIPTION_ZZ}
+" apt -qq search you today
+
+# Search in configured languages only
+configure_languages zz
+testempty apt -qq search where fire
+
+# Patterns are AND-ed i.e. all must match against a single
+# description translation
+configure_languages en zz
+testempty apt -qq search there best
+
+# -------[ apt-cache ]-------
+
+# Test that all translations are searched, but the short
+# description is in the first configured language
+
+configure_languages en zz
+testequal "${PKG_NAME} - ${SHORT_DESCRIPTION_EN}" aptcache search alter ego
+
+configure_languages zz en
+testequal "${PKG_NAME} - ${SHORT_DESCRIPTION_ZZ}" aptcache search you today
+
+# Search in configured languages only
+configure_languages zz
+testempty aptcache search where fire
+
+# Patterns are AND-ed i.e. all must match against a single
+# description translation
+configure_languages en zz
+testempty aptcache search there best