~thopiekar/zypper/libzypp-manual-import

« back to all changes in this revision

Viewing changes to zypp/PoolQuery.cc

  • Committer: Thomas-Karl Pietrowski
  • Date: 2014-01-29 22:44:28 UTC
  • Revision ID: thopiekar@googlemail.com-20140129224428-gpcqnsdakby362n8
firstĀ import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*---------------------------------------------------------------------\
 
2
|                          ____ _   __ __ ___                          |
 
3
|                         |__  / \ / / . \ . \                         |
 
4
|                           / / \ V /|  _/  _/                         |
 
5
|                          / /__ | | | | | |                           |
 
6
|                         /_____||_| |_| |_|                           |
 
7
|                                                                      |
 
8
\---------------------------------------------------------------------*/
 
9
/** \file       zypp/PoolQuery.cc
 
10
 *
 
11
*/
 
12
#include <iostream>
 
13
#include <sstream>
 
14
 
 
15
#include "zypp/base/Gettext.h"
 
16
#include "zypp/base/LogTools.h"
 
17
#include "zypp/base/Algorithm.h"
 
18
#include "zypp/base/String.h"
 
19
#include "zypp/repo/RepoException.h"
 
20
#include "zypp/RelCompare.h"
 
21
 
 
22
#include "zypp/sat/Pool.h"
 
23
#include "zypp/sat/Solvable.h"
 
24
#include "zypp/base/StrMatcher.h"
 
25
 
 
26
#include "zypp/PoolQuery.h"
 
27
 
 
28
#undef ZYPP_BASE_LOGGER_LOGGROUP
 
29
#define ZYPP_BASE_LOGGER_LOGGROUP "PoolQuery"
 
30
 
 
31
using namespace std;
 
32
using namespace zypp::sat;
 
33
 
 
34
///////////////////////////////////////////////////////////////////
 
35
namespace zypp
 
36
{ /////////////////////////////////////////////////////////////////
 
37
 
 
38
  ///////////////////////////////////////////////////////////////////
 
39
  namespace
 
40
  { /////////////////////////////////////////////////////////////////
 
41
 
 
42
    /////////////////////////////////////////////////////////////////
 
43
    // some Helpers and Predicates
 
44
    /////////////////////////////////////////////////////////////////
 
45
 
 
46
    bool isDependencyAttribute( sat::SolvAttr attr_r )
 
47
    {
 
48
      static sat::SolvAttr deps[] = {
 
49
        SolvAttr::provides,
 
50
        SolvAttr::requires,
 
51
        SolvAttr::recommends,
 
52
        SolvAttr::obsoletes,
 
53
        SolvAttr::conflicts,
 
54
        SolvAttr::suggests,
 
55
        SolvAttr::supplements,
 
56
        SolvAttr::enhances,
 
57
      };
 
58
      for_( it, arrayBegin(deps), arrayEnd(deps) )
 
59
        if ( *it == attr_r )
 
60
          return true;
 
61
      return false;
 
62
    }
 
63
 
 
64
    /** Whether the current capabilities edition range ovelaps and/or its solvables arch matches.
 
65
     * Query asserts \a iter_r points to a capability and we
 
66
     * have to check the range only.
 
67
     */
 
68
    struct EditionRangePredicate
 
69
    {
 
70
      EditionRangePredicate( const Rel & op, const Edition & edition )
 
71
        : _range( op, edition )
 
72
        , _arch( Arch_empty )
 
73
      {}
 
74
      EditionRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
 
75
        : _range( op, edition )
 
76
        , _arch( arch )
 
77
      {}
 
78
 
 
79
      bool operator()( sat::LookupAttr::iterator iter_r )
 
80
      {
 
81
        if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
 
82
          return false;
 
83
 
 
84
        CapDetail cap( iter_r.id() );
 
85
        if ( ! cap.isSimple() )
 
86
          return false;
 
87
        if ( cap.isNamed() ) // no range to match
 
88
          return true;
 
89
        return overlaps( Edition::MatchRange( cap.op(), cap.ed() ), _range );
 
90
      }
 
91
 
 
92
      std::string serialize() const
 
93
      {
 
94
        std::string ret( "EditionRange" );
 
95
        str::appendEscaped( ret, _range.op.asString() );
 
96
        str::appendEscaped( ret, _range.value.asString() );
 
97
        str::appendEscaped( ret, _arch.asString() );
 
98
        return ret;
 
99
      }
 
100
 
 
101
      Edition::MatchRange _range;
 
102
      Arch                _arch;
 
103
   };
 
104
 
 
105
    /** Whether the current Solvables edition is within a given range and/or its arch matches. */
 
106
    struct SolvableRangePredicate
 
107
    {
 
108
      SolvableRangePredicate( const Rel & op, const Edition & edition )
 
109
        : _range( op, edition )
 
110
        , _arch( Arch_empty )
 
111
      {}
 
112
 
 
113
      SolvableRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
 
114
        : _range( op, edition )
 
115
        , _arch( arch )
 
116
      {}
 
117
 
 
118
      bool operator()( sat::LookupAttr::iterator iter_r )
 
119
      {
 
120
        if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
 
121
          return false;
 
122
        return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
 
123
      }
 
124
 
 
125
      std::string serialize() const
 
126
      {
 
127
        std::string ret( "SolvableRange" );
 
128
        str::appendEscaped( ret, _range.op.asString() );
 
129
        str::appendEscaped( ret, _range.value.asString() );
 
130
        str::appendEscaped( ret, _arch.asString() );
 
131
        return ret;
 
132
      }
 
133
 
 
134
      Edition::MatchRange _range;
 
135
      Arch                _arch;
 
136
    };
 
137
 
 
138
    /** Whether the current capability matches a given one.
 
139
     * Query asserts \a iter_r points to a capability and we
 
140
     * have to check the match only.
 
141
     */
 
142
    struct CapabilityMatchPredicate
 
143
    {
 
144
      CapabilityMatchPredicate( Capability cap_r )
 
145
        : _cap( cap_r )
 
146
      {}
 
147
 
 
148
      bool operator()( sat::LookupAttr::iterator iter_r ) const
 
149
      {
 
150
        return _cap.matches( iter_r.asType<Capability>() ) == CapMatch::yes;
 
151
      }
 
152
 
 
153
      std::string serialize() const
 
154
      {
 
155
        std::string ret( "CapabilityMatch" );
 
156
        str::appendEscaped( ret, _cap.asString() );
 
157
        return ret;
 
158
      }
 
159
 
 
160
      Capability _cap;
 
161
    };
 
162
 
 
163
    /////////////////////////////////////////////////////////////////
 
164
    //
 
165
    /////////////////////////////////////////////////////////////////
 
166
    /** Match data per attribtue.
 
167
     *
 
168
     * This includes the attribute itself, an optional \ref StrMatcher
 
169
     * to restrict the query to certain string values, and an optional
 
170
     * boolean \ref Predicate that may apply further restrictions that can
 
171
     * not be expressed by the \ref strMatcher.
 
172
     *
 
173
     * Example for such a \ref predicate would be an additional edition range
 
174
     * check whan looking for dependencies. The \ref strMatcher would
 
175
     * find potential matches by looking at the dependencies name, the
 
176
     * predicate will then check the edition ranges.
 
177
     *
 
178
     * As the \ref predicate takes an iterator pointing to the current
 
179
     * match, it's also suitable for sub-structure (flexarray) inspection
 
180
     * (\see \ref sat::LookupAttr::iterator::solvAttrSubEntry).
 
181
     *
 
182
     * \note: \see \ref addPredicate for further constraints.
 
183
     */
 
184
    struct AttrMatchData
 
185
    {
 
186
      typedef function<bool(sat::LookupAttr::iterator)> Predicate;
 
187
 
 
188
      static bool always( sat::LookupAttr::iterator ) { return true; }
 
189
      static bool never( sat::LookupAttr::iterator ) { return false; }
 
190
 
 
191
      AttrMatchData()
 
192
      {}
 
193
 
 
194
      AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r )
 
195
        : attr( attr_r )
 
196
        , strMatcher( strMatcher_r )
 
197
      {}
 
198
 
 
199
      AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r,
 
200
                     const Predicate & predicate_r, const std::string & predicateStr_r )
 
201
        : attr( attr_r )
 
202
        , strMatcher( strMatcher_r )
 
203
        , predicate( predicate_r )
 
204
        , predicateStr( predicateStr_r )
 
205
      {}
 
206
 
 
207
      /** A usable Predicate must provide a string serialization.
 
208
       * As there is no \c operator== for \ref Predicate, we compare it's
 
209
       * string representation instead. If you add new predicated, check the
 
210
       * deserialization code in \ref deserialize.
 
211
       */
 
212
      template<class _Predicate>
 
213
      void addPredicate( const _Predicate & predicate_r )
 
214
      {
 
215
        predicate    = predicate_r;
 
216
        predicateStr = predicate_r.serialize();
 
217
      }
 
218
 
 
219
      /** Dumb serialization.
 
220
       * \code
 
221
       *   AttrMatchData ATTRIBUTE SEARCHSTRING [C|X] SERIALIZED_PREDICATE
 
222
       * \endcode
 
223
      */
 
224
      std::string serialize() const
 
225
      {
 
226
        std::string ret( "AttrMatchData" );
 
227
        str::appendEscaped( ret, attr.asString() );
 
228
        str::appendEscaped( ret, strMatcher.searchstring() );
 
229
        // TODO: Actually the flag should be serialized too, but for PoolQuery
 
230
        // it's by now sufficient to differ between mode OTHER and others,
 
231
        // i.e. whether to compile or not compile.
 
232
        str::appendEscaped( ret, strMatcher.flags().mode() == Match::OTHER ? "C" : "X" );
 
233
        str::appendEscaped( ret, predicateStr );
 
234
        return ret;
 
235
      }
 
236
 
 
237
       /** Dumb restore from serialized string.
 
238
        * \throw Exception on parse error.
 
239
        */
 
240
      static AttrMatchData deserialize( const std::string & str_r )
 
241
      {
 
242
        std::vector<std::string> words;
 
243
        str::splitEscaped( str_r, std::back_inserter(words) );
 
244
        if ( words.empty() || words[0] != "AttrMatchData" )
 
245
          ZYPP_THROW( Exception( str::Str() << "Expecting AttrMatchData: " << str_r ) );
 
246
        if ( words.size() != 5 )
 
247
          ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
 
248
 
 
249
        AttrMatchData ret;
 
250
        ret.attr = sat::SolvAttr( words[1] );
 
251
        ret.strMatcher = StrMatcher( words[2] );
 
252
        if ( words[3] == "C" )
 
253
          ret.strMatcher.setFlags( Match::OTHER );
 
254
        ret.predicateStr = words[4];
 
255
 
 
256
        // now the predicate
 
257
        words.clear();
 
258
        str::splitEscaped( ret.predicateStr, std::back_inserter(words) );
 
259
        if ( ! words.empty() )
 
260
        {
 
261
          if ( words[0] == "EditionRange" )
 
262
          {
 
263
            switch( words.size() )
 
264
            {
 
265
              case 3:
 
266
                ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]) );
 
267
                break;
 
268
              case 4:
 
269
                ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
 
270
                break;
 
271
              default:
 
272
                ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
 
273
                break;
 
274
            }
 
275
          }
 
276
          else if ( words[0] == "SolvableRange" )
 
277
          {
 
278
            switch( words.size() )
 
279
            {
 
280
              case 3:
 
281
                ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]) );
 
282
                break;
 
283
              case 4:
 
284
                ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
 
285
                break;
 
286
              default:
 
287
                ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
 
288
                break;
 
289
            }
 
290
          }
 
291
          else if ( words[0] == "CapabilityMatch" )
 
292
          {
 
293
            if ( words.size() != 2 )
 
294
              ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
 
295
            ret.predicate = CapabilityMatchPredicate( Capability(words[1]) );
 
296
          }
 
297
          else
 
298
            ZYPP_THROW( Exception( str::Str() << "Unknown predicate: " << str_r ) );
 
299
        }
 
300
        return ret;
 
301
     }
 
302
 
 
303
      sat::SolvAttr    attr;
 
304
      StrMatcher strMatcher;
 
305
      Predicate        predicate;
 
306
      std::string      predicateStr;
 
307
    };
 
308
 
 
309
    /** \relates AttrMatchData */
 
310
    inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
 
311
    {
 
312
      str << obj.attr << ": " << obj.strMatcher;
 
313
      if ( obj.predicate )
 
314
        str << " +(" << obj.predicateStr << ")";
 
315
      return str;
 
316
    }
 
317
 
 
318
    /** \relates AttrMatchData */
 
319
    inline bool operator==( const AttrMatchData & lhs, const AttrMatchData & rhs )
 
320
    {
 
321
      return ( lhs.attr == rhs.attr
 
322
               && lhs.strMatcher == rhs.strMatcher
 
323
               && lhs.predicateStr == rhs.predicateStr );
 
324
    }
 
325
 
 
326
    /** \relates AttrMatchData */
 
327
    inline bool operator!=( const AttrMatchData & lhs, const AttrMatchData & rhs )
 
328
    { return !( lhs == rhs ); }
 
329
 
 
330
    /** \relates AttrMatchData Arbitrary order for std::container. */
 
331
    inline bool operator<( const AttrMatchData & lhs, const AttrMatchData & rhs )
 
332
    {
 
333
      if ( lhs.attr != rhs.attr )
 
334
        return (  lhs.attr < rhs.attr );
 
335
      if ( lhs.strMatcher != rhs.strMatcher )
 
336
        return (  lhs.strMatcher < rhs.strMatcher );
 
337
      if ( lhs.predicateStr != rhs.predicateStr )
 
338
        return (  lhs.predicateStr < rhs.predicateStr );
 
339
      return false;
 
340
    }
 
341
 
 
342
    typedef std::list<AttrMatchData> AttrMatchList;
 
343
 
 
344
 
 
345
  } /////////////////////////////////////////////////////////////////
 
346
  // namespace
 
347
  ///////////////////////////////////////////////////////////////////
 
348
 
 
349
  ///////////////////////////////////////////////////////////////////
 
350
  //
 
351
  //  CLASS NAME : PoolQuery::Impl
 
352
  //
 
353
  /** */
 
354
  class PoolQuery::Impl
 
355
  {
 
356
  public:
 
357
    Impl()
 
358
      : _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND )
 
359
      , _match_word(false)
 
360
      , _require_all(false)
 
361
      , _status_flags(ALL)
 
362
    {}
 
363
 
 
364
    ~Impl()
 
365
    {}
 
366
 
 
367
  public:
 
368
    /** String representation */
 
369
    string asString() const;
 
370
 
 
371
    /** \name Raw query options. */
 
372
    //@{
 
373
    /** Raw search strings. */
 
374
    StrContainer _strings;
 
375
    /** Raw attributes */
 
376
    AttrRawStrMap _attrs;
 
377
    /** Uncompiled attributes with predicate. */
 
378
    std::set<AttrMatchData> _uncompiledPredicated;
 
379
 
 
380
    /** Sat solver search flags */
 
381
    Match _flags;
 
382
    bool _match_word;
 
383
    bool _require_all;
 
384
 
 
385
    /** Sat solver status flags */
 
386
    StatusFilter _status_flags;
 
387
 
 
388
    /** Edition condition operand */
 
389
    Edition _edition;
 
390
    /** Operator for edition condition */
 
391
    Rel _op;
 
392
 
 
393
    /** Repos to search. */
 
394
    StrContainer _repos;
 
395
 
 
396
    /** Kinds to search */
 
397
    Kinds _kinds;
 
398
    //@}
 
399
 
 
400
  public:
 
401
 
 
402
    bool operator==( const PoolQuery::Impl & rhs ) const
 
403
    {
 
404
      if ( _flags == rhs._flags
 
405
        // bnc#792901: while libzypp uses exact match mode for a single
 
406
        // package name lock, zypper always uses glob. :(
 
407
        // We unify those two forms to enable zypper to remove zypp locks
 
408
        // without need to actually evaluate the query (which would require
 
409
        // repos to be loaded).
 
410
        || ( ( _flags.isModeString() && rhs._flags.isModeGlob()
 
411
            || _flags.isModeGlob() && rhs._flags.isModeString() )
 
412
          && _strings.empty()
 
413
          && _attrs.size() == 1
 
414
          && _attrs.begin()->first == sat::SolvAttr::name ) )
 
415
      {
 
416
        return ( _strings == rhs._strings
 
417
              && _attrs == rhs._attrs
 
418
              && _uncompiledPredicated == rhs._uncompiledPredicated
 
419
              && _match_word == rhs._match_word
 
420
              && _require_all == rhs._require_all
 
421
              && _status_flags == rhs._status_flags
 
422
              && _edition == rhs._edition
 
423
              && _op == rhs._op
 
424
              && _repos == rhs._repos
 
425
              && _kinds == rhs._kinds );
 
426
      }
 
427
      return false;
 
428
    }
 
429
 
 
430
    bool operator!=( const PoolQuery::Impl & rhs ) const
 
431
    { return ! operator==( rhs ); }
 
432
 
 
433
  public:
 
434
    /** Compile the regex.
 
435
     * Basically building the \ref _attrMatchList from strings.
 
436
     * \throws MatchException Any of the exceptions thrown by \ref StrMatcher::compile.
 
437
     */
 
438
    void compile() const;
 
439
 
 
440
    /** StrMatcher per attribtue. */
 
441
    mutable AttrMatchList _attrMatchList;
 
442
 
 
443
  private:
 
444
    /** Pass flags from \ref compile, as they may have been changed. */
 
445
    string createRegex( const StrContainer & container, const Match & flags ) const;
 
446
 
 
447
  private:
 
448
    friend Impl * rwcowClone<Impl>( const Impl * rhs );
 
449
    /** clone for RWCOW_pointer */
 
450
    Impl * clone() const
 
451
    { return new Impl( *this ); }
 
452
  };
 
453
 
 
454
  ///////////////////////////////////////////////////////////////////
 
455
 
 
456
  struct MyInserter
 
457
  {
 
458
    MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
 
459
 
 
460
    bool operator()(const string & str)
 
461
    {
 
462
      _cont.insert(str);
 
463
      return true;
 
464
    }
 
465
 
 
466
    PoolQuery::StrContainer & _cont;
 
467
  };
 
468
 
 
469
 
 
470
  struct EmptyFilter
 
471
  {
 
472
    bool operator()(const string & str)
 
473
    {
 
474
      return !str.empty();
 
475
    }
 
476
  };
 
477
 
 
478
  void PoolQuery::Impl::compile() const
 
479
  {
 
480
    _attrMatchList.clear();
 
481
 
 
482
    Match cflags( _flags );
 
483
    if ( cflags.mode() == Match::OTHER ) // this will never succeed...
 
484
      ZYPP_THROW( MatchUnknownModeException( cflags ) );
 
485
 
 
486
    /** Compiled search strings. */
 
487
    string rcstrings;
 
488
 
 
489
 
 
490
    // 'different'         - will have to iterate through all and match by ourselves (slow)
 
491
    // 'same'              - will pass the compiled string to dataiterator_init
 
492
    // 'one-attr'          - will pass it to dataiterator_init
 
493
    // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
 
494
 
 
495
    // // NO ATTRIBUTE
 
496
    // else
 
497
    //   for all _strings
 
498
    //     create regex; store in rcstrings; if more strings flag regex;
 
499
    if (_attrs.empty())
 
500
    {
 
501
      ; // A default 'query-all' will be added after all sources are processed.
 
502
    }
 
503
 
 
504
    // // ONE ATTRIBUTE
 
505
    // else if _attrs is not empty but it contains just one attr
 
506
    //   for all _strings and _attr[key] strings
 
507
    //     create regex; flag 'one-attr'; if more strings flag regex;
 
508
    else if (_attrs.size() == 1)
 
509
    {
 
510
      StrContainer joined;
 
511
      invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
 
512
      invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
 
513
      rcstrings = createRegex(joined, cflags);
 
514
      if (joined.size() > 1) // switch to regex for multiple strings
 
515
        cflags.setModeRegex();
 
516
      _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
 
517
                                StrMatcher( rcstrings, cflags ) ) );
 
518
    }
 
519
 
 
520
    // // MULTIPLE ATTRIBUTES
 
521
    else
 
522
    {
 
523
      // check whether there are any per-attribute strings
 
524
      bool attrvals_empty = true;
 
525
      for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
 
526
        if (!ai->second.empty())
 
527
          for(StrContainer::const_iterator it = ai->second.begin();
 
528
              it != ai->second.end(); it++)
 
529
            if (!it->empty())
 
530
            {
 
531
              attrvals_empty = false;
 
532
              goto attremptycheckend;
 
533
            }
 
534
attremptycheckend:
 
535
 
 
536
      // chceck whether the per-attribute strings are all the same
 
537
      bool attrvals_thesame = true;
 
538
      AttrRawStrMap::const_iterator ai = _attrs.begin();
 
539
      const StrContainer & set1 = ai->second;
 
540
      ++ai;
 
541
      for (; ai != _attrs.end(); ++ai)
 
542
      {
 
543
        StrContainer result;
 
544
        set_difference(
 
545
          set1.begin(), set1.end(),
 
546
          ai->second.begin(), ai->second.end(),
 
547
          inserter(result, result.begin())/*, ltstr()*/);
 
548
        if (!result.empty())
 
549
        {
 
550
          attrvals_thesame = false;
 
551
          break;
 
552
        }
 
553
      }
 
554
 
 
555
      // // THE SAME STRINGS FOR DIFFERENT ATTRS
 
556
      // else if _attrs is not empty but it does not contain strings
 
557
      //   for each key in _attrs take all _strings
 
558
      //     create regex; store in rcstrings; flag 'same'; if more strings flag regex;
 
559
      if (attrvals_empty || attrvals_thesame)
 
560
      {
 
561
        StrContainer joined;
 
562
        if (attrvals_empty)
 
563
        {
 
564
          invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
 
565
          rcstrings = createRegex(joined, cflags);
 
566
        }
 
567
        else
 
568
        {
 
569
          invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
 
570
          invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
 
571
          rcstrings = createRegex(joined, cflags);
 
572
        }
 
573
        if (joined.size() > 1) // switch to regex for multiple strings
 
574
          cflags.setModeRegex();
 
575
        // May use the same StrMatcher for all
 
576
        StrMatcher matcher( rcstrings, cflags );
 
577
        for_( ai, _attrs.begin(), _attrs.end() )
 
578
        {
 
579
          _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
 
580
        }
 
581
      }
 
582
 
 
583
      // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
 
584
      // if _attrs is not empty and it contains non-empty vectors with non-empty strings
 
585
      //   for each key in _attrs take all _strings + all _attrs[key] strings
 
586
      //     create regex; flag 'different'; if more strings flag regex;
 
587
      else
 
588
      {
 
589
        for_(ai, _attrs.begin(), _attrs.end())
 
590
        {
 
591
          StrContainer joined;
 
592
          invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
 
593
          invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
 
594
          string s = createRegex(joined, cflags);
 
595
          if (joined.size() > 1) // switch to regex for multiple strings
 
596
            cflags.setModeRegex();
 
597
          _attrMatchList.push_back( AttrMatchData( ai->first,
 
598
                                    StrMatcher( s, cflags ) ) );
 
599
        }
 
600
      }
 
601
    }
 
602
 
 
603
    // Now handle any predicated queries
 
604
    if ( ! _uncompiledPredicated.empty() )
 
605
    {
 
606
      StrContainer global;
 
607
      invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
 
608
      for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
 
609
      {
 
610
        if ( it->strMatcher.flags().mode() == Match::OTHER )
 
611
        {
 
612
          // need to compile:
 
613
          StrContainer joined( global );
 
614
          const std::string & mstr( it->strMatcher.searchstring() );
 
615
          if ( ! mstr.empty() )
 
616
            joined.insert( mstr );
 
617
 
 
618
          cflags = _flags;
 
619
          rcstrings = createRegex( joined, cflags );
 
620
          if ( joined.size() > 1 ) // switch to regex for multiple strings
 
621
            cflags.setModeRegex();
 
622
 
 
623
          _attrMatchList.push_back( AttrMatchData( it->attr,
 
624
                                    StrMatcher( rcstrings, cflags ),
 
625
                                                      it->predicate, it->predicateStr ) );
 
626
        }
 
627
        else
 
628
        {
 
629
          // copy matcher
 
630
         _attrMatchList.push_back( *it );
 
631
        }
 
632
      }
 
633
    }
 
634
 
 
635
    // If no attributes defined at all, then add 'query all'
 
636
    if ( _attrMatchList.empty() )
 
637
    {
 
638
      cflags = _flags;
 
639
      rcstrings = createRegex( _strings, cflags );
 
640
      if ( _strings.size() > 1 ) // switch to regex for multiple strings
 
641
        cflags.setModeRegex();
 
642
      _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
 
643
                                StrMatcher( rcstrings, cflags ) ) );
 
644
    }
 
645
 
 
646
    // Finally check here, whether all involved regex compile.
 
647
    for_( it, _attrMatchList.begin(), _attrMatchList.end() )
 
648
    {
 
649
      it->strMatcher.compile(); // throws on error
 
650
    }
 
651
    //DBG << asString() << endl;
 
652
  }
 
653
 
 
654
 
 
655
  /**
 
656
   * Converts '*' and '?' wildcards within str into their regex equivalents.
 
657
   */
 
658
  static string wildcards2regex(const string & str)
 
659
  {
 
660
    string regexed = str;
 
661
 
 
662
    string r_all(".*"); // regex equivalent of '*'
 
663
    string r_one(".");  // regex equivalent of '?'
 
664
    string::size_type pos;
 
665
 
 
666
    // replace all "*" in input with ".*"
 
667
    for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
 
668
      regexed = regexed.replace(pos, 1, r_all);
 
669
 
 
670
    // replace all "?" in input with "."
 
671
    for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
 
672
      regexed = regexed.replace(pos, 1, r_one);
 
673
 
 
674
    return regexed;
 
675
  }
 
676
 
 
677
  string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const
 
678
  {
 
679
//! macro for word boundary tags for regexes
 
680
#define WB (_match_word ? string("\\b") : string())
 
681
    string rstr;
 
682
 
 
683
    if (container.empty())
 
684
      return rstr;
 
685
 
 
686
    if (container.size() == 1)
 
687
    {
 
688
      return WB + *container.begin() + WB;
 
689
    }
 
690
 
 
691
    // multiple strings
 
692
 
 
693
    bool use_wildcards = flags.isModeGlob();
 
694
    StrContainer::const_iterator it = container.begin();
 
695
    string tmp;
 
696
 
 
697
    if (use_wildcards)
 
698
      tmp = wildcards2regex(*it);
 
699
    else
 
700
      tmp = *it;
 
701
 
 
702
    if (_require_all)
 
703
    {
 
704
      if ( ! flags.isModeString() ) // not match exact
 
705
        tmp += ".*" + WB + tmp;
 
706
      rstr = "(?=" + tmp + ")";
 
707
    }
 
708
    else
 
709
    {
 
710
      if ( flags.isModeString() || flags.isModeGlob() )
 
711
        rstr = "^";
 
712
      rstr += WB + "(" + tmp;
 
713
    }
 
714
 
 
715
    ++it;
 
716
 
 
717
    for (; it != container.end(); ++it)
 
718
    {
 
719
      if (use_wildcards)
 
720
        tmp = wildcards2regex(*it);
 
721
      else
 
722
        tmp = *it;
 
723
 
 
724
      if (_require_all)
 
725
      {
 
726
        if ( ! flags.isModeString() ) // not match exact
 
727
          tmp += ".*" + WB + tmp;
 
728
        rstr += "(?=" + tmp + ")";
 
729
      }
 
730
      else
 
731
      {
 
732
        rstr += "|" + tmp;
 
733
      }
 
734
    }
 
735
 
 
736
    if (_require_all)
 
737
    {
 
738
      if ( ! flags.isModeString() ) // not match exact
 
739
        rstr += WB + ".*";
 
740
    }
 
741
    else
 
742
    {
 
743
      rstr += ")" + WB;
 
744
      if ( flags.isModeString() || flags.isModeGlob() )
 
745
        rstr += "$";
 
746
    }
 
747
 
 
748
    return rstr;
 
749
#undef WB
 
750
  }
 
751
 
 
752
  string PoolQuery::Impl::asString() const
 
753
  {
 
754
    ostringstream o;
 
755
 
 
756
    o << "kinds: ";
 
757
    if ( _kinds.empty() )
 
758
      o << "ALL";
 
759
    else
 
760
    {
 
761
      for(Kinds::const_iterator it = _kinds.begin();
 
762
          it != _kinds.end(); ++it)
 
763
        o << *it << " ";
 
764
    }
 
765
    o << endl;
 
766
 
 
767
    o << "repos: ";
 
768
    if ( _repos.empty() )
 
769
      o << "ALL";
 
770
    else
 
771
    {
 
772
      for(StrContainer::const_iterator it = _repos.begin();
 
773
          it != _repos.end(); ++it)
 
774
        o << *it << " ";
 
775
    }
 
776
    o << endl;
 
777
 
 
778
    o << "version: "<< _op << " " << _edition.asString() << endl;
 
779
    o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" )
 
780
                                       : "ALL" ) << endl;
 
781
 
 
782
    o << "string match flags: " << Match(_flags) << endl;
 
783
 
 
784
    // raw
 
785
    o << "strings: ";
 
786
    for(StrContainer::const_iterator it = _strings.begin();
 
787
        it != _strings.end(); ++it)
 
788
      o << *it << " ";
 
789
    o << endl;
 
790
 
 
791
    o << "attributes: " << endl;
 
792
    for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
 
793
    {
 
794
      o << "* " << ai->first << ": ";
 
795
      for(StrContainer::const_iterator vi = ai->second.begin();
 
796
          vi != ai->second.end(); ++vi)
 
797
        o << *vi << " ";
 
798
      o << endl;
 
799
    }
 
800
 
 
801
    o << "predicated: " << endl;
 
802
    for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
 
803
    {
 
804
      o << "* " << *it << endl;
 
805
    }
 
806
 
 
807
    // compiled
 
808
    o << "last attribute matcher compiled: " << endl;
 
809
    if ( _attrMatchList.empty() )
 
810
    {
 
811
      o << "not yet compiled" << endl;
 
812
    }
 
813
    else
 
814
    {
 
815
      for_( it, _attrMatchList.begin(), _attrMatchList.end() )
 
816
      {
 
817
        o << "* " << *it << endl;
 
818
      }
 
819
    }
 
820
    return o.str();
 
821
  }
 
822
 
 
823
  ///////////////////////////////////////////////////////////////////
 
824
 
 
825
  ///////////////////////////////////////////////////////////////////
 
826
  //
 
827
  //    CLASS NAME : PoolQuery
 
828
  //
 
829
  ///////////////////////////////////////////////////////////////////
 
830
 
 
831
  PoolQuery::PoolQuery()
 
832
    : _pimpl(new Impl())
 
833
  {}
 
834
 
 
835
  PoolQuery::~PoolQuery()
 
836
  {}
 
837
 
 
838
  void PoolQuery::addRepo(const std::string &repoalias)
 
839
  {
 
840
    if (repoalias.empty())
 
841
    {
 
842
      WAR << "ignoring an empty repository alias" << endl;
 
843
      return;
 
844
    }
 
845
    _pimpl->_repos.insert(repoalias);
 
846
  }
 
847
 
 
848
  void PoolQuery::addKind(const ResKind & kind)
 
849
  { _pimpl->_kinds.insert(kind); }
 
850
 
 
851
  void PoolQuery::addString(const string & value)
 
852
  { _pimpl->_strings.insert(value); }
 
853
 
 
854
  void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
 
855
  { _pimpl->_attrs[attr].insert(value); }
 
856
 
 
857
  void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
 
858
  { return addDependency( attr, name, op, edition, Arch_empty ); }
 
859
 
 
860
  void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch )
 
861
  {
 
862
    switch ( op.inSwitch() )
 
863
    {
 
864
      case Rel::ANY_e:  // no additional constraint on edition.
 
865
        if ( arch.empty() )     // no additional constraint on arch.
 
866
        {
 
867
          addAttribute( attr, name );
 
868
          return;
 
869
        }
 
870
        break;
 
871
 
 
872
      case Rel::NONE_e: // will never match.
 
873
        return;
 
874
 
 
875
      default: // go and add the predicated query (uncompiled)
 
876
        break;
 
877
    }
 
878
 
 
879
    // Match::OTHER indicates need to compile
 
880
    // (merge global search strings into name).
 
881
    AttrMatchData attrMatchData( attr, StrMatcher( name, Match::OTHER ) );
 
882
 
 
883
    if ( isDependencyAttribute( attr ) )
 
884
      attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) );
 
885
    else
 
886
      attrMatchData.addPredicate( SolvableRangePredicate( op, edition, arch ) );
 
887
 
 
888
    _pimpl->_uncompiledPredicated.insert( attrMatchData );
 
889
  }
 
890
 
 
891
  void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
 
892
  {
 
893
    CapDetail cap( cap_r );
 
894
    if ( ! cap.isSimple() ) // will never match.
 
895
      return;
 
896
 
 
897
    // Matches STRING per default. (won't get compiled!)
 
898
    AttrMatchData attrMatchData( attr, StrMatcher( cap.name().asString() ) );
 
899
 
 
900
    if ( isDependencyAttribute( attr ) )
 
901
      attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
 
902
    else
 
903
      attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) );
 
904
 
 
905
    _pimpl->_uncompiledPredicated.insert( attrMatchData );
 
906
  }
 
907
 
 
908
  void PoolQuery::setEdition(const Edition & edition, const Rel & op)
 
909
  {
 
910
    _pimpl->_edition = edition;
 
911
    _pimpl->_op = op;
 
912
  }
 
913
 
 
914
  void PoolQuery::setMatchSubstring()   { _pimpl->_flags.setModeSubstring(); }
 
915
  void PoolQuery::setMatchExact()       { _pimpl->_flags.setModeString(); }
 
916
  void PoolQuery::setMatchRegex()       { _pimpl->_flags.setModeRegex(); }
 
917
  void PoolQuery::setMatchGlob()        { _pimpl->_flags.setModeGlob(); }
 
918
  void PoolQuery::setMatchWord()
 
919
  {
 
920
    _pimpl->_match_word = true;
 
921
    _pimpl->_flags.setModeRegex();
 
922
  }
 
923
 
 
924
  Match PoolQuery::flags() const
 
925
  { return _pimpl->_flags; }
 
926
  void PoolQuery::setFlags( const Match & flags )
 
927
  { _pimpl->_flags = flags; }
 
928
 
 
929
 
 
930
  void PoolQuery::setInstalledOnly()
 
931
  { _pimpl->_status_flags = INSTALLED_ONLY; }
 
932
  void PoolQuery::setUninstalledOnly()
 
933
  { _pimpl->_status_flags = UNINSTALLED_ONLY; }
 
934
  void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
 
935
  { _pimpl->_status_flags = flags; }
 
936
 
 
937
 
 
938
  void PoolQuery::setRequireAll(bool require_all)
 
939
  { _pimpl->_require_all = require_all; }
 
940
 
 
941
 
 
942
  const PoolQuery::StrContainer &
 
943
  PoolQuery::strings() const
 
944
  { return _pimpl->_strings; }
 
945
 
 
946
  const PoolQuery::AttrRawStrMap &
 
947
  PoolQuery::attributes() const
 
948
  { return _pimpl->_attrs; }
 
949
 
 
950
  const PoolQuery::StrContainer &
 
951
  PoolQuery::attribute(const sat::SolvAttr & attr) const
 
952
  {
 
953
    static const PoolQuery::StrContainer nocontainer;
 
954
    AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
 
955
    return it != _pimpl->_attrs.end() ? it->second : nocontainer;
 
956
  }
 
957
 
 
958
  const Edition PoolQuery::edition() const
 
959
  { return _pimpl->_edition; }
 
960
  const Rel PoolQuery::editionRel() const
 
961
  { return _pimpl->_op; }
 
962
 
 
963
 
 
964
  const PoolQuery::Kinds &
 
965
  PoolQuery::kinds() const
 
966
  { return _pimpl->_kinds; }
 
967
 
 
968
  const PoolQuery::StrContainer &
 
969
  PoolQuery::repos() const
 
970
  { return _pimpl->_repos; }
 
971
 
 
972
 
 
973
  bool PoolQuery::caseSensitive() const
 
974
  { return !_pimpl->_flags.test( Match::NOCASE ); }
 
975
  void PoolQuery::setCaseSensitive( bool value )
 
976
  { _pimpl->_flags.turn( Match::NOCASE, !value ); }
 
977
 
 
978
  bool PoolQuery::filesMatchFullPath() const
 
979
  { return _pimpl->_flags.test( Match::FILES ); }
 
980
  void PoolQuery::setFilesMatchFullPath( bool value )
 
981
  { _pimpl->_flags.turn( Match::FILES, value ); }
 
982
 
 
983
  bool PoolQuery::matchExact() const            { return _pimpl->_flags.isModeString(); }
 
984
  bool PoolQuery::matchSubstring() const        { return _pimpl->_flags.isModeSubstring(); }
 
985
  bool PoolQuery::matchGlob() const             { return _pimpl->_flags.isModeGlob(); }
 
986
  bool PoolQuery::matchRegex() const            { return _pimpl->_flags.isModeRegex(); }
 
987
 
 
988
  bool PoolQuery::matchWord() const
 
989
  { return _pimpl->_match_word; }
 
990
 
 
991
  bool PoolQuery::requireAll() const
 
992
  { return _pimpl->_require_all; }
 
993
 
 
994
  PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
 
995
  { return _pimpl->_status_flags; }
 
996
 
 
997
  bool PoolQuery::empty() const
 
998
  {
 
999
    try { return begin() == end(); }
 
1000
    catch (const Exception & ex) {}
 
1001
    return true;
 
1002
  }
 
1003
 
 
1004
  PoolQuery::size_type PoolQuery::size() const
 
1005
  {
 
1006
    try
 
1007
    {
 
1008
      size_type count = 0;
 
1009
      for_( it, begin(), end() )
 
1010
        ++count;
 
1011
      return count;
 
1012
    }
 
1013
    catch (const Exception & ex) {}
 
1014
    return 0;
 
1015
  }
 
1016
 
 
1017
  void PoolQuery::execute(ProcessResolvable fnc)
 
1018
  { invokeOnEach( begin(), end(), fnc); }
 
1019
 
 
1020
 
 
1021
  ///////////////////////////////////////////////////////////////////
 
1022
  //
 
1023
  //  CLASS NAME : PoolQuery::Attr
 
1024
  //
 
1025
  /**
 
1026
   * represents all atributes in PoolQuery except SolvAtributes, which are
 
1027
   * used as is (not needed extend anything if someone adds new solv attr)
 
1028
   */
 
1029
  struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
 
1030
  {
 
1031
  private:
 
1032
    friend class IdStringType<PoolQueryAttr>;
 
1033
    IdString _str;
 
1034
  public:
 
1035
 
 
1036
    //noAttr
 
1037
    PoolQueryAttr(){}
 
1038
 
 
1039
    explicit PoolQueryAttr( const char* cstr_r )
 
1040
        : _str( cstr_r )
 
1041
      {}
 
1042
 
 
1043
    explicit PoolQueryAttr( const std::string & str_r )
 
1044
        : _str( str_r )
 
1045
      {}
 
1046
 
 
1047
    // unknown atributes
 
1048
    static const PoolQueryAttr noAttr;
 
1049
 
 
1050
    // PoolQuery's own attributes
 
1051
    static const PoolQueryAttr repoAttr;
 
1052
    static const PoolQueryAttr kindAttr;
 
1053
    static const PoolQueryAttr stringAttr;
 
1054
    static const PoolQueryAttr stringTypeAttr;
 
1055
    static const PoolQueryAttr requireAllAttr;
 
1056
    static const PoolQueryAttr caseSensitiveAttr;
 
1057
    static const PoolQueryAttr installStatusAttr;
 
1058
    static const PoolQueryAttr editionAttr;
 
1059
    static const PoolQueryAttr complexAttr;
 
1060
  };
 
1061
 
 
1062
  const PoolQueryAttr PoolQueryAttr::noAttr;
 
1063
 
 
1064
  const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
 
1065
  const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
 
1066
  const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
 
1067
  const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
 
1068
  const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
 
1069
  const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
 
1070
  const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
 
1071
  const PoolQueryAttr PoolQueryAttr::editionAttr("version");
 
1072
  const PoolQueryAttr PoolQueryAttr::complexAttr("complex");
 
1073
 
 
1074
  class StringTypeAttr : public IdStringType<PoolQueryAttr>
 
1075
  {
 
1076
    friend class IdStringType<StringTypeAttr>;
 
1077
    IdString _str;
 
1078
 
 
1079
  public:
 
1080
    StringTypeAttr(){}
 
1081
    explicit StringTypeAttr( const char* cstr_r )
 
1082
            : _str( cstr_r ){}
 
1083
    explicit StringTypeAttr( const std::string & str_r )
 
1084
             : _str( str_r ){}
 
1085
 
 
1086
    static const StringTypeAttr noAttr;
 
1087
 
 
1088
    static const StringTypeAttr exactAttr;
 
1089
    static const StringTypeAttr substringAttr;
 
1090
    static const StringTypeAttr regexAttr;
 
1091
    static const StringTypeAttr globAttr;
 
1092
    static const StringTypeAttr wordAttr;
 
1093
  };
 
1094
 
 
1095
  const StringTypeAttr StringTypeAttr::noAttr;
 
1096
 
 
1097
  const StringTypeAttr StringTypeAttr::exactAttr("exact");
 
1098
  const StringTypeAttr StringTypeAttr::substringAttr("substring");
 
1099
  const StringTypeAttr StringTypeAttr::regexAttr("regex");
 
1100
  const StringTypeAttr StringTypeAttr::globAttr("glob");
 
1101
  const StringTypeAttr StringTypeAttr::wordAttr("word");
 
1102
 
 
1103
  ///////////////////////////////////////////////////////////////////
 
1104
 
 
1105
 
 
1106
  //\TODO maybe ctor with stream can be usefull
 
1107
  //\TODO let it throw, let it throw, let it throw.
 
1108
  bool PoolQuery::recover( istream &str, char delim )
 
1109
  {
 
1110
    bool finded_something = false; //indicates some atributes is finded
 
1111
    string s;
 
1112
    do {
 
1113
      if ( str.eof() )
 
1114
        break;
 
1115
 
 
1116
      getline( str, s, delim );
 
1117
 
 
1118
      if ((!s.empty()) && s[0]=='#') //comment
 
1119
      {
 
1120
        continue;
 
1121
      }
 
1122
 
 
1123
      string::size_type pos = s.find(':');
 
1124
      if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
 
1125
      {
 
1126
        if (finded_something) //is first blank line after record?
 
1127
        {
 
1128
          break;
 
1129
        }
 
1130
        else
 
1131
        {
 
1132
          continue;
 
1133
        }
 
1134
      }
 
1135
 
 
1136
      finded_something = true;
 
1137
 
 
1138
      string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
 
1139
      string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
 
1140
 
 
1141
      PoolQueryAttr attribute( attrName );
 
1142
 
 
1143
      if ( attribute==PoolQueryAttr::repoAttr )
 
1144
      {
 
1145
        addRepo( attrValue );
 
1146
      }
 
1147
      /* some backwards compatibility */
 
1148
      else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" )
 
1149
      {
 
1150
        addKind( ResKind(attrValue) );
 
1151
      }
 
1152
      else if ( attribute==PoolQueryAttr::stringAttr
 
1153
        || attribute=="global_string")
 
1154
      {
 
1155
        addString( attrValue );
 
1156
      }
 
1157
      else if ( attribute==PoolQueryAttr::stringTypeAttr
 
1158
        || attribute=="string_type" )
 
1159
      {
 
1160
        StringTypeAttr s(attrValue);
 
1161
        if( s == StringTypeAttr::regexAttr )
 
1162
        {
 
1163
          setMatchRegex();
 
1164
        }
 
1165
        else if ( s == StringTypeAttr::globAttr )
 
1166
        {
 
1167
          setMatchGlob();
 
1168
        }
 
1169
        else if ( s == StringTypeAttr::exactAttr )
 
1170
        {
 
1171
          setMatchExact();
 
1172
        }
 
1173
        else if ( s == StringTypeAttr::substringAttr )
 
1174
        {
 
1175
          setMatchSubstring();
 
1176
        }
 
1177
        else if ( s == StringTypeAttr::wordAttr )
 
1178
        {
 
1179
          setMatchWord();
 
1180
        }
 
1181
        else if ( s == StringTypeAttr::noAttr )
 
1182
        {
 
1183
          WAR << "unknown string type " << attrValue << endl;
 
1184
        }
 
1185
        else
 
1186
        {
 
1187
          WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
 
1188
        }
 
1189
      }
 
1190
      else if ( attribute==PoolQueryAttr::requireAllAttr )
 
1191
      {
 
1192
        if ( str::strToTrue(attrValue) )
 
1193
        {
 
1194
          setRequireAll(true);
 
1195
        }
 
1196
        else if ( !str::strToFalse(attrValue) )
 
1197
        {
 
1198
          setRequireAll(false);
 
1199
        }
 
1200
        else
 
1201
        {
 
1202
          WAR << "unknown boolean value " << attrValue << endl;
 
1203
        }
 
1204
      }
 
1205
      else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
 
1206
      {
 
1207
        if ( str::strToTrue(attrValue) )
 
1208
        {
 
1209
          setCaseSensitive(true);
 
1210
        }
 
1211
        else if ( !str::strToFalse(attrValue) )
 
1212
        {
 
1213
          setCaseSensitive(false);
 
1214
        }
 
1215
        else
 
1216
        {
 
1217
          WAR << "unknown boolean value " << attrValue << endl;
 
1218
        }
 
1219
      }
 
1220
      else if ( attribute==PoolQueryAttr::installStatusAttr )
 
1221
      {
 
1222
        if( attrValue == "all" )
 
1223
        {
 
1224
          setStatusFilterFlags( ALL );
 
1225
        }
 
1226
        else if( attrValue == "installed" )
 
1227
        {
 
1228
          setInstalledOnly();
 
1229
        }
 
1230
        else if( attrValue == "not-installed" )
 
1231
        {
 
1232
          setUninstalledOnly();
 
1233
        }
 
1234
        else
 
1235
        {
 
1236
          WAR << "Unknown value for install status " << attrValue << endl;
 
1237
        }
 
1238
      }
 
1239
      else if ( attribute == PoolQueryAttr::editionAttr)
 
1240
      {
 
1241
        string::size_type pos;
 
1242
        Rel rel("==");
 
1243
        if (attrValue.find_first_of("=<>!") == 0)
 
1244
        {
 
1245
          pos = attrValue.find_last_of("=<>");
 
1246
          rel = Rel(attrValue.substr(0, pos+1));
 
1247
          attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos));
 
1248
        }
 
1249
 
 
1250
        setEdition(Edition(attrValue), rel);
 
1251
      }
 
1252
      else if ( attribute == PoolQueryAttr::complexAttr )
 
1253
      {
 
1254
        try
 
1255
        {
 
1256
          _pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) );
 
1257
        }
 
1258
        catch ( const Exception & err )
 
1259
        {
 
1260
          WAR << "Unparsable value for complex: " << err.asUserHistory() << endl;
 
1261
 
 
1262
        }
 
1263
      }
 
1264
      else if ( attribute==PoolQueryAttr::noAttr )
 
1265
      {
 
1266
        WAR << "empty attribute name" << endl;
 
1267
      }
 
1268
      else
 
1269
      {
 
1270
        string s = attrName;
 
1271
        str::replaceAll( s,"_",":" );
 
1272
        SolvAttr a(s);
 
1273
        if ( a == SolvAttr::name || isDependencyAttribute( a ) )
 
1274
        {
 
1275
          Capability c( attrValue );
 
1276
          CapDetail d( c );
 
1277
          if ( d.isVersioned() )
 
1278
            addDependency( a, d.name().asString(), d.op(), d.ed() );
 
1279
          else
 
1280
            addDependency( a, attrValue );
 
1281
        }
 
1282
        else
 
1283
          addAttribute( a, attrValue );
 
1284
      }
 
1285
 
 
1286
    } while ( true );
 
1287
 
 
1288
    return finded_something;
 
1289
  }
 
1290
 
 
1291
  void PoolQuery::serialize( ostream &str, char delim ) const
 
1292
  {
 
1293
    //separating delim
 
1294
    str << delim;
 
1295
    //iterate thrue all settings and write it
 
1296
    static const zypp::PoolQuery q; //not save default options, so create default query example
 
1297
 
 
1298
    for_( it, repos().begin(), repos().end() )
 
1299
    {
 
1300
      str << "repo: " << *it << delim ;
 
1301
    }
 
1302
 
 
1303
    for_( it, kinds().begin(), kinds().end() )
 
1304
    {
 
1305
      str << PoolQueryAttr::kindAttr.asString() << ": "
 
1306
          << it->idStr() << delim ;
 
1307
    }
 
1308
 
 
1309
    if (editionRel() != Rel::ANY && edition() != Edition::noedition)
 
1310
      str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim;
 
1311
 
 
1312
    if (matchMode()!=q.matchMode())
 
1313
    {
 
1314
      switch( matchMode() )
 
1315
      {
 
1316
      case Match::STRING:
 
1317
        str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
 
1318
        break;
 
1319
      case Match::SUBSTRING:
 
1320
        str << PoolQueryAttr::stringTypeAttr.asString()
 
1321
            << ": substring" << delim;
 
1322
        break;
 
1323
      case Match::GLOB:
 
1324
        str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
 
1325
        break;
 
1326
      case Match::REGEX:
 
1327
        str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
 
1328
        break;
 
1329
      default:
 
1330
        WAR << "unknown match type "  << matchMode() << endl;
 
1331
      }
 
1332
    }
 
1333
 
 
1334
    if( caseSensitive() != q.caseSensitive() )
 
1335
    {
 
1336
      str << "case_sensitive: ";
 
1337
      if (caseSensitive())
 
1338
      {
 
1339
        str << "on" << delim;
 
1340
      }
 
1341
      else
 
1342
      {
 
1343
        str << "off" << delim;
 
1344
      }
 
1345
    }
 
1346
 
 
1347
    if( requireAll() != q.requireAll() )
 
1348
    {
 
1349
      str << "require_all: ";
 
1350
      if (requireAll())
 
1351
      {
 
1352
        str << "on" << delim;
 
1353
      }
 
1354
      else
 
1355
      {
 
1356
        str << "off" << delim;
 
1357
      }
 
1358
    }
 
1359
 
 
1360
    if( statusFilterFlags() != q.statusFilterFlags() )
 
1361
    {
 
1362
      switch( statusFilterFlags() )
 
1363
      {
 
1364
      case ALL:
 
1365
        str << "install_status: all" << delim;
 
1366
        break;
 
1367
      case INSTALLED_ONLY:
 
1368
        str << "install_status: installed" << delim;
 
1369
        break;
 
1370
      case UNINSTALLED_ONLY:
 
1371
        str << "install_status: not-installed" << delim;
 
1372
        break;
 
1373
      }
 
1374
    }
 
1375
 
 
1376
    for_( it, strings().begin(), strings().end() )
 
1377
    {
 
1378
      str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
 
1379
    }
 
1380
 
 
1381
    for_( it, attributes().begin(), attributes().end() )
 
1382
    {
 
1383
      string s = it->first.asString();
 
1384
      str::replaceAll(s,":","_");
 
1385
      for_( it2,it->second.begin(),it->second.end() )
 
1386
      {
 
1387
        str << s <<": "<< *it2 << delim;
 
1388
      }
 
1389
    }
 
1390
 
 
1391
    for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() )
 
1392
    {
 
1393
      str << "complex: "<< it->serialize() << delim;
 
1394
    }
 
1395
 
 
1396
    //separating delim - protection
 
1397
    str << delim;
 
1398
  }
 
1399
 
 
1400
  string PoolQuery::asString() const
 
1401
  { return _pimpl->asString(); }
 
1402
 
 
1403
  ostream & operator<<( ostream & str, const PoolQuery & obj )
 
1404
  { return str << obj.asString(); }
 
1405
 
 
1406
  std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj )
 
1407
  { return dumpRange( str << obj, obj.begin(), obj.end() ); }
 
1408
 
 
1409
  bool PoolQuery::operator==( const PoolQuery & rhs ) const
 
1410
  { return *_pimpl == *rhs._pimpl; }
 
1411
 
 
1412
  ///////////////////////////////////////////////////////////////////
 
1413
  namespace detail
 
1414
  { /////////////////////////////////////////////////////////////////
 
1415
 
 
1416
    ///////////////////////////////////////////////////////////////////
 
1417
    //
 
1418
    //  CLASS NAME : PoolQueryMatcher
 
1419
    //
 
1420
    /** Store \ref PoolQuery settings and assist \ref PoolQueryIterator.
 
1421
     *
 
1422
     * Basically the matcher performs a base query, which should preselect
 
1423
     * candidates for a match. And has some filter conditions on top of it.
 
1424
     * Query and fileter depend on the \ref PoolQuery settings.
 
1425
     *
 
1426
     * Matcher must be stateless, as it is shared between multiple
 
1427
     * \ref PoolQueryIterator instances.
 
1428
     *
 
1429
     * If \ref base_iterator is at the \ref end, \ref advance moves it
 
1430
     * to the first match. Otherwise advance moves to the next match, or
 
1431
     * to the \ref end, if there is no more match.
 
1432
     *
 
1433
     * \note The original implementation treated an empty search string as
 
1434
     * <it>"match always"</it>. We stay compatible.
 
1435
     */
 
1436
    class PoolQueryMatcher
 
1437
    {
 
1438
      public:
 
1439
        typedef sat::LookupAttr::iterator base_iterator;
 
1440
 
 
1441
      public:
 
1442
        const base_iterator & end() const
 
1443
        {
 
1444
          static base_iterator _end;
 
1445
          return _end;
 
1446
        }
 
1447
 
 
1448
        bool advance( base_iterator & base_r ) const
 
1449
        {
 
1450
          if ( base_r == end() )
 
1451
            base_r = startNewQyery(); // first candidate
 
1452
          else
 
1453
          {
 
1454
            base_r.nextSkipSolvable(); // assert we don't visit this Solvable again
 
1455
            ++base_r; // advance to next candidate
 
1456
          }
 
1457
 
 
1458
          while ( base_r != end() )
 
1459
          {
 
1460
            if ( isAMatch( base_r ) )
 
1461
              return true;
 
1462
            // No match: try next
 
1463
            ++base_r;
 
1464
          }
 
1465
          return false;
 
1466
        }
 
1467
 
 
1468
        /** Provide all matching attributes within this solvable.
 
1469
         *
 
1470
         */
 
1471
        void matchDetail( const base_iterator & base_r, std::vector<base_iterator> & return_r ) const
 
1472
        {
 
1473
          if ( base_r == end() )
 
1474
            return;
 
1475
 
 
1476
          sat::Solvable inSolvable( base_r.inSolvable() );
 
1477
 
 
1478
          if ( _attrMatchList.size() == 1 )
 
1479
          {
 
1480
            // base_r is already on the 1st matching attribute!
 
1481
            // String matching is done by the base iterator. We must check the predicate here.
 
1482
            // Let's see if there are more matches for this solvable:
 
1483
            base_iterator base( base_r );
 
1484
            base.stayInThisSolvable(); // avoid discarding matches we found far away from here.
 
1485
            return_r.push_back( base );
 
1486
 
 
1487
            const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
 
1488
            for ( ++base; base.inSolvable() == inSolvable; ++base ) // safe even if base == end()
 
1489
            {
 
1490
              if ( ! predicate || predicate( base ) )
 
1491
                return_r.push_back( base );
 
1492
            }
 
1493
          }
 
1494
          else
 
1495
          {
 
1496
            // Here: search all attributes ;(
 
1497
            for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
 
1498
            {
 
1499
              const AttrMatchData & matchData( *mi );
 
1500
              sat::LookupAttr q( matchData.attr, inSolvable );
 
1501
              if ( matchData.strMatcher ) // an empty searchstring matches always
 
1502
                q.setStrMatcher( matchData.strMatcher );
 
1503
 
 
1504
              if ( ! q.empty() ) // there are matches.
 
1505
              {
 
1506
                // now check any predicate:
 
1507
                const AttrMatchData::Predicate & predicate( matchData.predicate );
 
1508
                for_( it, q.begin(), q.end() )
 
1509
                {
 
1510
                  if ( ! predicate || predicate( it ) )
 
1511
                    return_r.push_back( it );
 
1512
                }
 
1513
              }
 
1514
            }
 
1515
          }
 
1516
        }
 
1517
 
 
1518
      public:
 
1519
        /** Ctor stores the \ref PoolQuery settings.
 
1520
         * \throw MatchException Any of the exceptions thrown by \ref PoolQuery::Impl::compile.
 
1521
         */
 
1522
        PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r )
 
1523
        {
 
1524
          query_r->compile();
 
1525
 
 
1526
          // Repo restriction:
 
1527
          sat::Pool satpool( sat::Pool::instance() );
 
1528
 
 
1529
          for_( it, query_r->_repos.begin(), query_r->_repos.end() )
 
1530
          {
 
1531
            Repository r( satpool.reposFind( *it ) );
 
1532
            if ( r )
 
1533
              _repos.insert( r );
 
1534
            else
 
1535
              _neverMatchRepo = true;
 
1536
          }
 
1537
          // _neverMatchRepo: we just need to catch the case that no repo
 
1538
          // matched, so we'd interpret the empty list as 'take from all'
 
1539
          if ( _neverMatchRepo && ! _repos.empty() )
 
1540
            _neverMatchRepo = false;
 
1541
 
 
1542
          // Kind restriction:
 
1543
          _kinds = query_r->_kinds;
 
1544
          // Edition restriction:
 
1545
          _op      = query_r->_op;
 
1546
          _edition = query_r->_edition;
 
1547
          // Status restriction:
 
1548
          _status_flags = query_r->_status_flags;
 
1549
          // StrMatcher
 
1550
          _attrMatchList = query_r->_attrMatchList;
 
1551
        }
 
1552
 
 
1553
        ~PoolQueryMatcher()
 
1554
        {}
 
1555
 
 
1556
      private:
 
1557
        /** Initialize a new base query. */
 
1558
        base_iterator startNewQyery() const
 
1559
        {
 
1560
          sat::LookupAttr q;
 
1561
 
 
1562
          if ( _neverMatchRepo )
 
1563
            return q.end();
 
1564
 
 
1565
          // Repo restriction:
 
1566
          if ( _repos.size() == 1 )
 
1567
            q.setRepo( *_repos.begin() );
 
1568
          // else: handled in isAMatch.
 
1569
 
 
1570
          // Attribute restriction:
 
1571
          if ( _attrMatchList.size() == 1 ) // all (SolvAttr::allAttr) or 1 attr
 
1572
          {
 
1573
            const AttrMatchData & matchData( _attrMatchList.front() );
 
1574
            q.setAttr( matchData.attr );
 
1575
            if ( matchData.strMatcher ) // empty searchstring matches always
 
1576
              q.setStrMatcher( matchData.strMatcher );
 
1577
          }
 
1578
          else // more than 1 attr (but not all)
 
1579
          {
 
1580
            // no restriction, it's all handled in isAMatch.
 
1581
            q.setAttr( sat::SolvAttr::allAttr );
 
1582
          }
 
1583
 
 
1584
          return q.begin();
 
1585
        }
 
1586
 
 
1587
 
 
1588
        /** Check whether we are on a match.
 
1589
         *
 
1590
         * The check covers the whole Solvable, not just the current
 
1591
         * attribute \c base_r points to. If there's no match, also
 
1592
         * prepare \c base_r to advance appropriately. If there is
 
1593
         * a match, simply return \c true. \ref advance always moves
 
1594
         * to the next Solvable if there was a match.
 
1595
         *
 
1596
         * \note: Caller asserts we're not at \ref end.
 
1597
        */
 
1598
        bool isAMatch( base_iterator & base_r ) const
 
1599
        {
 
1600
          /////////////////////////////////////////////////////////////////////
 
1601
          Repository inRepo( base_r.inRepo() );
 
1602
          // Status restriction:
 
1603
          if ( _status_flags
 
1604
             && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
 
1605
          {
 
1606
            base_r.nextSkipRepo();
 
1607
            return false;
 
1608
          }
 
1609
          // Repo restriction:
 
1610
          if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
 
1611
          {
 
1612
            base_r.nextSkipRepo();
 
1613
            return false;
 
1614
          }
 
1615
          /////////////////////////////////////////////////////////////////////
 
1616
          sat::Solvable inSolvable( base_r.inSolvable() );
 
1617
          // Kind restriction:
 
1618
          if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
 
1619
          {
 
1620
            base_r.nextSkipSolvable();
 
1621
            return false;
 
1622
          }
 
1623
 
 
1624
          // Edition restriction:
 
1625
          if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
 
1626
          {
 
1627
            base_r.nextSkipSolvable();
 
1628
            return false;
 
1629
          }
 
1630
          /////////////////////////////////////////////////////////////////////
 
1631
          // string and predicate matching:
 
1632
 
 
1633
          if ( _attrMatchList.size() == 1 )
 
1634
          {
 
1635
            // String matching was done by the base iterator.
 
1636
            // Now check any predicate:
 
1637
            const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
 
1638
            if ( ! predicate || predicate( base_r ) )
 
1639
              return true;
 
1640
 
 
1641
            return false; // no skip as there may be more occurrences od this attr.
 
1642
          }
 
1643
 
 
1644
          // Here: search all attributes ;(
 
1645
          for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
 
1646
          {
 
1647
            const AttrMatchData & matchData( *mi );
 
1648
            sat::LookupAttr q( matchData.attr, inSolvable );
 
1649
            if ( matchData.strMatcher ) // an empty searchstring matches always
 
1650
              q.setStrMatcher( matchData.strMatcher );
 
1651
 
 
1652
            if ( ! q.empty() ) // there are matches.
 
1653
            {
 
1654
              // now check any predicate:
 
1655
              const AttrMatchData::Predicate & predicate( matchData.predicate );
 
1656
              if ( predicate )
 
1657
              {
 
1658
                for_( it, q.begin(), q.end() )
 
1659
                {
 
1660
                  if ( predicate( it ) )
 
1661
                    return true;
 
1662
                }
 
1663
              }
 
1664
              else
 
1665
                return true;
 
1666
            }
 
1667
          }
 
1668
          base_r.nextSkipSolvable();
 
1669
          return false;
 
1670
        }
 
1671
 
 
1672
      private:
 
1673
        /** Repositories include in the search. */
 
1674
        std::set<Repository> _repos;
 
1675
        DefaultIntegral<bool,false> _neverMatchRepo;
 
1676
        /** Resolvable kinds to include. */
 
1677
        std::set<ResKind> _kinds;
 
1678
        /** Edition filter. */
 
1679
        Rel _op;
 
1680
        Edition _edition;
 
1681
        /** Installed status filter flags. \see PoolQuery::StatusFilter */
 
1682
        int _status_flags;
 
1683
        /** StrMatcher per attribtue. */
 
1684
        AttrMatchList _attrMatchList;
 
1685
    };
 
1686
    ///////////////////////////////////////////////////////////////////
 
1687
 
 
1688
    void PoolQueryIterator::increment()
 
1689
    {
 
1690
      // matcher restarts if at end! It is called from the ctor
 
1691
      // to get the 1st match. But if the end is reached, it should
 
1692
      // be deleted, otherwise we'd start over again.
 
1693
      if ( !_matcher )
 
1694
        return; // at end
 
1695
      if ( _matches )
 
1696
        _matches.reset(); // invalidate old matches
 
1697
      if ( ! _matcher->advance( base_reference() ) )
 
1698
        _matcher.reset();
 
1699
    }
 
1700
 
 
1701
    const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
 
1702
    {
 
1703
      if ( _matches )
 
1704
        return *_matches;
 
1705
 
 
1706
      if ( !_matcher )
 
1707
      {
 
1708
        // at end of query:
 
1709
        static const Matches _none;
 
1710
        return _none;
 
1711
      }
 
1712
 
 
1713
      _matches.reset( new Matches );
 
1714
      _matcher->matchDetail( base_reference(), *_matches );
 
1715
      return *_matches;
 
1716
    }
 
1717
 
 
1718
    std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
 
1719
    {
 
1720
      str << *obj;
 
1721
      if ( ! obj.matchesEmpty() )
 
1722
      {
 
1723
        for_( it, obj.matchesBegin(), obj.matchesEnd() )
 
1724
        {
 
1725
          str << endl << "    " << it->inSolvAttr() << "\t" << it->asString();
 
1726
        }
 
1727
      }
 
1728
      return str;
 
1729
    }
 
1730
 
 
1731
    ///////////////////////////////////////////////////////////////////
 
1732
  } //namespace detail
 
1733
  ///////////////////////////////////////////////////////////////////
 
1734
 
 
1735
  detail::PoolQueryIterator PoolQuery::begin() const
 
1736
  {
 
1737
    return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
 
1738
  }
 
1739
 
 
1740
  /////////////////////////////////////////////////////////////////
 
1741
} // namespace zypp
 
1742
///////////////////////////////////////////////////////////////////
 
1743