1
/*---------------------------------------------------------------------\
3
| |__ / \ / / . \ . \ |
8
\---------------------------------------------------------------------*/
9
/** \file zypp/PoolQuery.cc
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"
22
#include "zypp/sat/Pool.h"
23
#include "zypp/sat/Solvable.h"
24
#include "zypp/base/StrMatcher.h"
26
#include "zypp/PoolQuery.h"
28
#undef ZYPP_BASE_LOGGER_LOGGROUP
29
#define ZYPP_BASE_LOGGER_LOGGROUP "PoolQuery"
32
using namespace zypp::sat;
34
///////////////////////////////////////////////////////////////////
36
{ /////////////////////////////////////////////////////////////////
38
///////////////////////////////////////////////////////////////////
40
{ /////////////////////////////////////////////////////////////////
42
/////////////////////////////////////////////////////////////////
43
// some Helpers and Predicates
44
/////////////////////////////////////////////////////////////////
46
bool isDependencyAttribute( sat::SolvAttr attr_r )
48
static sat::SolvAttr deps[] = {
55
SolvAttr::supplements,
58
for_( it, arrayBegin(deps), arrayEnd(deps) )
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.
68
struct EditionRangePredicate
70
EditionRangePredicate( const Rel & op, const Edition & edition )
71
: _range( op, edition )
74
EditionRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
75
: _range( op, edition )
79
bool operator()( sat::LookupAttr::iterator iter_r )
81
if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
84
CapDetail cap( iter_r.id() );
85
if ( ! cap.isSimple() )
87
if ( cap.isNamed() ) // no range to match
89
return overlaps( Edition::MatchRange( cap.op(), cap.ed() ), _range );
92
std::string serialize() const
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() );
101
Edition::MatchRange _range;
105
/** Whether the current Solvables edition is within a given range and/or its arch matches. */
106
struct SolvableRangePredicate
108
SolvableRangePredicate( const Rel & op, const Edition & edition )
109
: _range( op, edition )
110
, _arch( Arch_empty )
113
SolvableRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
114
: _range( op, edition )
118
bool operator()( sat::LookupAttr::iterator iter_r )
120
if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
122
return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
125
std::string serialize() const
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() );
134
Edition::MatchRange _range;
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.
142
struct CapabilityMatchPredicate
144
CapabilityMatchPredicate( Capability cap_r )
148
bool operator()( sat::LookupAttr::iterator iter_r ) const
150
return _cap.matches( iter_r.asType<Capability>() ) == CapMatch::yes;
153
std::string serialize() const
155
std::string ret( "CapabilityMatch" );
156
str::appendEscaped( ret, _cap.asString() );
163
/////////////////////////////////////////////////////////////////
165
/////////////////////////////////////////////////////////////////
166
/** Match data per attribtue.
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.
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.
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).
182
* \note: \see \ref addPredicate for further constraints.
186
typedef function<bool(sat::LookupAttr::iterator)> Predicate;
188
static bool always( sat::LookupAttr::iterator ) { return true; }
189
static bool never( sat::LookupAttr::iterator ) { return false; }
194
AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r )
196
, strMatcher( strMatcher_r )
199
AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r,
200
const Predicate & predicate_r, const std::string & predicateStr_r )
202
, strMatcher( strMatcher_r )
203
, predicate( predicate_r )
204
, predicateStr( predicateStr_r )
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.
212
template<class _Predicate>
213
void addPredicate( const _Predicate & predicate_r )
215
predicate = predicate_r;
216
predicateStr = predicate_r.serialize();
219
/** Dumb serialization.
221
* AttrMatchData ATTRIBUTE SEARCHSTRING [C|X] SERIALIZED_PREDICATE
224
std::string serialize() const
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 );
237
/** Dumb restore from serialized string.
238
* \throw Exception on parse error.
240
static AttrMatchData deserialize( const std::string & str_r )
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 ) );
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];
258
str::splitEscaped( ret.predicateStr, std::back_inserter(words) );
259
if ( ! words.empty() )
261
if ( words[0] == "EditionRange" )
263
switch( words.size() )
266
ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]) );
269
ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
272
ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
276
else if ( words[0] == "SolvableRange" )
278
switch( words.size() )
281
ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]) );
284
ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
287
ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
291
else if ( words[0] == "CapabilityMatch" )
293
if ( words.size() != 2 )
294
ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
295
ret.predicate = CapabilityMatchPredicate( Capability(words[1]) );
298
ZYPP_THROW( Exception( str::Str() << "Unknown predicate: " << str_r ) );
304
StrMatcher strMatcher;
306
std::string predicateStr;
309
/** \relates AttrMatchData */
310
inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
312
str << obj.attr << ": " << obj.strMatcher;
314
str << " +(" << obj.predicateStr << ")";
318
/** \relates AttrMatchData */
319
inline bool operator==( const AttrMatchData & lhs, const AttrMatchData & rhs )
321
return ( lhs.attr == rhs.attr
322
&& lhs.strMatcher == rhs.strMatcher
323
&& lhs.predicateStr == rhs.predicateStr );
326
/** \relates AttrMatchData */
327
inline bool operator!=( const AttrMatchData & lhs, const AttrMatchData & rhs )
328
{ return !( lhs == rhs ); }
330
/** \relates AttrMatchData Arbitrary order for std::container. */
331
inline bool operator<( const AttrMatchData & lhs, const AttrMatchData & rhs )
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 );
342
typedef std::list<AttrMatchData> AttrMatchList;
345
} /////////////////////////////////////////////////////////////////
347
///////////////////////////////////////////////////////////////////
349
///////////////////////////////////////////////////////////////////
351
// CLASS NAME : PoolQuery::Impl
354
class PoolQuery::Impl
358
: _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND )
360
, _require_all(false)
368
/** String representation */
369
string asString() const;
371
/** \name Raw query options. */
373
/** Raw search strings. */
374
StrContainer _strings;
375
/** Raw attributes */
376
AttrRawStrMap _attrs;
377
/** Uncompiled attributes with predicate. */
378
std::set<AttrMatchData> _uncompiledPredicated;
380
/** Sat solver search flags */
385
/** Sat solver status flags */
386
StatusFilter _status_flags;
388
/** Edition condition operand */
390
/** Operator for edition condition */
393
/** Repos to search. */
396
/** Kinds to search */
402
bool operator==( const PoolQuery::Impl & rhs ) const
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() )
413
&& _attrs.size() == 1
414
&& _attrs.begin()->first == sat::SolvAttr::name ) )
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
424
&& _repos == rhs._repos
425
&& _kinds == rhs._kinds );
430
bool operator!=( const PoolQuery::Impl & rhs ) const
431
{ return ! operator==( rhs ); }
434
/** Compile the regex.
435
* Basically building the \ref _attrMatchList from strings.
436
* \throws MatchException Any of the exceptions thrown by \ref StrMatcher::compile.
438
void compile() const;
440
/** StrMatcher per attribtue. */
441
mutable AttrMatchList _attrMatchList;
444
/** Pass flags from \ref compile, as they may have been changed. */
445
string createRegex( const StrContainer & container, const Match & flags ) const;
448
friend Impl * rwcowClone<Impl>( const Impl * rhs );
449
/** clone for RWCOW_pointer */
451
{ return new Impl( *this ); }
454
///////////////////////////////////////////////////////////////////
458
MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
460
bool operator()(const string & str)
466
PoolQuery::StrContainer & _cont;
472
bool operator()(const string & str)
478
void PoolQuery::Impl::compile() const
480
_attrMatchList.clear();
482
Match cflags( _flags );
483
if ( cflags.mode() == Match::OTHER ) // this will never succeed...
484
ZYPP_THROW( MatchUnknownModeException( cflags ) );
486
/** Compiled search strings. */
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
498
// create regex; store in rcstrings; if more strings flag regex;
501
; // A default 'query-all' will be added after all sources are processed.
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)
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 ) ) );
520
// // MULTIPLE ATTRIBUTES
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++)
531
attrvals_empty = false;
532
goto attremptycheckend;
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;
541
for (; ai != _attrs.end(); ++ai)
545
set1.begin(), set1.end(),
546
ai->second.begin(), ai->second.end(),
547
inserter(result, result.begin())/*, ltstr()*/);
550
attrvals_thesame = false;
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)
564
invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
565
rcstrings = createRegex(joined, cflags);
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);
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() )
579
_attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
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;
589
for_(ai, _attrs.begin(), _attrs.end())
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 ) ) );
603
// Now handle any predicated queries
604
if ( ! _uncompiledPredicated.empty() )
607
invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
608
for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
610
if ( it->strMatcher.flags().mode() == Match::OTHER )
613
StrContainer joined( global );
614
const std::string & mstr( it->strMatcher.searchstring() );
615
if ( ! mstr.empty() )
616
joined.insert( mstr );
619
rcstrings = createRegex( joined, cflags );
620
if ( joined.size() > 1 ) // switch to regex for multiple strings
621
cflags.setModeRegex();
623
_attrMatchList.push_back( AttrMatchData( it->attr,
624
StrMatcher( rcstrings, cflags ),
625
it->predicate, it->predicateStr ) );
630
_attrMatchList.push_back( *it );
635
// If no attributes defined at all, then add 'query all'
636
if ( _attrMatchList.empty() )
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 ) ) );
646
// Finally check here, whether all involved regex compile.
647
for_( it, _attrMatchList.begin(), _attrMatchList.end() )
649
it->strMatcher.compile(); // throws on error
651
//DBG << asString() << endl;
656
* Converts '*' and '?' wildcards within str into their regex equivalents.
658
static string wildcards2regex(const string & str)
660
string regexed = str;
662
string r_all(".*"); // regex equivalent of '*'
663
string r_one("."); // regex equivalent of '?'
664
string::size_type pos;
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);
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);
677
string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const
679
//! macro for word boundary tags for regexes
680
#define WB (_match_word ? string("\\b") : string())
683
if (container.empty())
686
if (container.size() == 1)
688
return WB + *container.begin() + WB;
693
bool use_wildcards = flags.isModeGlob();
694
StrContainer::const_iterator it = container.begin();
698
tmp = wildcards2regex(*it);
704
if ( ! flags.isModeString() ) // not match exact
705
tmp += ".*" + WB + tmp;
706
rstr = "(?=" + tmp + ")";
710
if ( flags.isModeString() || flags.isModeGlob() )
712
rstr += WB + "(" + tmp;
717
for (; it != container.end(); ++it)
720
tmp = wildcards2regex(*it);
726
if ( ! flags.isModeString() ) // not match exact
727
tmp += ".*" + WB + tmp;
728
rstr += "(?=" + tmp + ")";
738
if ( ! flags.isModeString() ) // not match exact
744
if ( flags.isModeString() || flags.isModeGlob() )
752
string PoolQuery::Impl::asString() const
757
if ( _kinds.empty() )
761
for(Kinds::const_iterator it = _kinds.begin();
762
it != _kinds.end(); ++it)
768
if ( _repos.empty() )
772
for(StrContainer::const_iterator it = _repos.begin();
773
it != _repos.end(); ++it)
778
o << "version: "<< _op << " " << _edition.asString() << endl;
779
o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" )
782
o << "string match flags: " << Match(_flags) << endl;
786
for(StrContainer::const_iterator it = _strings.begin();
787
it != _strings.end(); ++it)
791
o << "attributes: " << endl;
792
for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
794
o << "* " << ai->first << ": ";
795
for(StrContainer::const_iterator vi = ai->second.begin();
796
vi != ai->second.end(); ++vi)
801
o << "predicated: " << endl;
802
for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
804
o << "* " << *it << endl;
808
o << "last attribute matcher compiled: " << endl;
809
if ( _attrMatchList.empty() )
811
o << "not yet compiled" << endl;
815
for_( it, _attrMatchList.begin(), _attrMatchList.end() )
817
o << "* " << *it << endl;
823
///////////////////////////////////////////////////////////////////
825
///////////////////////////////////////////////////////////////////
827
// CLASS NAME : PoolQuery
829
///////////////////////////////////////////////////////////////////
831
PoolQuery::PoolQuery()
835
PoolQuery::~PoolQuery()
838
void PoolQuery::addRepo(const std::string &repoalias)
840
if (repoalias.empty())
842
WAR << "ignoring an empty repository alias" << endl;
845
_pimpl->_repos.insert(repoalias);
848
void PoolQuery::addKind(const ResKind & kind)
849
{ _pimpl->_kinds.insert(kind); }
851
void PoolQuery::addString(const string & value)
852
{ _pimpl->_strings.insert(value); }
854
void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
855
{ _pimpl->_attrs[attr].insert(value); }
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 ); }
860
void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch )
862
switch ( op.inSwitch() )
864
case Rel::ANY_e: // no additional constraint on edition.
865
if ( arch.empty() ) // no additional constraint on arch.
867
addAttribute( attr, name );
872
case Rel::NONE_e: // will never match.
875
default: // go and add the predicated query (uncompiled)
879
// Match::OTHER indicates need to compile
880
// (merge global search strings into name).
881
AttrMatchData attrMatchData( attr, StrMatcher( name, Match::OTHER ) );
883
if ( isDependencyAttribute( attr ) )
884
attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) );
886
attrMatchData.addPredicate( SolvableRangePredicate( op, edition, arch ) );
888
_pimpl->_uncompiledPredicated.insert( attrMatchData );
891
void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
893
CapDetail cap( cap_r );
894
if ( ! cap.isSimple() ) // will never match.
897
// Matches STRING per default. (won't get compiled!)
898
AttrMatchData attrMatchData( attr, StrMatcher( cap.name().asString() ) );
900
if ( isDependencyAttribute( attr ) )
901
attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
903
attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) );
905
_pimpl->_uncompiledPredicated.insert( attrMatchData );
908
void PoolQuery::setEdition(const Edition & edition, const Rel & op)
910
_pimpl->_edition = edition;
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()
920
_pimpl->_match_word = true;
921
_pimpl->_flags.setModeRegex();
924
Match PoolQuery::flags() const
925
{ return _pimpl->_flags; }
926
void PoolQuery::setFlags( const Match & flags )
927
{ _pimpl->_flags = flags; }
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; }
938
void PoolQuery::setRequireAll(bool require_all)
939
{ _pimpl->_require_all = require_all; }
942
const PoolQuery::StrContainer &
943
PoolQuery::strings() const
944
{ return _pimpl->_strings; }
946
const PoolQuery::AttrRawStrMap &
947
PoolQuery::attributes() const
948
{ return _pimpl->_attrs; }
950
const PoolQuery::StrContainer &
951
PoolQuery::attribute(const sat::SolvAttr & attr) const
953
static const PoolQuery::StrContainer nocontainer;
954
AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
955
return it != _pimpl->_attrs.end() ? it->second : nocontainer;
958
const Edition PoolQuery::edition() const
959
{ return _pimpl->_edition; }
960
const Rel PoolQuery::editionRel() const
961
{ return _pimpl->_op; }
964
const PoolQuery::Kinds &
965
PoolQuery::kinds() const
966
{ return _pimpl->_kinds; }
968
const PoolQuery::StrContainer &
969
PoolQuery::repos() const
970
{ return _pimpl->_repos; }
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 ); }
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 ); }
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(); }
988
bool PoolQuery::matchWord() const
989
{ return _pimpl->_match_word; }
991
bool PoolQuery::requireAll() const
992
{ return _pimpl->_require_all; }
994
PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
995
{ return _pimpl->_status_flags; }
997
bool PoolQuery::empty() const
999
try { return begin() == end(); }
1000
catch (const Exception & ex) {}
1004
PoolQuery::size_type PoolQuery::size() const
1008
size_type count = 0;
1009
for_( it, begin(), end() )
1013
catch (const Exception & ex) {}
1017
void PoolQuery::execute(ProcessResolvable fnc)
1018
{ invokeOnEach( begin(), end(), fnc); }
1021
///////////////////////////////////////////////////////////////////
1023
// CLASS NAME : PoolQuery::Attr
1026
* represents all atributes in PoolQuery except SolvAtributes, which are
1027
* used as is (not needed extend anything if someone adds new solv attr)
1029
struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
1032
friend class IdStringType<PoolQueryAttr>;
1039
explicit PoolQueryAttr( const char* cstr_r )
1043
explicit PoolQueryAttr( const std::string & str_r )
1047
// unknown atributes
1048
static const PoolQueryAttr noAttr;
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;
1062
const PoolQueryAttr PoolQueryAttr::noAttr;
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");
1074
class StringTypeAttr : public IdStringType<PoolQueryAttr>
1076
friend class IdStringType<StringTypeAttr>;
1081
explicit StringTypeAttr( const char* cstr_r )
1083
explicit StringTypeAttr( const std::string & str_r )
1086
static const StringTypeAttr noAttr;
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;
1095
const StringTypeAttr StringTypeAttr::noAttr;
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");
1103
///////////////////////////////////////////////////////////////////
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 )
1110
bool finded_something = false; //indicates some atributes is finded
1116
getline( str, s, delim );
1118
if ((!s.empty()) && s[0]=='#') //comment
1123
string::size_type pos = s.find(':');
1124
if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
1126
if (finded_something) //is first blank line after record?
1136
finded_something = true;
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
1141
PoolQueryAttr attribute( attrName );
1143
if ( attribute==PoolQueryAttr::repoAttr )
1145
addRepo( attrValue );
1147
/* some backwards compatibility */
1148
else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" )
1150
addKind( ResKind(attrValue) );
1152
else if ( attribute==PoolQueryAttr::stringAttr
1153
|| attribute=="global_string")
1155
addString( attrValue );
1157
else if ( attribute==PoolQueryAttr::stringTypeAttr
1158
|| attribute=="string_type" )
1160
StringTypeAttr s(attrValue);
1161
if( s == StringTypeAttr::regexAttr )
1165
else if ( s == StringTypeAttr::globAttr )
1169
else if ( s == StringTypeAttr::exactAttr )
1173
else if ( s == StringTypeAttr::substringAttr )
1175
setMatchSubstring();
1177
else if ( s == StringTypeAttr::wordAttr )
1181
else if ( s == StringTypeAttr::noAttr )
1183
WAR << "unknown string type " << attrValue << endl;
1187
WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
1190
else if ( attribute==PoolQueryAttr::requireAllAttr )
1192
if ( str::strToTrue(attrValue) )
1194
setRequireAll(true);
1196
else if ( !str::strToFalse(attrValue) )
1198
setRequireAll(false);
1202
WAR << "unknown boolean value " << attrValue << endl;
1205
else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
1207
if ( str::strToTrue(attrValue) )
1209
setCaseSensitive(true);
1211
else if ( !str::strToFalse(attrValue) )
1213
setCaseSensitive(false);
1217
WAR << "unknown boolean value " << attrValue << endl;
1220
else if ( attribute==PoolQueryAttr::installStatusAttr )
1222
if( attrValue == "all" )
1224
setStatusFilterFlags( ALL );
1226
else if( attrValue == "installed" )
1230
else if( attrValue == "not-installed" )
1232
setUninstalledOnly();
1236
WAR << "Unknown value for install status " << attrValue << endl;
1239
else if ( attribute == PoolQueryAttr::editionAttr)
1241
string::size_type pos;
1243
if (attrValue.find_first_of("=<>!") == 0)
1245
pos = attrValue.find_last_of("=<>");
1246
rel = Rel(attrValue.substr(0, pos+1));
1247
attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos));
1250
setEdition(Edition(attrValue), rel);
1252
else if ( attribute == PoolQueryAttr::complexAttr )
1256
_pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) );
1258
catch ( const Exception & err )
1260
WAR << "Unparsable value for complex: " << err.asUserHistory() << endl;
1264
else if ( attribute==PoolQueryAttr::noAttr )
1266
WAR << "empty attribute name" << endl;
1270
string s = attrName;
1271
str::replaceAll( s,"_",":" );
1273
if ( a == SolvAttr::name || isDependencyAttribute( a ) )
1275
Capability c( attrValue );
1277
if ( d.isVersioned() )
1278
addDependency( a, d.name().asString(), d.op(), d.ed() );
1280
addDependency( a, attrValue );
1283
addAttribute( a, attrValue );
1288
return finded_something;
1291
void PoolQuery::serialize( ostream &str, char delim ) const
1295
//iterate thrue all settings and write it
1296
static const zypp::PoolQuery q; //not save default options, so create default query example
1298
for_( it, repos().begin(), repos().end() )
1300
str << "repo: " << *it << delim ;
1303
for_( it, kinds().begin(), kinds().end() )
1305
str << PoolQueryAttr::kindAttr.asString() << ": "
1306
<< it->idStr() << delim ;
1309
if (editionRel() != Rel::ANY && edition() != Edition::noedition)
1310
str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim;
1312
if (matchMode()!=q.matchMode())
1314
switch( matchMode() )
1317
str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
1319
case Match::SUBSTRING:
1320
str << PoolQueryAttr::stringTypeAttr.asString()
1321
<< ": substring" << delim;
1324
str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
1327
str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
1330
WAR << "unknown match type " << matchMode() << endl;
1334
if( caseSensitive() != q.caseSensitive() )
1336
str << "case_sensitive: ";
1337
if (caseSensitive())
1339
str << "on" << delim;
1343
str << "off" << delim;
1347
if( requireAll() != q.requireAll() )
1349
str << "require_all: ";
1352
str << "on" << delim;
1356
str << "off" << delim;
1360
if( statusFilterFlags() != q.statusFilterFlags() )
1362
switch( statusFilterFlags() )
1365
str << "install_status: all" << delim;
1367
case INSTALLED_ONLY:
1368
str << "install_status: installed" << delim;
1370
case UNINSTALLED_ONLY:
1371
str << "install_status: not-installed" << delim;
1376
for_( it, strings().begin(), strings().end() )
1378
str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
1381
for_( it, attributes().begin(), attributes().end() )
1383
string s = it->first.asString();
1384
str::replaceAll(s,":","_");
1385
for_( it2,it->second.begin(),it->second.end() )
1387
str << s <<": "<< *it2 << delim;
1391
for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() )
1393
str << "complex: "<< it->serialize() << delim;
1396
//separating delim - protection
1400
string PoolQuery::asString() const
1401
{ return _pimpl->asString(); }
1403
ostream & operator<<( ostream & str, const PoolQuery & obj )
1404
{ return str << obj.asString(); }
1406
std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj )
1407
{ return dumpRange( str << obj, obj.begin(), obj.end() ); }
1409
bool PoolQuery::operator==( const PoolQuery & rhs ) const
1410
{ return *_pimpl == *rhs._pimpl; }
1412
///////////////////////////////////////////////////////////////////
1414
{ /////////////////////////////////////////////////////////////////
1416
///////////////////////////////////////////////////////////////////
1418
// CLASS NAME : PoolQueryMatcher
1420
/** Store \ref PoolQuery settings and assist \ref PoolQueryIterator.
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.
1426
* Matcher must be stateless, as it is shared between multiple
1427
* \ref PoolQueryIterator instances.
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.
1433
* \note The original implementation treated an empty search string as
1434
* <it>"match always"</it>. We stay compatible.
1436
class PoolQueryMatcher
1439
typedef sat::LookupAttr::iterator base_iterator;
1442
const base_iterator & end() const
1444
static base_iterator _end;
1448
bool advance( base_iterator & base_r ) const
1450
if ( base_r == end() )
1451
base_r = startNewQyery(); // first candidate
1454
base_r.nextSkipSolvable(); // assert we don't visit this Solvable again
1455
++base_r; // advance to next candidate
1458
while ( base_r != end() )
1460
if ( isAMatch( base_r ) )
1462
// No match: try next
1468
/** Provide all matching attributes within this solvable.
1471
void matchDetail( const base_iterator & base_r, std::vector<base_iterator> & return_r ) const
1473
if ( base_r == end() )
1476
sat::Solvable inSolvable( base_r.inSolvable() );
1478
if ( _attrMatchList.size() == 1 )
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 );
1487
const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
1488
for ( ++base; base.inSolvable() == inSolvable; ++base ) // safe even if base == end()
1490
if ( ! predicate || predicate( base ) )
1491
return_r.push_back( base );
1496
// Here: search all attributes ;(
1497
for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
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 );
1504
if ( ! q.empty() ) // there are matches.
1506
// now check any predicate:
1507
const AttrMatchData::Predicate & predicate( matchData.predicate );
1508
for_( it, q.begin(), q.end() )
1510
if ( ! predicate || predicate( it ) )
1511
return_r.push_back( it );
1519
/** Ctor stores the \ref PoolQuery settings.
1520
* \throw MatchException Any of the exceptions thrown by \ref PoolQuery::Impl::compile.
1522
PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r )
1526
// Repo restriction:
1527
sat::Pool satpool( sat::Pool::instance() );
1529
for_( it, query_r->_repos.begin(), query_r->_repos.end() )
1531
Repository r( satpool.reposFind( *it ) );
1535
_neverMatchRepo = true;
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;
1542
// Kind restriction:
1543
_kinds = query_r->_kinds;
1544
// Edition restriction:
1546
_edition = query_r->_edition;
1547
// Status restriction:
1548
_status_flags = query_r->_status_flags;
1550
_attrMatchList = query_r->_attrMatchList;
1557
/** Initialize a new base query. */
1558
base_iterator startNewQyery() const
1562
if ( _neverMatchRepo )
1565
// Repo restriction:
1566
if ( _repos.size() == 1 )
1567
q.setRepo( *_repos.begin() );
1568
// else: handled in isAMatch.
1570
// Attribute restriction:
1571
if ( _attrMatchList.size() == 1 ) // all (SolvAttr::allAttr) or 1 attr
1573
const AttrMatchData & matchData( _attrMatchList.front() );
1574
q.setAttr( matchData.attr );
1575
if ( matchData.strMatcher ) // empty searchstring matches always
1576
q.setStrMatcher( matchData.strMatcher );
1578
else // more than 1 attr (but not all)
1580
// no restriction, it's all handled in isAMatch.
1581
q.setAttr( sat::SolvAttr::allAttr );
1588
/** Check whether we are on a match.
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.
1596
* \note: Caller asserts we're not at \ref end.
1598
bool isAMatch( base_iterator & base_r ) const
1600
/////////////////////////////////////////////////////////////////////
1601
Repository inRepo( base_r.inRepo() );
1602
// Status restriction:
1604
&& ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
1606
base_r.nextSkipRepo();
1609
// Repo restriction:
1610
if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
1612
base_r.nextSkipRepo();
1615
/////////////////////////////////////////////////////////////////////
1616
sat::Solvable inSolvable( base_r.inSolvable() );
1617
// Kind restriction:
1618
if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
1620
base_r.nextSkipSolvable();
1624
// Edition restriction:
1625
if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
1627
base_r.nextSkipSolvable();
1630
/////////////////////////////////////////////////////////////////////
1631
// string and predicate matching:
1633
if ( _attrMatchList.size() == 1 )
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 ) )
1641
return false; // no skip as there may be more occurrences od this attr.
1644
// Here: search all attributes ;(
1645
for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
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 );
1652
if ( ! q.empty() ) // there are matches.
1654
// now check any predicate:
1655
const AttrMatchData::Predicate & predicate( matchData.predicate );
1658
for_( it, q.begin(), q.end() )
1660
if ( predicate( it ) )
1668
base_r.nextSkipSolvable();
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. */
1681
/** Installed status filter flags. \see PoolQuery::StatusFilter */
1683
/** StrMatcher per attribtue. */
1684
AttrMatchList _attrMatchList;
1686
///////////////////////////////////////////////////////////////////
1688
void PoolQueryIterator::increment()
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.
1696
_matches.reset(); // invalidate old matches
1697
if ( ! _matcher->advance( base_reference() ) )
1701
const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
1709
static const Matches _none;
1713
_matches.reset( new Matches );
1714
_matcher->matchDetail( base_reference(), *_matches );
1718
std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
1721
if ( ! obj.matchesEmpty() )
1723
for_( it, obj.matchesBegin(), obj.matchesEnd() )
1725
str << endl << " " << it->inSolvAttr() << "\t" << it->asString();
1731
///////////////////////////////////////////////////////////////////
1732
} //namespace detail
1733
///////////////////////////////////////////////////////////////////
1735
detail::PoolQueryIterator PoolQuery::begin() const
1737
return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
1740
/////////////////////////////////////////////////////////////////
1742
///////////////////////////////////////////////////////////////////