#include "solverdebug.h"
#include "repo_solv.h"
#include "chksum.h"
+#include "selection.h"
#include "repo_write.h"
#ifdef ENABLE_RPMDB
Id toid;
} TransactionClass;
+typedef struct {
+ Pool *pool;
+ Queue q;
+ int flags;
+} Selection;
+
typedef Dataiterator Datamatch;
%}
typedef struct {
Pool* const pool;
+} Selection;
+
+typedef struct {
+ Pool* const pool;
Id const id;
} Dep;
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;
}
}
}
+%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);
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 {
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'};
$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))) {
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') {
}
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()) {
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
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
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:
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)
# 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
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)
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:
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
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)
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'
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)
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'
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?}
#include "solverdebug.h"
#include "chksum.h"
#include "repo_solv.h"
+#include "selection.h"
#include "repo_write.h"
#ifdef ENABLE_RPMDB
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)
{
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;
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;
if (!cinfo->enabled)
continue;
if (--rnum == 0)
- repofilter = cinfo->repo->repoid;
+ repoid = cinfo->repo->repoid;
}
}
else
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;
}
for (i = 1; i < argc; i++)
{
Queue job2;
- int j;
+ int j, flags, rflags;
if (commandlinepkgs && commandlinepkgs[i])
{
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 */
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));
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)
repodata_write;
repodata_write_filtered;
repopagestore_compress_page;
+ selection_add;
+ selection_limit;
+ selection_make;
solv_bin2hex;
solv_calloc;
solv_chksum_add;
*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)
--- /dev/null
+/*
+ * 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]);
+}
+
--- /dev/null
+/*
+ * 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