Index: bs_repserver
===================================================================
--- bs_repserver	(Revision 9328)
+++ bs_repserver	(Arbeitskopie)
@@ -223,13 +223,20 @@
   my $repo = addrepo_scan($pool, $prp, $arch);
   my %rnames = $repo ? $repo->pkgnames() : ();
   my @send;
+  my $dirty = 0;
   for my $n (@qbins) {
     my $p = $rnames{$n};
     if (!$p) {
       push @send, {'name' => $n, 'error' => 'not available'};
       next;
     }
-    my $path = "$reporoot/".$pool->pkg2fullpath($p, $arch);
+    my $path = "$reporoot/" . $pool->pkg2fullpath($p, $arch);
+    unless (-e $path) {
+      my $rel = {"rpath" => $pool->pkg2rpath($p)};
+      # XXX: investigate if we can use something like "worker_getbinaries()" in bs_srcserver
+      fetchbinary($path, $rel, $repo->hasdodurl());
+      $dirty = 1;
+    }
     if ($path =~ /\.rpm$/) {
       push @send, {'name' => "$n.rpm", 'filename' => $path};
     } else {
@@ -243,6 +250,14 @@
       push @send, {'name' => "$n.meta", 'filename' => "$path-MD5SUMS.meta"};
     }
   }
+  if ($dirty) {
+    my $ev = { type => 'scanrepo', 'project' => $projid, 'repository' => $repoid };
+    my $evname = "scanrepo:${projid}::$repoid";
+    if (-d "$eventdir/$arch") {
+      writexml("$eventdir/$arch/.$evname", "$eventdir/$arch/$evname", $ev, $BSXML::event);
+      ping($arch);
+    }
+  }
   undef $repo;
   undef $pool;
   BSServer::reply_cpio(\@send);
@@ -619,29 +634,29 @@
 #
 # XXX: DOD
 # 
-#sub fetchbinary {
-#  my ($dest, $c, $url) = @_;
-#  return undef unless $c;
-#  return undef unless $c->{'rpath'};
-#  my $uri = "$url/$c->{'rpath'}";
-#  print "fetching: $uri\n";
-#  # FIXME: this should be "more" atomic
-#  eval {
-#    BSRPC::rpc({
-#      uri => $uri,
-#      maxredirects => 3,
-#      filename => "$dest$$",
-#      receiver => \&BSHTTP::file_receiver
-#    }, undef);
-#  };
-#  if ($@) {
-#    print "failed: $@";
-#    unlink("$dest$$");
-#    return undef;
-#  }
-#  rename("$dest$$", $dest) || die("rename $dest$$ $dest: $!\n");
-#  return $dest;
-#}
+sub fetchbinary {
+  my ($dest, $c, $url) = @_;
+  return undef unless $c;
+  return undef unless $c->{'rpath'};
+  my $uri = "$url/$c->{'rpath'}";
+  print "fetching: $uri\n";
+  # FIXME: this should be "more" atomic
+  eval {
+    BSRPC::rpc({
+      uri => $uri,
+      maxredirects => 3,
+      filename => "$dest$$",
+      receiver => \&BSHTTP::file_receiver
+    }, undef);
+  };
+  if ($@) {
+    print "failed: $@";
+    unlink("$dest$$");
+    return undef;
+  }
+  rename("$dest$$", $dest) || die("rename $dest$$ $dest: $!\n");
+  return $dest;
+}
 
 sub getbinary_repository {
   my ($cgi, $projid, $repoid, $arch, $bin) = @_;
Index: bs_sched
===================================================================
--- bs_sched	(Revision 9328)
+++ bs_sched	(Arbeitskopie)
@@ -87,6 +87,7 @@
 my $historylay = [qw{versrel bcnt srcmd5 rev time}];
 
 my %remoteprojs;	# remote project cache
+my %dodprojs;
 
 # Create directory on first start
 mkdir_p($infodir) || die ("Failed to create ".$infodir);
@@ -241,10 +242,44 @@
   my ($projid, $repoid) = split('/', $prp, 2);
   if ($remoteprojs{$projid}) {
     return addrepo_remote($pool, $prp, $remoteprojs{$projid});
+  } elsif ($dodprojs{$projid}) {
+    return addrepo_dod($pool, $prp, $dodprojs{$projid});
   }
   return addrepo_scan($pool, $prp);
 }
 
+sub addrepo_dod {
+  my ($pool, $prp, $doddata) = @_;
+  print "    loading metadata(" . $doddata->{'mtype'} . ") for $prp...\n";
+  my $dir = "$reporoot/$prp/$myarch/:full";
+  my $cache;
+  eval {$cache = Meta::parse("$dir/$doddata->{'metafile'}", "$doddata->{'mtype'}", { 'arch' => [ $myarch ] })};
+  for (values %$cache) {
+    delete $_->{'id'};
+    delete $_->{'hdrmd5'};
+    $_->{'rpath'} = $_->{'path'};
+    $_->{'path'} =~ s/.*\///;
+  }
+  warn("cannot read metadata: $@\n") if $@;
+  return {} if $@;
+  $cache->{'/url'} = $doddata->{'baseurl'};
+  $cache = $pool->repofromdata($prp, $cache);
+  if (opendir(D, "$dir")) {
+    my @bins = grep {/\.(?:rpm|deb)$/} readdir(D);
+    for (splice @bins) {
+      my @s = stat("$dir/$_");
+      next unless @s;
+      push @bins, $_, "$s[9]/$s[7]/$s[1]";
+    }
+    closedir D;
+    $cache->updatefrombins("$dir", @bins);
+  }
+  $cache->tofile("$dir.solv.new");
+  rename("$dir.solv.new", "$dir.solv") || die("rename $dir.solv.new $dir.solv: $!\n");
+  $repodatas{$prp}->{'lastscan'} = time();
+  return $cache;
+}
+
 # add :full repo to pool, make sure repo is up-to-data by
 # scanning the directory
 sub addrepo_scan {
@@ -1297,6 +1332,10 @@
   #print Dumper($projpacks);
   calc_projpacks_linked();	# modifies watchremote/watchremoteprojs
   calc_prps();			# modifies watchremote/watchremoteprojs
+  for (keys %$projpacks) {
+    next unless exists($projpacks->{$_}->{'download'});
+    $dodprojs{$_} = $projpacks->{$_}->{'download'}->[0];
+  }
 
   updateremoteprojs();
   %watchremoteprojs = ();
@@ -4148,6 +4187,8 @@
 	  push @new_meta, @$meta;
 	} else {
 	  my $pkgid = $pool->pkg2pkgid($pkg);
+          # dummy in case someone just removed the downloaded pkg from :full tree (triggers rebuild)
+          $pkgid = "dodododododododododododododododo" unless $pkgid;
 	  push @new_meta, "$pkgid  $bpack";
 	}
       }
@@ -4176,30 +4217,30 @@
 	$packstatus{$packid} = 'done';
 	goto relsynccheck;
       }
-      if (($BSConfig::enable_download_on_demand || $BSConfig::enable_dod) && @meta == @new_meta) {
-        # unfetched dod packages have dodo... as hdrid
-        my @dodbins = grep {/^dodododododododododododododododo/} @new_meta;
-        if (@dodbins) {
-	  # package was built with other data than we had, refresh repos and redo check
-	  my $rerun;
-	  s/^.*  // for @dodbins;
-	  for my $bin (@dodbins) {
-	    my $p = $dep2pkg{$bin};
-	    next unless $p;
-	    my $dodprp = $pool->pkg2reponame($p);
-	    next unless $dodprp;
-	    delete $repodatas{$dodprp};
-	    $rerun = 1;
-	  }
-	  if ($rerun) {
-	    unshift @lookat_high, $prp unless @lookat_high && $lookat_high[0] eq $prp;
-	    $nharder++;
-	    $lastcheck{"$prp/$packid"} = $mylastcheck;
-	    $packstatus{$packid} = 'done';
-	    goto relsynccheck;
-	  }
-	}
-      }
+#      if (($BSConfig::enable_download_on_demand || $BSConfig::enable_dod) && @meta == @new_meta) {
+#        # unfetched dod packages have dodo... as hdrid
+#        my @dodbins = grep {/^dodododododododododododododododo/} @new_meta;
+#        if (@dodbins) {
+#	  # package was built with other data than we had, refresh repos and redo check
+#	  my $rerun;
+#	  s/^.*  // for @dodbins;
+#	  for my $bin (@dodbins) {
+#	    my $p = $dep2pkg{$bin};
+#	    next unless $p;
+#	    my $dodprp = $pool->pkg2reponame($p);
+#	    next unless $dodprp;
+#	    delete $repodatas{$dodprp};
+#	    $rerun = 1;
+#	  }
+#	  if ($rerun) {
+#	    unshift @lookat_high, $prp unless @lookat_high && $lookat_high[0] eq $prp;
+#	    $nharder++;
+#	    $lastcheck{"$prp/$packid"} = $mylastcheck;
+#	    $packstatus{$packid} = 'done';
+#	    goto relsynccheck;
+#	  }
+#	}
+#      }
       my @diff = diffsortedmd5(0, \@meta, \@new_meta);
       print "      - $packid ($packtype)\n";
       print "        $_\n" for @diff;
Index: BSSolv.xs
===================================================================
--- BSSolv.xs	(Revision 9328)
+++ BSSolv.xs	(Arbeitskopie)
@@ -44,6 +44,8 @@
 static Id buildservice_id;
 static Id buildservice_repocookie;
 static Id buildservice_external;
+static Id buildservice_dodurl;
+static Id buildservice_dodrpath;
 
 /* make sure bit n is usable */
 #define MAPEXP(m, n) ((m)->size < (((n) + 8) >> 3) ? map_grow(m, n + 256) : 0)
@@ -545,6 +547,8 @@
 	continue;
       FOR_REPO_SOLVABLES(repo, p, s)
 	{
+          //printf("processing name: %s\n", id2str(pool, s->name));
+          //fflush(stdout);
 	  if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
 	    continue;
 	  pb = best[s->name];
@@ -578,8 +582,12 @@
 			continue;
 		    }
 		}
-	      else
-		continue;
+	      else {
+                const char *bsid = solvable_lookup_str(sb, buildservice_id);
+                /* solvables are identical - don't take the one without bsid */
+                if (bsid)
+		  continue;
+              }
 	      MAPCLR(considered, pb);
 	    }
 	  best[s->name] = p;
@@ -1112,6 +1120,8 @@
 	    buildservice_id = str2id(pool, "buildservice:id", 1);
 	    buildservice_repocookie= str2id(pool, "buildservice:repocookie", 1);
 	    buildservice_external = str2id(pool, "buildservice:external", 1);
+            buildservice_dodurl = str2id(pool, "buildservice:dodurl", 1);
+            buildservice_dodrpath = str2id(pool, "buildservice:dodrpath", 1);
 	    pool_freeidhashes(pool);
 	    RETVAL = pool;
 	}
@@ -1248,6 +1258,9 @@
 		      ss = str;
 		    repodata_set_str(data, p, SOLVABLE_MEDIAFILE, ss);
 		  }
+                str = hvlookupstr(hv, "rpath", 5);
+                if (str)
+                  repodata_set_str(data, p, buildservice_dodrpath, str);
 		str = hvlookupstr(hv, "id", 2);
 		if (str)
 		  repodata_set_str(data, p, buildservice_id, str);
@@ -1297,6 +1310,9 @@
 	    repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
 	    if (name && !strcmp(name, "/external/"))
 	      repodata_set_void(data, SOLVID_META, buildservice_external);
+            str = hvlookupstr(rhv, "/url", 4);
+            if (str)
+              repodata_set_str(data, SOLVID_META, buildservice_dodurl, str);
 	    repo_internalize(repo);
 	    RETVAL = repo;
 	}
@@ -1411,6 +1427,15 @@
 	RETVAL
 	
 const char *
+pkg2rpath(BSSolv::pool pool, int p)
+    CODE:
+	{
+	    RETVAL = solvable_lookup_str(pool->solvables + p, buildservice_dodrpath);
+	}
+    OUTPUT:
+	RETVAL
+
+const char *
 pkg2fullpath(BSSolv::pool pool, int p, char *myarch)
     CODE:
 	{
@@ -1624,8 +1649,13 @@
 		FOR_REPO_SOLVABLES(repo, p, s)
 		  {
 		    const char *str = solvable_lookup_str(s, buildservice_id);
-		    if (!str)
-		      continue;
+		    if (!str) {
+                      const char *url = repo_lookup_str(repo, SOLVID_META, buildservice_dodurl);
+                      if (url)
+                        /* keep all packages which have no stat() id (dod pkgs) */
+                        MAPSET(&reused, p - repo->start);
+                      continue;
+                    }
 		    h = strhash(str) & hm;
 		    hh = HASHCHAIN_START;
 		    while ((id = ht[h]) != 0)
@@ -1754,6 +1784,12 @@
     OUTPUT:
 	RETVAL
 
+const char *
+hasdodurl(BSSolv::repo repo)
+    CODE:
+        RETVAL = repo_lookup_str(repo, SOLVID_META, buildservice_dodurl);
+    OUTPUT:
+        RETVAL
 
 
 
