- more ruby code, better array handling in solv.i
authorMichael Schroeder <mls@suse.de>
Mon, 14 Mar 2011 17:53:48 +0000 (18:53 +0100)
committerMichael Schroeder <mls@suse.de>
Mon, 14 Mar 2011 17:53:48 +0000 (18:53 +0100)
examples/p5solv
examples/pysolv
examples/rbsolv
examples/solv.i

index be6d76f..33565dd 100755 (executable)
@@ -14,8 +14,10 @@ use strict;
 package Repo::generic;
 
 sub new {
-  my ($class, $attr) = @_;
-  my $r = { %$attr };
+  my ($class, $alias, $type, $attr) = @_;
+  my $r = { %{$attr || {}} };
+  $r->{'alias'} = $alias;
+  $r->{'type'} = $type;
   return bless $r, $class;
 }
 
@@ -61,6 +63,10 @@ sub load {
   return $self->load_if_changed();
 }
 
+sub load_if_changed {
+  return 0;
+}
+
 sub load_ext {
   return 0;
 }
@@ -113,7 +119,7 @@ sub usecachedrepo {
     my $fcookie = '';
     return undef if sysread($f, $fcookie, 32) != 32;
     return undef if $cookie && $fcookie ne $cookie;
-    if ($self->{'alias'} ne '@System' && !$ext) {
+    if ($self->{'type'} ne 'system' && !$ext) {
       sysseek($f, -32 * 2, Fcntl::SEEK_END);
       return undef if sysread($f, $fextcookie, 32) != 32;
     }
@@ -165,7 +171,7 @@ sub writecachedrepo {
      $self->{'handle'}->write_first_repodata($ff);
   }
   solv::xfclose($ff);
-  if ($self->{'alias'} ne '@System' && !$ext) {
+  if ($self->{'type'} ne 'system' && !$ext) {
     $self->genextcookie($f) unless $self->{'extcookie'};
     syswrite($f, $self->{'extcookie'});
   }
@@ -216,7 +222,7 @@ sub add_ext {
   my $handle = $repodata->new_handle();
   $repodata->set_poolstr($handle, $solv::REPOSITORY_REPOMD_TYPE, $what);
   $repodata->set_str($handle, $solv::REPOSITORY_REPOMD_LOCATION, $filename);
-  $repodata->set_bin_checksum($handle, $solv::REPOSITORY_REPOMD_CHECKSUM, $chksum);
+  $repodata->set_checksum($handle, $solv::REPOSITORY_REPOMD_CHECKSUM, $chksum);
   if ($ext eq 'DL') {
     $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOSITORY_DELTAINFO);
     $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_FLEXARRAY);
@@ -341,7 +347,7 @@ sub add_ext {
   my ($filename, $chksum) = $self->find($what);
   my $handle = $repodata->new_handle();
   $repodata->set_str($handle, $solv::SUSETAGS_FILE_NAME, $filename);
-  $repodata->set_bin_checksum($handle, $solv::SUSETAGS_FILE_CHECKSUM, $chksum);
+  $repodata->set_checksum($handle, $solv::SUSETAGS_FILE_CHECKSUM, $chksum);
   if ($ext eq 'DL') {
     $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOSITORY_DELTAINFO);
     $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_FLEXARRAY);
@@ -471,7 +477,7 @@ sub load {
   }
   print "reading\n";
   $self->{'handle'}->add_products("/etc/products.d", $solv::Repo::REPO_NO_INTERNALIZE);
-  $self->{'handle'}->add_rpmdb(undef, 0);
+  $self->{'handle'}->add_rpmdb(undef, $solv::Repo::REPO_REUSE_REPODATA);
   return 1;
 }
 
@@ -640,9 +646,6 @@ $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]);
-$pool->set_loadcallback(\&load_stub);
 my @repos;
 for my $reposdir ('/etc/zypp/repos.d') {
   next unless -d $reposdir;
@@ -656,18 +659,22 @@ for my $reposdir ('/etc/zypp/repos.d') {
       }
       my $repo;
       if ($repoattr->{'type'} eq 'rpm-md') {
-       $repo = Repo::rpmmd->new($repoattr);
+       $repo = Repo::rpmmd->new($alias, 'repomd', $repoattr);
       } elsif ($repoattr->{'type'} eq 'yast2') {
-       $repo = Repo::susetags->new($repoattr);
+       $repo = Repo::susetags->new($alias, 'susetags', $repoattr);
       } else {
-       $repo = Repo::unknown->new($repoattr);
+       $repo = Repo::unknown->new($alias, 'unknown', $repoattr);
       }
       push @repos, $repo;
     }
   }
 }
 
-my $sysrepo = Repo::system->new({'alias' => '@System', 'type' => 'system'});
+my $pool = solv::Pool->new();
+$pool->setarch((POSIX::uname())[4]);
+$pool->set_loadcallback(\&load_stub);
+
+my $sysrepo = Repo::system->new('@System', 'system');
 $sysrepo->load($pool);
 for my $repo (@repos) {
   $repo->load($pool) if $repo->{'enabled'};
@@ -870,7 +877,7 @@ if ($cmd eq 'install' || $cmd eq 'erase' || $cmd eq 'up' || $cmd eq 'dup' || $cm
       my $repo = $p->{'repo'}->{'appdata'};
       my ($location, $medianr) = $p->lookup_location();
       next unless $location;
-      if ($repo->{'type'} eq 'yast2') {
+      if ($repo->{'type'} eq 'susetags') {
        $location = ($repo->{'handle'}->lookup_str($solv::SOLVID_META, $solv::SUSETAGS_DATADIR) || 'suse') ."/$location";
       }
       my $chksum = $p->lookup_checksum($solv::SOLVABLE_CHECKSUM);
index aca68a1..d3541b2 100755 (executable)
@@ -57,7 +57,7 @@ def calc_cookie_fp(fp):
     chksum.add_fp(fp)
     return chksum.raw()
 
-class generic_repo(dict):
+class repo_generic(dict):
     def __init__(self, name, type, attribs = {}):
        for k in attribs:
            self[k] = attribs[k]
@@ -73,9 +73,9 @@ class generic_repo(dict):
        return "/var/cache/solv/" + re.sub(r'[/]', '_', path)
        
     def load(self, pool):
-       self.handle = pool.add_repo(repo.name)
-       self.handle.appdata = repo
-       self.handle.priority = 99 - repo['priority']
+       self.handle = pool.add_repo(self.name)
+       self.handle.appdata = self
+       self.handle.priority = 99 - self['priority']
        if self['autorefresh']:
            dorefresh = True
        if dorefresh:
@@ -91,6 +91,9 @@ class generic_repo(dict):
            return True
        return self.load_if_changed()
 
+    def load_if_changed(self):
+       return False
+
     def load_ext(repodata):
        return False
 
@@ -300,7 +303,7 @@ class generic_repo(dict):
            repodata.internalize()
            self.writecachedrepo(None, repodata)
 
-class repomd_repo(generic_repo):
+class repo_repomd(repo_generic):
     def load_if_changed(self):
        print "rpmmd repo '%s':" % self.name,
        sys.stdout.flush()
@@ -363,7 +366,7 @@ class repomd_repo(generic_repo):
        handle = repodata.new_handle()
        repodata.set_poolstr(handle, solv.REPOSITORY_REPOMD_TYPE, what)
        repodata.set_str(handle, solv.REPOSITORY_REPOMD_LOCATION, filename)
-       repodata.set_bin_checksum(handle, solv.REPOSITORY_REPOMD_CHECKSUM, chksum)
+       repodata.set_checksum(handle, solv.REPOSITORY_REPOMD_CHECKSUM, chksum)
        if ext == 'DL':
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO)
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY)
@@ -406,7 +409,7 @@ class repomd_repo(generic_repo):
        self.writecachedrepo(ext, repodata)
        return True
 
-class susetags_repo(generic_repo):
+class repo_susetags(repo_generic):
     def load_if_changed(self):
        print "susetags repo '%s':" % self.name,
        sys.stdout.flush()
@@ -468,7 +471,7 @@ class susetags_repo(generic_repo):
        handle = repodata.new_handle()
        repodata.set_str(handle, solv.SUSETAGS_FILE_NAME, filename)
        if chksum:
-           repodata.set_bin_checksum(handle, solv.SUSETAGS_FILE_CHECKSUM, chksum)
+           repodata.set_checksum(handle, solv.SUSETAGS_FILE_CHECKSUM, chksum)
        if ext == 'DU':
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_DISKUSAGE)
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRNUMNUMARRAY)
@@ -532,12 +535,12 @@ class susetags_repo(generic_repo):
        self.writecachedrepo(ext, repodata)
        return True
 
-class unknown_repo(generic_repo):
+class repo_unknown(repo_generic):
     def load(self, pool):
        print "unsupported repo '%s': skipped" % self.name
        return False
 
-class system_repo(generic_repo):
+class repo_system(repo_generic):
     def load(self, pool):
        self.handle = pool.add_repo(self.name)
        self.handle.appdata = self
@@ -549,11 +552,11 @@ class system_repo(generic_repo):
            return True
        print "reading"
        self.handle.add_products("/etc/products.d", Repo.REPO_NO_INTERNALIZE)
-       self.handle.add_rpmdb(None)
+       self.handle.add_rpmdb(None, Repo.REPO_REUSE_REPODATA)
        self.writecachedrepo(None)
        return True
 
-class cmdline_repo(generic_repo):
+class repo_cmdline(repo_generic):
     def load(self, pool):
        self.handle = pool.add_repo(self.name)
        self.handle.appdata = self 
@@ -721,10 +724,6 @@ if cmd == 'se':
     cmd = 'search'
 
 
-pool = solv.Pool()
-pool.setarch(os.uname()[4])
-pool.set_loadcallback(load_stub)
-
 # read all repo configs
 repos = []
 for reposdir in ["/etc/zypp/repos.d"]:
@@ -741,15 +740,19 @@ for reposdir in ["/etc/zypp/repos.d"]:
                    repoattr['metalink'] = repoattr['mirrorlist']
                    del repoattr['mirrorlist']
            if repoattr['type'] == 'rpm-md':
-               repo = repomd_repo(alias, 'repomd', repoattr)
+               repo = repo_repomd(alias, 'repomd', repoattr)
            elif repoattr['type'] == 'yast2':
-               repo = susetags_repo(alias, 'susetags', repoattr)
+               repo = repo_susetags(alias, 'susetags', repoattr)
            else:
-               repo = unknown_repo(alias, 'unknown', repoattr)
+               repo = repo_unknown(alias, 'unknown', repoattr)
            repos.append(repo)
 
+pool = solv.Pool()
+pool.setarch(os.uname()[4])
+pool.set_loadcallback(load_stub)
+
 # now load all enabled repos into the pool
-sysrepo = system_repo('@System', 'system')
+sysrepo = repo_system('@System', 'system')
 sysrepo.load(pool)
 for repo in repos:
     if int(repo['enabled']):
@@ -769,7 +772,7 @@ if cmd == 'list' or cmd == 'info' or cmd == 'install':
     for arg in args:
        if arg.endswith(".rpm") and os.access(arg, os.R_OK):
            if not cmdlinerepo:
-               cmdlinerepo = cmdline_repo('@commandline', 'cmdline')
+               cmdlinerepo = repo_cmdline('@commandline', 'cmdline')
                cmdlinerepo.load(pool)
                cmdlinerepo['packages'] = {}
            cmdlinerepo['packages'][arg] = cmdlinerepo.handle.add_rpm(arg, Repo.REPO_REUSE_REPODATA|Repo.REPO_NO_INTERNALIZE)
index b1da968..8de2684 100755 (executable)
@@ -8,9 +8,166 @@
 # grep => find_all
 
 require 'solv'
+require 'rubygems'
+require 'inifile'
+
+class Repo_generic
+  def initialize(name, type, attribs = {})
+    @name = name
+    @type = type
+    @attribs = attribs.dup
+  end
+
+  def enabled?
+    return @attribs['enabled'].to_i != 0
+  end
+
+  def autorefresh?
+    return @attribs['autorefresh'].to_i != 0
+  end
+
+  def calc_cookie_fp(f)
+    chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
+    chksum.add_fp(f)
+    return chksum.raw
+  end
+
+  def calc_cookie_file(filename)
+    chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
+    chksum.add("1.1")
+    chksum.add_stat(filename)
+    return chksum.raw
+  end
+
+  def cachepath(ext = nil)
+    path = @name.sub(/^\./, '_')
+    path += ext ? "_#{ext}.solvx" : '.solv'
+    return '/var/cache/solv/' + path.gsub(/\//, '_')
+  end
+
+  def load(pool)
+    @handle = pool.add_repo(@name)
+    @handle.appdata = self
+    @handle.priority = 99 - @attribs['priority'] if @attribs['priority']
+    dorefresh = autorefresh?
+    if dorefresh
+      begin
+        s = File.stat(cachepath)
+        dorefresh = false if s && Time.now - s.mtime < @attribs['metadata_expire']
+      rescue SystemCallError
+      end
+    end
+    @cookie = nil
+    if !dorefresh && usecachedrepo()
+      puts "repo: '#{@name}' cached"
+      return true
+    end
+    return load_if_changed()
+  end
+
+  def load_ext
+    return false
+  end
+
+  def load_if_changed
+    return false
+  end
+
+  def download(file, uncompress, chksum, markincomplete = false)
+    return nil
+  end
+
+  def usecachedrepo(ext, mark = false)
+    cookie = ext ? @extcookie : @cookie
+    begin
+      repopath = cachepath(ext)
+      @handle.add_solv(repopath)
+    rescue
+      return false
+    end
+    return true
+  end
+
+  def genextcookie(f)
+  end
+
+  def writecachedrepo(ext, info = nil)
+  end
+
+end
+
+class Repo_rpmmd < Repo_generic
+
+  def load_if_changed
+    print "rpmmd repo '#{@attribs['alias']}: "
+    f = download("repodata/repomd.xml", false, nil, nil)
+    if !f
+      puts "no repomd.xml file, skipped"
+      @handle.free(true)
+      @handle = nil
+      return false
+    end
+    @cookie = calc_cookie_fp(f)
+    if usecachedrepo(nil, true)
+      puts "cached"
+      Solv.xfclose(f)
+      return true
+    end
+    return false
+  end
+
+end
+
+class Repo_susetags < Repo_generic
+
+  def load_if_changed
+    print "susetags repo '#{@attribs['alias']}: "
+    f = download("content", false, nil, nil)
+    if !f
+      puts "no content file, skipped"
+      @handle.free(true)
+      @handle = nil
+      return false
+    end
+    @cookie = calc_cookie_fp(f)
+    if usecachedrepo(nil, true)
+      puts "cached"
+      Solv.xfclose(f)
+      return true
+    end
+    return false
+  end
+
+end
+
+class Repo_unknown < Repo_generic
+  def load(pool)
+    puts "unsupported repo '#{@attribs['alias']}: skipped"
+    return false
+  end
+end
+
+class Repo_system < Repo_generic
+  def load(pool)
+    @handle = pool.add_repo(@name)
+    @handle.appdata = self
+    pool.installed = @handle
+    print "rpm database: "
+    @cookie = calc_cookie_file("/var/lib/rpm/Packages")
+    if usecachedrepo(nil)
+      puts "cached"
+      return true
+    end
+    puts "reading"
+    @handle.add_products("/etc/products.d", Solv::Repo::REPO_NO_INTERNALIZE)
+    @handle.add_rpmdb(nil, Solv::Repo::REPO_REUSE_REPODATA)
+    writecachedrepo(nil)
+    return true
+  end
+end
 
 def depglob(pool, name, globname, globdep)
-  id = pool.str2id(name, 0)
+  id = pool.str2id(name, false)
   if id != 0
     match = false
     providers = pool.providers(id)
@@ -44,17 +201,71 @@ def depglob(pool, name, globname, globdep)
 end
 
 
+args = ARGV
+cmd = args.shift
+cmd = 'list' if cmd == 'li'
+cmd = 'install' if cmd == 'in'
+cmd = 'erase' if cmd == 'rm'
+cmd = 'verify' if cmd == 've'
+cmd = 'search' if cmd == 'se'
+
+repos = []
+for reposdir in [ '/etc/zypp/repos.d' ] do
+  next unless FileTest.directory?(reposdir)
+  for reponame in Dir["#{reposdir}/*.repo"].sort do
+    cfg = IniFile.new(reponame)
+    cfg.each_section do |ali|
+      repoattr = { 'alias' => ali, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900}
+      repoattr.update(cfg[ali])
+      if repoattr['type'] == 'rpm-md'
+        repo = Repo_rpmmd.new(ali, 'repomd', repoattr)
+      elsif repoattr['type'] == 'yast2'
+        repo = Repo_susetags.new(ali, 'susetags', repoattr)
+      else
+        repo = Repo_unknown.new(ali, 'unknown', repoattr)
+      end
+      repos.push(repo)
+    end
+  end
+end
+
 pool = Solv::Pool.new()
-repo = pool.add_repo("TEST")
-pool.installed = repo
-repo.add_solv("/var/cache/solv/@System.solv", 0);
+# require 'sys/uname' ; sysarch = Sys::Uname.machine
+sysarch = `uname -p`.strip
+pool.setarch(sysarch)
+
+sysrepo = Repo_system.new('@System', 'system')
+sysrepo.load(pool)
+for repo in repos
+  repo.load(pool) if repo.enabled?
+end
+
+if cmd == 'search'
+  matches = {}
+  for di in pool.Dataiterator(0, Solv::SOLVABLE_NAME, args[0], Solv::Dataiterator::SEARCH_SUBSTRING | Solv::Dataiterator::SEARCH_NOCASE)
+    matches[di.solvid] = true
+  end
+  for solvid in matches.keys.sort
+    s = pool.solvables[solvid]
+    puts "- #{s.str} [#{s.repo.name}]"
+  end
+  exit
+end
 
 pool.addfileprovides
 pool.createwhatprovides
-jobs = depglob(pool, ARGV[0], true, true)
+
+jobs = []
+for arg in args
+  njobs = depglob(pool, ARGV[0], true, true)
+  abort("nothing matches '#{arg}'") if njobs.empty?
+  jobs += njobs
+end
+
 for job in jobs
   job.how |= Solv::Job::SOLVER_ERASE
 end
+
 solver = pool.Solver
 problems = solver.solve(jobs)
 for problem in problems
index 262290d..e395f2a 100644 (file)
@@ -38,6 +38,7 @@
     return NULL;
   }
 }
+
 %typemap(out) Queue {
   int i;
   PyObject *o = PyList_New($1.count);
   queue_free(&$1);
   $result = o;
 }
+
+%define Queue2Array(type, step, con) %{
+  int i;
+  int cnt = $1.count / step;
+  Id *idp = $1.elements;
+  PyObject *o = PyList_New(cnt);
+  for (i = 0; i < cnt; i++, idp += step)
+    {
+      Id id = *idp;
+#define result resultx
+      type result = con;
+      $typemap(out, type)
+      PyList_SetItem(o, i, $result);
+#undef result
+    }
+  queue_free(&$1);
+  $result = o;
+%}
+
+%enddef
+
 #endif
+
+
 #if defined(SWIGPERL)
 %typemap(in) Queue {
   AV *av;
   queue_free(&$1);
   $result = 0;
 }
+%define Queue2Array(type, step, con) %{
+  int i;
+  int cnt = $1.count / step;
+  Id *idp = $1.elements;
+  if (argvi + cnt + 1 >= items) {
+    EXTEND(sp, items - (argvi + cnt + 1) + 1);
+  }
+  for (i = 0; i < cnt; i++, idp += step)
+    {
+      Id id = *idp;
+#define result resultx
+      type result = con;
+      $typemap(out, type)
+      SvREFCNT_inc(ST(argvi - 1));
+#undef result
+    }
+  queue_free(&$1);
+  $result = 0;
+%}
+%enddef
+
 #endif
+
 %typemap(arginit) Queue {
   queue_init(&$1);
 }
 %typemap(freearg) Queue {
   queue_free(&$1);
 }
+%define Queue2Array(type, step, con) %{
+  int i;
+  int cnt = $1.count / step;
+  Id *idp = $1.elements;
+  VALUE o = rb_ary_new2(cnt);
+  for (i = 0; i < cnt; i++, idp += step)
+    {
+      Id id = *idp;
+#define result resultx
+      type result = con;
+      $typemap(out, type)
+      rb_ary_store(o, i, $result);
+#undef result
+    }
+  queue_free(&$1);
+  $result = o;
+%}
+%enddef
 #endif
 
+
+
+
 #if defined(SWIGPERL)
 
 # work around a swig bug
@@ -393,7 +460,6 @@ typedef struct {
   Id const id;
 } XSolvable;
 
-%nodefaultctor Ruleinfo;
 typedef struct {
   Solver* const solv;
   Id const type;
@@ -576,34 +642,11 @@ typedef struct {
       queue_push(&q, p);
     return q;
   }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def solvables(self, *args):
-      return [ self.pool.solvables[id] for id in self.solvableids(*args) ]
-  }
-#endif
-#if defined(SWIGPERL)
-  %perlcode {
-    sub solv::Job::solvables {
-      my ($self, @args) = @_;
-      return map {$self->{'pool'}->{'solvables'}->[$_]} $self->solvableids(@args);
-    }
+  %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject solvables;
+  Queue solvables() {
+    return Job_solvableids($self);
   }
-#endif
-#if defined(SWIGRUBY)
-%init %{
-rb_eval_string(
-    "class Solv::Job\n"
-    "  def solvables\n"
-    "    solvableids.collect do |id|\n"
-    "      pool.solvables[id]\n"
-    "    end\n"
-    "  end\n"
-    "end\n"
-);
-%}
-#endif
-
 }
 
 %extend Chksum {
@@ -760,7 +803,7 @@ SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
 #endif
     pool_free($self);
   }
-  Id str2id(const char *str, int create=1) {
+  Id str2id(const char *str, bool create=1) {
     return str2id($self, str, create);
   }
   const char *id2str(Id id) {
@@ -769,10 +812,10 @@ SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
   const char *dep2str(Id id) {
     return dep2str($self, id);
   }
-  Id rel2id(Id name, Id evr, int flags, int create=1) {
+  Id rel2id(Id name, Id evr, int flags, bool create=1) {
     return rel2id($self, name, evr, flags, create);
   }
-  Id id2langid(Id id, const char *lang, int create=1) {
+  Id id2langid(Id id, const char *lang, bool create=1) {
     return pool_id2langid($self, id, lang, create);
   }
   void setarch(const char *arch) {
@@ -888,38 +931,22 @@ SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
     }
     return q;
   }
-  # move to job?
+
   Job *Job(Id how, Id what) {
     return new_Job($self, how, what);
   }
 
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def providers(self, *args):
-      return [ self.solvables[id] for id in self.providerids(*args) ]
-  }
-#endif
-#if defined(SWIGPERL)
-  %perlcode {
-    sub solv::Pool::providers {
-      my ($self, @args) = @_;
-      return map {$self->{'solvables'}->[$_]} $self->providerids(@args);
-    }
+  %typemap(out) Queue providers Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
+  %newobject providers;
+  Queue providers(Id dep) {
+    Pool *pool = $self;
+    Queue q;
+    Id p, pp;
+    queue_init(&q);
+    FOR_PROVIDES(p, pp, dep)
+      queue_push(&q, p);
+    return q;
   }
-#endif
-#if defined(SWIGRUBY)
-%init %{
-rb_eval_string(
-    "class Solv::Pool\n"
-    "  def providers(dep)\n"
-    "    providerids(dep).collect do |id|\n"
-    "      solvables[id]\n"
-    "    end\n"
-    "  end\n"
-    "end\n"
-  );
-%}
-#endif
 
   Id towhatprovides(Queue q) {
     return pool_queuetowhatprovides($self, &q);
@@ -951,10 +978,10 @@ rb_eval_string(
   static const int SUSETAGS_RECORD_SHARES = SUSETAGS_RECORD_SHARES; /* repo_susetags */
   static const int SOLV_ADD_NO_STUBS = SOLV_ADD_NO_STUBS ; /* repo_solv */
 
-  void free(int reuseids = 0) {
+  void free(bool reuseids = 0) {
     repo_free($self, reuseids);
   }
-  void empty(int reuseids = 0) {
+  void empty(bool reuseids = 0) {
     repo_empty($self, reuseids);
   }
 #ifdef SWIGRUBY
@@ -1509,7 +1536,9 @@ rb_eval_string(
     Id r = solver_findproblemrule($self->solv, $self->id);
     return new_XRule($self->solv, r);
   }
-  Queue findallproblemrules_helper(int unfiltered=0) {
+  %newobject findallproblemrules;
+  %typemap(out) Queue findallproblemrules Queue2Array(XRule *, 1, new_XRule(arg1->solv, id));
+  Queue findallproblemrules(int unfiltered=0) {
     Solver *solv = $self->solv;
     Id probr;
     int i, j;
@@ -1533,37 +1562,17 @@ rb_eval_string(
   int solution_count() {
     return solver_solution_count($self->solv, $self->id);
   }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def findallproblemrules(self, unfiltered=0):
-      return [ XRule(self.solv, i) for i in self.findallproblemrules_helper(unfiltered) ]
-    def solutions(self):
-      return [ Solution(self, i) for i in range(1, self.solution_count() + 1) ];
-  }
-#endif
-#if defined(SWIGPERL)
-  %perlcode {
-    sub solv::Problem::findallproblemrules {
-      my ($self, $unfiltered) = @_;
-      return map {solv::XRule->new($self->{'solv'}, $_)} $self->findallproblemrules_helper($unfiltered);
-    }
-    sub solv::Problem::solutions {
-      my ($self) = @_;
-      return map {solv::Solution->new($self, $_)} 1..($self->solution_count());
-    }
+  %newobject solutions;
+  %typemap(out) Queue solutions Queue2Array(Solution *, 1, new_Solution(arg1, id));
+  Queue solutions() {
+    Queue q;
+    int i, cnt;
+    queue_init(&q);
+    cnt = solver_solution_count($self->solv, $self->id);
+    for (i = 1; i <= cnt; i++)
+      queue_push(&q, i);
+    return q;
   }
-#endif
-#if defined(SWIGRUBY)
-%init %{
-rb_eval_string(
-    "class Solv::Problem\n"
-    "  def solutions()\n"
-    "    (1..solution_count).collect do |id| ; Solv::Solution.new(self,id) ; end\n"
-    "  end\n"
-    "end\n"
-  );
-%}
-#endif
 }
 
 %extend Solution {
@@ -1578,31 +1587,17 @@ rb_eval_string(
   int element_count() {
     return solver_solutionelement_count($self->solv, $self->problemid, $self->id);
   }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def elements(self):
-      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());
-    }
+  %newobject elements;
+  %typemap(out) Queue elements Queue2Array(Solutionelement *, 1, new_Solutionelement(arg1, id));
+  Queue elements() {
+    Queue q;
+    int i, cnt;
+    queue_init(&q);
+    cnt = solver_solution_count($self->solv, $self->id);
+    for (i = 1; i <= cnt; i++)
+      queue_push(&q, i);
+    return q;
   }
-#endif
-#if defined(SWIGRUBY)
-%init %{
-rb_eval_string(
-    "class Solv::Solution\n"
-    "  def elements()\n"
-    "    (1..element_count).collect do |id| ; Solv::Solutionelement.new(self,id) ; end\n"
-    "  end\n"
-    "end\n"
-  );
-%}
-#endif
 }
 
 %extend Solutionelement {
@@ -1695,8 +1690,7 @@ rb_eval_string(
     def solve(self, jobs):
       j = []
       for job in jobs: j += [job.how, job.what]
-      nprob = self.solve_helper(j)
-      return [ Problem(self, pid) for pid in range(1, nprob + 1) ]
+      return self.solve_helper(j)
   }
 #endif
 #if defined(SWIGPERL)
@@ -1704,8 +1698,7 @@ rb_eval_string(
     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;
+      return $self->solve_helper(\@j);
     }
   }
 #endif
@@ -1716,16 +1709,23 @@ rb_eval_string(
     "  def solve(jobs)\n"
     "    jl = []\n"
     "    jobs.each do |j| ; jl << j.how << j.what ; end\n"
-    "    nprob = solve_helper(jl)\n"
-    "    (1..nprob).collect do |id| ; Solv::Problem.new(self,id) ; end\n"
+    "    solve_helper(jl)\n"
     "  end\n"
     "end\n"
   );
 %}
 #endif
-  int solve_helper(Queue jobs) {
+  %typemap(out) Queue solve_helper Queue2Array(Problem *, 1, new_Problem(arg1, id));
+  %newobject solve_helper;
+  Queue solve_helper(Queue jobs) {
+    Queue q;
+    int i, cnt;
+    queue_init(&q);
     solver_solve($self, &jobs);
-    return solver_problem_count($self);
+    cnt = solver_problem_count($self);
+    for (i = 1; i <= cnt; i++)
+      queue_push(&q, i);
+    return q;
   }
   %newobject transaction;
   Transaction *transaction() {
@@ -1818,7 +1818,10 @@ rb_eval_string(
     }
   }
 #endif
-  Queue newpackages_helper() {
+
+  %typemap(out) Queue newpackages Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject newpackages;
+  Queue newpackages() {
     Queue q;
     int cut;
     queue_init(&q);
@@ -1826,7 +1829,10 @@ rb_eval_string(
     queue_truncate(&q, cut);
     return q;
   }
-  Queue keptpackages_helper() {
+
+  %typemap(out) Queue keptpackages Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject keptpackages;
+  Queue keptpackages() {
     Queue q;
     int cut;
     queue_init(&q);
@@ -1835,40 +1841,18 @@ rb_eval_string(
       queue_deleten(&q, 0, cut);
     return q;
   }
-  Queue steps_helper() {
+
+  %typemap(out) Queue steps Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject steps ;
+  Queue steps() {
     Queue q;
     queue_init_clone(&q, &$self->steps);
     return q;
   }
+
   int steptype(XSolvable *s, int mode) {
     return transaction_type($self, s->id, mode);
   }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def newpackages(self):
-      return [ self.pool.solvables[i] for i in self.newpackages_helper() ]
-    def keptpackages(self):
-      return [ self.pool.solvables[i] for i in self.keptpackages_helper() ]
-    def steps(self):
-      return [ self.pool.solvables[i] for i in self.steps_helper() ]
-  }
-#endif
-#if defined(SWIGPERL)
-  %perlcode {
-    sub solv::Transaction::newpackages {
-      my ($self) = @_;
-      return map {$self->{'pool'}->{'solvables'}->[$_]} $self->newpackages_helper();
-    }
-    sub solv::Transaction::keptpackages {
-      my ($self) = @_;
-      return map {$self->{'pool'}->{'solvables'}->[$_]} $self->newpackages_helper();
-    }
-    sub solv::Transaction::steps {
-      my ($self) = @_;
-      return map {$self->{'pool'}->{'solvables'}->[$_]} $self->steps_helper();
-    }
-  }
-#endif
   int calc_installsizechange() {
     return transaction_calc_installsizechange($self);
   }
@@ -1887,14 +1871,31 @@ rb_eval_string(
     return xr;
   }
   Ruleinfo *info() {
-    Ruleinfo *ri = sat_calloc(1, sizeof(*ri));
-    ri->solv = $self->solv;
-    ri->type = solver_ruleinfo($self->solv, $self->id, &ri->source, &ri->target, &ri->dep);
-    return ri;
+    Id type, source, target, dep;
+    type =  solver_ruleinfo($self->solv, $self->id, &source, &target, &dep);
+    return new_Ruleinfo($self, type, source, target, dep);
+  }
+  %typemap(out) Queue allinfos Queue2Array(Ruleinfo *, 4, new_Ruleinfo(arg1, id, idp[1], idp[2], idp[3]));
+  %newobject allinfos;
+  Queue allinfos() {
+    Queue q;
+    queue_init(&q);
+    solver_allruleinfos($self->solv, $self->id, &q);
+    return q;
   }
 }
 
 %extend Ruleinfo {
+  Ruleinfo(XRule *r, Id type, Id source, Id target, Id dep) {
+    Ruleinfo *ri = sat_calloc(1, sizeof(*ri));
+    ri->solv = r->solv;
+    ri->rid = r->id;
+    ri->type = type;
+    ri->source = source;
+    ri->target = target;
+    ri->dep = dep;
+    return ri;
+  }
   XSolvable * const solvable;
   XSolvable * const othersolvable;
   %{
@@ -1935,7 +1936,7 @@ rb_eval_string(
   void add_flexarray(Id solvid, Id keyname, Id handle) {
     repodata_add_flexarray($self->repo->repodata + $self->id, solvid, keyname, handle);
   }
-  void set_bin_checksum(Id solvid, Id keyname, Chksum *chksum) {
+  void set_checksum(Id solvid, Id keyname, Chksum *chksum) {
     const unsigned char *buf = sat_chksum_get(chksum, 0);
     if (buf)
       repodata_set_bin_checksum($self->repo->repodata + $self->id, solvid, keyname, sat_chksum_get_type(chksum), buf);