]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
- implement repository handling and load callback in perl
authorMichael Schroeder <mls@suse.de>
Wed, 9 Mar 2011 15:59:36 +0000 (16:59 +0100)
committerMichael Schroeder <mls@suse.de>
Wed, 9 Mar 2011 15:59:36 +0000 (16:59 +0100)
examples/p5solv
examples/pysolv
examples/solv.i

index 706d62551c99749f7da66b286ffe7512dbb56cf1..0af2452b526eab7162a074cc7a249d2834699bb0 100755 (executable)
@@ -8,6 +8,7 @@ use Data::Dumper;
 use solv;
 use Devel::Peek;
 use FileHandle;
+use File::Temp ();
 use strict;
 
 package Repo::generic;
@@ -18,6 +19,21 @@ sub new {
   return bless $r, $class;
 }
 
+sub calc_cookie_fp {
+  my ($self, $fp) = @_;
+  my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256);
+  $chksum->add_fp($fp);
+  return $chksum->raw();
+}
+
+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 cachepath {
   my ($self, $ext) = @_;
   my $path = $self->{'alias'};
@@ -32,8 +48,21 @@ sub load {
   $self->{'handle'} = $pool->add_repo($self->{'alias'});
   $self->{'handle'}->{'appdata'} = $self;
   $self->{'handle'}->{'priority'} = 99 - $self->{'priority'};
+  my $dorefresh = $self->{'autorefresh'};
+  if ($dorefresh) {
+    my @s = stat($self->cachepath());
+    $dorefresh = 0 if @s && time() - $s[9] < $self->{'metadata_expire'};
+  }
   $self->{'cookie'} = '';
-  $self->usecachedrepo();
+  if (!$dorefresh && $self->usecachedrepo()) {
+    print "repo: '$self->{'alias'}' cached\n";
+    return 1;
+  }
+  return $self->load_if_changed();
+}
+
+sub load_ext {
+  return 0;
 }
 
 sub download {
@@ -77,8 +106,18 @@ sub usecachedrepo {
   my ($self, $ext, $mark) = @_;
   my $cookie = $ext ? $self->{'extcookie'} : $self->{'cookie'};
   my $handle = $self->{'handle'};
-  my $cachepath = $self->cachepath();
+  my $cachepath = $self->cachepath($ext);
+  my $fextcookie;
   if (sysopen(my $f, $cachepath, POSIX::O_RDONLY)) {
+    sysseek($f, -32, Fcntl::SEEK_END);
+    my $fcookie = '';
+    return undef if sysread($f, $fcookie, 32) != 32;
+    return undef if $cookie && $fcookie ne $cookie;
+    if ($self->{'alias'} ne '@System' && !$ext) {
+      sysseek($f, -32 * 2, Fcntl::SEEK_END);
+      return undef if sysread($f, $fextcookie, 32) != 32;
+    }
+    sysseek($f, 0, Fcntl::SEEK_SET);
     $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';
@@ -87,19 +126,323 @@ sub usecachedrepo {
       return undef;
     }
     solv::xfclose($f);
+    $self->{'cookie'} = $fcookie unless $ext;
+    $self->{'extcookie'} = $fextcookie if $fextcookie;
+    utime undef, undef, $f if $mark;
     return 1;
   }
   return undef;
 }
 
+sub genextcookie {
+  my ($self, $f) = @_;
+  my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256);
+  $chksum->add($self->{'cookie'});
+  if ($f) {
+    my @s = stat($f);
+    $chksum->add("@s");
+  }
+  my $extcookie = $chksum->raw();
+  substr($extcookie, 0, 1) = chr(1) if ord(substr($extcookie, 0, 1)) == 0;
+  $self->{'extcookie'} = $extcookie;
+}
+
+sub writecachedrepo {
+  my ($self, $ext, $info) = @_;
+  mkdir("/var/cache/solv", 0755) unless -d "/var/cache/solv";
+  my ($f, $tmpname);
+  eval {
+    ($f, $tmpname) = File::Temp::tempfile(".newsolv-XXXXXX", 'DIR' => '/var/cache/solv');
+  };
+  return unless $f;
+  chmod 0444, $f;
+  my $ff = solv::xfopen_fd('', POSIX::dup(fileno($f)));
+  if (!$info) {
+    $self->{'handle'}->write($ff);
+  } elsif ($ext) {
+    $info->write($ff);
+  } else {
+     $self->{'handle'}->write_first_repodata($ff);
+  }
+  solv::xfclose($ff);
+  if ($self->{'alias'} ne '@System' && !$ext) {
+    $self->genextcookie($f) unless $self->{'extcookie'};
+    syswrite($f, $self->{'extcookie'});
+  }
+  syswrite($f, $ext ? $self->{'extcookie'} : $self->{'cookie'});
+  close($f);
+  if ($self->{'handle'}->iscontiguous()) {
+    $f = solv::xfopen($tmpname);
+    if ($f) {
+      if (!$ext) {
+        $self->{'handle'}->empty();
+        die("internal error, cannot reload solv file\n") unless $self->{'handle'}->add_solv($f, $solv::Repo::SOLV_ADD_NO_STUBS);
+      } else {
+       $info->extend_to_repo();
+       $info->read_solv_flags($f, $solv::Repo::REPO_EXTEND_SOLVABLES);
+      }
+      solv::xfclose($f);
+    }
+  }
+  rename($tmpname, $self->cachepath($ext));
+}
+
 package Repo::rpmmd;
 
 our @ISA = ('Repo::generic');
 
+sub find {
+  my ($self, $what) = @_;
+  my $di = $self->{'handle'}->Dataiterator($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_TYPE, $what, $solv::Dataiterator::SEARCH_STRING);
+  $di->prepend_keyname($solv::REPOSITORY_REPOMD);
+  for my $d (@$di) {
+    $d->setpos_parent();
+    my $filename = $d->{'pool'}->lookup_str($solv::SOLVID_POS, $solv::REPOSITORY_REPOMD_LOCATION);
+    my $chksum = $d->{'pool'}->lookup_checksum($solv::SOLVID_POS, $solv::REPOSITORY_REPOMD_CHECKSUM);
+    if ($filename && !$chksum) {
+      print "no $filename file checksum!\n";
+      return (undef, undef);
+    }
+    return ($filename, $chksum) if $filename;
+  }
+  return (undef, undef);
+}
+
+sub add_ext {
+  my ($self, $repodata, $what, $ext) = @_;
+  my ($filename, $chksum) = $self->find($what);
+  ($filename, $chksum) = $self->find('prestodelta') if !$filename && $what eq 'deltainfo';
+  return unless $filename;
+  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);
+  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);
+  } elsif ($ext eq 'FL') {
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_FILELIST);
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRSTRARRAY);
+  }
+  $repodata->add_flexarray($solv::SOLVID_META, $solv::REPOSITORY_EXTERNAL, $handle);
+}
+
+sub add_exts {
+  my ($self) = @_;
+  my $repodata = $self->{'handle'}->add_repodata(0);
+  $self->add_ext($repodata, 'deltainfo', 'DL');
+  $self->add_ext($repodata, 'filelists', 'FL');
+  $repodata->internalize();
+}
+
+sub load_ext {
+  my ($self, $repodata) = @_;
+  my $repomdtype = $repodata->lookup_str($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_TYPE);
+  my $ext;
+  if ($repomdtype eq 'filelists') {
+    $ext = 'FL';
+  } elsif ($repomdtype eq 'deltainfo') {
+    $ext = 'DL';
+  } else {
+    return 0;
+  }
+  print("[$self->{'alias'}:$ext: ");
+  STDOUT->flush();
+  if ($self->usecachedrepo($ext)) {
+    print "cached]\n";
+    return 1;
+  }
+  print "fetching]\n";
+  my $filename = $repodata->lookup_str($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_LOCATION);
+  my $filechksum = $repodata->lookup_checksum($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_CHECKSUM);
+  my $f = $self->download($filename, 1, $filechksum);
+  return 0 unless $f;
+  if ($ext eq 'FL') {
+    $self->{'handle'}->add_rpmmd($f, 'FL', $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES);
+  } elsif ($ext eq 'FL') {
+    $self->{'handle'}->add_deltainfoxml($f, $solv::Repo::REPO_USE_LOADING);
+  }
+  solv::xfclose($f);
+  $self->writecachedrepo($ext, $repodata);
+  return 1;
+}
+
+sub load_if_changed {
+  my ($self) = @_;
+  print "rpmmd repo '$self->{'alias'}': ";
+  STDOUT->flush();
+  my $f = $self->download("repodata/repomd.xml");
+  if (!$f) {
+    print "no repomd.xml file, skipped\n";
+    $self->{'handle'}->free(1);
+    delete $self->{'handle'};
+    return undef;
+  }
+  $self->{'cookie'} = $self->calc_cookie_fp($f);
+  if ($self->usecachedrepo(undef, 1)) {
+    print "cached\n";
+    solv::xfclose($f);
+    return 1;
+  }
+  $self->{'handle'}->add_repomdxml($f, 0);
+  solv::xfclose($f);
+  print "fetching\n";
+  my ($filename, $filechksum) = $self->find('primary');
+  if ($filename) {
+    $f = $self->download($filename, 1, $filechksum, 1);
+    if ($f) {
+      $self->{'handle'}->add_rpmmd($f, undef, 0);
+      solv::xfclose($f);
+    }
+    return undef if $self->{'incomplete'};
+  }
+  ($filename, $filechksum) = $self->find('updateinfo');
+  if ($filename) {
+    $f = $self->download($filename, 1, $filechksum, 1);
+    if ($f) {
+      $self->{'handle'}->add_updateinfoxml($f, 0);
+      solv::xfclose($f);
+    }
+  }
+  $self->add_exts();
+  $self->writecachedrepo() unless $self->{'incomplete'};
+  $self->{'handle'}->create_stubs();
+  return 1;
+}
+
 package Repo::susetags;
 
 our @ISA = ('Repo::generic');
 
+sub find {
+  my ($self, $what) = @_;
+  
+  my $di = $self->{'handle'}->Dataiterator($solv::SOLVID_META, $solv::SUSETAGS_FILE_NAME, $what, $solv::Dataiterator::SEARCH_STRING);
+  $di->prepend_keyname($solv::SUSETAGS_FILE);
+  for my $d (@$di) {
+    $d->setpos_parent();
+    my $chksum = $d->{'pool'}->lookup_checksum($solv::SOLVID_POS, $solv::SUSETAGS_FILE_CHECKSUM);
+    return ($what, $chksum);
+  }
+  return (undef, undef);
+}
+
+my %langtags = (
+  $solv::SOLVABLE_SUMMARY     => $solv::REPOKEY_TYPE_STR,
+  $solv::SOLVABLE_DESCRIPTION => $solv::REPOKEY_TYPE_STR,
+  $solv::SOLVABLE_EULA        => $solv::REPOKEY_TYPE_STR,
+  $solv::SOLVABLE_MESSAGEINS  => $solv::REPOKEY_TYPE_STR,
+  $solv::SOLVABLE_MESSAGEDEL  => $solv::REPOKEY_TYPE_STR,
+  $solv::SOLVABLE_CATEGORY    => $solv::REPOKEY_TYPE_ID,
+);
+
+sub add_ext {
+  my ($self, $repodata, $what, $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);
+  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);
+  } elsif ($ext eq 'DU') {
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_DISKUSAGE);
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRNUMNUMARRAY);
+  } elsif ($ext eq 'FL') {
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_FILELIST);
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRSTRARRAY);
+  } else {
+    for my $langid (sort {$a <=> $b} keys %langtags) {
+      $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $self->{'handle'}->{'pool'}->id2langid($langid, $ext, 1));
+      $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $langtags{$langid});
+    }
+  }
+  $repodata->add_flexarray($solv::SOLVID_META, $solv::REPOSITORY_EXTERNAL, $handle);
+}
+
+sub add_exts {
+  my ($self) = @_;
+  my $repodata = $self->{'handle'}->add_repodata(0);
+  my $di = $self->{'handle'}->Dataiterator($solv::SOLVID_META, $solv::SUSETAGS_FILE_NAME, undef, 0);
+  $di->prepend_keyname($solv::SUSETAGS_FILE);
+  for my $d (@$di) {
+    my $filename = $d->match_str();
+    next unless $filename && $filename =~ /^packages\.(..)(?:\..*)$/;
+    next if $1 eq 'en' || $1 eq 'gz';
+    $self->add_ext($repodata, $filename, $1);
+  }
+  $repodata->internalize();
+}
+
+sub load_ext {
+  my ($self, $repodata) = @_;
+  my $filename = $repodata->lookup_str($solv::SOLVID_META, $solv::SUSETAGS_FILE_NAME);
+  my $ext = substr($filename, 9, 2);
+  print("[$self->{'alias'}:$ext: ");
+  STDOUT->flush();
+  if ($self->usecachedrepo($ext)) {
+    print "cached]\n";
+    return 1;
+  }
+  print "fetching]\n";
+  my $defvendorid = $self->{'handle'}->lookup_id($solv::SOLVID_META, $solv::SUSETAGS_DEFAULTVENDOR);
+  my $descrdir = $self->{'handle'}->lookup_str($solv::SOLVID_META, $solv::SUSETAGS_DESCRDIR) || 'suse/setup/descr'; 
+  my $filechksum = $repodata->lookup_checksum($solv::SOLVID_META, $solv::SUSETAGS_FILE_CHECKSUM);
+  my $f = $self->download("$descrdir/$filename", 1, $filechksum);
+  return 0 unless $f;
+  $self->{'handle'}->add_susetags($f, $defvendorid, $ext, $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES);
+  solv::xfclose($f);
+  $self->writecachedrepo($ext, $repodata);
+  return 1;
+}
+
+sub load_if_changed {
+  my ($self) = @_;
+  print "susetags repo '$self->{'alias'}': ";
+  STDOUT->flush();
+  my $f = $self->download("content");
+  if (!$f) {
+    print "no content file, skipped\n";
+    $self->{'handle'}->free(1);
+    delete $self->{'handle'};
+    return undef;
+  }
+  $self->{'cookie'} = $self->calc_cookie_fp($f);
+  if ($self->usecachedrepo(undef, 1)) {
+    print "cached\n";
+    solv::xfclose($f);
+    return 1;
+  }
+  $self->{'handle'}->add_content($f, 0);
+  solv::xfclose($f);
+  print "fetching\n";
+  my $defvendorid = $self->{'handle'}->lookup_id($solv::SOLVID_META, $solv::SUSETAGS_DEFAULTVENDOR);
+  my $descrdir = $self->{'handle'}->lookup_str($solv::SOLVID_META, $solv::SUSETAGS_DESCRDIR) || 'suse/setup/descr'; 
+  my ($filename, $filechksum) = $self->find('packages.gz');
+  ($filename, $filechksum) = $self->find('packages') unless $filename;
+  if ($filename) {
+    $f = $self->download("$descrdir/$filename", 1, $filechksum, 1);
+    if ($f) {
+      $self->{'handle'}->add_susetags($f, $defvendorid, undef, $solv::Repo::REPO_NO_INTERNALIZE|$solv::Repo::SUSETAGS_RECORD_SHARES);
+      solv::xfclose($f);
+      ($filename, $filechksum) = $self->find('packages.en.gz');
+      ($filename, $filechksum) = $self->find('packages.en') unless $filename;
+      if ($filename) {
+        $f = $self->download("$descrdir/$filename", 1, $filechksum, 1);
+       if ($f) {
+          $self->{'handle'}->add_susetags($f, $defvendorid, undef, $solv::Repo::REPO_NO_INTERNALIZE|$solv::Repo::REPO_REUSE_REPODATA|$solv::Repo::REPO_EXTEND_SOLVABLES);
+          solv::xfclose($f);
+       }
+      }
+      $self->{'handle'}->internalize();
+    }
+  }
+  $self->add_exts();
+  $self->writecachedrepo() unless $self->{'incomplete'};
+  $self->{'handle'}->create_stubs();
+  return undef;
+}
+
 package Repo::unknown;
 
 our @ISA = ('Repo::generic');
@@ -114,14 +457,6 @@ 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) = @_;
 
@@ -134,7 +469,10 @@ sub load {
     print "cached\n";
     return 1;
   }
-  return undef;
+  print "reading\n";
+  $self->{'handle'}->add_products("/etc/products.d", $solv::Repo::REPO_NO_INTERNALIZE);
+  $self->{'handle'}->add_rpmdb(undef, 0);
+  return 1;
 }
 
 package main;
@@ -164,7 +502,7 @@ sub depglob {
   return unless $name =~ /[[*?]/;
   if ($globname) {
     my %idmatches;
-    for my $d (@{$pool->dataiterator_new(0, $solv::SOLVABLE_NAME, $name, $solv::Dataiterator::SEARCH_GLOB)}) {
+    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();
     }
@@ -256,16 +594,16 @@ sub mkjobs_filelist {
   $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);
+    $di = $pool->{'installed'}->Dataiterator(0, $solv::SOLVABLE_FILELIST, $arg, $type);
   } else {
-    $di = $pool->dataiterator_new(0, $solv::SOLVABLE_FILELIST, $arg, $type);
+    $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'};
-    tied(@$di)->iter()->skip_solvable();
+    $di->skip_solvable();
   }
   return () unless @matches;
   print "[using file list match for '$arg']\n";
@@ -289,6 +627,12 @@ sub mkjobs {
   }
 }
 
+sub load_stub {
+  my ($repodata) = @_;
+  my $repo = $repodata->{'repo'}->{'appdata'};
+  return $repo ? $repo->load_ext($repodata) : 0;
+}
+
 die("Usage: p5solv COMMAND [ARGS]\n") unless @ARGV;
 my $cmd = shift @ARGV;
 $cmd = 'list' if $cmd eq 'li';
@@ -299,6 +643,7 @@ $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;
@@ -331,7 +676,7 @@ for my $repo (@repos) {
 
 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);
+  my $di = $pool->Dataiterator(0, $solv::SOLVABLE_NAME, $ARGV[0], $solv::Dataiterator::SEARCH_SUBSTRING | $solv::Dataiterator::SEARCH_NOCASE);
   for my $d (@$di) {
     $matches{$d->{'solvid'}} = 1;
   }
index 0831f8c642fcb6191d22a17adb0505bb210aceb9..1415e1cbcd3fda20e38c2a4ef5ebdfd1f02c8925 100755 (executable)
@@ -339,7 +339,7 @@ class repomd_repo(generic_repo):
        return True
 
     def find(self, what):
-       di = self['handle'].dataiterator_new(solv.SOLVID_META, solv.REPOSITORY_REPOMD_TYPE, what, Dataiterator.SEARCH_STRING)
+       di = self['handle'].Dataiterator(solv.SOLVID_META, solv.REPOSITORY_REPOMD_TYPE, what, Dataiterator.SEARCH_STRING)
        di.prepend_keyname(solv.REPOSITORY_REPOMD)
        for d in di:
            d.setpos_parent()
@@ -363,10 +363,10 @@ class repomd_repo(generic_repo):
        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)
-       if what == 'deltainfo':
+       if ext == 'DL':
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO)
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY)
-       elif what == 'filelists':
+       elif ext == 'FL':
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST)
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY)
        repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle)
@@ -385,12 +385,12 @@ class repomd_repo(generic_repo):
            ext = 'DL'
        else:
            return False
-       sys.stdout.write("[%s:%s" % (self['alias'], ext))
+       sys.stdout.write("[%s:%s" % (self['alias'], ext))
        if self.usecachedrepo(ext):
-           sys.stdout.write(" cached]\n")
+           sys.stdout.write("cached]\n")
            sys.stdout.flush()
            return True
-       sys.stdout.write(" fetching]\n")
+       sys.stdout.write("fetching]\n")
        sys.stdout.flush()
        filename = repodata.lookup_str(solv.SOLVID_META, solv.REPOSITORY_REPOMD_LOCATION)
        filechksum = repodata.lookup_checksum(solv.SOLVID_META, solv.REPOSITORY_REPOMD_CHECKSUM)
@@ -452,7 +452,7 @@ class susetags_repo(generic_repo):
        return True
 
     def find(self, what):
-       di = self['handle'].dataiterator_new(solv.SOLVID_META, solv.SUSETAGS_FILE_NAME, what, Dataiterator.SEARCH_STRING)
+       di = self['handle'].Dataiterator(solv.SOLVID_META, solv.SUSETAGS_FILE_NAME, what, Dataiterator.SEARCH_STRING)
        di.prepend_keyname(solv.SUSETAGS_FILE)
        for d in di:
            d.setpos_parent()
@@ -489,7 +489,7 @@ class susetags_repo(generic_repo):
        
     def add_exts(self):
        repodata = self['handle'].add_repodata(0)
-       di = self['handle'].dataiterator_new(solv.SOLVID_META, solv.SUSETAGS_FILE_NAME, None, 0)
+       di = self['handle'].Dataiterator(solv.SOLVID_META, solv.SUSETAGS_FILE_NAME, None, 0)
        di.prepend_keyname(solv.SUSETAGS_FILE)
        for d in di:
            filename = d.match_str()
@@ -511,12 +511,12 @@ class susetags_repo(generic_repo):
     def load_ext(self, repodata):
        filename = repodata.lookup_str(solv.SOLVID_META, solv.SUSETAGS_FILE_NAME)
        ext = filename[9:11]
-       sys.stdout.write("[%s:%s" % (self['alias'], ext))
+       sys.stdout.write("[%s:%s" % (self['alias'], ext))
        if self.usecachedrepo(ext):
-           sys.stdout.write(" cached]\n")
+           sys.stdout.write("cached]\n")
            sys.stdout.flush()
            return True
-       sys.stdout.write(" fetching]\n")
+       sys.stdout.write("fetching]\n")
        sys.stdout.flush()
        defvendorid = self['handle'].lookup_id(solv.SOLVID_META, solv.SUSETAGS_DEFAULTVENDOR)
        descrdir = self['handle'].lookup_str(solv.SOLVID_META, solv.SUSETAGS_DESCRDIR)
@@ -526,7 +526,7 @@ class susetags_repo(generic_repo):
        f = self.download(descrdir + '/' + filename, True, filechksum)
        if not f:
            return False
-       self['handle'].add_susetags(f, defvendorid, None, Repo.REPO_USE_LOADING|Repo.REPO_EXTEND_SOLVABLES)
+       self['handle'].add_susetags(f, defvendorid, $ext, Repo.REPO_USE_LOADING|Repo.REPO_EXTEND_SOLVABLES)
        solv.xfclose(f)
        self.writecachedrepo(ext, repodata)
        return True
@@ -596,9 +596,9 @@ def mkjobs_filelist(pool, cmd, arg):
     else:
        type = Dataiterator.SEARCH_STRING
     if cmd == 'erase':
-       di = pool.installed.dataiterator_new(0, solv.SOLVABLE_FILELIST, arg, type | Dataiterator.SEARCH_FILES|Dataiterator.SEARCH_COMPLETE_FILELIST)
+       di = pool.installed.Dataiterator(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)
+       di = pool.Dataiterator(0, solv.SOLVABLE_FILELIST, arg, type | Dataiterator.SEARCH_FILES|Dataiterator.SEARCH_COMPLETE_FILELIST)
     matches = []
     for d in di:
        s = d.solvable
@@ -678,7 +678,7 @@ def depglob(pool, name, globname, globdep):
     if globname:
        # try name glob
        idmatches = {}
-       for d in pool.dataiterator_new(0, solv.SOLVABLE_NAME, name, Dataiterator.SEARCH_GLOB):
+       for d in pool.Dataiterator(0, solv.SOLVABLE_NAME, name, Dataiterator.SEARCH_GLOB):
            s = d.solvable
            if s.installable():
                idmatches[s.nameid] = True
@@ -756,7 +756,7 @@ for repo in repos:
     
 if cmd == 'search':
     matches = {}
-    di = pool.dataiterator_new(0, solv.SOLVABLE_NAME, args[0], Dataiterator.SEARCH_SUBSTRING|Dataiterator.SEARCH_NOCASE)
+    di = pool.Dataiterator(0, solv.SOLVABLE_NAME, args[0], Dataiterator.SEARCH_SUBSTRING|Dataiterator.SEARCH_NOCASE)
     for d in di:
        matches[d.solvid] = True
     for solvid in sorted(matches.keys()):
@@ -988,7 +988,7 @@ if cmd == 'install' or cmd == 'erase' or cmd == 'up' or cmd == 'dup' or cmd == '
                continue
            if sysrepo['handle'].nsolvables and os.access('/usr/bin/applydeltarpm', os.X_OK):
                pname = p.name
-               di = p.repo.dataiterator_new(solv.SOLVID_META, solv.DELTA_PACKAGE_NAME, pname, Dataiterator.SEARCH_STRING)
+               di = p.repo.Dataiterator(solv.SOLVID_META, solv.DELTA_PACKAGE_NAME, pname, Dataiterator.SEARCH_STRING)
                di.prepend_keyname(solv.REPOSITORY_DELTAINFO)
                for d in di:
                    d.setpos_parent()
index a292130b1a0287120722ffe3062b77a200f7d079..4237ff8090cf76dc9e4eea9d5496b669cfff703f 100644 (file)
@@ -1,3 +1,9 @@
+#
+# WARNING: for perl iterator/array support you need to run
+#   sed -i -e 's/SvTYPE(tsv) == SVt_PVHV/SvTYPE(tsv) == SVt_PVHV || SvTYPE(tsv) == SVt_PVAV/'
+# on the generated c code
+#
+
 #
 ##if defined(SWIGRUBY)
 #  %rename("to_s") string();
@@ -205,6 +211,7 @@ typedef SV *AppObjectPtr;
 typedef VALUE AppObjectPtr;
 #endif
 
+
 %include "cdata.i"
 #ifndef SWIGPERL
 %include "file.i"
@@ -591,30 +598,60 @@ typedef struct {
     XRepodata *xd = new_XRepodata(data->repo, data - data->repo->repodata);
     PyObject *args = Py_BuildValue("(O)", SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_POINTER_OWN | 0));
     PyObject *result = PyEval_CallObject((PyObject *)d, args);
-    if (!result)
-      return 0; /* exception */
     int ecode = 0;
     int vresult = 0;
     Py_DECREF(args);
+    if (!result)
+      return 0; /* exception */
     ecode = SWIG_AsVal_int(result, &vresult);
     Py_DECREF(result);
     return SWIG_IsOK(ecode) ? vresult : 0;
   }
   %}
   void set_loadcallback(PyObject *callable) {
-    if (!callable) {
-      if ($self->loadcallback == loadcallback) {
-        Py_DECREF($self->loadcallbackdata);
-        pool_setloadcallback($self, 0, 0);
-      }
-      return;
-    }
-    Py_INCREF(callable);
-    pool_setloadcallback($self, loadcallback, callable);
+    if ($self->loadcallback == loadcallback)
+      Py_DECREF($self->loadcallbackdata);
+    if (callable)
+      Py_INCREF(callable);
+    pool_setloadcallback($self, callable ? loadcallback : 0, callable);
   }
 #endif
+#if defined(SWIGPERL)
+  %{
+
+SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
+  int count;
+  int ret = 0;
+  dSP;
+  XRepodata *xd = new_XRepodata(data->repo, data - data->repo->repodata);
+
+  ENTER;
+  SAVETMPS;
+  PUSHMARK(SP);
+  XPUSHs(SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_OWNER | SWIG_SHADOW));
+  PUTBACK;
+  count = perl_call_sv((SV *)d, G_EVAL|G_SCALAR);
+  SPAGAIN;
+  if (count)
+    ret = POPi;
+  PUTBACK;
+  FREETMPS;
+  LEAVE;
+  return ret;
+}
+
+  %}
+  void set_loadcallback(SV *callable) {
+    if ($self->loadcallback == loadcallback)
+      SvREFCNT_dec($self->loadcallbackdata);
+    if (callable)
+      SvREFCNT_inc(callable);
+    pool_setloadcallback($self, callable ? loadcallback : 0, callable);
+  }
+#endif
+
   void free() {
-#if defined(SWIGPYTHON)
+#if defined(SWIGPYTHON) || defined(SWIGPERL)
     Pool_set_loadcallback($self, 0);
 #endif
     pool_free($self);
@@ -659,8 +696,8 @@ typedef struct {
     return sat_chksum_create_from_bin(type, b);
   }
 
-  %newobject dataiterator_new;
-  Dataiterator *dataiterator_new(Id p, Id key,  const char *match, int flags) {
+  %newobject Dataiterator;
+  Dataiterator *Dataiterator(Id p, Id key, const char *match, int flags) {
     return new_Dataiterator($self, 0, p, key, match, flags);
   }
   const char *solvid2str(Id solvid) {
@@ -887,8 +924,8 @@ typedef struct {
     return 1;
   }
 
-  %newobject dataiterator_new;
-  Dataiterator *dataiterator_new(Id p, Id key,  const char *match, int flags) {
+  %newobject Dataiterator;
+  Dataiterator *Dataiterator(Id p, Id key, const char *match, int flags) {
     return new_Dataiterator($self->pool, $self, p, key, match, flags);
   }