From 280187472ec0a87fca4572bc6ee46864ba57e557 Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Fri, 4 Mar 2011 18:30:58 +0100 Subject: [PATCH] - start of p5solv and perl bindings --- examples/p5solv | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ examples/pysolv | 11 +- examples/solv.i | 220 ++++++++++++++++++++++++++++----- 3 files changed, 575 insertions(+), 34 deletions(-) create mode 100755 examples/p5solv diff --git a/examples/p5solv b/examples/p5solv new file mode 100755 index 0000000..60e867b --- /dev/null +++ b/examples/p5solv @@ -0,0 +1,378 @@ +#!/usr/bin/perl + +use POSIX; +use Config::IniFiles; +use File::FnMatch; +use Data::Dumper; +use solv; +use strict; + +package Repo::generic; + +sub new { + my ($class, $attr) = @_; + my $r = { %$attr }; + return bless $r, $class; +} + +sub cachepath { + my ($self, $ext) = @_; + my $path = $self->{'alias'}; + $path =~ s/^\./_/s; + $path .= $ext ? "_$ext.solvx" : '.solv'; + $path =~ s/\//_/gs; + return "/var/cache/solv/$path"; +} + +sub load { + my ($self, $pool) = @_; + $self->{'handle'} = $pool->add_repo($self->{'alias'}); + $self->{'handle'}->{'appdata'} = $self; + $self->{'handle'}->{'priority'} = 99 - $self->{'priority'}; + $self->{'cookie'} = ''; + $self->usecachedrepo(); +} + +sub usecachedrepo { + my ($self, $ext, $mark) = @_; + my $cookie = $ext ? $self->{'extcookie'} : $self->{'cookie'}; + my $handle = $self->{'handle'}; + my $cachepath = $self->cachepath(); + if (sysopen(my $f, $cachepath, POSIX::O_RDONLY)) { + $f = solv::xfopen_fd('', POSIX::dup(fileno($f))); + my $flags = $ext ? $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES : 0; + $flags |= $solv::Repo::REPO_LOCALPOOL if $ext && $ext ne 'DL'; + if (!$self->{'handle'}->add_solv($f, $flags)) { + solv::xfclose($f); + return undef; + } + return 1; + } + return undef; +} + +package Repo::rpmmd; + +our @ISA = ('Repo::generic'); + +package Repo::system; + +our @ISA = ('Repo::generic'); + +sub calc_cookie_file { + my ($self, $filename) = @_; + my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256); + $chksum->add("1.1"); + $chksum->add_stat($filename); + return $chksum->raw(); +} + +sub load { + my ($self, $pool) = @_; + + $self->{'handle'} = $pool->add_repo($self->{'alias'}); + $self->{'handle'}->{'appdata'} = $self; + $pool->{'installed'} = $self->{'handle'}; + print "rpm database: "; + $self->{'cookie'} = $self->calc_cookie_file('/var/lib/rpm/Packages'); + if ($self->usecachedrepo()) { + print "cached\n"; + return 1; + } + return undef; +} + +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->providers($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; + my @j = $pool->Job($solv::Job::SOLVER_SOLVABLE_PROVIDES, $id); + return $pool->Job($solv::Job::SOLVER_SOLVABLE_PROVIDES, $id); + } + } + return unless $name =~ /[[*?]/; + if ($globname) { + my %idmatches; + for my $s (@{$pool->{'solvables_iter'}}) { + $idmatches{$s->{'nameid'}} = 1 if $s->installable() && File::FnMatch::fnmatch($name, $s->{'name'}, 0); + } + if (%idmatches) { + return map {$pool->Job($solv::Job::SOLVER_SOLVABLE_NAME, $_)} sort(keys %idmatches); + } + } + if ($globdep) { + my %idmatches; + for $id (@{$pool->allprovidingids()}) { + $idmatches{$id} = 1 if File::FnMatch::fnmatch($name, $pool->id2str($id), 0); + } + if (%idmatches) { + print "[using capability match for '$name']\n"; + return map {$pool->Job($solv::Job::SOLVER_SOLVABLE_PROVIDES, $_)} sort(keys %idmatches); + } + } + return; +} + +sub limitjobs { + my ($pool, $jobs, $flags, $evr) = @_; + my @jobs; + 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 |= $pool->id2str($evr) =~ /-/ ? $solv::Job::SOLVER_SETEVR : $solv::Job::SOLVER_SETEV; + } + push @jobs, $pool->Job($how, $what); + } + return @jobs; +} + +sub limitjobs_arch { + my ($pool, $jobs, $flags, $evrstr) = @_; + if ($evrstr =~ /^(.+)\.(.+?)$/ && validarch($pool, $2)) { + my $evr = $pool->str2id($1); + my @jobs = limitjobs($pool, $jobs, $solv::solv::REL_ARCH, $pool->str2id($2)); + return limitjobs($pool, \@jobs, $flags, $evr); + } + return limitjobs($pool, $jobs, $flags, $pool->str2id($evrstr)); +} + +sub mkjobs_rel { + my ($pool, $cmd, $name, $rel, $evr) = @_; + my $flags = 0; + $flags |= $solv::REL_LT if $rel =~ //; + my @jobs = depglob($pool, $name, 1, 1); + return limitjobs($pool, \@jobs, $flags, $pool->str2id($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::solv::REL_ARCH, $pool->str2id($arch)); + return limitjobs($pool, \@jobs, $flags, $pool->str2id($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, $pool->str2id($arch)) if @jobs; + } + if ($arg =~ /^(.+)-(.+?)$/s) { + my $evr = $2; + @jobs = depglob($pool, $1, 1, 0); + return limitjobs_arch($pool, \@jobs, $solv::REL_EQ, $evr) if @jobs; + } + if ($arg =~ /^(.+)-(.+?-.+?)$/s) { + my $evr = $2; + @jobs = depglob($pool, $1, 1, 0); + return limitjobs_arch($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_new(0, $solv::SOLVABLE_FILELIST, $arg, $type); + } else { + $di = $pool->dataiterator_new(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'}; + tied(@$di)->iter()->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::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); + } +} + +die("Usage: p5solv COMMAND [ARGS]\n") unless @ARGV; +my $cmd = shift @ARGV; +$cmd = 'list' if $cmd eq 'li'; +$cmd = 'install' if $cmd eq 'in'; +$cmd = 'erase' if $cmd eq 'rm'; +$cmd = 'verify' if $cmd eq 've'; +$cmd = 'search' if $cmd eq 'se'; + +my $pool = solv::Pool->new(); +$pool->setarch((POSIX::uname())[4]); +my @repos; +for my $reposdir ('/etc/zypp/repos.d') { + next unless -d $reposdir; + next unless opendir(DIR, $reposdir); + for my $reponame (sort(grep {/\.repo$/} readdir(DIR))) { + my $cfg = new Config::IniFiles('-file' => "$reposdir/$reponame"); + for my $alias ($cfg->Sections()) { + my $repoattr = {'alias' => $alias, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900}; + for my $p ($cfg->Parameters($alias)) { + $repoattr->{$p} = $cfg->val($alias, $p); + } + my $repo; + if ($repoattr->{'type'} == 'rpm-md') { + $repo = Repo::rpmmd->new($repoattr); + } + push @repos, $repo; + } + } +} + +my $sysrepo = Repo::system->new({'alias' => '@System', 'type' => 'system'}); +$sysrepo->load($pool); +for my $repo (@repos) { + $repo->load($pool) if $repo->{'enabled'}; +} + +if ($cmd eq 'search') { + my %matches; + my $di = $pool->dataiterator_new(0, $solv::SOLVABLE_NAME, $ARGV[0], $solv::Dataiterator::SEARCH_SUBSTRING | $solv::Dataiterator::SEARCH_NOCASE); + for my $d (@$di) { + $matches{$d->{'solvid'}} = 1; + } + for my $solvid (sort keys %matches) { + my $s = $pool->{'solvables'}->[$solvid]; + print "- ".$s->str()." [$s->{'repo'}->{'name'}] ".$s->lookup_str($solv::SOLVABLE_SUMMARY)."\n"; + } + exit(0); +} + +my $addedprovides = $pool->addfileprovides_ids(); +$pool->createwhatprovides(); + +my @jobs; +for my $arg (@ARGV) { + my @njobs = mkjobs($pool, $cmd, $arg); + die("nothing matches '$arg'\n") unless @njobs; + push @jobs, @njobs; +} + +if ($cmd eq 'list' || $cmd eq 'info') { + die("no package matched.\n") unless @jobs; + for my $job (@jobs) { + for my $s ($pool->jobsolvables($job)) { + if ($cmd eq 'info') { + printf "Name: %s\n", $s->str(); + printf "Repo: %s\n", $s->{'repo'}->{'name'}; + printf "Summary: %s\n", $s->lookup_str($solv::SOLVABLE_SUMMARY); + my $str = $s->lookup_str($solv::SOLVABLE_URL); + printf "Url: %s\n", $str if $str; + my $str = $s->lookup_str($solv::SOLVABLE_LICENSE); + printf "License: %s\n", $str if $str; + printf "Description:\n%s\n", $s->lookup_str($solv::SOLVABLE_DESCRIPTION); + } else { + printf " - %s [%s]\n", $s->str(), $s->{'repo'}->{'name'}; + printf " %s\n", $s->lookup_str($solv::SOLVABLE_SUMMARY); + } + } + } + exit 0; +} + +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') { + push @jobs, $pool->Job($solv::Job::SOLVER_SOLVABLE_ALL, 0); + } elsif ($cmd ne 'dup') { + die("no package matched.\n"); + } + } + for my $job (@jobs) { + if ($cmd eq 'up') { + if ($job->{'how'} == $solv::Job::SOLVER_SOLVABLE_ALL || grep {$_->isinstalled()} @{$pool->jobsolvables($job)}) { + $job->{'how'} |= $solv::Job::SOLVER_UPDATE; + } else { + $job->{'how'} |= $solv::Job::SOLVER_INSTALL; + } + } elsif ($cmd eq 'install') { + $job->{'how'} |= $solv::Job::SOLVER_INSTALL; + } elsif ($cmd eq 'erase') { + $job->{'how'} |= $solv::Job::SOLVER_ERASE; + } elsif ($cmd eq 'dup') { + $job->{'how'} |= $solv::Job::SOLVER_DISTUPGRADE; + } elsif ($cmd eq 'verify') { + $job->{'how'} |= $solv::Job::SOLVER_VERIFY; + } + } + my $solver; + while (1) { + $solver = $pool->create_solver(); + $solver->{'ignorealreadyrecommended'} = 1; + $solver->{'allowuninstall'} = 1 if $cmd eq 'erase'; + if ($cmd eq 'dup' && !@jobs) { + $solver->{'distupgrade'} = 1; + $solver->{'updatesystem'} = 1; + $solver->{'allowdowngrade'} = 1; + $solver->{'allowvendorchange'} = 1; + $solver->{'allowarchchange'} = 1; + $solver->{'dosplitprovides'} = 1; + } elsif ($cmd eq 'up' and @jobs == 1 and $jobs[0]->{'how'} == ($solv::Job::SOLVER_UPDATE | $solv::Job::SOLVER_SOLVABLE_ALL)) { + $solver->{'dosplitprovides'} = 1; + } + my @problems = $solver->solve(\@jobs); + last unless @problems; + for my $problem (@problems) { + print "Problem $problem->{'id'}:\n"; + my $r = $problem->findproblemrule(); + my ($type, $source, $target, $dep) = $r->info(); + if ($type == $solv::Solver::SOLVER_RULE_RPM_PACKAGE_CONFLICT) { + printf "package %s conflicts with %s provided by %s\n", $source->str(), $pool->dep2str($dep), $target->str(); + } + print "TYPE: $type\n"; + printf "SOURCE: %s\n", $source->str() if $source; + printf "TARGET: %s\n", $target->str() if $target; + printf "DEP: %s\n", $pool->dep2str($dep) if $dep; + } + exit(0); + } +} + +exit 0; diff --git a/examples/pysolv b/examples/pysolv index 1ebf931..c035ba1 100755 --- a/examples/pysolv +++ b/examples/pysolv @@ -574,7 +574,7 @@ def limitjobs(pool, jobs, flags, evr): what = pool.rel2id(j.what, evr, flags) if flags == solv.REL_ARCH: how |= Job.SOLVER_SETARCH - if flags == solv.REL_EQ and sel == Job.SOLVER_SOLVABLE_NAME: + elif flags == solv.REL_EQ and sel == Job.SOLVER_SOLVABLE_NAME: if pool.id2str(evr).find('-') >= 0: how |= Job.SOLVER_SETEVR else: @@ -595,7 +595,7 @@ def mkjobs_filelist(pool, cmd, arg): type = Dataiterator.SEARCH_GLOB else: type = Dataiterator.SEARCH_STRING - if cmd == 'rm' or cmd == 'erase': + if cmd == 'erase': di = pool.installed.dataiterator_new(0, solv.SOLVABLE_FILELIST, arg, type | Dataiterator.SEARCH_FILES|Dataiterator.SEARCH_COMPLETE_FILELIST) else: di = pool.dataiterator_new(0, solv.SOLVABLE_FILELIST, arg, type | Dataiterator.SEARCH_FILES|Dataiterator.SEARCH_COMPLETE_FILELIST) @@ -791,7 +791,11 @@ for arg in args: if cmdlinerepo and arg in cmdlinerepo['packages']: jobs.append(pool.Job(Job.SOLVER_SOLVABLE, cmdlinerepo['packages'][arg])) else: - jobs += mkjobs(pool, cmd, arg) + njobs = mkjobs(pool, cmd, arg) + if not njobs: + print "nothing matches '%s'" % arg + sys.exit(1) + jobs += njobs if cmd == 'list' or cmd == 'info': if not jobs: @@ -853,6 +857,7 @@ if cmd == 'install' or cmd == 'erase' or cmd == 'up' or cmd == 'dup' or cmd == ' solver.updatesystem = True solver.allowdowngrade = True solver.allowvendorchange = True + solver.allowarchchange = True solver.dosplitprovides = True if cmd == 'up' and len(jobs) == 1 and jobs[0].how == (Job.SOLVER_UPDATE | Job.SOLVER_SOLVABLE_ALL): solver.dosplitprovides = True diff --git a/examples/solv.i b/examples/solv.i index 7924386..16aff49 100644 --- a/examples/solv.i +++ b/examples/solv.i @@ -9,6 +9,7 @@ %module solv +#if defined(SWIGPYTHON) %typemap(in) Queue { /* Check if is a list */ queue_init(&$1); @@ -39,6 +40,35 @@ queue_free(&$1); $result = o; } +#endif +#if defined(SWIGPERL) +%typemap(in) Queue { + AV *av; + int i, size; + queue_init(&$1); + if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) + SWIG_croak("Argument $argnum is not an array reference."); + av = (AV*)SvRV($input); + size = av_len(av); + for (i = 0; i <= size; i++) { + SV **sv = av_fetch(av, i, 0); + int v; + int e = SWIG_AsVal_int(*sv, &v); + if (!SWIG_IsOK(e)) { + SWIG_croak("list must contain only integers"); + } + queue_push(&$1, v); + } +} +%typemap(out) Queue { + int i; + AV *o = newAV(); + for (i = 0; i < $1.count; i++) + av_push(o, SvREFCNT_inc(SWIG_From_int($1.elements[i]))); + queue_free(&$1); + $result = newRV_noinc((SV*)o); argvi++; +} +#endif %typemap(arginit) Queue { queue_init(&$1); } @@ -46,9 +76,51 @@ queue_free(&$1); } +#if defined(SWIGPERL) +%define perlmkarray(class,accessor,constructor) + %perlcode { + *solv::##class##::array::TIEARRAY = sub { bless $_[1], 'solv::class::array' }; + *solv::##class##::array::FETCHSIZE = *solv::##class##::__len__; + *solv::##class##::array::FETCH = *solv::##class##::__getitem__; + undef *solv::##accessor##; + *solv::##accessor = sub { my @a; tie(@a, 'solv::class::array', ##constructor##(@_)); \@a }; + } +%enddef +%define perlmkiter(class,accessor,constructor) + %perlcode { + *solv::##class##::iter::TIEARRAY = sub { bless [$_[1], 0], 'solv::class::iter' }; + *solv::##class##::iter::FETCHSIZE = sub { ($_[0]->[2] = $_[0]->[0]->__next__()) ? ++$_[0]->[1] : 0 }; + *solv::##class##::iter::FETCH = sub { $_[1] == $_[0]->[1] - 1 ? $_[0]->[2] : undef }; + *solv::##class##::iter::iter = sub { return $_[0]->[0] }; + undef *solv::##accessor##; + *solv::##accessor = sub { my @a; tie(@a, 'solv::class::iter', ##constructor##(@_)); \@a }; + } +%enddef +#endif + + +#if defined(SWIGPYTHON) +typedef PyObject *AppObjectPtr; +%typemap(out) AppObjectPtr { + $result = $1; + Py_INCREF($result); +} +#endif +#if defined(SWIGPERL) +typedef SV *AppObjectPtr; +%typemap(out) AppObjectPtr { + $result = $1; + SvREFCNT_inc($result); +} +#endif +#if defined(SWIGRUBY) +typedef VALUE AppObjectPtr; +#endif %include "cdata.i" +#ifndef SWIGPERL %include "file.i" +#endif %include "typemaps.i" %{ @@ -78,6 +150,7 @@ #define SOLVER_SOLUTION_REPLACE -101 typedef struct chksum Chksum; typedef int bool; +typedef void *AppObjectPtr; typedef struct { Pool* pool; @@ -186,6 +259,7 @@ typedef struct { %nodefaultctor Pool; %nodefaultdtor Pool; typedef struct { + AppObjectPtr appdata; } Pool; %nodefaultctor Repo; @@ -196,12 +270,7 @@ typedef struct _Repo { int priority; int subpriority; int const nsolvables; -#if defined(SWIGRUBY) - VALUE appdata; -#endif -#if defined(SWIGPERL) - SV *appdata; -#endif + AppObjectPtr appdata; } Repo; %nodefaultctor Pool_solvable_iterator; @@ -509,6 +578,10 @@ typedef struct { const unsigned char *b = pool_lookup_bin_checksum($self, entry, keyname, &type); return sat_chksum_create_from_bin(type, b); } + +#ifdef SWIGPERL + perlmkiter(Dataiterator, Pool::dataiterator_new, solvc::Pool_dataiterator_new) +#endif %newobject dataiterator_new; Dataiterator *dataiterator_new(Id p, Id key, const char *match, int flags) { return new_Dataiterator($self, 0, p, key, match, flags); @@ -533,6 +606,13 @@ typedef struct { void createwhatprovides() { pool_createwhatprovides($self); } + + +#if defined(SWIGPERL) + perlmkarray(Pool_solvable_iterator, Pool::swig_solvables_get, solvc::Pool_solvables_get) + perlmkiter(Pool_solvable_iterator, Pool::swig_solvables_iter_get, solvc::Pool_solvables_get) +#endif + %newobject solvables; Pool_solvable_iterator * const solvables; %{ @@ -544,6 +624,12 @@ typedef struct { return s; } %} + +#if defined(SWIGPERL) + perlmkarray(Pool_repo_iterator, Pool::swig_repos_get, solvc::Pool_repos_get) + perlmkiter(Pool_repo_iterator, Pool::swig_repos_iter_get, solvc::Pool_repos_get) +#endif + %newobject repos; Pool_repo_iterator * const repos; %{ @@ -555,6 +641,7 @@ typedef struct { return s; } %} + Repo *installed; %{ SWIGINTERN void Pool_installed_set(Pool *pool, Repo *installed) { @@ -607,6 +694,18 @@ typedef struct { return [ self.solvables[id] for id in self.providerids(*args) ] } #endif +#if defined(SWIGPERL) + %perlcode { + sub solv::Pool::jobsolvables { + my ($self, @args) = @_; + return map {$self->{'solvables'}->[$_]} @{$self->jobsolvids(@args)}; + } + sub solv::Pool::providers { + my ($self, @args) = @_; + return map {$self->{'solvables'}->[$_]} @{$self->providerids(@args)}; + } + } +#endif Id towhatprovides(Queue q) { return pool_queuetowhatprovides($self, &q); @@ -711,6 +810,11 @@ typedef struct { $self->nrepodata = oldnrepodata; return 1; } + +#ifdef SWIGPERL + perlmkiter(Dataiterator, Repo::dataiterator_new, solvc::Repo_dataiterator_new) +#endif + %newobject dataiterator_new; Dataiterator *dataiterator_new(Id p, Id key, const char *match, int flags) { return new_Dataiterator($self->pool, $self, p, key, match, flags); @@ -746,19 +850,6 @@ typedef struct { if (data->state != REPODATA_STUB) repodata_create_stubs(data); } -#if defined(SWIGPYTHON) - PyObject *appdata; - %{ - SWIGINTERN void Repo_appdata_set(Repo *repo, PyObject *o) { - repo->appdata = o; - } - SWIGINTERN PyObject *Repo_appdata_get(Repo *repo) { - PyObject *o = repo->appdata; - Py_INCREF(o); - return o; - } - %} -#endif bool iscontiguous() { int i; for (i = $self->start; i < $self->end; i++) @@ -798,6 +889,7 @@ typedef struct { dataiterator_free($self); sat_free($self); } +#if defined(SWIGPYTHON) %newobject __iter__; Dataiterator *__iter__() { Dataiterator *ndi; @@ -805,15 +897,17 @@ typedef struct { dataiterator_init_clone(ndi, $self); return ndi; } - %exception next { + %rename("next") __next__(); + %exception __next__ { $action if (!result) { PyErr_SetString(PyExc_StopIteration,"no more matches"); return NULL; } } - %newobject next; - Dataiterator *next() { +#endif + %newobject __next__; + Dataiterator *__next__() { Dataiterator *ndi; if (!dataiterator_step($self)) { return 0; @@ -868,8 +962,8 @@ typedef struct { } } - %extend Pool_solvable_iterator { +#if defined(SWIGPYTHON) %newobject __iter__; Pool_solvable_iterator *__iter__() { Pool_solvable_iterator *s; @@ -877,15 +971,17 @@ typedef struct { *s = *$self; return s; } - %exception next { + %rename("next") __next__(); + %exception __next__ { $action if (!result) { PyErr_SetString(PyExc_StopIteration,"no more matches"); return NULL; } } - %newobject next; - XSolvable *next() { +#endif + %newobject __next__; + XSolvable *__next__() { Pool *pool = $self->pool; XSolvable *s; if ($self->id >= pool->nsolvables) @@ -902,9 +998,13 @@ typedef struct { return new_XSolvable(pool, key); return 0; } + int __len__() { + return $self->pool->nsolvables; + } } %extend Pool_repo_iterator { +#if defined(SWIGPYTHON) %newobject __iter__; Pool_repo_iterator *__iter__() { Pool_repo_iterator *s; @@ -912,14 +1012,17 @@ typedef struct { *s = *$self; return s; } - %exception next { + %rename("next") __next__(); + %exception __next__ { $action if (!result) { PyErr_SetString(PyExc_StopIteration,"no more matches"); return NULL; } } - Repo *next() { +#endif + %newobject __next__; + Repo *__next__() { Pool *pool = $self->pool; if ($self->id >= pool->nrepos + 1) return 0; @@ -936,9 +1039,13 @@ typedef struct { return pool_id2repo(pool, key); return 0; } + int __len__() { + return $self->pool->nrepos + 1; + } } %extend Repo_solvable_iterator { +#if defined(SWIGPYTHON) %newobject __iter__; Repo_solvable_iterator *__iter__() { Repo_solvable_iterator *s; @@ -946,15 +1053,17 @@ typedef struct { *s = *$self; return s; } - %exception next { + %rename("next") __next__(); + %exception __next__ { $action if (!result) { PyErr_SetString(PyExc_StopIteration,"no more matches"); return NULL; } } - %newobject next; - XSolvable *next() { +#endif + %newobject __next__; + XSolvable *__next__() { Repo *repo = $self->repo; Pool *pool = repo->pool; XSolvable *s; @@ -975,6 +1084,9 @@ typedef struct { return new_XSolvable(pool, key); return 0; } + int __len__() { + return $self->repo->pool->nsolvables; + } } %extend XSolvable { @@ -1123,6 +1235,22 @@ typedef struct { return [ Solution(self, i) for i in range(1, self.solution_count() + 1) ]; } #endif +#if defined(SWIGPERL) + %perlcode { + sub solv::Problem::findproblemrule { + my ($self) = @_; + return solv::XRule->new($self->{'solv'}, $self->findproblemrule_helper()); + } + sub solv::Problem::findallproblemrule { + my ($self, $unfiltered) = @_; + return map {solv::XRule->new($self->{'solv'}, $_)} @{$self->findallproblemrule_helper($unfiltered)}; + } + sub solv::Problem::solutions { + my ($self) = @_; + return map {solv::Solution->new($self, $_)} 1..($self->solution_count()); + } + } +#endif } %extend Solution { @@ -1143,6 +1271,14 @@ typedef struct { return [ Solutionelement(self, i) for i in range(1, self.element_count() + 1) ]; } #endif +#if defined(SWIGPERL) + %perlcode { + sub solv::Solution::elements { + my ($self) = @_; + return map {solv::Solutionelement->new($self, $_)} 1..($self->element_count()); + } + } +#endif } %extend Solutionelement { @@ -1229,6 +1365,16 @@ typedef struct { return [ Problem(self, pid) for pid in range(1, nprob + 1) ] } #endif +#if defined(SWIGPERL) + %perlcode { + sub solv::Solver::solve { + my ($self, $jobs) = @_; + my @j = map {($_->{'how'}, $_->{'what'})} @$jobs; + my $nprob = $self->solve_helper(\@j); + return map {solv::Problem->new($self, $_)} 1..$nprob; + } + } +#endif int solve_helper(Queue jobs) { solver_solve($self, &jobs); return solver_problem_count($self); @@ -1364,6 +1510,17 @@ typedef struct { return type, source, target, dep } #endif +#if defined(SWIGPERL) + %perlcode { + sub solv::XRule::info { + my ($self) = @_; + my ($type, $source, $target, $dep) = $self->info_helper(); + $source = $self->{'solv'}->{'pool'}->{'solvables'}->[$source] if $source; + $target = $self->{'solv'}->{'pool'}->{'solvables'}->[$target] if $target; + return ($type, $source, $target, $dep); + } + } +#endif } @@ -1435,3 +1592,4 @@ typedef struct { repodata_extend_block(data, data->repo->start, data->repo->end - data->repo->start); } } + -- 2.7.4