~synaptic-developers/synaptic/trunk

« back to all changes in this revision

Viewing changes to common/rpackagelister.cc

  • Committer: Michael Vogt
  • Date: 2010-07-29 13:13:09 UTC
  • mfrom: (1529.2.106 ubuntu)
  • Revision ID: michael.vogt@ubuntu.com-20100729131309-0gdmwd09phcr1gc0
merged from the synaptic ubuntu branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
#include <sys/stat.h>
37
37
#include <unistd.h>
38
38
#include <time.h>
 
39
#include <algorithm>
39
40
 
40
41
#include "rpackagelister.h"
41
42
#include "rpackagecache.h"
78
79
 
79
80
RPackageLister::RPackageLister()
80
81
   : _records(0), _progMeter(new OpProgress)
 
82
#ifdef WITH_EPT
 
83
   , _xapianDatabase(0)
 
84
#endif
81
85
{
82
86
   _cache = new RPackageCache();
83
87
 
85
89
   _searchData.isRegex = false;
86
90
   _viewMode = _config->FindI("Synaptic::ViewMode", 0);
87
91
   _updating = true;
88
 
   _sortMode = LIST_SORT_NAME_ASC;
 
92
   _sortMode = LIST_SORT_DEFAULT;
89
93
 
90
94
   // keep order in sync with rpackageview.h 
91
95
   _views.push_back(new RPackageViewSections(_packages));
94
98
   _filterView = new RPackageViewFilter(_packages);
95
99
   _views.push_back(_filterView);
96
100
   _searchView =  new RPackageViewSearch(_packages);
97
 
   _views.push_back(_searchView);   
 
101
   _views.push_back(_searchView);
98
102
   //_views.push_back(new RPackageViewAlphabetic(_packages));
 
103
#ifdef WITH_EPT
 
104
   openXapianIndex();
 
105
#endif
99
106
 
100
107
   if (_viewMode >= _views.size())
101
108
      _viewMode = 0;
419
426
   return true;
420
427
}
421
428
 
422
 
 
 
429
#ifdef WITH_EPT
 
430
bool RPackageLister::xapianIndexNeedsUpdate()
 
431
{
 
432
   struct stat buf;
 
433
   
 
434
   if(_config->FindB("Debug::Synaptic::Xapian",false))
 
435
      std::cerr << "xapainIndexNeedsUpdate()" << std::endl;
 
436
 
 
437
   // check the xapian index
 
438
   if(FileExists("/usr/sbin/update-apt-xapian-index") && 
 
439
      (!_xapianDatabase )) {
 
440
      if(_config->FindB("Debug::Synaptic::Xapian",false))
 
441
         std::cerr << "xapain index not build yet" << std::endl;
 
442
      return true;
 
443
   } 
 
444
 
 
445
   // compare timestamps, rebuild everytime, its now cheap(er) 
 
446
   // because we use u-a-x-i --update
 
447
   stat(_config->FindFile("Dir::Cache::pkgcache").c_str(), &buf);
 
448
   if(ept::axi::timestamp() < buf.st_mtime) {
 
449
      if(_config->FindB("Debug::Synaptic::Xapian",false))
 
450
         std::cerr << "xapian outdated " 
 
451
                   << buf.st_mtime - ept::axi::timestamp()  << std::endl;
 
452
      return true;
 
453
   }
 
454
 
 
455
   return false;
 
456
}
 
457
 
 
458
bool RPackageLister::openXapianIndex()
 
459
{
 
460
   if(_xapianDatabase)
 
461
      delete _xapianDatabase;
 
462
   try {
 
463
      _xapianDatabase = new Xapian::Database(ept::axi::path_db());
 
464
   } catch (Xapian::DatabaseOpeningError) {
 
465
      return false;
 
466
   };
 
467
   return true;
 
468
}
 
469
#endif
423
470
 
424
471
void RPackageLister::applyInitialSelection()
425
472
{
635
682
 
636
683
   switch(mode) {
637
684
   case LIST_SORT_NAME_ASC:
 
685
   case LIST_SORT_DEFAULT:
638
686
      // Do nothing, already done
639
687
      break;
640
688
   case LIST_SORT_NAME_DES:
1235
1283
   // Get the source list
1236
1284
   //pkgSourceList List;
1237
1285
   _cache->list()->ReadMainList();
 
1286
 
1238
1287
   // Lock the list directory
1239
1288
   FileFd Lock;
1240
1289
   if (_config->FindB("Debug::NoLocking", false) == false) {
1246
1295
 
1247
1296
   _updating = true;
1248
1297
 
 
1298
 
 
1299
#ifndef HAVE_RPM
 
1300
// apt-0.7.10 has the new UpdateList code in algorithms, we use it
 
1301
   string s;
 
1302
   bool res = ListUpdate(*status, *_cache->list(), 5000);
 
1303
   if(res == false)
 
1304
   {
 
1305
      while(!_error->empty())
 
1306
      {
 
1307
         bool isError = _error->PopMessage(s);
 
1308
         error += s;
 
1309
      }
 
1310
   }
 
1311
   return res;
 
1312
#else
1249
1313
   // Create the download object
1250
1314
   pkgAcquire Fetcher(status);
1251
1315
 
1252
1316
   bool Failed = false;
1253
1317
 
1254
 
#if HAVE_RPM
1255
1318
   if (_cache->list()->GetReleases(&Fetcher) == false)
1256
1319
      return false;
1257
1320
   Fetcher.Run();
1266
1329
      _error->Warning(_("Release files for some repositories could not be "
1267
1330
                        "retrieved or authenticated. Such repositories are "
1268
1331
                        "being ignored."));
1269
 
#endif /* HAVE_RPM */
1270
1332
 
1271
1333
   if (!_cache->list()->GetIndexes(&Fetcher))
1272
1334
      return false;
1273
1335
 
1274
 
// apt-rpm does not support the pulseInterval
1275
 
#ifdef HAVE_RPM 
1276
1336
   // Run it
1277
1337
   if (Fetcher.Run() == pkgAcquire::Failed)
1278
1338
      return false;
1279
 
#else
1280
 
   if (Fetcher.Run(50000) == pkgAcquire::Failed)
1281
 
      return false;
1282
 
#endif
1283
 
 
1284
1339
 
1285
1340
   //bool AuthFailed = false;
1286
1341
   Failed = false;
1313
1368
      return false; 
1314
1369
   }
1315
1370
   return true;
 
1371
#endif
1316
1372
}
1317
1373
 
1318
1374
bool RPackageLister::getDownloadUris(vector<string> &uris)
1410
1466
 
1411
1467
         serverError = getServerErrorMessage(errm);
1412
1468
 
1413
 
         _error->Warning(tmp.str().c_str());
 
1469
         _error->Warning("%s", tmp.str().c_str());
1414
1470
         Failed = true;
1415
1471
      }
1416
1472
 
1883
1939
}
1884
1940
 
1885
1941
 
 
1942
#ifdef WITH_EPT
 
1943
bool RPackageLister::limitBySearch(string searchString)
 
1944
{
 
1945
   //cerr << "limitBySearch(): " << searchString << endl;
 
1946
    if (ept::axi::timestamp() == 0)
 
1947
        return false;
 
1948
   return xapianSearch(searchString);
 
1949
}
 
1950
 
 
1951
bool RPackageLister::xapianSearch(string unsplitSearchString)
 
1952
{
 
1953
   //std::cerr << "RPackageLister::xapianSearch()" << std::endl;
 
1954
   static const int defaultQualityCutoff = 15;
 
1955
   int qualityCutoff = _config->FindI("Synaptic::Xapian::qualityCutoff", 
 
1956
                                      defaultQualityCutoff);
 
1957
    if (ept::axi::timestamp() == 0) 
 
1958
        return false;
 
1959
 
 
1960
   try {
 
1961
      int maxItems = _xapianDatabase->get_doccount();
 
1962
      Xapian::Enquire enquire(*_xapianDatabase);
 
1963
      Xapian::QueryParser parser;
 
1964
      parser.set_database(*_xapianDatabase);
 
1965
      parser.add_prefix("name","XP");
 
1966
      parser.add_prefix("section","XS");
 
1967
      // default op is AND to narrow down the resultset
 
1968
      parser.set_default_op( Xapian::Query::OP_AND );
 
1969
   
 
1970
      /* Workaround to allow searching an hyphenated package name using a prefix (name:)
 
1971
       * LP: #282995
 
1972
       * Xapian currently doesn't support wildcard for boolean prefix and 
 
1973
       * doesn't handle implicit wildcards at the end of hypenated phrases.
 
1974
       *
 
1975
       * e.g searching for name:ubuntu-res will be equivalent to 'name:ubuntu res*'
 
1976
       * however 'name:(ubuntu* res*) won't return any result because the 
 
1977
       * index is built with the full package name
 
1978
       */
 
1979
      // Always search for the package name
 
1980
      string xpString = "name:";
 
1981
      string::size_type pos = unsplitSearchString.find_first_of(" ,;");
 
1982
      if (pos > 0) {
 
1983
          xpString += unsplitSearchString.substr(0,pos);
 
1984
      } else {
 
1985
          xpString += unsplitSearchString;
 
1986
      }
 
1987
      Xapian::Query xpQuery = parser.parse_query(xpString);
 
1988
 
 
1989
      pos = 0;
 
1990
      while ( (pos = unsplitSearchString.find("-", pos)) != string::npos ) {
 
1991
         unsplitSearchString.replace(pos, 1, " ");
 
1992
         pos+=1;
 
1993
      }
 
1994
 
 
1995
      if(_config->FindB("Debug::Synaptic::Xapian",false)) 
 
1996
         std::cerr << "searching for : " << unsplitSearchString << std::endl;
 
1997
      
 
1998
      // Build the query
 
1999
      // apply a weight factor to XP term to increase relevancy on package name
 
2000
      Xapian::Query query = parser.parse_query(unsplitSearchString, 
 
2001
         Xapian::QueryParser::FLAG_WILDCARD |
 
2002
         Xapian::QueryParser::FLAG_BOOLEAN |
 
2003
         Xapian::QueryParser::FLAG_PARTIAL);
 
2004
      query = Xapian::Query(Xapian::Query::OP_OR, query, 
 
2005
              Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT, xpQuery, 3));
 
2006
      enquire.set_query(query);
 
2007
      Xapian::MSet matches = enquire.get_mset(0, maxItems);
 
2008
 
 
2009
      if(_config->FindB("Debug::Synaptic::Xapian",false)) {
 
2010
         cerr << "enquire: " << enquire.get_description() << endl;
 
2011
         cerr << "matches estimated: " << matches.get_matches_estimated() << " results found" << endl;
 
2012
      }
 
2013
 
 
2014
      // Retrieve the results
 
2015
      int top_percent = 0;
 
2016
      _viewPackages.clear();
 
2017
      for (Xapian::MSetIterator i = matches.begin(); i != matches.end(); ++i)
 
2018
      {
 
2019
         RPackage* pkg = getPackage(i.get_document().get_data());
 
2020
         // Filter out results that apt doesn't know
 
2021
         if (!pkg || !_selectedView->hasPackage(pkg))
 
2022
            continue;
 
2023
 
 
2024
         // Save the confidence interval of the top value, to use it as
 
2025
         // a reference to compute an adaptive quality cutoff
 
2026
         if (top_percent == 0)
 
2027
            top_percent = i.get_percent();
 
2028
   
 
2029
         // Stop producing if the quality goes below a cutoff point
 
2030
         if (i.get_percent() < qualityCutoff * top_percent / 100)
 
2031
         {
 
2032
            cerr << "Discarding: " << i.get_percent() << " over " << qualityCutoff * top_percent / 100 << endl;
 
2033
            break;
 
2034
         }
 
2035
   
 
2036
         if(_config->FindB("Debug::Synaptic::Xapian",false)) 
 
2037
            cerr << i.get_rank() + 1 << ": " << i.get_percent() << "% docid=" << *i << "        [" << i.get_document().get_data() << "]" << endl;
 
2038
         _viewPackages.push_back(pkg);
 
2039
         }
 
2040
      // re-apply sort criteria only if an explicit search is set
 
2041
      if (_sortMode != LIST_SORT_DEFAULT)
 
2042
          sortPackages(_sortMode);
 
2043
      return true;
 
2044
   } catch (const Xapian::Error & error) {
 
2045
      /* We are here if a Xapian call failed. The main cause is a parser exception.
 
2046
       * The error message is always in English currently. 
 
2047
       * The possible parser errors are:
 
2048
       *    Unknown range operation
 
2049
       *    parse error
 
2050
       *    Syntax: <expression> AND <expression>
 
2051
       *    Syntax: <expression> AND NOT <expression>
 
2052
       *    Syntax: <expression> NOT <expression>
 
2053
       *    Syntax: <expression> OR <expression>
 
2054
       *    Syntax: <expression> XOR <expression>
 
2055
       */
 
2056
      cerr << "Exception in RPackageLister::xapianSearch():" << error.get_msg() << endl;
 
2057
      return false;
 
2058
   }
 
2059
}
 
2060
#else
 
2061
bool RPackageLister::limitBySearch(string searchString)
 
2062
{
 
2063
   return false;
 
2064
}
 
2065
 
 
2066
bool RPackageLister::xapianSearch(string searchString) 
 
2067
 
2068
   return false; 
 
2069
}
 
2070
#endif
 
2071
 
 
2072
 
1886
2073
// vim:ts=3:sw=3:et