diff options
-rw-r--r-- | apt-private/private-cmndline.cc | 5 | ||||
-rw-r--r-- | apt-private/private-search.cc | 206 | ||||
-rw-r--r-- | apt-private/private-search.h | 5 | ||||
-rw-r--r-- | cmdline/apt-cache.cc | 202 | ||||
-rw-r--r-- | cmdline/apt.cc | 8 | ||||
-rwxr-xr-x | test/integration/test-apt-cli-list | 13 |
6 files changed, 219 insertions, 220 deletions
diff --git a/apt-private/private-cmndline.cc b/apt-private/private-cmndline.cc index 1299b85f0..463c087cc 100644 --- a/apt-private/private-cmndline.cc +++ b/apt-private/private-cmndline.cc @@ -324,9 +324,14 @@ static void BinarySpecificConfiguration(char const * const Binary) /*{{{*/ std::string const binary = flNotDir(Binary); if (binary == "apt" || binary == "apt-config") { + _config->CndSet("Binary::apt::APT::Color", true); _config->CndSet("Binary::apt::APT::Cache::Show::Version", 2); _config->CndSet("Binary::apt::APT::Cache::AllVersions", false); _config->CndSet("Binary::apt::APT::Cache::ShowVirtuals", true); + _config->CndSet("Binary::apt::APT::Cache::Search::Version", 2); + _config->CndSet("Binary::apt::APT::Get::Upgrade-Allow-New", true); + _config->CndSet("Binary::apt::APT::Cmd::Show-Update-Stats", true); + _config->CndSet("Binary::apt::DPkg::Progress-Fancy", true); } _config->Set("Binary", binary); diff --git a/apt-private/private-search.cc b/apt-private/private-search.cc index 6bce9ffa4..0728b26c8 100644 --- a/apt-private/private-search.cc +++ b/apt-private/private-search.cc @@ -16,6 +16,7 @@ #include <apt-private/private-cacheset.h> #include <apt-private/private-output.h> #include <apt-private/private-search.h> +#include <apt-private/private-show.h> #include <string.h> #include <iostream> @@ -27,7 +28,7 @@ #include <apti18n.h> /*}}}*/ -bool FullTextSearch(CommandLine &CmdL) /*{{{*/ +static bool FullTextSearch(CommandLine &CmdL) /*{{{*/ { pkgCacheFile CacheFile; pkgCache *Cache = CacheFile.GetPkgCache(); @@ -56,8 +57,6 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ Patterns.push_back(pattern); } - bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly", false); - std::map<std::string, std::string> output_map; LocalitySortedVersionSet bag; @@ -76,6 +75,7 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ else format += " ${LongDescription}\n"; + bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly", false); int Done = 0; std::vector<bool> PkgsDone(Cache->Head().PackageCount, false); for ( ;V != bag.end(); ++V) @@ -127,3 +127,203 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ return true; } /*}}}*/ +// LocalitySort - Sort a version list by package file locality /*{{{*/ +static int LocalityCompare(const void * const a, const void * const b) +{ + pkgCache::VerFile const * const A = *(pkgCache::VerFile const * const * const)a; + pkgCache::VerFile const * const B = *(pkgCache::VerFile const * const * const)b; + + if (A == 0 && B == 0) + return 0; + if (A == 0) + return 1; + if (B == 0) + return -1; + + if (A->File == B->File) + return A->Offset - B->Offset; + return A->File - B->File; +} +void LocalitySort(pkgCache::VerFile ** const begin, unsigned long long const Count,size_t const Size) +{ + qsort(begin,Count,Size,LocalityCompare); +} +static void LocalitySort(pkgCache::DescFile ** const begin, unsigned long long const Count,size_t const Size) +{ + qsort(begin,Count,Size,LocalityCompare); +} + /*}}}*/ +// Search - Perform a search /*{{{*/ +// --------------------------------------------------------------------- +/* This searches the package names and package descriptions for a pattern */ +struct ExDescFile +{ + pkgCache::DescFile *Df; + pkgCache::VerIterator V; + map_id_t ID; +}; +static bool Search(CommandLine &CmdL) +{ + bool const ShowFull = _config->FindB("APT::Cache::ShowFull",false); + unsigned int const NumPatterns = CmdL.FileSize() -1; + + pkgCacheFile CacheFile; + pkgCache *Cache = CacheFile.GetPkgCache(); + pkgDepCache::Policy *Plcy = CacheFile.GetPolicy(); + if (unlikely(Cache == NULL || Plcy == NULL)) + return false; + + // Make sure there is at least one argument + if (NumPatterns < 1) + return _error->Error(_("You must give at least one search pattern")); + + // Compile the regex pattern + regex_t *Patterns = new regex_t[NumPatterns]; + memset(Patterns,0,sizeof(*Patterns)*NumPatterns); + for (unsigned I = 0; I != NumPatterns; I++) + { + if (regcomp(&Patterns[I],CmdL.FileList[I+1],REG_EXTENDED | REG_ICASE | + REG_NOSUB) != 0) + { + for (; I != 0; I--) + regfree(&Patterns[I]); + return _error->Error("Regex compilation error"); + } + } + + if (_error->PendingError() == true) + { + for (unsigned I = 0; I != NumPatterns; I++) + regfree(&Patterns[I]); + return false; + } + + size_t const descCount = Cache->HeaderP->GroupCount + 1; + ExDescFile *DFList = new ExDescFile[descCount]; + memset(DFList,0,sizeof(*DFList) * descCount); + + bool *PatternMatch = new bool[descCount * NumPatterns]; + memset(PatternMatch,false,sizeof(*PatternMatch) * descCount * NumPatterns); + + // Map versions that we want to write out onto the VerList array. + bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly",false); + for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() == false; ++G) + { + size_t const PatternOffset = G->ID * NumPatterns; + size_t unmatched = 0, matched = 0; + for (unsigned I = 0; I < NumPatterns; ++I) + { + if (PatternMatch[PatternOffset + I] == true) + ++matched; + else if (regexec(&Patterns[I],G.Name(),0,0,0) == 0) + PatternMatch[PatternOffset + I] = true; + else + ++unmatched; + } + + // already dealt with this package? + if (matched == NumPatterns) + continue; + + // Doing names only, drop any that don't match.. + if (NamesOnly == true && unmatched == NumPatterns) + continue; + + // Find the proper version to use + pkgCache::PkgIterator P = G.FindPreferredPkg(); + if (P.end() == true) + continue; + pkgCache::VerIterator V = Plcy->GetCandidateVer(P); + if (V.end() == false) + { + pkgCache::DescIterator const D = V.TranslatedDescription(); + //FIXME: packages without a description can't be found + if (D.end() == true) + continue; + DFList[G->ID].Df = D.FileList(); + DFList[G->ID].V = V; + DFList[G->ID].ID = G->ID; + } + + if (unmatched == NumPatterns) + continue; + + // Include all the packages that provide matching names too + for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; ++Prv) + { + pkgCache::VerIterator V = Plcy->GetCandidateVer(Prv.OwnerPkg()); + if (V.end() == true) + continue; + + unsigned long id = Prv.OwnerPkg().Group()->ID; + pkgCache::DescIterator const D = V.TranslatedDescription(); + //FIXME: packages without a description can't be found + if (D.end() == true) + continue; + DFList[id].Df = D.FileList(); + DFList[id].V = V; + DFList[id].ID = id; + + size_t const PrvPatternOffset = id * NumPatterns; + for (unsigned I = 0; I < NumPatterns; ++I) + PatternMatch[PrvPatternOffset + I] |= PatternMatch[PatternOffset + I]; + } + } + + LocalitySort(&DFList->Df, Cache->HeaderP->GroupCount, sizeof(*DFList)); + + // Create the text record parser + pkgRecords Recs(*Cache); + // 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) + { + 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; + } + } + + bool matchedAll = true; + for (unsigned I = 0; I < NumPatterns; ++I) + if (PatternMatch[PatternOffset + I] == false) + { + matchedAll = false; + break; + } + + if (matchedAll == true) + { + if (ShowFull == true) + DisplayRecordV1(CacheFile, J->V, std::cout); + else + printf("%s - %s\n",P.Name().c_str(),P.ShortDesc().c_str()); + } + } + + delete [] DFList; + delete [] PatternMatch; + for (unsigned I = 0; I != NumPatterns; I++) + regfree(&Patterns[I]); + delete [] Patterns; + if (ferror(stdout)) + return _error->Error("Write to stdout failed"); + return true; +} + /*}}}*/ +bool DoSearch(CommandLine &CmdL) /*{{{*/ +{ + int const ShowVersion = _config->FindI("APT::Cache::Search::Version", 1); + if (ShowVersion <= 1) + return Search(CmdL); + return FullTextSearch(CmdL); +} + diff --git a/apt-private/private-search.h b/apt-private/private-search.h index d4786233a..8ae1f38f3 100644 --- a/apt-private/private-search.h +++ b/apt-private/private-search.h @@ -1,11 +1,12 @@ #ifndef APT_PRIVATE_SEARCH_H #define APT_PRIVATE_SEARCH_H +#include <apt-pkg/pkgcache.h> #include <apt-pkg/macros.h> class CommandLine; -APT_PUBLIC bool FullTextSearch(CommandLine &CmdL); - +APT_PUBLIC bool DoSearch(CommandLine &CmdL); +APT_PUBLIC void LocalitySort(pkgCache::VerFile ** const begin, unsigned long long const Count,size_t const Size); #endif diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index 82cb45acd..24ed9eef3 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -44,6 +44,7 @@ #include <apt-private/private-cacheset.h> #include <apt-private/private-cmndline.h> #include <apt-private/private-show.h> +#include <apt-private/private-search.h> #include <regex.h> #include <stddef.h> @@ -65,38 +66,6 @@ using namespace std; -// LocalitySort - Sort a version list by package file locality /*{{{*/ -// --------------------------------------------------------------------- -/* */ -static int LocalityCompare(const void *a, const void *b) -{ - pkgCache::VerFile *A = *(pkgCache::VerFile **)a; - pkgCache::VerFile *B = *(pkgCache::VerFile **)b; - - if (A == 0 && B == 0) - return 0; - if (A == 0) - return 1; - if (B == 0) - return -1; - - if (A->File == B->File) - return A->Offset - B->Offset; - return A->File - B->File; -} - -static void LocalitySort(pkgCache::VerFile **begin, - unsigned long Count,size_t Size) -{ - qsort(begin,Count,Size,LocalityCompare); -} - -static void LocalitySort(pkgCache::DescFile **begin, - unsigned long Count,size_t Size) -{ - qsort(begin,Count,Size,LocalityCompare); -} - /*}}}*/ // UnMet - Show unmet dependencies /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -1215,173 +1184,6 @@ static bool Dotty(CommandLine &CmdL) return true; } /*}}}*/ -struct ExDescFile -{ - pkgCache::DescFile *Df; - pkgCache::VerIterator V; - map_id_t ID; -}; - -// Search - Perform a search /*{{{*/ -// --------------------------------------------------------------------- -/* This searches the package names and package descriptions for a pattern */ -static bool Search(CommandLine &CmdL) -{ - bool const ShowFull = _config->FindB("APT::Cache::ShowFull",false); - bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly",false); - unsigned int const NumPatterns = CmdL.FileSize() -1; - - pkgCacheFile CacheFile; - pkgCache *Cache = CacheFile.GetPkgCache(); - pkgDepCache::Policy *Plcy = CacheFile.GetPolicy(); - if (unlikely(Cache == NULL || Plcy == NULL)) - return false; - - // Make sure there is at least one argument - if (NumPatterns < 1) - return _error->Error(_("You must give at least one search pattern")); - - // Compile the regex pattern - regex_t *Patterns = new regex_t[NumPatterns]; - memset(Patterns,0,sizeof(*Patterns)*NumPatterns); - for (unsigned I = 0; I != NumPatterns; I++) - { - if (regcomp(&Patterns[I],CmdL.FileList[I+1],REG_EXTENDED | REG_ICASE | - REG_NOSUB) != 0) - { - for (; I != 0; I--) - regfree(&Patterns[I]); - return _error->Error("Regex compilation error"); - } - } - - if (_error->PendingError() == true) - { - for (unsigned I = 0; I != NumPatterns; I++) - regfree(&Patterns[I]); - return false; - } - - size_t const descCount = Cache->HeaderP->GroupCount + 1; - ExDescFile *DFList = new ExDescFile[descCount]; - memset(DFList,0,sizeof(*DFList) * descCount); - - bool *PatternMatch = new bool[descCount * NumPatterns]; - memset(PatternMatch,false,sizeof(*PatternMatch) * descCount * NumPatterns); - - // Map versions that we want to write out onto the VerList array. - for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() == false; ++G) - { - size_t const PatternOffset = G->ID * NumPatterns; - size_t unmatched = 0, matched = 0; - for (unsigned I = 0; I < NumPatterns; ++I) - { - if (PatternMatch[PatternOffset + I] == true) - ++matched; - else if (regexec(&Patterns[I],G.Name(),0,0,0) == 0) - PatternMatch[PatternOffset + I] = true; - else - ++unmatched; - } - - // already dealt with this package? - if (matched == NumPatterns) - continue; - - // Doing names only, drop any that don't match.. - if (NamesOnly == true && unmatched == NumPatterns) - continue; - - // Find the proper version to use - pkgCache::PkgIterator P = G.FindPreferredPkg(); - if (P.end() == true) - continue; - pkgCache::VerIterator V = Plcy->GetCandidateVer(P); - if (V.end() == false) - { - pkgCache::DescIterator const D = V.TranslatedDescription(); - //FIXME: packages without a description can't be found - if (D.end() == true) - continue; - DFList[G->ID].Df = D.FileList(); - DFList[G->ID].V = V; - DFList[G->ID].ID = G->ID; - } - - if (unmatched == NumPatterns) - continue; - - // Include all the packages that provide matching names too - for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; ++Prv) - { - pkgCache::VerIterator V = Plcy->GetCandidateVer(Prv.OwnerPkg()); - if (V.end() == true) - continue; - - unsigned long id = Prv.OwnerPkg().Group()->ID; - pkgCache::DescIterator const D = V.TranslatedDescription(); - //FIXME: packages without a description can't be found - if (D.end() == true) - continue; - DFList[id].Df = D.FileList(); - DFList[id].V = V; - DFList[id].ID = id; - - size_t const PrvPatternOffset = id * NumPatterns; - for (unsigned I = 0; I < NumPatterns; ++I) - PatternMatch[PrvPatternOffset + I] |= PatternMatch[PatternOffset + I]; - } - } - - LocalitySort(&DFList->Df,Cache->HeaderP->GroupCount,sizeof(*DFList)); - - // Create the text record parser - pkgRecords Recs(*Cache); - // 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) - { - 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; - } - } - - bool matchedAll = true; - for (unsigned I = 0; I < NumPatterns; ++I) - if (PatternMatch[PatternOffset + I] == false) - { - matchedAll = false; - break; - } - - if (matchedAll == true) - { - if (ShowFull == true) - DisplayRecordV1(CacheFile, J->V, std::cout); - else - printf("%s - %s\n",P.Name().c_str(),P.ShortDesc().c_str()); - } - } - - delete [] DFList; - delete [] PatternMatch; - for (unsigned I = 0; I != NumPatterns; I++) - regfree(&Patterns[I]); - delete [] Patterns; - if (ferror(stdout)) - return _error->Error("Write to stdout failed"); - return true; -} - /*}}}*/ /* ShowAuto - show automatically installed packages (sorted) {{{*/ static bool ShowAuto(CommandLine &) { @@ -1776,7 +1578,7 @@ int main(int argc,const char *argv[]) /*{{{*/ {"dump",&Dump}, {"dumpavail",&DumpAvail}, {"unmet",&UnMet}, - {"search",&Search}, + {"search",&DoSearch}, {"depends",&Depends}, {"rdepends",&RDepends}, {"dotty",&Dotty}, diff --git a/cmdline/apt.cc b/cmdline/apt.cc index 78cfd5c91..efc263a5d 100644 --- a/cmdline/apt.cc +++ b/cmdline/apt.cc @@ -71,7 +71,7 @@ int main(int argc, const char *argv[]) /*{{{*/ CommandLine::Dispatch Cmds[] = { // query {"list",&DoList}, - {"search", &FullTextSearch}, + {"search", &DoSearch}, {"show", &ShowPackage}, // package stuff @@ -114,12 +114,6 @@ int main(int argc, const char *argv[]) /*{{{*/ return 100; } - // some different defaults - _config->CndSet("DPkg::Progress-Fancy", "1"); - _config->CndSet("Apt::Color", "1"); - _config->CndSet("APT::Get::Upgrade-Allow-New", true); - _config->CndSet("APT::Cmd::Show-Update-Stats", true); - // Parse the command line and initialize the package library CommandLine CmdL; ParseCommandLine(CmdL, Cmds, Args.data(), NULL, &_system, argc, argv, ShowHelp); diff --git a/test/integration/test-apt-cli-list b/test/integration/test-apt-cli-list index d3c44e126..1e9ef871c 100755 --- a/test/integration/test-apt-cli-list +++ b/test/integration/test-apt-cli-list @@ -7,12 +7,6 @@ TESTDIR=$(readlink -f $(dirname $0)) setupenvironment configarchitecture "i386" -if [ ! -x ${BUILDDIRECTORY}/apt ]; then - msgmsg "No ${BUILDDIRECTORY}/apt" - msgskip - exit 0 -fi - insertpackage 'unstable' 'foo' 'all' '1.0' insertinstalledpackage 'bar' 'i386' '1.0' @@ -25,8 +19,6 @@ insertpackage 'unstable' 'baz' 'all' '2.0' setupaptarchive -APTARCHIVE=$(readlink -f ./aptarchive) - testsuccessequal "Listing... bar/now 1.0 i386 [installed,local] baz/unstable 2.0 all [upgradable from: 0.1] @@ -69,6 +61,11 @@ conf-only/now 1.0 i386 [residual-config]" apt list conf-only testsuccessequal "Listing... baz/unstable 2.0 all [upgradable from: 0.1] N: There are 2 additional versions. Please use the '-a' switch to see them." apt list baz -o quiet=0 +testsuccessequal 'Listing... +baz/unstable 2.0 all [upgradable from: 0.1] +baz/testing 1.0 all +baz/now 0.1 all [installed,upgradable to: 2.0] +' apt list baz -o quiet=0 -a # test format strings for machine parseable output testsuccessequal 'bar - 1.0 - 1.0 |