Przeglądaj źródła

support regular expressions in 'apt search'

apt-cache search supported this since ever and in the code for apt was a
fixme indicating this should be added here as well, so here we go.
David Kalnischkies 12 lat temu
rodzic
commit
859093dae7

+ 7 - 2
apt-private/private-cmndline.cc

@@ -70,6 +70,8 @@ static bool addArgumentsAPTCache(std::vector<CommandLine::Args> &Args, char cons
    else
    else
       return false;
       return false;
 
 
+   bool const found_something = Args.empty() == false;
+
    // FIXME: move to the correct command(s)
    // FIXME: move to the correct command(s)
    addArg('g', "generate", "APT::Cache::Generate", 0);
    addArg('g', "generate", "APT::Cache::Generate", 0);
    addArg('t', "target-release", "APT::Default-Release", CommandLine::HasArg);
    addArg('t', "target-release", "APT::Default-Release", CommandLine::HasArg);
@@ -77,7 +79,8 @@ static bool addArgumentsAPTCache(std::vector<CommandLine::Args> &Args, char cons
 
 
    addArg('p', "pkg-cache", "Dir::Cache::pkgcache", CommandLine::HasArg);
    addArg('p', "pkg-cache", "Dir::Cache::pkgcache", CommandLine::HasArg);
    addArg('s', "src-cache", "Dir::Cache::srcpkgcache", CommandLine::HasArg);
    addArg('s', "src-cache", "Dir::Cache::srcpkgcache", CommandLine::HasArg);
-   return true;
+
+   return found_something;
 }
 }
 									/*}}}*/
 									/*}}}*/
 static bool addArgumentsAPTCDROM(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/
 static bool addArgumentsAPTCDROM(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/
@@ -172,6 +175,8 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const
       addArg('s', "no-act", "APT::Get::Simulate", 0);
       addArg('s', "no-act", "APT::Get::Simulate", 0);
    }
    }
 
 
+   bool const found_something = Args.empty() == false;
+
    // FIXME: move to the correct command(s)
    // FIXME: move to the correct command(s)
    addArg('d',"download-only","APT::Get::Download-Only",0);
    addArg('d',"download-only","APT::Get::Download-Only",0);
    addArg('y',"yes","APT::Get::Assume-Yes",0);
    addArg('y',"yes","APT::Get::Assume-Yes",0);
@@ -197,7 +202,7 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const
    addArg(0,"install-suggests","APT::Install-Suggests",CommandLine::Boolean);
    addArg(0,"install-suggests","APT::Install-Suggests",CommandLine::Boolean);
    addArg(0,"fix-policy","APT::Get::Fix-Policy-Broken",0);
    addArg(0,"fix-policy","APT::Get::Fix-Policy-Broken",0);
 
 
-   return true;
+   return found_something;
 }
 }
 									/*}}}*/
 									/*}}}*/
 static bool addArgumentsAPTMark(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/
 static bool addArgumentsAPTMark(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/

+ 35 - 17
apt-private/private-search.cc

@@ -36,8 +36,28 @@ bool FullTextSearch(CommandLine &CmdL)					/*{{{*/
    if (unlikely(Cache == NULL || Plcy == NULL))
    if (unlikely(Cache == NULL || Plcy == NULL))
       return false;
       return false;
 
 
-   const char **patterns;
-   patterns = CmdL.FileList + 1;
+   // Make sure there is at least one argument
+   unsigned int const NumPatterns = CmdL.FileSize() -1;
+   if (NumPatterns < 1)
+      return _error->Error(_("You must give at least one search pattern"));
+
+#define APT_FREE_PATTERNS() for (std::vector<regex_t>::iterator P = Patterns.begin(); \
+      P != Patterns.end(); ++P) { regfree(&(*P)); }
+
+   // Compile the regex pattern
+   std::vector<regex_t> Patterns;
+   for (unsigned int I = 0; I != NumPatterns; ++I)
+   {
+      regex_t pattern;
+      if (regcomp(&pattern, CmdL.FileList[I + 1], REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0)
+      {
+	 APT_FREE_PATTERNS();
+	 return _error->Error("Regex compilation error");
+      }
+      Patterns.push_back(pattern);
+   }
+
+   bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly", false);
 
 
    std::map<std::string, std::string> output_map;
    std::map<std::string, std::string> output_map;
    std::map<std::string, std::string>::const_iterator K;
    std::map<std::string, std::string>::const_iterator K;
@@ -56,26 +76,23 @@ bool FullTextSearch(CommandLine &CmdL)					/*{{{*/
       if (Done%500 == 0)
       if (Done%500 == 0)
          progress.Progress(Done);
          progress.Progress(Done);
       ++Done;
       ++Done;
-      
-      int i;
+
       pkgCache::DescIterator Desc = V.TranslatedDescription();
       pkgCache::DescIterator Desc = V.TranslatedDescription();
       pkgRecords::Parser &parser = records.Lookup(Desc.FileList());
       pkgRecords::Parser &parser = records.Lookup(Desc.FileList());
-     
+
       bool all_found = true;
       bool all_found = true;
-      for(i=0; patterns[i] != NULL; ++i)
+      for (std::vector<regex_t>::const_iterator pattern = Patterns.begin();
+	    pattern != Patterns.end(); ++pattern)
       {
       {
-         // FIXME: use regexp instead of simple find()
-         const char *pattern = patterns[i];
-         all_found &=  (
-            strstr(V.ParentPkg().Name(), pattern) != NULL ||
-            strcasestr(parser.ShortDesc().c_str(), pattern) != NULL ||
-            strcasestr(parser.LongDesc().c_str(), pattern) != NULL);
-         // search patterns are AND by default so we can skip looking further
-         // on the first mismatch
-         if(all_found == false)
-            break;
+	 if (regexec(&(*pattern), V.ParentPkg().Name(), 0, 0, 0) == 0)
+	    continue;
+	 else if (NamesOnly == false && regexec(&(*pattern), parser.LongDesc().c_str(), 0, 0, 0) == 0)
+	    continue;
+	 // search patterns are AND, so one failing fails all
+	 all_found = false;
+	 break;
       }
       }
-      if (all_found)
+      if (all_found == true)
       {
       {
             std::stringstream outs;
             std::stringstream outs;
             ListSingleVersion(CacheFile, records, V, outs);
             ListSingleVersion(CacheFile, records, V, outs);
@@ -83,6 +100,7 @@ bool FullTextSearch(CommandLine &CmdL)					/*{{{*/
                                  V.ParentPkg().Name(), outs.str()));
                                  V.ParentPkg().Name(), outs.str()));
       }
       }
    }
    }
+   APT_FREE_PATTERNS();
    progress.Done();
    progress.Done();
 
 
    // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status)
    // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status)

+ 7 - 1
test/integration/framework

@@ -1019,7 +1019,13 @@ testfileequal() {
 
 
 testempty() {
 testempty() {
 	msgtest "Test for no output of" "$*"
 	msgtest "Test for no output of" "$*"
-	test -z "$($* 2>&1)" && msgpass || msgfail
+	local COMPAREFILE="${TMPWORKINGDIRECTORY}/rootdir/tmp/testempty.comparefile"
+	if $* >$COMPAREFILE 2>&1 && test ! -s $COMPAREFILE; then
+		msgpass
+	else
+		cat $COMPAREFILE
+		msgfail
+	fi
 }
 }
 
 
 testequal() {
 testequal() {

+ 15 - 0
test/integration/test-apt-cli-search

@@ -33,16 +33,31 @@ foo/unstable 1.0 all
 testequal "foo/unstable 1.0 all
 testequal "foo/unstable 1.0 all
   $DESCR
   $DESCR
 " apt search -qq xxyyzz
 " apt search -qq xxyyzz
+testempty apt search -qq --names-only xxyyzz
+
+# search name
+testequal "foo/unstable 1.0 all
+  $DESCR
+" apt search -qq foo
+testequal "foo/unstable 1.0 all
+  $DESCR
+" apt search -qq --names-only foo
 
 
 # search with multiple words is a AND search
 # search with multiple words is a AND search
 testequal "foo/unstable 1.0 all
 testequal "foo/unstable 1.0 all
   $DESCR
   $DESCR
 " apt search -qq aabbcc xxyyzz
 " apt search -qq aabbcc xxyyzz
+testequal "foo/unstable 1.0 all
+  $DESCR
+" apt search -qq 'a+b+c+' 'i*xxy{0,2}zz'
 
 
 # search is not case-sensitive by default
 # search is not case-sensitive by default
 testequal "foo/unstable 1.0 all
 testequal "foo/unstable 1.0 all
   $DESCR
   $DESCR
 " apt search -qq uppercase
 " apt search -qq uppercase
+testequal "foo/unstable 1.0 all
+  $DESCR
+" apt search -qq 'up[pP]erc[Aa]se'
 
 
 # output is sorted and search word finds both package
 # output is sorted and search word finds both package
 testequal "bar/testing 2.0 i386
 testequal "bar/testing 2.0 i386