support regular expressions in 'apt search'
authorDavid Kalnischkies <david@kalnischkies.de>
Sat, 30 Aug 2014 09:29:45 +0000 (11:29 +0200)
committerDavid Kalnischkies <david@kalnischkies.de>
Sun, 7 Sep 2014 17:23:28 +0000 (19:23 +0200)
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.

apt-private/private-cmndline.cc
apt-private/private-search.cc
test/integration/framework
test/integration/test-apt-cli-search

index a21a9dc..a4490f5 100644 (file)
@@ -70,6 +70,8 @@ static bool addArgumentsAPTCache(std::vector<CommandLine::Args> &Args, char cons
    else
       return false;
 
+   bool const found_something = Args.empty() == false;
+
    // FIXME: move to the correct command(s)
    addArg('g', "generate", "APT::Cache::Generate", 0);
    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('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)/*{{{*/
@@ -172,6 +175,8 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const
       addArg('s', "no-act", "APT::Get::Simulate", 0);
    }
 
+   bool const found_something = Args.empty() == false;
+
    // FIXME: move to the correct command(s)
    addArg('d',"download-only","APT::Get::Download-Only",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,"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)/*{{{*/
index ecd5d7f..2230c97 100644 (file)
@@ -36,8 +36,28 @@ bool FullTextSearch(CommandLine &CmdL)                                       /*{{{*/
    if (unlikely(Cache == NULL || Plcy == NULL))
       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>::const_iterator K;
@@ -56,26 +76,23 @@ bool FullTextSearch(CommandLine &CmdL)                                      /*{{{*/
       if (Done%500 == 0)
          progress.Progress(Done);
       ++Done;
-      
-      int i;
+
       pkgCache::DescIterator Desc = V.TranslatedDescription();
       pkgRecords::Parser &parser = records.Lookup(Desc.FileList());
-     
+
       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;
             ListSingleVersion(CacheFile, records, V, outs);
@@ -83,6 +100,7 @@ bool FullTextSearch(CommandLine &CmdL)                                       /*{{{*/
                                  V.ParentPkg().Name(), outs.str()));
       }
    }
+   APT_FREE_PATTERNS();
    progress.Done();
 
    // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status)
index 3bbf440..fde74f5 100644 (file)
@@ -1019,7 +1019,13 @@ testfileequal() {
 
 testempty() {
        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() {
index 5861371..3ac0749 100755 (executable)
@@ -33,16 +33,31 @@ foo/unstable 1.0 all
 testequal "foo/unstable 1.0 all
   $DESCR
 " 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
 testequal "foo/unstable 1.0 all
   $DESCR
 " 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
 testequal "foo/unstable 1.0 all
   $DESCR
 " 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
 testequal "bar/testing 2.0 i386