generalize matching code from examples/solv.c to src/selection.c
authorMichael Schroeder <mls@suse.de>
Thu, 25 Oct 2012 14:55:11 +0000 (16:55 +0200)
committerMichael Schroeder <mls@suse.de>
Thu, 25 Oct 2012 14:55:11 +0000 (16:55 +0200)
Adapt the examples to use the new mechanism. This is probably
not the final version of the interface, so handle with care.

bindings/solv.i
examples/p5solv
examples/pysolv
examples/rbsolv
examples/solv.c
src/CMakeLists.txt
src/libsolv.ver
src/rules.c
src/selection.c [new file with mode: 0644]
src/selection.h [new file with mode: 0644]

index ec7280f..5bef32b 100644 (file)
@@ -349,6 +349,7 @@ typedef int bool;
 #include "solverdebug.h"
 #include "repo_solv.h"
 #include "chksum.h"
+#include "selection.h"
 
 #include "repo_write.h"
 #ifdef ENABLE_RPMDB
@@ -474,6 +475,12 @@ typedef struct {
   Id toid;
 } TransactionClass;
 
+typedef struct {
+  Pool *pool;
+  Queue q;
+  int flags;
+} Selection;
+
 typedef Dataiterator Datamatch;
 
 %}
@@ -500,6 +507,10 @@ typedef int Id;
 
 typedef struct {
   Pool* const pool;
+} Selection;
+
+typedef struct {
+  Pool* const pool;
   Id const id;
 } Dep;
 
@@ -682,8 +693,25 @@ typedef struct {
     Queue q;
     queue_init(&q);
     how = $self->how & SOLVER_SELECTMASK;
-    FOR_JOB_SELECT(p, pp, how, $self->what)
-      queue_push(&q, p);
+    if (how == SOLVER_SOLVABLE_ALL)
+      {
+        for (p = 2; p < pool->nsolvables; p++)
+          if (pool->solvables[p].repo)
+            queue_push(&q, p);
+      }
+    else if (how == SOLVER_SOLVABLE_REPO)
+      {
+        Repo *repo = pool_id2repo(pool, $self->what);
+        Solvable *s;
+        if (repo)
+          FOR_REPO_SOLVABLES(repo, p, s)
+            queue_push(&q, p);
+      }
+    else
+      {
+        FOR_JOB_SELECT(p, pp, how, $self->what)
+          queue_push(&q, p);
+      }
     return q;
   }
 
@@ -705,6 +733,78 @@ typedef struct {
   }
 }
 
+%extend Selection {
+  static const Id SELECTION_NAME = SELECTION_NAME;
+  static const Id SELECTION_PROVIDES = SELECTION_PROVIDES;
+  static const Id SELECTION_FILELIST = SELECTION_FILELIST;
+  static const Id SELECTION_GLOB = SELECTION_GLOB;
+  static const Id SELECTION_NOCASE = SELECTION_NOCASE;
+  static const Id SELECTION_INSTALLED_ONLY = SELECTION_INSTALLED_ONLY;
+  static const Id SELECTION_FLAT = SELECTION_FLAT;
+
+  Selection(Pool *pool) {
+    Selection *s;
+    s = solv_calloc(1, sizeof(*s));
+    s->pool = pool;
+    return s;
+  }
+
+  ~Selection() {
+    queue_free(&$self->q);
+    solv_free($self);
+  }
+  int flags() {
+    return $self->flags;
+  }
+  void make(const char *name, int flags) {
+    $self->flags = selection_make($self->pool, &$self->q, name, flags);
+  }
+#ifdef SWIGRUBY
+  %rename("isempty?") isempty;
+#endif
+  bool isempty() {
+    return $self->q.count == 0;
+  }
+  void limit(Selection *lsel) {
+    if ($self->pool != lsel->pool)
+      queue_empty(&$self->q);
+    else
+      selection_limit($self->pool, &$self->q, &lsel->q);
+  }
+  void add(Selection *lsel) {
+    if ($self->pool == lsel->pool)
+      {
+        selection_add($self->pool, &$self->q, &lsel->q);
+        $self->flags |= lsel->flags;
+      }
+  }
+  void addsimple(Id how, Id what) {
+    queue_push2(&$self->q, how, what);
+  }
+  %typemap(out) Queue jobs Queue2Array(Job *, 2, new_Job(arg1->pool, id, idp[1]));
+  %newobject jobs;
+  Queue jobs(int flags) {
+    Queue q;
+    int i;
+    queue_init_clone(&q, &$self->q);
+    for (i = 0; i < q.count; i += 2)
+      q.elements[i] |= flags;
+    return q;
+  }
+
+#if defined(SWIGPERL)
+  %rename("str") __str__;
+#endif
+  const char *__str__() {
+    char *s;
+    int i;
+    s = pool_tmpjoin($self->pool, 0, 0, 0);
+    for (i = 0; i < $self->q.count; i += 2)
+      s = pool_tmpappend($self->pool, s, " | ", solver_select2str($self->pool, $self->q.elements[i] & SOLVER_SELECTMASK, $self->q.elements[i + 1]));
+    return *s ? s + 3 : s;
+  }
+}
+
 %extend Chksum {
   Chksum(Id type) {
     return (Chksum *)solv_chksum_create(type);
@@ -1086,6 +1186,17 @@ typedef struct {
   Solver *Solver() {
     return solver_create($self);
   }
+
+  %newobject Selection;
+  Selection *Selection() {
+    return new_Selection($self);
+  }
+  %newobject select;
+  Selection *select(const char *name, int flags) {
+    Selection *sel = new_Selection($self);
+    sel->flags = selection_make($self, &sel->q, name, flags);
+    return sel;
+  }
 }
 
 %extend Repo {
index 58cdc9a..cda9a9c 100755 (executable)
@@ -486,155 +486,6 @@ sub load {
 
 package main;
 
-sub validarch {
-  my ($pool, $arch) = @_;
-  return undef unless $arch;
-  my $id = $pool->str2id($arch, 0);
-  return $id && $pool->isknownarch($id) ? 1 : undef;
-}
-
-sub depglob {
-  my ($pool, $name, $globname, $globdep) = @_;
-  my $id = $pool->str2id($name, 0);
-  if ($id) {
-    my $match;
-    for my $s ($pool->whatprovides($id)) {
-      return $pool->Job($solv::Job::SOLVER_SOLVABLE_NAME, $id) if $globname && $s->{'nameid'} == $id;
-      $match = 1;
-    }
-    if ($match) {
-      print "[using capability match for '$name']\n" if $globname && $globdep;
-      return $pool->Job($solv::Job::SOLVER_SOLVABLE_PROVIDES, $id);
-    }
-  }
-  return unless $name =~ /[[*?]/;
-  if ($globname) {
-    my %idmatches;
-    for my $d (@{$pool->Dataiterator(0, $solv::SOLVABLE_NAME, $name, $solv::Dataiterator::SEARCH_GLOB)}) {
-      my $s = $d->{'solvable'};
-      $idmatches{$s->{'nameid'}} = 1 if $s->installable();
-    }
-    if (%idmatches) {
-      return map {$pool->Job($solv::Job::SOLVER_SOLVABLE_NAME, $_)} sort(keys %idmatches);
-    }
-  }
-  if ($globdep) {
-    my @idmatches = $pool->matchprovidingids($name, $solv::Dataiterator::SEARCH_GLOB);
-    if (@idmatches) {
-      print "[using capability match for '$name']\n";
-      return map {$pool->Job($solv::Job::SOLVER_SOLVABLE_PROVIDES, $_)} sort(@idmatches);
-    }
-  }
-  return;
-}
-
-sub limitjobs {
-  my ($pool, $jobs, $flags, $evrstr) = @_;
-  my @jobs;
-  my $evr = $pool->str2id($evrstr);
-  for my $j (@$jobs) {
-    my $how = $j->{'how'};
-    my $sel = $how & $solv::Job::SOLVER_SELECTMASK;
-    my $what = $pool->rel2id($j->{'what'}, $evr, $flags);
-    if ($flags == $solv::REL_ARCH) {
-      $how |= $solv::Job::SOLVER_SETARCH;
-    } elsif ($flags == $solv::REL_EQ && $sel == $solv::Job::SOLVER_SOLVABLE_NAME) {
-      $how |= $evrstr =~ /-/ ? $solv::Job::SOLVER_SETEVR : $solv::Job::SOLVER_SETEV;
-    }
-    push @jobs, $pool->Job($how, $what);
-  }
-  return @jobs;
-}
-
-sub limitjobs_evrarch {
-  my ($pool, $jobs, $flags, $evrstr) = @_;
-  if ($evrstr =~ /^(.+)\.(.+?)$/ && validarch($pool, $2)) {
-    $evrstr = $1;
-    $jobs = [ limitjobs($pool, $jobs, $solv::REL_ARCH, $2) ];
-  }
-  return limitjobs($pool, $jobs, $flags, $evrstr);
-}
-
-sub mkjobs_rel {
-  my ($pool, $cmd, $name, $rel, $evr) = @_;
-  my $flags = 0;
-  $flags |= $solv::REL_LT if $rel =~ /</;
-  $flags |= $solv::REL_EQ if $rel =~ /=/;
-  $flags |= $solv::REL_GT if $rel =~ />/;
-  my @jobs = depglob($pool, $name, 1, 1);
-  return limitjobs($pool, \@jobs, $flags, $evr) if @jobs;
-  if (($name =~ /^(.+)\.(.+?)$/s) && validarch($pool, $2)) {
-    my $arch = $2;
-    @jobs = depglob($pool, $1, 1, 1);
-    if (@jobs) {
-      @jobs = limitjobs($pool, \@jobs, $solv::REL_ARCH, $arch);
-      return limitjobs($pool, \@jobs, $flags, $evr);
-    }
-  }
-  return ();
-}
-
-sub mkjobs_nevra {
-  my ($pool, $cmd, $arg) = @_;
-  my @jobs = depglob($pool, $arg, 1, 1);
-  return @jobs if @jobs;
-  if (($arg =~ /^(.+)\.(.+?)$/s) && validarch($pool, $2)) {
-    my $arch = $2;
-    @jobs = depglob($pool, $1, 1, 1);
-    return limitjobs($pool, \@jobs, $solv::REL_ARCH, $arch) if @jobs;
-  }
-  if ($arg =~ /^(.+)-(.+?)$/s) {
-    my $evr = $2;
-    @jobs = depglob($pool, $1, 1, 0);
-    return limitjobs_evrarch($pool, \@jobs, $solv::REL_EQ, $evr) if @jobs;
-  }
-  if ($arg =~ /^(.+)-(.+?-.+?)$/s) {
-    my $evr = $2;
-    @jobs = depglob($pool, $1, 1, 0);
-    return limitjobs_evrarch($pool, \@jobs, $solv::REL_EQ, $evr) if @jobs;
-  }
-  return ();
-}
-
-sub mkjobs_filelist {
-  my ($pool, $cmd, $arg) = @_;
-  my $type = ($arg =~ /[[*?]/) ? $solv::Dataiterator::SEARCH_GLOB : $solv::Dataiterator::SEARCH_STRING;
-  $type |= $solv::Dataiterator::SEARCH_FILES | $solv::Dataiterator::SEARCH_COMPLETE_FILELIST;
-  my $di;
-  if ($cmd eq 'erase') {
-    $di = $pool->{'installed'}->Dataiterator(0, $solv::SOLVABLE_FILELIST, $arg, $type);
-  } else {
-    $di = $pool->Dataiterator(0, $solv::SOLVABLE_FILELIST, $arg, $type);
-  }
-  my @matches;
-  for my $d (@$di) {
-    my $s = $d->{'solvable'};
-    next unless $s && $s->installable();
-    push @matches, $s->{'id'};
-    $di->skip_solvable();
-  }
-  return () unless @matches;
-  print "[using file list match for '$arg']\n";
-  if (@matches > 1) {
-    return $pool->Job($solv::Job::SOLVER_SOLVABLE_ONE_OF, $pool->towhatprovides(\@matches));
-  } else {
-    return $pool->Job($solv::Job::SOLVER_SOLVABLE | $solv::Job::SOLVER_NOAUTOSET, $matches[0]);
-  }
-}
-
-sub mkjobs {
-  my ($pool, $cmd, $arg) = @_;
-  if ($arg && $arg =~ /^\//) {
-    my @jobs = mkjobs_filelist($pool, $cmd, $arg);
-    return @jobs if @jobs;
-  }
-  if ($arg =~ /^(.+?)\s*([<=>]+)\s*(.+?)$/s) {
-    return mkjobs_rel($pool, $cmd, $1, $2, $3);
-  } else {
-    return mkjobs_nevra($pool, $cmd, $arg);
-  }
-}
-
 sub load_stub {
   my ($repodata) = @_;
   my $repo = $repodata->{'repo'}->{'appdata'};
@@ -650,7 +501,13 @@ $cmd = 'verify' if $cmd eq 've';
 $cmd = 'search' if $cmd eq 'se';
 
 my @repos;
-for my $reposdir ('/etc/zypp/repos.d') {
+my @reposdirs;
+if (-d '/etc/zypp/repos.d') {
+  @reposdirs = ( '/etc/zypp/repos.d' );
+} else {
+  @reposdirs = ( '/etc/yum/repos.d' );
+}
+for my $reposdir (@reposdirs) {
   next unless -d $reposdir;
   next unless opendir(DIR, $reposdir);
   for my $reponame (sort(grep {/\.repo$/} readdir(DIR))) {
@@ -701,9 +558,25 @@ $pool->createwhatprovides();
 
 my @jobs;
 for my $arg (@ARGV) {
-  my @njobs = mkjobs($pool, $cmd, $arg);
-  die("nothing matches '$arg'\n") unless @njobs;
-  push @jobs, @njobs;
+  my $flags = $solv::Selection::SELECTION_NAME | $solv::Selection::SELECTION_PROVIDES | $solv::Selection::SELECTION_GLOB;
+  if ($arg =~ /^\//) {
+    $flags |= $solv::Selection::SELECTION_FILELIST;
+    $flags |= $solv::Selection::SELECTION_INSTALLED_ONLY if $cmd eq 'erase';
+  }
+  my $sel = $pool->select($arg, $flags);
+  if ($sel->isempty()) {
+    $sel = $pool->select($arg, $flags | $solv::Selection::SELECTION_NOCASE);
+    print "[ignoring case for '$arg']\n" unless $sel->isempty();
+  }
+  die("nothing matches '$arg'\n") if $sel->isempty();
+  print "[using file list match for '$arg']\n" if $sel->flags() & $solv::Selection::SELECTION_FILELIST;
+  print "[using capability match for '$arg']\n" if $sel->flags() & $solv::Selection::SELECTION_PROVIDES;
+  push @jobs, $sel->jobs(0);
+}
+if (!@jobs && ($cmd eq 'up' || $cmd eq 'dup' || $cmd eq 'verify')) {
+  my $sel = $pool->Selection();
+  $sel->addsimple($solv::Job::SOLVER_SOLVABLE_ALL, 0);
+  push @jobs, $sel->jobs(0);
 }
 
 if ($cmd eq 'list' || $cmd eq 'info') {
@@ -729,13 +602,7 @@ if ($cmd eq 'list' || $cmd eq 'info') {
 }
 
 if ($cmd eq 'install' || $cmd eq 'erase' || $cmd eq 'up' || $cmd eq 'dup' || $cmd eq 'verify') {
-  if (!@jobs) {
-    if ($cmd eq 'up' || $cmd eq 'verify' || $cmd eq 'dup') {
-      push @jobs, $pool->Job($solv::Job::SOLVER_SOLVABLE_ALL, 0);
-    } else {
-      die("no package matched.\n");
-    }
-  }
+  die("no package matched.\n") unless @jobs;
   for my $job (@jobs) {
     if ($cmd eq 'up') {
       if ($job->{'how'} == $solv::Job::SOLVER_SOLVABLE_ALL || grep {$_->isinstalled()} $job->solvables()) {
index af86961..40e8c7f 100755 (executable)
@@ -38,7 +38,7 @@ import time
 import subprocess
 import rpm
 from stat import *
-from solv import Pool, Repo, Dataiterator, Job, Solver, Transaction
+from solv import Pool, Repo, Dataiterator, Job, Solver, Transaction, Selection
 from iniparse import INIConfig
 from optparse import OptionParser
 
@@ -287,7 +287,7 @@ class repo_generic(dict):
     def updateaddedprovides(self, addedprovides):
         if 'incomplete' in self:
             return 
-        if 'handle' not in self:
+        if not hasattr(self, 'handle'):
             return 
         if self.handle.isempty():
             return
@@ -562,141 +562,6 @@ class repo_cmdline(repo_generic):
         self.handle.appdata = self 
         return True
 
-def validarch(pool, arch):
-    if not arch:
-        return False
-    id = pool.str2id(arch, False)
-    if not id:
-        return False
-    return pool.isknownarch(id)
-
-def limitjobs(pool, jobs, flags, evrstr):
-    njobs = []
-    evr = pool.str2id(evrstr)
-    for j in jobs:
-        how = j.how
-        sel = how & Job.SOLVER_SELECTMASK
-        what = pool.rel2id(j.what, evr, flags)
-        if flags == solv.REL_ARCH:
-            how |= Job.SOLVER_SETARCH
-        elif flags == solv.REL_EQ and sel == Job.SOLVER_SOLVABLE_NAME:
-            if evrstr.find('-') >= 0:
-                how |= Job.SOLVER_SETEVR
-            else:
-                how |= Job.SOLVER_SETEV
-        njobs.append(pool.Job(how, what))
-    return njobs
-
-def limitjobs_evrarch(pool, jobs, flags, evrstr):
-    m = re.match(r'(.+)\.(.+?)$', evrstr)
-    if m and validarch(pool, m.group(2)):
-        jobs = limitjobs(pool, jobs, solv.REL_ARCH, m.group(2))
-        evrstr = m.group(1)
-    return limitjobs(pool, jobs, flags, evrstr)
-
-def mkjobs_filelist(pool, cmd, arg):
-    if re.search(r'[[*?]', arg):
-        type = Dataiterator.SEARCH_GLOB
-    else:
-        type = Dataiterator.SEARCH_STRING
-    if cmd == 'erase':
-        di = pool.installed.Dataiterator(0, solv.SOLVABLE_FILELIST, arg, type | Dataiterator.SEARCH_FILES|Dataiterator.SEARCH_COMPLETE_FILELIST)
-    else:
-        di = pool.Dataiterator(0, solv.SOLVABLE_FILELIST, arg, type | Dataiterator.SEARCH_FILES|Dataiterator.SEARCH_COMPLETE_FILELIST)
-    matches = []
-    for d in di:
-        s = d.solvable
-        if s and s.installable():
-            matches.append(s.id)
-            di.skip_solvable()  # one match is enough
-    if matches:
-        print "[using file list match for '%s']" % arg
-        if len(matches) > 1:
-            return [ pool.Job(Job.SOLVER_SOLVABLE_ONE_OF, pool.towhatprovides(matches)) ]
-        else:
-            return [ pool.Job(Job.SOLVER_SOLVABLE | Job.SOLVER_NOAUTOSET, matches[0]) ]
-    return []
-
-def mkjobs_rel(pool, cmd, name, rel, evr):
-    flags = 0
-    if rel.find('<') >= 0: flags |= solv.REL_LT
-    if rel.find('=') >= 0: flags |= solv.REL_EQ 
-    if rel.find('>') >= 0: flags |= solv.REL_GT
-    jobs = depglob(pool, name, True, True)
-    if jobs:
-        return limitjobs(pool, jobs, flags, evr)
-    m = re.match(r'(.+)\.(.+?)$', name)
-    if m and validarch(pool, m.group(2)):
-        jobs = depglob(pool, m.group(1), True, True)
-        if jobs:
-            jobs = limitjobs(pool, jobs, solv.REL_ARCH, m.group(2))
-            return limitjobs(pool, jobs, flags, evr)
-    return []
-
-def mkjobs_nevra(pool, cmd, arg):
-    jobs = depglob(pool, arg, True, True)
-    if jobs:
-        return jobs
-    m = re.match(r'(.+)\.(.+?)$', arg)
-    if m and validarch(pool, m.group(2)):
-        jobs = depglob(pool, m.group(1), True, True)
-        if jobs:
-            return limitjobs(pool, jobs, solv.REL_ARCH, m.group(2))
-    m = re.match(r'(.+)-(.+?)$', arg)
-    if m:
-        jobs = depglob(pool, m.group(1), True, False)
-        if jobs:
-            return limitjobs_evrarch(pool, jobs, solv.REL_EQ, m.group(2))
-    m = re.match(r'(.+)-(.+?-.+?)$', arg)
-    if m:
-        jobs = depglob(pool, m.group(1), True, False)
-        if jobs:
-            return limitjobs_evrarch(pool, jobs, solv.REL_EQ, m.group(2))
-    return []
-
-def mkjobs(pool, cmd, arg):
-    if len(arg) and arg[0] == '/':
-        jobs = mkjobs_filelist(pool, cmd, arg)
-        if jobs:
-            return jobs
-    m = re.match(r'(.+?)\s*([<=>]+)\s*(.+?)$', arg)
-    if m:
-        return mkjobs_rel(pool, cmd, m.group(1), m.group(2), m.group(3))
-    else:
-        return mkjobs_nevra(pool, cmd, arg)
-            
-def depglob(pool, name, globname, globdep):
-    id = pool.str2id(name, False)
-    if id:
-        match = False
-        for s in pool.whatprovides(id):
-            if globname and s.nameid == id:
-                return [ pool.Job(Job.SOLVER_SOLVABLE_NAME, id) ]
-            match = True
-        if match:
-            if globname and globdep:
-                print "[using capability match for '%s']" % name
-            return [ pool.Job(Job.SOLVER_SOLVABLE_PROVIDES, id) ]
-    if not re.search(r'[[*?]', name):
-        return []
-    if globname:
-        # try name glob
-        idmatches = {}
-        for d in pool.Dataiterator(0, solv.SOLVABLE_NAME, name, Dataiterator.SEARCH_GLOB):
-            s = d.solvable
-            if s.installable():
-                idmatches[s.nameid] = True
-        if idmatches:
-            return [ pool.Job(Job.SOLVER_SOLVABLE_NAME, id) for id in sorted(idmatches.keys()) ]
-    if globdep:
-        # try dependency glob
-        idmatches = pool.matchprovidingids(name, Dataiterator.SEARCH_GLOB)
-        if idmatches:
-            print "[using capability match for '%s']" % name
-            return [ pool.Job(Job.SOLVER_SOLVABLE_PROVIDES, id) for id in sorted(idmatches) ]
-    return []
-    
-
 def load_stub(repodata):
     repo = repodata.repo.appdata
     if repo:
@@ -705,6 +570,7 @@ def load_stub(repodata):
 
 
 parser = OptionParser(usage="usage: solv.py [options] COMMAND")
+parser.add_option('-r', '--repo', action="append", type="string", dest="repos")
 (options, args) = parser.parse_args()
 if not args:
     parser.print_help(sys.stderr)
@@ -726,6 +592,12 @@ if cmd == 'se':
 
 # read all repo configs
 repos = []
+reposdirs = []
+if os.path.isdir("/etc/zypp/repos.d"):
+  reposdirs = [ "/etc/zypp/repos.d" ]
+else:
+  reposdirs = [ "/etc/yum/repos.d" ]
+
 for reposdir in ["/etc/zypp/repos.d"]:
     if not os.path.isdir(reposdir):
         continue
@@ -758,6 +630,19 @@ for repo in repos:
     if int(repo['enabled']):
         repo.load(pool)
     
+repolimiter = None
+if options.repos:
+    for reponame in options.repos:
+       mrepos = [ repo for repo in repos if repo.name == reponame ]
+       if not mrepos:
+           print "no repository matches '%s'" % reponame
+           sys.exit(1)
+       repo = mrepos[0]
+       if hasattr(repo, 'handle'):
+           if not repolimiter:
+               repolimiter = pool.Selection()
+           repolimiter.addsimple(Job.SOLVER_SOLVABLE_REPO, repo.handle.id)
+
 if cmd == 'search':
     matches = {}
     di = pool.Dataiterator(0, solv.SOLVABLE_NAME, args[0], Dataiterator.SEARCH_SUBSTRING|Dataiterator.SEARCH_NOCASE)
@@ -793,11 +678,35 @@ for arg in args:
     if cmdlinerepo and arg in cmdlinerepo['packages']:
         jobs.append(pool.Job(Job.SOLVER_SOLVABLE, cmdlinerepo['packages'][arg]))
     else:
-        njobs = mkjobs(pool, cmd, arg)
-        if not njobs:
-            print "nothing matches '%s'" % arg
+       flags = Selection.SELECTION_NAME|Selection.SELECTION_PROVIDES|Selection.SELECTION_GLOB
+       if len(arg) and arg[0] == '/':
+           flags |= Selection.SELECTION_FILELIST
+           if cmd == 'erase':
+               flags |= Selection.SELECTION_INSTALLED_ONLY
+       sel = pool.select(arg, flags)
+       if repolimiter:
+          sel.limit(repolimiter)
+        if sel.isempty():
+           sel = pool.select(arg, flags | Selection.SELECTION_NOCASE)
+           if repolimiter:
+              sel.limit(repolimiter)
+           if not sel.isempty():
+               print "[ignoring case for '%s']" % arg
+        if sel.isempty():
+           print "nothing matches '%s'" % arg
             sys.exit(1)
-        jobs += njobs
+       if sel.flags() & Selection.SELECTION_FILELIST:
+           print "[using file list match for '%s']" % arg
+       if sel.flags() & Selection.SELECTION_PROVIDES:
+           print "[using capability match for '%s']" % arg
+       jobs += sel.jobs(0)
+
+if not jobs and (cmd == 'up' or cmd == 'dup' or cmd == 'verify' or repolimiter):
+    sel = pool.Selection()
+    sel.addsimple(Job.SOLVER_SOLVABLE_ALL, 0)
+    if repolimiter:
+       sel.limit(repolimiter)
+    jobs += sel.jobs(0)
 
 if cmd == 'list' or cmd == 'info':
     if not jobs:
@@ -824,11 +733,8 @@ if cmd == 'list' or cmd == 'info':
 
 if cmd == 'install' or cmd == 'erase' or cmd == 'up' or cmd == 'dup' or cmd == 'verify':
     if not jobs:
-        if cmd == 'up' or cmd == 'verify' or cmd == 'dup':
-            jobs = [ pool.Job(Job.SOLVER_SOLVABLE_ALL, 0) ]
-        else:
-            print "no package matched."
-            sys.exit(1)
+       print "no package matched."
+       sys.exit(1)
     for job in jobs:
         if cmd == 'up':
             # up magic: use install instead of update if no installed package matches
index 4ff477f..56b3370 100755 (executable)
@@ -21,6 +21,10 @@ class Repo_generic
     return @attribs['autorefresh'].to_i != 0
   end
 
+  def id
+    return @handle ? @handle.id : 0
+  end
+
   def calc_cookie_fp(f)
     chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
     chksum.add_fp(f)
@@ -493,146 +497,6 @@ class Repo_system < Repo_generic
   end
 end
 
-
-def validarch?(pool, arch)
-  return false unless arch && arch != ''
-  id = pool.str2id(arch, false)
-  return id != 0 && pool.isknownarch?(id)
-end
-
-def depglob(pool, name, globname, globdep)
-  id = pool.str2id(name, false)
-  if id != 0
-    match = false
-    providers = pool.whatprovides(id)
-    if globname && providers.find {|s| s.nameid == id }
-      return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_NAME, id) ]
-    end
-    if !providers.empty?
-      puts "[using capability match for '#{name}']" if globname && globdep
-      return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_PROVIDES, id) ]
-    end
-  end
-  return [] unless name =~ /[\[*?]/
-  if globname
-    idmatches = {}
-    for d in pool.Dataiterator(0, Solv::SOLVABLE_NAME, name, Solv::Dataiterator::SEARCH_GLOB)
-      s = d.solvable
-      idmatches[s.nameid] = 1 if s.installable?
-    end
-    if !idmatches.empty?
-      return idmatches.keys.sort.collect { |id| pool.Job(Solv::Job::SOLVER_SOLVABLE_NAME, id) }
-    end
-  end
-  if globdep
-    idmatches = pool.matchprovidingids(name, Solv::Dataiterator::SEARCH_GLOB)
-    if !idmatches.empty?
-      puts "[using capability match for '#{name}']"
-      return idmatches.sort.collect { |id| pool.Job(Solv::Job::SOLVER_SOLVABLE_PROVIDES, id) }
-    end
-  end
-  return []
-end
-
-def limitjobs(pool, jobs, flags, evrstr)
-  njobs = []
-  evr = pool.str2id(evrstr)
-  for j in jobs
-    how = j.how
-    sel = how & Solv::Job::SOLVER_SELECTMASK
-    what = pool.rel2id(j.what, evr, flags)
-    if flags == Solv::REL_ARCH
-      how |= Solv::Job::SOLVER_SETARCH
-    elsif flags == Solv::REL_EQ && sel == Solv::Job::SOLVER_SOLVABLE_NAME
-      how |= evrstr.include?(?-) ? Solv::Job::SOLVER_SETEVR : Solv::Job::SOLVER_SETEV
-    end
-    njobs << pool.Job(how, what)
-  end
-  return njobs
-end
-
-def limitjobs_evrarch(pool, jobs, flags, evrstr)
-  if evrstr =~ /^(.+)\.(.+?)$/ && validarch?(pool, $2)
-    evrstr = $1
-    jobs = limitjobs(pool, jobs, Solv::REL_ARCH, $2)
-  end
-  return limitjobs(pool, jobs, flags, evrstr)
-end
-
-def mkjobs_rel(pool, cmd, name, rel, evr)
-  flags = 0
-  flags |= Solv::REL_LT if rel.include?(?<)
-  flags |= Solv::REL_EQ if rel.include?(?=)
-  flags |= Solv::REL_GT if rel.include?(?>)
-  jobs = depglob(pool, name, true, true)
-  return limitjobs(pool, jobs, flags, evr) unless jobs.empty?
-  if (name =~ /^(.+)\.(.+?)$/) && validarch?(pool, $2)
-    arch = $2
-    jobs = depglob(pool, name, true, true)
-    return [] if jobs.empty?
-    jobs = limitjobs(pool, jobs, Solv::REL_ARCH, arch)
-    return limitjobs(pool, jobs, flags, evr)
-  end
-  return []
-end
-
-def mkjobs_nevra(pool, cmd, arg)
-  jobs = depglob(pool, arg, true, true)
-  return jobs unless jobs.empty?
-  if ((arg =~ /^(.+)\.(.+?)$/) && validarch?(pool, $2))
-    arch = $2
-    jobs = depglob(pool, $1, true, true)
-    return limitjobs(pool, jobs, Solv::REL_ARCH, arch) unless jobs.empty?
-  end
-  if (arg =~ /^(.+)-(.+?)$/)
-    evr = $2
-    jobs = depglob(pool, $1, true, false)
-    return limitjobs_evrarch(pool, jobs, Solv::REL_EQ, evr) unless jobs.empty?
-  end
-  if (arg =~ /^(.+)-(.+?-.+?)$/)
-    evr = $2
-    jobs = depglob(pool, $1, true, false)
-    return limitjobs_evrarch(pool, jobs, Solv::REL_EQ, evr) unless jobs.empty?
-  end
-  return []
-end
-
-def mkjobs_filelist(pool, cmd, arg)
-  type = Solv::Dataiterator::SEARCH_STRING
-  type = Solv::Dataiterator::SEARCH_GLOB if arg =~ /[\[*?]/
-  if cmd == 'erase'
-    di = pool.installed.Dataiterator(0, Solv::SOLVABLE_FILELIST, arg, type | Solv::Dataiterator::SEARCH_FILES|Solv::Dataiterator::SEARCH_COMPLETE_FILELIST)
-  else
-    di = pool.Dataiterator(0, Solv::SOLVABLE_FILELIST, arg, type | Solv::Dataiterator::SEARCH_FILES|Solv::Dataiterator::SEARCH_COMPLETE_FILELIST)
-  end
-  matches = []
-  for d in di
-    s = d.solvable
-    next unless s && s.installable?
-    matches.push(s.id)
-    di.skip_solvable()
-  end
-  return [] if matches.empty?
-  puts "[using file list match for '#{arg}']"
-  if matches.length > 1
-    return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_ONE_OF, pool.towhatprovides(matches)) ]
-  else
-    return [ pool.Job(Solv::Job::SOLVER_SOLVABLE | Solv::Job::SOLVER_NOAUTOSET, matches[0]) ]
-  end
-end
-
-def mkjobs(pool, cmd, arg)
-  if arg =~ /^\//
-    jobs = mkjobs_filelist(pool, cmd, arg)
-    return jobs unless jobs.empty?
-  end
-  if (arg =~ /^(.+?)\s*([<=>]+)\s*(.+?)$/)
-    return mkjobs_rel(pool, cmd, $1, $2, $3)
-  else
-    return mkjobs_nevra(pool, cmd, arg)
-  end
-end
-
 args = ARGV
 cmd = args.shift
 cmd = 'list' if cmd == 'li'
@@ -642,7 +506,13 @@ cmd = 'verify' if cmd == 've'
 cmd = 'search' if cmd == 'se'
 
 repos = []
-for reposdir in [ '/etc/zypp/repos.d' ] do
+reposdirs = []
+if FileTest.directory?('/etc/zypp/repos.d')
+  reposdirs = [ '/etc/zypp/repos.d' ]
+else
+  reposdirs = [ '/etc/yum/repos.d' ]
+end
+for reposdir in reposdirs do
   next unless FileTest.directory?(reposdir)
   for reponame in Dir["#{reposdir}/*.repo"].sort do
     cfg = IniFile.new(reponame)
@@ -700,9 +570,25 @@ pool.createwhatprovides()
 
 jobs = []
 for arg in args
-  njobs = mkjobs(pool, cmd, ARGV[0])
-  abort("nothing matches '#{arg}'") if njobs.empty?
-  jobs += njobs
+  flags = Solv::Selection::SELECTION_NAME | Solv::Selection::SELECTION_PROVIDES|Solv::Selection::SELECTION_GLOB
+  if arg =~ /^\//
+    flags |= Solv::Selection::SELECTION_FILELIST
+    flags |= Solv::Selection::SELECTION_INSTALLED_ONLY if cmd == 'erase'
+  end
+  sel = pool.select(arg, flags)
+  if sel.isempty?
+    sel = pool.select(arg, flags |  Solv::Selection::SELECTION_NOCASE)
+    puts "[ignoring case for '#{arg}']" unless sel.isempty?
+  end
+  puts "[using file list match for '#{arg}']" if sel.flags & Solv::Selection::SELECTION_FILELIST != 0
+  puts "[using capability match for '#{arg}']" if sel.flags & Solv::Selection::SELECTION_PROVIDES != 0
+  jobs += sel.jobs(0)
+end
+
+if jobs.empty? && (cmd == 'up' || cmd == 'dup' || cmd == 'verify')
+  sel = pool.Selection()
+  sel.addsimple(Solv::Job::SOLVER_SOLVABLE_ALL, 0)
+  jobs += sel.jobs(0)
 end
 
 if cmd == 'list' || cmd == 'info'
@@ -729,13 +615,7 @@ if cmd == 'list' || cmd == 'info'
 end
 
 if cmd == 'install' || cmd == 'erase' || cmd == 'up' || cmd == 'dup' || cmd == 'verify'
-  if jobs.empty?
-    if cmd == 'up' || cmd == 'verify' || cmd == 'dup'
-      jobs = [ pool.Job(Solv::Job::SOLVER_SOLVABLE_ALL, 0) ]
-    else
-      abort("no package matched.")
-    end
-  end
+  abort("no package matched.") if jobs.empty?
   for job in jobs
     if cmd == 'up'
       if job.how == Solv::Job::SOLVER_SOLVABLE_ALL || job.solvables.any? {|s| s.isinstalled?}
index 5723f54..42791ac 100644 (file)
@@ -57,6 +57,7 @@
 #include "solverdebug.h"
 #include "chksum.h"
 #include "repo_solv.h"
+#include "selection.h"
 
 #include "repo_write.h"
 #ifdef ENABLE_RPMDB
@@ -2028,341 +2029,6 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
     pool_free(sigpool);
 }
 
-
-int
-str2archid(Pool *pool, char *arch)
-{
-  Id id;
-  if (!*arch)
-    return 0;
-  id = pool_str2id(pool, arch, 0);
-  if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
-    return id;
-  if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
-    return 0;
-  return id;
-}
-
-
-#define DEPGLOB_NAME     1
-#define DEPGLOB_DEP      2
-#define DEPGLOB_NAMEDEP  3
-
-int
-depglob(Pool *pool, char *name, Queue *job, int what)
-{
-  Id p, pp;
-  Id id = pool_str2id(pool, name, 0);
-  int i, match = 0;
-
-  if (id)
-    {
-      FOR_PROVIDES(p, pp, id)
-       {
-         Solvable *s = pool->solvables + p;
-         match = 1;
-         if (s->name == id && (what & DEPGLOB_NAME) != 0)
-           {
-             queue_push2(job, SOLVER_SOLVABLE_NAME, id);
-             return 1;
-           }
-       }
-      if (match)
-       {
-         if (what == DEPGLOB_NAMEDEP)
-           printf("[using capability match for '%s']\n", name);
-         queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id);
-         return 1;
-       }
-    }
-
-  if (strpbrk(name, "[*?") == 0)
-    return 0;
-
-  if ((what & DEPGLOB_NAME) != 0)
-    {
-      /* looks like a name glob. hard work. */
-      for (p = 1; p < pool->nsolvables; p++)
-       {
-         Solvable *s = pool->solvables + p;
-         if (!s->repo || !pool_installable(pool, s))
-           continue;
-         id = s->name;
-         if (fnmatch(name, pool_id2str(pool, id), 0) == 0)
-           {
-             for (i = 0; i < job->count; i += 2)
-               if (job->elements[i] == SOLVER_SOLVABLE_NAME && job->elements[i + 1] == id)
-                 break;
-             if (i == job->count)
-               queue_push2(job, SOLVER_SOLVABLE_NAME, id);
-             match = 1;
-           }
-       }
-      if (match)
-       return 1;
-    }
-  if ((what & DEPGLOB_DEP))
-    {
-      /* looks like a dep glob. really hard work. */
-      for (id = 1; id < pool->ss.nstrings; id++)
-       {
-         if (!pool->whatprovides[id])
-           continue;
-         if (fnmatch(name, pool_id2str(pool, id), 0) == 0)
-           {
-             if (!match && what == DEPGLOB_NAMEDEP)
-               printf("[using capability match for '%s']\n", name);
-             for (i = 0; i < job->count; i += 2)
-               if (job->elements[i] == SOLVER_SOLVABLE_PROVIDES && job->elements[i + 1] == id)
-                 break;
-             if (i == job->count)
-               queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id);
-             match = 1;
-           }
-       }
-      if (match)
-       return 1;
-    }
-  return 0;
-}
-
-int
-limitrelation(Pool *pool, Queue *job, int flags, Id evr)
-{
-  int i, j;
-  Id p, pp;
-  for (i = j = 0; i < job->count; i += 2)
-    {
-      Id select = job->elements[i] & SOLVER_SELECTMASK;
-      if (select != SOLVER_SOLVABLE_NAME && select != SOLVER_SOLVABLE_PROVIDES)
-       {
-         fprintf(stderr, "limitrelation only works on name/provides jobs\n");
-         exit(1);
-       }
-      job->elements[i + 1] = pool_rel2id(pool, job->elements[i + 1], evr, flags, 1);
-      if (flags == REL_ARCH)
-       job->elements[i] |= SOLVER_SETARCH;
-      if (flags == REL_EQ && select == SOLVER_SOLVABLE_NAME && job->elements[i])
-       {
-#ifndef DEBIAN
-         const char *evrstr = pool_id2str(pool, evr);
-         if (!strchr(evrstr, '-'))
-           job->elements[i] |= SOLVER_SETEV;
-         else
-#endif
-           job->elements[i] |= SOLVER_SETEVR;
-       }
-      /* make sure we still have matches */
-      FOR_JOB_SELECT(p, pp, job->elements[i], job->elements[i + 1])
-       break;
-      if (p)
-       {
-         job->elements[j] = job->elements[i];
-         job->elements[j + 1] = job->elements[i + 1];
-         j += 2;
-       }
-    }
-  queue_truncate(job, j);
-  return j / 2;
-}
-
-int
-limitrelation_arch(Pool *pool, Queue *job, int flags, char *evr)
-{
-  char *r;
-  Id archid;
-  if ((r = strrchr(evr, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
-    {
-      *r = 0;
-      limitrelation(pool, job, REL_ARCH, archid);
-      limitrelation(pool, job, flags, pool_str2id(pool, evr, 1));
-      *r = '.';
-    }
-  else
-    limitrelation(pool, job, flags, pool_str2id(pool, evr, 1));
-  return job->count / 2;
-}
-
-int
-limitrepo(Pool *pool, Id repofilter, Queue *job)
-{
-  Queue mq;
-  Id p, pp;
-  int i, j;
-  Solvable *s;
-
-  queue_init(&mq);
-  for (i = j = 0; i < job->count; i += 2)
-    {
-      queue_empty(&mq);
-      FOR_JOB_SELECT(p, pp, job->elements[i], job->elements[i + 1])
-       {
-         s = pool_id2solvable(pool, p);
-         if (s->repo && s->repo->repoid == repofilter)
-            queue_push(&mq, p);
-       }
-      if (mq.count)
-       {
-         /* here we assume that repo == vendor, so we also set SOLVER_SETVENDOR */
-         Id flags = (job->elements[i] & SOLVER_SETMASK) | SOLVER_SETVENDOR | SOLVER_SETREPO;
-         if ((job->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_NAME)
-           flags |= SOLVER_SETNAME;
-         if (mq.count == 1)
-           {
-             job->elements[j] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET | flags;
-             job->elements[j + 1] = mq.elements[0];
-           }
-         else
-           {
-             job->elements[j] = SOLVER_SOLVABLE_ONE_OF | flags;
-             job->elements[j + 1] = pool_queuetowhatprovides(pool, &mq);
-           }
-         j += 2;
-       }
-    }
-  queue_truncate(job, j);
-  queue_free(&mq);
-  return j / 2;
-}
-
-int
-mkselect(Pool *pool, int mode, char *name, Queue *job)
-{
-  char *r, *r2;
-  Id archid;
-
-  if (*name == '/')
-    {
-      Dataiterator di;
-      int type = strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
-      Queue q;
-      queue_init(&q);
-      dataiterator_init(&di, pool, mode == SOLVER_ERASE ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
-      while (dataiterator_step(&di))
-       {
-         Solvable *s = pool->solvables + di.solvid;
-         if (!s->repo || !pool_installable(pool, s))
-           continue;
-         queue_push(&q, di.solvid);
-         dataiterator_skip_solvable(&di);
-       }
-      dataiterator_free(&di);
-      if (q.count)
-       {
-         printf("[using file list match for '%s']\n", name);
-         if (q.count > 1)
-           queue_push2(job, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
-         else
-           queue_push2(job, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
-         queue_free(&q);
-         return job->count / 2;
-       }
-    }
-  if ((r = strpbrk(name, "<=>")) != 0)
-    {
-      /* relation case, support:
-       * depglob rel
-       * depglob.arch rel
-       */
-      int rflags = 0;
-      int nend = r - name;
-      char oldnend;
-      for (; *r; r++)
-       {
-         if (*r == '<')
-           rflags |= REL_LT;
-         else if (*r == '=')
-           rflags |= REL_EQ;
-         else if (*r == '>')
-           rflags |= REL_GT;
-         else
-           break;
-       }
-      while (*r && *r == ' ' && *r == '\t')
-       r++;
-      while (nend && (name[nend - 1] == ' ' || name[nend -1 ] == '\t'))
-       nend--;
-      if (!*name || !*r)
-       {
-         fprintf(stderr, "bad relation\n");
-         exit(1);
-       }
-      oldnend = name[nend];
-      name[nend] = 0;
-      if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
-       {
-         name[nend] = oldnend;
-         limitrelation(pool, job, rflags, pool_str2id(pool, r, 1));
-         return job->count / 2;
-       }
-      if ((r2 = strrchr(name, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
-       {
-         *r2 = 0;
-         if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
-           {
-             name[nend] = oldnend;
-             *r2 = '.';
-             limitrelation(pool, job, REL_ARCH, archid);
-             limitrelation(pool, job, rflags, pool_str2id(pool, r, 1));
-             return job->count / 2;
-           }
-         *r2 = '.';
-       }
-      name[nend] = oldnend;
-    }
-  else
-    {
-      /* no relation case, support:
-       * depglob
-       * depglob.arch
-       * nameglob-version
-       * nameglob-version.arch
-       * nameglob-version-release
-       * nameglob-version-release.arch
-       */
-      if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
-       return job->count / 2;
-      if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
-       {
-         *r = 0;
-         if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
-           {
-             *r = '.';
-             limitrelation(pool, job, REL_ARCH, archid);
-             return job->count / 2;
-           }
-         *r = '.';
-       }
-      if ((r = strrchr(name, '-')) != 0)
-       {
-         *r = 0;
-         if (depglob(pool, name, job, DEPGLOB_NAME))
-           {
-             /* have just the version */
-             limitrelation_arch(pool, job, REL_EQ, r + 1);
-             *r = '-';
-             return job->count / 2;
-           }
-         if ((r2 = strrchr(name, '-')) != 0)
-           {
-             *r = '-';
-             *r2 = 0;
-             r = r2;
-             if (depglob(pool, name, job, DEPGLOB_NAME))
-               {
-                 /* have version-release */
-                 limitrelation_arch(pool, job, REL_EQ, r + 1);
-                 *r = '-';
-                 return job->count / 2;
-               }
-           }
-         *r = '-';
-       }
-    }
-  return 0;
-}
-
-
 int
 yesno(const char *str)
 {
@@ -2754,11 +2420,10 @@ main(int argc, char **argv)
   Solver *solv = 0;
   Transaction *trans;
   char inbuf[128], *ip;
-  int allpkgs = 0;
   FILE **newpkgsfps;
   Queue addedfileprovides;
   Queue addedfileprovides_inst;
-  Id repofilter = 0;
+  Queue repofilter;
   int cleandeps = 0;
   char *rootdir = 0;
 
@@ -2869,9 +2534,11 @@ main(int argc, char **argv)
 
   read_repos(pool, repoinfos, nrepoinfos);
 
-  if (argc > 2 && !strcmp(argv[1], "-r"))
+  queue_init(&repofilter);
+  while (argc > 2 && !strcmp(argv[1], "-r"))
     {
       const char *rname = argv[2], *rp;
+      Id repoid = 0;
       for (rp = rname; *rp; rp++)
        if (*rp <= '0' || *rp >= '9')
          break;
@@ -2885,7 +2552,7 @@ main(int argc, char **argv)
              if (!cinfo->enabled)
                continue;
              if (--rnum == 0)
-               repofilter = cinfo->repo->repoid;
+               repoid = cinfo->repo->repoid;
            }
        }
       else
@@ -2895,14 +2562,15 @@ main(int argc, char **argv)
          FOR_REPOS(i, repo)
            {
              if (!strcasecmp(rname, repo->name))
-               repofilter = repo->repoid;
+               repoid = repo->repoid;
            }
        }
-      if (!repofilter)
+      if (!repoid)
        {
          fprintf(stderr, "%s: no such repo\n", rname);
          exit(1);
        }
+      queue_push2(&repofilter, SOLVER_SOLVABLE_REPO, repoid);
       argc -= 2;
       argv += 2;
     }
@@ -2996,7 +2664,7 @@ main(int argc, char **argv)
   for (i = 1; i < argc; i++)
     {
       Queue job2;
-      int j;
+      int j, flags, rflags;
 
       if (commandlinepkgs && commandlinepkgs[i])
        {
@@ -3004,30 +2672,49 @@ main(int argc, char **argv)
          continue;
        }
       queue_init(&job2);
-      if (!mkselect(pool, mode, argv[i], &job2))
+      flags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_GLOB;
+      if (argv[i][0] == '/')
+       flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0);
+      rflags = selection_make(pool, &job2, argv[i], flags);
+      if (repofilter.count)
+       selection_limit(pool, &job2, &repofilter);
+      if (!job2.count)
+       {
+         flags |= SELECTION_NOCASE;
+          rflags = selection_make(pool, &job2, argv[i], flags);
+         if (repofilter.count)
+           selection_limit(pool, &job2, &repofilter);
+         if (job2.count)
+           printf("[ignoring case for '%s']\n", argv[i]);
+       }
+      if (!job2.count)
        {
          fprintf(stderr, "nothing matches '%s'\n", argv[i]);
          exit(1);
        }
-      if (repofilter && !limitrepo(pool, repofilter, &job2))
-        {
-         fprintf(stderr, "nothing in repo matches '%s'\n", argv[i]);
-         exit(1);
-        }
+      if (rflags & SELECTION_FILELIST)
+        printf("[using file list match for '%s']\n", argv[i]);
+      if (rflags & SELECTION_PROVIDES)
+       printf("[using capability match for '%s']\n", argv[i]);
       for (j = 0; j < job2.count; j++)
        queue_push(&job, job2.elements[j]);
       queue_free(&job2);
     }
 
-  if (!job.count && mainmode != MODE_UPDATE && mainmode != MODE_DISTUPGRADE && mainmode != MODE_VERIFY && mainmode != MODE_PATCH)
+  if (!job.count && (mainmode == MODE_UPDATE || mainmode == MODE_DISTUPGRADE || mainmode == MODE_VERIFY || repofilter.count))
+    {
+      queue_push2(&job, SOLVER_SOLVABLE_ALL, 0);
+      if (repofilter.count)
+       selection_limit(pool, &job, &repofilter);
+    }
+  queue_free(&repofilter);
+
+  if (!job.count && MODE_PATCH)
     {
       printf("no package matched\n");
       exit(1);
     }
 
-  if (!job.count)
-    allpkgs = 1;
-
   if (mainmode == MODE_LIST || mainmode == MODE_INFO)
     {
       /* list mode, no solver needed */
@@ -3100,28 +2787,6 @@ main(int argc, char **argv)
         job.elements[i] |= SOLVER_CLEANDEPS;
     }
 
-  if (mainmode == MODE_DISTUPGRADE && allpkgs)
-    {
-      if (repofilter)
-        queue_push2(&job, SOLVER_DISTUPGRADE|SOLVER_SOLVABLE_REPO, repofilter);
-      else
-        queue_push2(&job, SOLVER_DISTUPGRADE|SOLVER_SOLVABLE_ALL, 0);
-    }
-  if (mainmode == MODE_UPDATE && allpkgs)
-    {
-      if (repofilter)
-        queue_push2(&job, SOLVER_UPDATE|SOLVER_SOLVABLE_REPO, repofilter);
-      else
-        queue_push2(&job, SOLVER_UPDATE|SOLVER_SOLVABLE_ALL, 0);
-    }
-  if (mainmode == MODE_VERIFY && allpkgs)
-    {
-      if (repofilter)
-        queue_push2(&job, SOLVER_VERIFY|SOLVER_SOLVABLE_REPO, repofilter);
-      else
-        queue_push2(&job, SOLVER_VERIFY|SOLVER_SOLVABLE_ALL, 0);
-    }
-
   // multiversion test
   // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae", 1));
   // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-base", 1));
index a19c935..2dada2f 100644 (file)
@@ -18,12 +18,12 @@ SET (libsolv_SRCS
     solver.c solverdebug.c repo_solv.c repo_write.c evr.c pool.c
     queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
     transaction.c rules.c problems.c
-    chksum.c md5.c sha1.c sha2.c solvversion.c)
+    chksum.c md5.c sha1.c sha2.c solvversion.c selection.c)
 
 SET (libsolv_HEADERS
     bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
     poolid.h pooltypes.h queue.h solvable.h solver.h solverdebug.h
-    repo.h repodata.h repo_solv.h repo_write.h util.h
+    repo.h repodata.h repo_solv.h repo_write.h util.h selection.h
     strpool.h dirpool.h knownid.h transaction.h rules.h problems.h
     chksum.h dataiterator.h ${CMAKE_BINARY_DIR}/src/solvversion.h)
 
index 16fd774..d5f2d5e 100644 (file)
@@ -221,6 +221,9 @@ SOLV_1.0 {
                repodata_write;
                repodata_write_filtered;
                repopagestore_compress_page;
+               selection_add;
+               selection_limit;
+               selection_make;
                solv_bin2hex;
                solv_calloc;
                solv_chksum_add;
index 4d5d18f..b565282 100644 (file)
@@ -1994,8 +1994,13 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
        *top = solv->job.elements[jidx];
       if (depp)
        *depp = solv->job.elements[jidx + 1];
-      if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && (solv->job.elements[jidx] & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_ONE_OF)
-       return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
+      if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE)
+       {
+         if ((solv->job.elements[jidx] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_NAME)
+           return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
+         if ((solv->job.elements[jidx] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES)
+           return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
+       }
       return SOLVER_RULE_JOB;
     }
   if (rid >= solv->updaterules && rid < solv->updaterules_end)
diff --git a/src/selection.c b/src/selection.c
new file mode 100644 (file)
index 0000000..2a86910
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * selection.c
+ *
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <fnmatch.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "selection.h"
+#include "solver.h"
+
+
+static int
+str2archid(Pool *pool, const char *arch)
+{
+  Id id;
+  if (!*arch)
+    return 0;
+  id = pool_str2id(pool, arch, 0);
+  if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
+    return id;
+  if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
+    return 0;
+  return id;
+}
+
+static void
+selection_prune(Pool *pool, Queue *selection)
+{
+  int i, j;
+  Id p, pp;
+  for (i = j = 0; i < selection->count; i += 2)
+    {
+      Id select = selection->elements[i] & SOLVER_SELECTMASK;
+      p = 0;
+      if (select == SOLVER_SOLVABLE_ALL)
+       p = 1;
+      else if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Solvable *s;
+         Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
+         if (repo)
+           FOR_REPO_SOLVABLES(repo, p, s)
+             break;
+       }
+      else
+       {
+         FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
+           break;
+       }
+      if (!p)
+       continue;
+      selection->elements[j] = selection->elements[i];
+      selection->elements[j + 1] = selection->elements[i + 1];
+      j += 2;
+    }
+  queue_truncate(selection, j);
+}
+
+
+static int
+selection_flatten_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  return *(const Id *)ap - *(const Id *)bp;
+}
+
+static void
+selection_flatten(Pool *pool, Queue *selection)
+{
+  Queue q;
+  int i, j;
+  Id p, pp, lastid;
+  if (selection->count <= 1)
+    return;
+  queue_init(&q);
+  for (i = 0; i < selection->count; i += 2)
+    {
+      Id select = selection->elements[i] & SOLVER_SELECTMASK;
+      if (select == SOLVER_SOLVABLE_ALL)
+       {
+         selection->elements[0] = selection->elements[i];
+         selection->elements[1] = selection->elements[i + 1];
+         queue_truncate(selection, 2);
+         return;
+       }
+      if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Solvable *s;
+         Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
+         if (repo)
+           FOR_REPO_SOLVABLES(repo, p, s)
+             queue_push(&q, p);
+       }
+      else
+       {
+         FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
+           queue_push(&q, p);
+       }
+    }
+  if (!q.count)
+    {
+      queue_empty(selection);
+      return;
+    }
+  if (q.count > 1)
+    {
+      /* sort and unify */
+      solv_sort(q.elements, q.count, sizeof(Id), selection_flatten_sortcmp, NULL);
+      lastid = q.elements[0];
+      for (i = j = 1; i < q.count; i++)
+       if (q.elements[i] != lastid)
+         q.elements[j++] = lastid = q.elements[i];
+      queue_truncate(&q, j);
+    }
+  queue_truncate(selection, 2);
+  if (q.count > 1)
+    {
+      selection->elements[0] = SOLVER_SOLVABLE_ONE_OF;
+      selection->elements[1] = pool_queuetowhatprovides(pool, &q);
+    }
+  else
+    {
+      selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+      selection->elements[1] = q.elements[0];
+    }
+}
+
+static void
+selection_limit_rel(Pool *pool, Queue *selection, Id flags, Id evr)
+{
+  int i, j;
+  for (i = j = 0; i < selection->count; i += 2)
+    {
+      Id select = selection->elements[i] & SOLVER_SELECTMASK;
+      if (select != SOLVER_SOLVABLE_NAME && select != SOLVER_SOLVABLE_PROVIDES)
+       continue;       /* actually internal error */
+      selection->elements[i + 1] = pool_rel2id(pool, selection->elements[i + 1], evr, flags, 1);
+      if (flags == REL_ARCH)
+        selection->elements[i] |= SOLVER_SETARCH;
+      if (flags == REL_EQ && select == SOLVER_SOLVABLE_NAME && selection->elements[i])
+        {
+         if (pool->disttype == DISTTYPE_DEB)
+            selection->elements[i] |= SOLVER_SETEVR;   /* debian can't match version only like rpm */
+         else
+           selection->elements[i] |= strchr(pool_id2str(pool, evr), '-') != 0 ? SOLVER_SETEVR : SOLVER_SETEV;
+        }
+    }
+  selection_prune(pool, selection);
+}
+
+static int
+selection_depglob(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  Id id, p, pp;
+  int i, match = 0;
+  int doglob = 0;
+  int globflags = 0;
+
+  if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES)))
+    return 0;
+
+  if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
+    return 0;
+
+  if (!(flags & SELECTION_NOCASE))
+    {
+      id = pool_str2id(pool, name, 0);
+      if (id)
+       {
+         FOR_PROVIDES(p, pp, id)
+           {
+             Solvable *s = pool->solvables + p;
+             if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+               continue;
+             match = 1;
+             if (s->name == id && (flags & SELECTION_NAME) != 0)
+               {
+                 queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
+                 return SELECTION_NAME;
+               }
+           }
+         if (match && (flags & SELECTION_PROVIDES) != 0)
+           {
+             queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+             return SELECTION_PROVIDES;
+           }
+       }
+    }
+
+  if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0)
+    doglob = 1;
+
+  if (!doglob && !(flags & SELECTION_NOCASE))
+    return 0;
+
+  if (doglob && (flags & SELECTION_NOCASE) != 0)
+    globflags = FNM_CASEFOLD;
+
+#if 0  /* doesn't work with selection_limit_rel yet */
+  if (doglob && !strcmp(name, "*") && (flags & SELECTION_FLAT) != 0)
+    {
+      /* can't do this for SELECTION_PROVIDES, as src rpms don't provide anything */
+      if ((flags & SELECTION_NAME) != 0)
+       {
+         queue_push2(selection, SOLVER_SOLVABLE_ALL, 0);
+          return SELECTION_NAME;
+       }
+    }
+#endif
+
+  if ((flags & SELECTION_NAME) != 0)
+    {
+      /* looks like a name glob. hard work. */
+      for (p = 1; p < pool->nsolvables; p++)
+        {
+          Solvable *s = pool->solvables + p;
+          if (!s->repo || !pool_installable(pool, s))
+            continue;
+         if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+           continue;
+          id = s->name;
+          if ((doglob ? fnmatch(name, pool_id2str(pool, id), globflags) : strcasecmp(name, pool_id2str(pool, id))) == 0)
+            {
+              for (i = 0; i < selection->count; i += 2)
+                if (selection->elements[i] == SOLVER_SOLVABLE_NAME && selection->elements[i + 1] == id)
+                  break;
+              if (i == selection->count)
+                queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
+              match = 1;
+            }
+        }
+      if (match)
+        return SELECTION_NAME;
+    }
+  if ((flags & SELECTION_PROVIDES))
+    {
+      /* looks like a dep glob. really hard work. */
+      for (id = 1; id < pool->ss.nstrings; id++)
+        {
+          if (!pool->whatprovides[id])
+            continue;
+          if ((doglob ? fnmatch(name, pool_id2str(pool, id), globflags) : strcasecmp(name, pool_id2str(pool, id))) == 0)
+            {
+             if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+               {
+                 FOR_PROVIDES(p, pp, id)
+                   if (pool->solvables[p].repo == pool->installed)
+                     break;
+                 if (!p)
+                   continue;
+               }
+             queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+              match = 1;
+            }
+        }
+      if (match)
+        return SELECTION_PROVIDES;
+    }
+  return 0;
+}
+
+static int
+selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  int ret;
+  const char *r;
+  Id archid;
+
+  if ((ret = selection_depglob(pool, selection, name, flags)) != 0)
+    return ret;
+  /* check if theres an .arch suffix */
+  if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
+    {
+      char *rname = solv_strdup(name);
+      rname[r - name] = 0;
+      if ((ret = selection_depglob(pool, selection, rname, flags)) != 0)
+       {
+         selection_limit_rel(pool, selection, REL_ARCH, archid);
+         solv_free(rname);
+         return ret;
+       }
+      solv_free(rname);
+    }
+  return 0;
+}
+
+static int
+selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  Dataiterator di;
+  Queue q;
+  int type;
+
+  type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
+  if ((flags & SELECTION_NOCASE) != 0)
+    type |= SEARCH_NOCASE;
+  queue_init(&q);
+  dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
+  while (dataiterator_step(&di))
+    {
+      Solvable *s = pool->solvables + di.solvid;
+      if (!s->repo || !pool_installable(pool, s))
+       continue;
+      queue_push(&q, di.solvid);
+      dataiterator_skip_solvable(&di);
+    }
+  dataiterator_free(&di);
+  if (!q.count)
+    return 0;
+  if (q.count > 1) 
+    queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
+  else
+    queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
+  queue_free(&q);
+  return SELECTION_FILELIST;
+}
+
+static int
+selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  int ret, rflags = 0;
+  char *r, *rname;
+  
+  /* relation case, support:
+   * depglob rel
+   * depglob.arch rel
+   */
+  rname = solv_strdup(name);
+  if ((r = strpbrk(rname, "<=>")) != 0)
+    {
+      int nend = r - rname;
+      for (; *r; r++)
+        {
+          if (*r == '<')
+            rflags |= REL_LT;
+          else if (*r == '=')
+            rflags |= REL_EQ;
+          else if (*r == '>')
+            rflags |= REL_GT;
+          else
+            break;
+        }
+      while (*r && *r == ' ' && *r == '\t')
+        r++;
+      while (nend && (rname[nend - 1] == ' ' || rname[nend -1 ] == '\t'))
+        nend--;
+      if (!*rname || !*r)
+        {
+         solv_free(rname);
+         return 0;
+        }
+      rname[nend] = 0;
+    }
+  if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0)
+    {
+      if (rflags)
+       selection_limit_rel(pool, selection, rflags, pool_str2id(pool, r, 1));
+      solv_free(rname);
+      return ret;
+    }
+  solv_free(rname);
+  return 0;
+}
+
+static int
+selection_nevra(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  char *rname, *r, *r2;
+  Id archid = 0;
+  int ret;
+
+  /*
+   * nameglob-version
+   * nameglob-version.arch
+   * nameglob-version-release
+   * nameglob-version-release.arch
+   */
+  flags |= SELECTION_NAME;
+  flags &= ~SELECTION_PROVIDES;
+
+  if (pool->disttype == DISTTYPE_DEB)
+    {
+      if ((r = strchr(name, '_')) == 0)
+       return 0;
+      rname = solv_strdup(name);       /* so we can modify it */
+      r = rname + (r - name);
+      *r++ = 0;
+      if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+       {
+         solv_free(rname);
+         return 0;
+       }
+      /* is there a vaild arch? */
+      if ((r2 = strchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
+       {
+         *r2 = 0;      /* split off */
+          selection_limit_rel(pool, selection, REL_ARCH, archid);
+       }
+      selection_limit_rel(pool, selection, flags, pool_str2id(pool, r, 1));
+      solv_free(rname);
+      return ret;
+    }
+
+  if ((r = strrchr(name, '-')) == 0)
+    return 0;
+  rname = solv_strdup(name);   /* so we can modify it */
+  r = rname + (r - name);
+  *r = 0; 
+  /* try with just the version */
+  if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+    {
+      /* no luck, try with version-release */
+      if ((r2 = strrchr(rname, '-')) == 0)
+       {
+         solv_free(rname);
+         return 0;
+       }
+      *r = '-'; 
+      *r2 = 0; 
+      r = r2;
+      if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+       {
+         solv_free(rname);
+         return 0;
+       }
+    }
+  /* we now know the name, check if we need to split of the arch */
+  r++;
+  if ((r2 = strrchr(r, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
+    {
+      /* found valid arch, split it off */
+      *r2 = 0;
+      selection_limit_rel(pool, selection, REL_ARCH, archid);
+    }
+  selection_limit_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
+  solv_free(rname);
+  return ret;
+}
+
+int
+selection_make(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  int ret = 0;
+  const char *r;
+
+  queue_empty(selection);
+  if (*name == '/' && (flags & SELECTION_FILELIST))
+    ret = selection_filelist(pool, selection, name, flags);
+  if (!ret && (r = strpbrk(name, "<=>")) != 0)
+    ret = selection_rel(pool, selection, name, flags);
+  if (!ret)
+    ret = selection_depglob_arch(pool, selection, name, flags);
+  if (!ret && (flags & SELECTION_NAME) != 0)
+    ret = selection_nevra(pool, selection, name, flags);
+  if (ret && (flags & SELECTION_FLAT) != 0)
+    selection_flatten(pool, selection);
+  return ret;
+}
+
+void
+selection_limit(Pool *pool, Queue *sel1, Queue *sel2)
+{
+  int i, j, miss;
+  Id p, pp;
+  Queue q1;
+  Map m2;
+  Id setflags = 0;
+
+  if (!sel1->count || !sel2->count)
+    {
+      queue_empty(sel1);
+      return;
+    }
+  if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
+    {
+      /* XXX: not 100% correct, but very useful */
+      queue_free(sel1);
+      queue_init_clone(sel1, sel2);
+      return;
+    }
+  queue_init(&q1);
+  map_init(&m2, pool->nsolvables);
+  for (i = 0; i < sel2->count; i += 2)
+    {
+      Id select = sel2->elements[i] & SOLVER_SELECTMASK;
+      if (select == SOLVER_SOLVABLE_ALL)
+       return;
+      if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Solvable *s;
+         Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
+         if (repo)
+           FOR_REPO_SOLVABLES(repo, p, s)
+             map_set(&m2, p);
+       }
+      else
+       {
+         FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1])
+           map_set(&m2, p);
+       }
+    }
+  if (sel2->count == 2)                /* XXX: AND all setmasks instead? */
+    setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
+  for (i = j = 0; i < sel1->count; i += 2)
+    {
+      Id select = sel1->elements[i] & SOLVER_SELECTMASK;
+      queue_empty(&q1);
+      miss = 0;
+      if (select == SOLVER_SOLVABLE_ALL)
+       {
+         for (p = 2; p < pool->nsolvables; p++)
+           if (map_tst(&m2, p))
+             queue_push(&q1, p);
+           else
+             miss = 1;
+       }
+      else if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Solvable *s;
+         Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
+         if (repo)
+           FOR_REPO_SOLVABLES(repo, p, s)
+             {
+               if (map_tst(&m2, p))
+                 queue_push(&q1, p);
+               else
+                 miss = 1;
+             }
+       }
+      else
+       {
+         FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1])
+           {
+             if (map_tst(&m2, p))
+               queue_pushunique(&q1, p);
+             else
+               miss = 1;
+           }
+       }
+      if (!q1.count)
+       continue;
+      if (!miss)
+       {
+         sel1->elements[j] = sel1->elements[i] | setflags;
+         sel1->elements[j + 1] = sel1->elements[i + 1];
+       }
+      else if (q1.count > 1) 
+       {
+         sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
+         sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1);
+       }
+      else
+       {
+         sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
+         sel1->elements[j + 1] = q1.elements[0];
+       }
+      j += 2;
+    }
+  queue_truncate(sel1, j);
+}
+
+void
+selection_add(Pool *pool, Queue *sel1, Queue *sel2)
+{
+  int i;
+  for (i = 0; i < sel2->count; i++)
+    queue_push(sel1, sel2->elements[i]);
+}
+
diff --git a/src/selection.h b/src/selection.h
new file mode 100644 (file)
index 0000000..62eb37d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * selection.h
+ * 
+ */
+
+#ifndef LIBSOLV_SELECTION_H
+#define LIBSOLV_SELECTION_H
+
+#include "pool.h"
+
+#define SELECTION_NAME                 (1 << 0)
+#define SELECTION_PROVIDES             (1 << 1)
+#define SELECTION_FILELIST             (1 << 2)
+
+#define SELECTION_INSTALLED_ONLY       (1 << 8)
+#define SELECTION_GLOB                 (1 << 9)
+#define SELECTION_FLAT                 (1 << 10)
+#define SELECTION_NOCASE               (1 << 11)
+
+extern int selection_make(Pool *pool, Queue *selection, const char *name, int flags);
+extern void selection_limit(Pool *pool, Queue *sel1, Queue *sel2);
+extern void selection_add(Pool *pool, Queue *sel1, Queue *sel2);
+
+#endif