cleanup example code
authorMichael Schroeder <mls@suse.de>
Tue, 27 Nov 2012 14:24:40 +0000 (15:24 +0100)
committerMichael Schroeder <mls@suse.de>
Tue, 27 Nov 2012 14:24:40 +0000 (15:24 +0100)
examples/p5solv
examples/pysolv
examples/rbsolv

index 2a7648f..56edbd5 100755 (executable)
@@ -493,11 +493,19 @@ sub load_stub {
 
 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 %cmdabbrev = ( 'li' => 'list', 'in' => 'install', 'rm' => 'erase',
+                  've' => 'verify', 'se' => 'search' );
+$cmd = $cmdabbrev{$cmd} if $cmdabbrev{$cmd};
+
+my %cmdactionmap = (
+  'install' => $solv::Job::SOLVER_INSTALL,
+  'erase'   => $solv::Job::SOLVER_ERASE,
+  'up'      => $solv::Job::SOLVER_UPDATE,
+  'dup'     => $solv::Job::SOLVER_DISTUPGRADE,
+  'verify'  => $solv::Job::SOLVER_VERIFY,
+  'list'    => 0,  
+  'info'    => 0,
+);
 
 my @repos;
 my @reposdirs;
@@ -540,18 +548,20 @@ for my $repo (@repos) {
 }
 
 if ($cmd eq 'search') {
-  my %matches;
+  $pool->createwhatprovides();
+  my $sel = $pool->Selection();
   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;
+    $sel->add_raw($solv::Job::SOLVER_SOLVABLE, $d->{'solvid'});
   }
-  for my $solvid (sort keys %matches) {
-    my $s = $pool->{'solvables'}->[$solvid];
-    print "- ".$s->str()." [$s->{'repo'}->{'name'}] ".$s->lookup_str($solv::SOLVABLE_SUMMARY)."\n";
+  for my $s ($sel->solvables()) {
+    print "- ".$s->str()." [$s->{'repo'}->{'name'}]: ".$s->lookup_str($solv::SOLVABLE_SUMMARY)."\n";
   }
   exit(0);
 }
 
+die("unknown command '$cmd'\n") unless defined $cmdactionmap{$cmd};
+
 my @addedprovides = $pool->addfileprovides_queue();
 $pool->createwhatprovides();
 
@@ -570,16 +580,18 @@ for my $arg (@ARGV) {
   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);
+  push @jobs, $sel->jobs($cmdactionmap{$cmd});
 }
+
 if (!@jobs && ($cmd eq 'up' || $cmd eq 'dup' || $cmd eq 'verify')) {
   my $sel = $pool->Selection();
   $sel->add_raw($solv::Job::SOLVER_SOLVABLE_ALL, 0);
-  push @jobs, $sel->jobs(0);
+  push @jobs, $sel->jobs($cmdactionmap{$cmd});
 }
 
+die("no package matched.\n") unless @jobs;
+
 if ($cmd eq 'list' || $cmd eq 'info') {
-  die("no package matched.\n") unless @jobs;
   for my $job (@jobs) {
     for my $s ($job->solvables()) {
       if ($cmd eq 'info') {
@@ -600,145 +612,138 @@ if ($cmd eq 'list' || $cmd eq 'info') {
   exit 0;
 }
 
-if ($cmd eq 'install' || $cmd eq 'erase' || $cmd eq 'up' || $cmd eq 'dup' || $cmd eq 'verify') {
-  die("no package matched.\n") unless @jobs;
-  for my $job (@jobs) {
-    if ($cmd eq 'up') {
-      $job->{'how'} |= $solv::Job::SOLVER_UPDATE;
-      $job->{'how'} ^= $solv::Job::SOLVER_UPDATE ^ $solv::Job::SOLVER_INSTALL if $job->isemptyupdate();
-    } 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->Solver();
-    $solver->set_flag($solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1);
-    $solver->set_flag($solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if $cmd eq 'erase';
-    my @problems = $solver->solve(\@jobs);
-    last unless @problems;
-    for my $problem (@problems) {
-      print "Problem $problem->{'id'}/".@problems.":\n";
-      my $r = $problem->findproblemrule();
-      my $ri = $r->info();
-      print $ri->problemstr()."\n";
-      my @solutions = $problem->solutions();
-      for my $solution (@solutions) {
-       print "  Solution $solution->{'id'}:\n";
-       for my $element ($solution->elements(1)) {
-         print "  - ".$element->str()."\n";
-       }
-       print "\n";
-      }
-      my $sol;
-      while (1) {
-       print "Please choose a solution: ";
-       $sol = <STDIN>;
-       chomp $sol;
-       last if $sol eq 's' || $sol eq 'q' || ($sol =~ /^\d+$/ && $sol >= 1 && $sol <= @solutions);
-      }
-      next if $sol eq 's';
-      exit(1) if $sol eq 'q';
-      my $solution = $solutions[$sol - 1];
-      for my $element ($solution->elements()) {
-       my $newjob = $element->Job();
-       if ($element->{'type'} == $solv::Solver::SOLVER_SOLUTION_JOB) {
-         $jobs[$element->{'jobidx'}] = $newjob;
-       } else {
-         push @jobs, $newjob if $newjob && !grep {$_ == $newjob} @jobs;
-       }
+# up magic, turn into install if nothing matches
+for my $job (@jobs) {
+  $job->{'how'} ^= $solv::Job::SOLVER_UPDATE ^ $solv::Job::SOLVER_INSTALL if $cmd eq 'up' && $job->isemptyupdate();
+}
+
+my $solver;
+while (1) {
+  $solver = $pool->Solver();
+  $solver->set_flag($solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1);
+  $solver->set_flag($solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if $cmd eq 'erase';
+  my @problems = $solver->solve(\@jobs);
+  last unless @problems;
+  for my $problem (@problems) {
+    print "Problem $problem->{'id'}/".@problems.":\n";
+    my $r = $problem->findproblemrule();
+    my $ri = $r->info();
+    print $ri->problemstr()."\n";
+    my @solutions = $problem->solutions();
+    for my $solution (@solutions) {
+      print "  Solution $solution->{'id'}:\n";
+      for my $element ($solution->elements(1)) {
+       print "  - ".$element->str()."\n";
       }
+      print "\n";
     }
-  }
-  my $trans = $solver->transaction();
-  undef $solver;
-  if ($trans->isempty()) {
-    print "Nothing to do.\n";
-    exit 0;
-  }
-  print "\nTransaction summary:\n\n";
-  for my $c ($trans->classify()) {
-    if ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_ERASE) {
-      print "$c->{'count'} erased packages:\n";
-    } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_INSTALL) {
-      print "$c->{'count'} installed packages:\n";
-    } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_REINSTALLED) {
-      print "$c->{'count'} reinstalled packages:\n";
-    } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED) {
-      print "$c->{'count'} downgraded packages:\n";
-    } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_CHANGED) {
-      print "$c->{'count'} changed packages:\n";
-    } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_UPGRADED) {
-      print "$c->{'count'} upgraded packages:\n";
-    } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE) {
-      printf "$c->{'count'} vendor changes from '%s' to '%s':\n", $c->fromdep()->str(), $c->todep()->str();
-    } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE) {
-      printf "$c->{'count'} arch changes from '%s' to '%s':\n", $c->fromdep()->str(), $c->todep()->str();
-    } else {
-      next;
+    my $sol;
+    while (1) {
+      print "Please choose a solution: ";
+      $sol = <STDIN>;
+      chomp $sol;
+      last if $sol eq 's' || $sol eq 'q' || ($sol =~ /^\d+$/ && $sol >= 1 && $sol <= @solutions);
     }
-    for my $p ($c->solvables()) {
-      if ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_UPGRADED || $c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED) {
-       my $other = $trans->othersolvable($p);
-       printf "  - %s -> %s\n", $p->str(), $other->str();
+    next if $sol eq 's';
+    exit(1) if $sol eq 'q';
+    my $solution = $solutions[$sol - 1];
+    for my $element ($solution->elements()) {
+      my $newjob = $element->Job();
+      if ($element->{'type'} == $solv::Solver::SOLVER_SOLUTION_JOB) {
+       $jobs[$element->{'jobidx'}] = $newjob;
       } else {
-       printf "  - %s\n", $p->str();
+       push @jobs, $newjob if $newjob && !grep {$_ == $newjob} @jobs;
       }
     }
-    print "\n";
-  }
-  printf "install size change: %d K\n\n", $trans->calc_installsizechange();
-  while (1) {
-    print("OK to continue (y/n)? ");
-    my $yn = <STDIN>;
-    chomp $yn;
-    last if $yn eq 'y';
-    exit(1) if $yn eq 'n';
-  }
-  my @newpkgs = $trans->newpackages();
-  my %newpkgsfps;
-  if (@newpkgs) {
-    my $downloadsize = 0;
-    $downloadsize += $_->lookup_num($solv::SOLVABLE_DOWNLOADSIZE) for @newpkgs;
-    printf "Downloading %d packages, %d K\n", scalar(@newpkgs), $downloadsize;
-    for my $p (@newpkgs) {
-      my $repo = $p->{'repo'}->{'appdata'};
-      my ($location, $medianr) = $p->lookup_location();
-      next unless $location;
-      $location = $repo->packagespath() . $location;
-      my $chksum = $p->lookup_checksum($solv::SOLVABLE_CHECKSUM);
-      my $f = $repo->download($location, 0, $chksum);
-      die("\n$repo->{'alias'}: $location not found in repository\n") unless $f;
-      $newpkgsfps{$p->{'id'}} = $f;
-      print ".";
-      STDOUT->flush();
-    }
-    print "\n";
-  }
-  print "Committing transaction:\n\n";
-  $trans->order(0);
-  for my $p ($trans->steps()) {
-    my $steptype = $trans->steptype($p, $solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY);
-    if ($steptype == $solv::Transaction::SOLVER_TRANSACTION_ERASE) {
-      print "erase ".$p->str()."\n";
-      next unless $p->lookup_num($solv::RPM_RPMDBID);
-      my $evr = $p->{'evr'};
-      $evr =~ s/^[0-9]+://;    # strip epoch
-      system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "$p->{'name'}-$evr.$p->{'arch'}") && die("rpm failed: $?\n");
-    } elsif ($steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL || $steptype == $solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL) {
-      print "install ".$p->str()."\n";
-      my $f = $newpkgsfps{$p->{'id'}};
-      my $mode = $steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i';
-      system('rpm', $mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/".$f->fileno()) && die("rpm failed: $?\n");
-      delete $newpkgsfps{$p->{'id'}};
+  }
+}
+
+my $trans = $solver->transaction();
+undef $solver;
+if ($trans->isempty()) {
+  print "Nothing to do.\n";
+  exit 0;
+}
+
+print "\nTransaction summary:\n\n";
+for my $c ($trans->classify()) {
+  if ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_ERASE) {
+    print "$c->{'count'} erased packages:\n";
+  } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_INSTALL) {
+    print "$c->{'count'} installed packages:\n";
+  } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_REINSTALLED) {
+    print "$c->{'count'} reinstalled packages:\n";
+  } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED) {
+    print "$c->{'count'} downgraded packages:\n";
+  } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_CHANGED) {
+    print "$c->{'count'} changed packages:\n";
+  } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_UPGRADED) {
+    print "$c->{'count'} upgraded packages:\n";
+  } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE) {
+    printf "$c->{'count'} vendor changes from '%s' to '%s':\n", $c->fromdep()->str(), $c->todep()->str();
+  } elsif ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE) {
+    printf "$c->{'count'} arch changes from '%s' to '%s':\n", $c->fromdep()->str(), $c->todep()->str();
+  } else {
+    next;
+  }
+  for my $p ($c->solvables()) {
+    if ($c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_UPGRADED || $c->{'type'} == $solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED) {
+      my $other = $trans->othersolvable($p);
+      printf "  - %s -> %s\n", $p->str(), $other->str();
+    } else {
+      printf "  - %s\n", $p->str();
     }
   }
+  print "\n";
+}
+printf "install size change: %d K\n\n", $trans->calc_installsizechange();
+
+while (1) {
+  print("OK to continue (y/n)? ");
+  my $yn = <STDIN>;
+  chomp $yn;
+  last if $yn eq 'y';
+  exit(1) if $yn eq 'n';
+}
+
+my @newpkgs = $trans->newpackages();
+my %newpkgsfps;
+if (@newpkgs) {
+  my $downloadsize = 0;
+  $downloadsize += $_->lookup_num($solv::SOLVABLE_DOWNLOADSIZE) for @newpkgs;
+  printf "Downloading %d packages, %d K\n", scalar(@newpkgs), $downloadsize;
+  for my $p (@newpkgs) {
+    my $repo = $p->{'repo'}->{'appdata'};
+    my ($location, $medianr) = $p->lookup_location();
+    next unless $location;
+    $location = $repo->packagespath() . $location;
+    my $chksum = $p->lookup_checksum($solv::SOLVABLE_CHECKSUM);
+    my $f = $repo->download($location, 0, $chksum);
+    die("\n$repo->{'alias'}: $location not found in repository\n") unless $f;
+    $newpkgsfps{$p->{'id'}} = $f;
+    print ".";
+    STDOUT->flush();
+  }
+  print "\n";
+}
+
+print "Committing transaction:\n\n";
+$trans->order(0);
+for my $p ($trans->steps()) {
+  my $steptype = $trans->steptype($p, $solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY);
+  if ($steptype == $solv::Transaction::SOLVER_TRANSACTION_ERASE) {
+    print "erase ".$p->str()."\n";
+    next unless $p->lookup_num($solv::RPM_RPMDBID);
+    my $evr = $p->{'evr'};
+    $evr =~ s/^[0-9]+://;      # strip epoch
+    system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "$p->{'name'}-$evr.$p->{'arch'}") && die("rpm failed: $?\n");
+  } elsif ($steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL || $steptype == $solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL) {
+    print "install ".$p->str()."\n";
+    my $f = $newpkgsfps{$p->{'id'}};
+    my $mode = $steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i';
+    system('rpm', $mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/".$f->fileno()) && die("rpm failed: $?\n");
+    delete $newpkgsfps{$p->{'id'}};
+  }
 }
 
 exit 0;
index 0285e4d..23cdd98 100755 (executable)
@@ -576,17 +576,20 @@ if not args:
 
 cmd = args[0]
 args = args[1:]
-if cmd == 'li':
-    cmd = 'list'
-if cmd == 'in':
-    cmd = 'install'
-if cmd == 'rm':
-    cmd = 'erase'
-if cmd == 've':
-    cmd = 'verify'
-if cmd == 'se':
-    cmd = 'search'
 
+cmdabbrev = {'li': 'list', 'in': 'install', 'rm': 'erase', 've': 'verify', 'se': 'search'}
+if cmd in cmdabbrev:
+    cmd = cmdabbrev[cmd]
+
+cmdactionmap = {
+  'install': Job.SOLVER_INSTALL,
+  'erase':   Job.SOLVER_ERASE,
+  'up':      Job.SOLVER_UPDATE,
+  'dup':     Job.SOLVER_DISTUPGRADE,
+  'verify':  Job.SOLVER_VERIFY,
+  'list':    0,
+  'info':    0
+}
 
 # read all repo configs
 repos = []
@@ -653,6 +656,10 @@ if cmd == 'search':
         print " - %s [%s]: %s" % (s, s.repo.name, s.lookup_str(solv.SOLVABLE_SUMMARY))
     sys.exit(0)
 
+if cmd not in cmdactionmap:
+    print "unknown command", cmd
+    sys.exit(1)
+
 cmdlinerepo = None
 if cmd == 'list' or cmd == 'info' or cmd == 'install':
     for arg in args:
@@ -700,19 +707,20 @@ for arg in args:
             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)
+        jobs += sel.jobs(cmdactionmap[cmd])
 
 if not jobs and (cmd == 'up' or cmd == 'dup' or cmd == 'verify' or repolimiter):
     sel = pool.Selection()
     sel.add_raw(Job.SOLVER_SOLVABLE_ALL, 0)
     if repolimiter:
        sel.limit(repolimiter)
-    jobs += sel.jobs(0)
+    jobs += sel.jobs(cmdactionmap[cmd])
+
+if not jobs:
+    print "no package matched."
+    sys.exit(1)
 
 if cmd == 'list' or cmd == 'info':
-    if not jobs:
-        print "no package matched."
-        sys.exit(1)
     for job in jobs:
         for s in job.solvables():
             if cmd == 'info':
@@ -732,220 +740,203 @@ if cmd == 'list' or cmd == 'info':
                 print "    %s" % s.lookup_str(solv.SOLVABLE_SUMMARY)
     sys.exit(0)
 
-if cmd == 'install' or cmd == 'erase' or cmd == 'up' or cmd == 'dup' or cmd == 'verify':
-    if not jobs:
-        print "no package matched."
-        sys.exit(1)
-    for job in jobs:
-        if cmd == 'up':
-            job.how |= Job.SOLVER_UPDATE
-            # up magic: use install instead of update if no installed package matches
-            if job.isemptyupdate():
-                job.how ^= Job.SOLVER_UPDATE ^ Job.SOLVER_INSTALL
-        elif cmd == 'install':
-            job.how |= Job.SOLVER_INSTALL
-        elif cmd == 'erase':
-            job.how |= Job.SOLVER_ERASE
-        elif cmd == 'dup':
-            job.how |= Job.SOLVER_DISTUPGRADE
-        elif cmd == 'verify':
-            job.how |= Job.SOLVER_VERIFY
-
-    #pool.set_debuglevel(2)
-    solver = None
-    while True:
-        solver = pool.Solver()
-        solver.set_flag(Solver.SOLVER_FLAG_SPLITPROVIDES, 1);
-        if cmd == 'erase':
-            solver.set_flag(Solver.SOLVER_FLAG_ALLOW_UNINSTALL, 1);
-        problems = solver.solve(jobs)
-        if not problems:
-            break
-        for problem in problems:
-            print "Problem %d:" % problem.id
-            r = problem.findproblemrule()
-            ri = r.info()
-            print ri.problemstr()
-            solutions = problem.solutions()
-            for solution in solutions:
-                print "  Solution %d:" % solution.id
-                elements = solution.elements(True)
-                for element in elements:
-                    print "  - %s" % element.str()
-                print
-            sol = ''
-            while not (sol == 's' or sol == 'q' or (sol.isdigit() and int(sol) >= 1 and int(sol) <= len(solutions))):
-                sys.stdout.write("Please choose a solution: ")
-                sys.stdout.flush()
-                sol = sys.stdin.readline().strip()
-            if sol == 's':
-                continue        # skip problem
-            if sol == 'q':
-                sys.exit(1)
-            solution = solutions[int(sol) - 1]
-            for element in solution.elements():
-                newjob = element.Job()
-                if element.type == Solver.SOLVER_SOLUTION_JOB:
-                    jobs[element.jobidx] = newjob
-                else:
-                    if newjob and newjob not in jobs:
-                        jobs.append(newjob)
-                        
-    # no problems, show transaction
-    trans = solver.transaction()
-    del solver
-    if trans.isempty():
-        print "Nothing to do."
-        sys.exit(0)
-    print
-    print "Transaction summary:"
-    print
-    for cl in trans.classify():
-        if cl.type == Transaction.SOLVER_TRANSACTION_ERASE:
-            print "%d erased packages:" % cl.count
-        elif cl.type == Transaction.SOLVER_TRANSACTION_INSTALL:
-            print "%d installed packages:" % cl.count
-        elif cl.type == Transaction.SOLVER_TRANSACTION_REINSTALLED:
-            print "%d reinstalled packages:" % cl.count
-        elif cl.type == Transaction.SOLVER_TRANSACTION_DOWNGRADED:
-            print "%d downgraded packages:" % cl.count
-        elif cl.type == Transaction.SOLVER_TRANSACTION_CHANGED:
-            print "%d changed packages:" % cl.count
-        elif cl.type == Transaction.SOLVER_TRANSACTION_UPGRADED:
-            print "%d upgraded packages:" % cl.count
-        elif cl.type == Transaction.SOLVER_TRANSACTION_VENDORCHANGE:
-            print "%d vendor changes from '%s' to '%s':" % (cl.count, cl.fromdep(), cl.todep())
-        elif cl.type == Transaction.SOLVER_TRANSACTION_ARCHCHANGE:
-            print "%d arch changes from '%s' to '%s':" % (cl.count, cl.fromdep(), cl.todep())
-        else:
-            continue
-        for p in cl.solvables():
-            if cl.type == Transaction.SOLVER_TRANSACTION_UPGRADED or cl.type == Transaction.SOLVER_TRANSACTION_DOWNGRADED:
-                op = trans.othersolvable(p)
-                print "  - %s -> %s" % (p, op)
+# up magic: use install instead of update if no installed package matches
+for job in jobs:
+    if cmd == 'up' and job.isemptyupdate():
+        job.how ^= Job.SOLVER_UPDATE ^ Job.SOLVER_INSTALL
+
+#pool.set_debuglevel(2)
+solver = None
+while True:
+    solver = pool.Solver()
+    solver.set_flag(Solver.SOLVER_FLAG_SPLITPROVIDES, 1);
+    if cmd == 'erase':
+        solver.set_flag(Solver.SOLVER_FLAG_ALLOW_UNINSTALL, 1);
+    problems = solver.solve(jobs)
+    if not problems:
+        break
+    for problem in problems:
+        print "Problem %d:" % problem.id
+        r = problem.findproblemrule()
+        ri = r.info()
+        print ri.problemstr()
+        solutions = problem.solutions()
+        for solution in solutions:
+            print "  Solution %d:" % solution.id
+            elements = solution.elements(True)
+            for element in elements:
+                print "  - %s" % element.str()
+            print
+        sol = ''
+        while not (sol == 's' or sol == 'q' or (sol.isdigit() and int(sol) >= 1 and int(sol) <= len(solutions))):
+            sys.stdout.write("Please choose a solution: ")
+            sys.stdout.flush()
+            sol = sys.stdin.readline().strip()
+        if sol == 's':
+            continue        # skip problem
+        if sol == 'q':
+            sys.exit(1)
+        solution = solutions[int(sol) - 1]
+        for element in solution.elements():
+            newjob = element.Job()
+            if element.type == Solver.SOLVER_SOLUTION_JOB:
+                jobs[element.jobidx] = newjob
             else:
-                print "  - %s" % p
-        print
-    print "install size change: %d K" % trans.calc_installsizechange()
+                if newjob and newjob not in jobs:
+                    jobs.append(newjob)
+                    
+# no problems, show transaction
+trans = solver.transaction()
+del solver
+if trans.isempty():
+    print "Nothing to do."
+    sys.exit(0)
+print
+print "Transaction summary:"
+print
+for cl in trans.classify():
+    if cl.type == Transaction.SOLVER_TRANSACTION_ERASE:
+        print "%d erased packages:" % cl.count
+    elif cl.type == Transaction.SOLVER_TRANSACTION_INSTALL:
+        print "%d installed packages:" % cl.count
+    elif cl.type == Transaction.SOLVER_TRANSACTION_REINSTALLED:
+        print "%d reinstalled packages:" % cl.count
+    elif cl.type == Transaction.SOLVER_TRANSACTION_DOWNGRADED:
+        print "%d downgraded packages:" % cl.count
+    elif cl.type == Transaction.SOLVER_TRANSACTION_CHANGED:
+        print "%d changed packages:" % cl.count
+    elif cl.type == Transaction.SOLVER_TRANSACTION_UPGRADED:
+        print "%d upgraded packages:" % cl.count
+    elif cl.type == Transaction.SOLVER_TRANSACTION_VENDORCHANGE:
+        print "%d vendor changes from '%s' to '%s':" % (cl.count, cl.fromdep(), cl.todep())
+    elif cl.type == Transaction.SOLVER_TRANSACTION_ARCHCHANGE:
+        print "%d arch changes from '%s' to '%s':" % (cl.count, cl.fromdep(), cl.todep())
+    else:
+        continue
+    for p in cl.solvables():
+        if cl.type == Transaction.SOLVER_TRANSACTION_UPGRADED or cl.type == Transaction.SOLVER_TRANSACTION_DOWNGRADED:
+            op = trans.othersolvable(p)
+            print "  - %s -> %s" % (p, op)
+        else:
+            print "  - %s" % p
     print
-    
-    while True:
-        sys.stdout.write("OK to continue (y/n)? ")
-        sys.stdout.flush()
-        yn = sys.stdin.readline().strip()
-        if yn == 'y': break
-        if yn == 'n': sys.exit(1)
-    newpkgs = trans.newpackages()
-    newpkgsfp = {}
-    if newpkgs:
-        downloadsize = 0
-        for p in newpkgs:
-            downloadsize += p.lookup_num(solv.SOLVABLE_DOWNLOADSIZE)
-        print "Downloading %d packages, %d K" % (len(newpkgs), downloadsize)
-        for p in newpkgs:
-            repo = p.repo.appdata
-            location, medianr = p.lookup_location()
-            if not location:
-                continue
-            if repo.type == 'commandline':
-                f = solv.xfopen(location)
-                if not f:
-                    sys.exit("\n%s: %s not found" % location)
-                newpkgsfp[p.id] = f
-                continue
-            if not sysrepo.handle.isempty() and os.access('/usr/bin/applydeltarpm', os.X_OK):
-                pname = p.name
-                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:
-                    dp = d.parentpos()
-                    if dp.lookup_id(solv.DELTA_PACKAGE_EVR) != p.evrid or dp.lookup_id(solv.DELTA_PACKAGE_ARCH) != p.archid:
-                        continue
-                    baseevrid = dp.lookup_id(solv.DELTA_BASE_EVR)
-                    candidate = None
-                    for installedp in pool.whatprovides(p.nameid):
-                        if installedp.isinstalled() and installedp.nameid == p.nameid and installedp.archid == p.archid and installedp.evrid == baseevrid:
-                            candidate = installedp
-                    if not candidate:
-                        continue
-                    seq = dp.lookup_deltaseq()
-                    st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, '-c', '-s', seq])
-                    if st:
-                        continue
-                    chksum = dp.lookup_checksum(solv.DELTA_CHECKSUM)
-                    if not chksum:
-                        continue
-                    dloc, dmedianr = dp.lookup_deltalocation()
-                    dloc = repo.packagespath() + dloc
-                    f = repo.download(dloc, False, chksum)
-                    if not f:
-                        continue
-                    nf = tempfile.TemporaryFile()
-                    nf = os.dup(nf.fileno())   # get rid of CLOEXEC
-                    st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, "/dev/fd/%d" % f.fileno(), "/dev/fd/%d" % nf])
-                    os.lseek(nf, 0, os.SEEK_SET)
-                    newpkgsfp[p.id] = solv.xfopen_fd("", nf)
-                    os.close(nf)
-                    break
-                if p.id in newpkgsfp:
-                    sys.stdout.write("d")
-                    sys.stdout.flush()
-                    continue
-                        
-            chksum = p.lookup_checksum(solv.SOLVABLE_CHECKSUM)
-            location = repo.packagespath() + location
-            f = repo.download(location, False, chksum)
+print "install size change: %d K" % trans.calc_installsizechange()
+print
+
+while True:
+    sys.stdout.write("OK to continue (y/n)? ")
+    sys.stdout.flush()
+    yn = sys.stdin.readline().strip()
+    if yn == 'y': break
+    if yn == 'n': sys.exit(1)
+newpkgs = trans.newpackages()
+newpkgsfp = {}
+if newpkgs:
+    downloadsize = 0
+    for p in newpkgs:
+        downloadsize += p.lookup_num(solv.SOLVABLE_DOWNLOADSIZE)
+    print "Downloading %d packages, %d K" % (len(newpkgs), downloadsize)
+    for p in newpkgs:
+        repo = p.repo.appdata
+        location, medianr = p.lookup_location()
+        if not location:
+            continue
+        if repo.type == 'commandline':
+            f = solv.xfopen(location)
             if not f:
-                sys.exit("\n%s: %s not found in repository" % (repo.name, location))
+                sys.exit("\n%s: %s not found" % location)
             newpkgsfp[p.id] = f
-            sys.stdout.write(".")
-            sys.stdout.flush()
-        print
-    print "Committing transaction:"
+            continue
+        if not sysrepo.handle.isempty() and os.access('/usr/bin/applydeltarpm', os.X_OK):
+            pname = p.name
+            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:
+                dp = d.parentpos()
+                if dp.lookup_id(solv.DELTA_PACKAGE_EVR) != p.evrid or dp.lookup_id(solv.DELTA_PACKAGE_ARCH) != p.archid:
+                    continue
+                baseevrid = dp.lookup_id(solv.DELTA_BASE_EVR)
+                candidate = None
+                for installedp in pool.whatprovides(p.nameid):
+                    if installedp.isinstalled() and installedp.nameid == p.nameid and installedp.archid == p.archid and installedp.evrid == baseevrid:
+                        candidate = installedp
+                if not candidate:
+                    continue
+                seq = dp.lookup_deltaseq()
+                st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, '-c', '-s', seq])
+                if st:
+                    continue
+                chksum = dp.lookup_checksum(solv.DELTA_CHECKSUM)
+                if not chksum:
+                    continue
+                dloc, dmedianr = dp.lookup_deltalocation()
+                dloc = repo.packagespath() + dloc
+                f = repo.download(dloc, False, chksum)
+                if not f:
+                    continue
+                nf = tempfile.TemporaryFile()
+                nf = os.dup(nf.fileno())   # get rid of CLOEXEC
+                st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, "/dev/fd/%d" % f.fileno(), "/dev/fd/%d" % nf])
+                os.lseek(nf, 0, os.SEEK_SET)
+                newpkgsfp[p.id] = solv.xfopen_fd("", nf)
+                os.close(nf)
+                break
+            if p.id in newpkgsfp:
+                sys.stdout.write("d")
+                sys.stdout.flush()
+                continue
+                    
+        chksum = p.lookup_checksum(solv.SOLVABLE_CHECKSUM)
+        location = repo.packagespath() + location
+        f = repo.download(location, False, chksum)
+        if not f:
+            sys.exit("\n%s: %s not found in repository" % (repo.name, location))
+        newpkgsfp[p.id] = f
+        sys.stdout.write(".")
+        sys.stdout.flush()
     print
-    ts = rpm.TransactionSet('/')
-    ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES)
-    erasenamehelper = {}
-    for p in trans.steps():
-        type = trans.steptype(p, Transaction.SOLVER_TRANSACTION_RPM_ONLY)
-        if type == Transaction.SOLVER_TRANSACTION_ERASE:
-            rpmdbid = p.lookup_num(solv.RPM_RPMDBID)
-            erasenamehelper[p.name] = p
-            if not rpmdbid:
-                sys.exit("\ninternal error: installed package %s has no rpmdbid\n" % p)
-            ts.addErase(rpmdbid)
-        elif type == Transaction.SOLVER_TRANSACTION_INSTALL:
-            f = newpkgsfp[p.id]
-            h = ts.hdrFromFdno(f.fileno())
-            os.lseek(f.fileno(), 0, os.SEEK_SET)
-            ts.addInstall(h, p, 'u')
-        elif type == Transaction.SOLVER_TRANSACTION_MULTIINSTALL:
-            f = newpkgsfp[p.id]
-            h = ts.hdrFromFdno(f.fileno())
-            os.lseek(f.fileno(), 0, os.SEEK_SET)
-            ts.addInstall(h, p, 'i')
-    checkproblems = ts.check()
-    if checkproblems:
-        print checkproblems
-        sys.exit("Sorry.")
-    ts.order()
-    def runCallback(reason, amount, total, p, d):
-        if reason == rpm.RPMCALLBACK_INST_OPEN_FILE:
-            return newpkgsfp[p.id].fileno()
-        if reason == rpm.RPMCALLBACK_INST_START:
-            print "install", p
-        if reason == rpm.RPMCALLBACK_UNINST_START:
-            # argh, p is just the name of the package
-            if p in erasenamehelper:
-                p = erasenamehelper[p]
-                print "erase", p
-    runproblems = ts.run(runCallback, '')
-    if runproblems:
-        print runproblems
-        sys.exit(1)
-    sys.exit(0)
-
-print "unknown command", cmd
-sys.exit(1)
+print "Committing transaction:"
+print
+ts = rpm.TransactionSet('/')
+ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES)
+erasenamehelper = {}
+for p in trans.steps():
+    type = trans.steptype(p, Transaction.SOLVER_TRANSACTION_RPM_ONLY)
+    if type == Transaction.SOLVER_TRANSACTION_ERASE:
+        rpmdbid = p.lookup_num(solv.RPM_RPMDBID)
+        erasenamehelper[p.name] = p
+        if not rpmdbid:
+            sys.exit("\ninternal error: installed package %s has no rpmdbid\n" % p)
+        ts.addErase(rpmdbid)
+    elif type == Transaction.SOLVER_TRANSACTION_INSTALL:
+        f = newpkgsfp[p.id]
+        h = ts.hdrFromFdno(f.fileno())
+        os.lseek(f.fileno(), 0, os.SEEK_SET)
+        ts.addInstall(h, p, 'u')
+    elif type == Transaction.SOLVER_TRANSACTION_MULTIINSTALL:
+        f = newpkgsfp[p.id]
+        h = ts.hdrFromFdno(f.fileno())
+        os.lseek(f.fileno(), 0, os.SEEK_SET)
+        ts.addInstall(h, p, 'i')
+checkproblems = ts.check()
+if checkproblems:
+    print checkproblems
+    sys.exit("Sorry.")
+ts.order()
+def runCallback(reason, amount, total, p, d):
+    if reason == rpm.RPMCALLBACK_INST_OPEN_FILE:
+        return newpkgsfp[p.id].fileno()
+    if reason == rpm.RPMCALLBACK_INST_START:
+        print "install", p
+    if reason == rpm.RPMCALLBACK_UNINST_START:
+        # argh, p is just the name of the package
+        if p in erasenamehelper:
+            p = erasenamehelper[p]
+            print "erase", p
+runproblems = ts.run(runCallback, '')
+if runproblems:
+    print runproblems
+    sys.exit(1)
+sys.exit(0)
 
 # vim: sw=4 et
index 61b35af..b9db10d 100755 (executable)
@@ -500,11 +500,20 @@ 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'
+
+cmdabbrev = { 'li' => 'list', 'in' => 'install', 'rm' => 'erase',
+              've' => 'verify', 'se' => 'search' }
+cmd = cmdabbrev[cmd] if cmdabbrev.has_key?(cmd)
+
+cmdactionmap = { 
+  'install' => Solv::Job::SOLVER_INSTALL,
+  'erase'   => Solv::Job::SOLVER_ERASE,
+  'up'      => Solv::Job::SOLVER_UPDATE,
+  'dup'     => Solv::Job::SOLVER_DISTUPGRADE,
+  'verify'  => Solv::Job::SOLVER_VERIFY,
+  'list'    => 0,  
+  'info'    => 0,
+}
 
 repos = []
 reposdirs = []
@@ -547,17 +556,19 @@ for repo in repos
 end
 
 if cmd == 'search'
-  matches = {}
+  pool.createwhatprovides()
+  sel = pool.Selection
   for di in pool.Dataiterator(0, Solv::SOLVABLE_NAME, args[0], Solv::Dataiterator::SEARCH_SUBSTRING | Solv::Dataiterator::SEARCH_NOCASE)
-    matches[di.solvid] = true
+    sel.add_raw(Solv::Job::SOLVER_SOLVABLE, di.solvid)
   end
-  for solvid in matches.keys.sort
-    s = pool.solvables[solvid]
-    puts "- #{s.str} [#{s.repo.name}]"
+  for s in sel.solvables
+    puts "- #{s.str} [#{s.repo.name}]: #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
   end
   exit
 end
 
+abort("unknown command '#{cmd}'\n") unless cmdactionmap.has_key?(cmd)
+
 addedprovides = pool.addfileprovides_queue()
 if !addedprovides.empty?
   sysrepo.updateaddedprovides(addedprovides)
@@ -581,179 +592,171 @@ for arg in args
   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)
+  jobs += sel.jobs(cmdactionmap[cmd])
 end
 
 if jobs.empty? && (cmd == 'up' || cmd == 'dup' || cmd == 'verify')
   sel = pool.Selection()
   sel.add_raw(Solv::Job::SOLVER_SOLVABLE_ALL, 0)
-  jobs += sel.jobs(0)
+  jobs += sel.jobs(cmdactionmap[cmd])
 end
 
+abort("no package matched.") if jobs.empty?
+
 if cmd == 'list' || cmd == 'info'
-  abort("no package matched.") if jobs.empty?
-    for job in jobs
-      for s in job.solvables()
-       if cmd == 'info'
-         puts "Name:        #{s.str}"
-         puts "Repo:        #{s.repo.name}"
-         puts "Summary:     #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
-         str = s.lookup_str(Solv::SOLVABLE_URL)
-         puts "Url:         #{str}" if str
-         str = s.lookup_str(Solv::SOLVABLE_LICENSE)
-         puts "License:     #{str}" if str
-         puts "Description:\n#{s.lookup_str(Solv::SOLVABLE_DESCRIPTION)}"
-         puts
-       else
-         puts "  - #{s.str} [#{s.repo.name}]"
-         puts "    #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
-       end
+  for job in jobs
+    for s in job.solvables()
+      if cmd == 'info'
+       puts "Name:        #{s.str}"
+       puts "Repo:        #{s.repo.name}"
+       puts "Summary:     #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
+       str = s.lookup_str(Solv::SOLVABLE_URL)
+       puts "Url:         #{str}" if str
+       str = s.lookup_str(Solv::SOLVABLE_LICENSE)
+       puts "License:     #{str}" if str
+       puts "Description:\n#{s.lookup_str(Solv::SOLVABLE_DESCRIPTION)}"
+       puts
+      else
+       puts "  - #{s.str} [#{s.repo.name}]"
+       puts "    #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
       end
     end
+  end
   exit
 end
 
-if cmd == 'install' || cmd == 'erase' || cmd == 'up' || cmd == 'dup' || cmd == 'verify'
-  abort("no package matched.") if jobs.empty?
-  for job in jobs
-    if cmd == 'up'
-      job.how |= Solv::Job::SOLVER_UPDATE
-      job.how ^= Solv::Job::SOLVER_UPDATE ^ Solv::Job::SOLVER_INSTALL if job.isemptyupdate?
-    elsif cmd == 'install'
-      job.how |= Solv::Job::SOLVER_INSTALL
-    elsif cmd == 'erase'
-      job.how |= Solv::Job::SOLVER_ERASE
-    elsif cmd == 'dup'
-      job.how |= Solv::Job::SOLVER_DISTUPGRADE
-    elsif cmd == 'verify'
-      job.how |= Solv::Job::SOLVER_VERIFY
-    end
-  end
-
-  solver = nil
-  #pool.set_debuglevel(1)
-  while true
-    solver = pool.Solver
-    solver.set_flag(Solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1)
-    solver.set_flag(Solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if cmd == 'erase'
-    problems = solver.solve(jobs)
-    break if problems.empty?
-    for problem in problems
-      puts "Problem #{problem.id}:"
-      puts problem.findproblemrule.info.problemstr
-      solutions = problem.solutions
-      for solution in solutions
-       puts "  Solution #{solution.id}:"
-       elements = solution.elements(true)
-       for element in elements
-         puts "  - #{element.str}"
-       end
-       puts
-      end
-      sol = nil
-      while true
-       print "Please choose a solution: "
-       STDOUT.flush
-       sol = STDIN.gets.strip
-       break if sol == 's' || sol == 'q'
-       break if sol =~ /^\d+$/ && sol.to_i >= 1 && sol.to_i <= solutions.length
+for job in jobs
+  job.how ^= Solv::Job::SOLVER_UPDATE ^ Solv::Job::SOLVER_INSTALL if cmd == 'up' and job.isemptyupdate?
+end
+
+solver = nil
+#pool.set_debuglevel(1)
+while true
+  solver = pool.Solver
+  solver.set_flag(Solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1)
+  solver.set_flag(Solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if cmd == 'erase'
+  problems = solver.solve(jobs)
+  break if problems.empty?
+  for problem in problems
+    puts "Problem #{problem.id}:"
+    puts problem.findproblemrule.info.problemstr
+    solutions = problem.solutions
+    for solution in solutions
+      puts "  Solution #{solution.id}:"
+      elements = solution.elements(true)
+      for element in elements
+       puts "  - #{element.str}"
       end
-      next if sol == 's'
-      abort if sol == 'q'
-      solution = solutions[sol.to_i - 1]
-      for element in solution.elements
-       newjob = element.Job()
-       if element.type == Solv::Solver::SOLVER_SOLUTION_JOB
-         jobs[element.jobidx] = newjob
-       else
-         jobs.push(newjob) if newjob && !jobs.include?(newjob)
-       end
+      puts
+    end
+    sol = nil
+    while true
+      print "Please choose a solution: "
+      STDOUT.flush
+      sol = STDIN.gets.strip
+      break if sol == 's' || sol == 'q'
+      break if sol =~ /^\d+$/ && sol.to_i >= 1 && sol.to_i <= solutions.length
+    end
+    next if sol == 's'
+    abort if sol == 'q'
+    solution = solutions[sol.to_i - 1]
+    for element in solution.elements
+      newjob = element.Job()
+      if element.type == Solv::Solver::SOLVER_SOLUTION_JOB
+       jobs[element.jobidx] = newjob
+      else
+       jobs.push(newjob) if newjob && !jobs.include?(newjob)
       end
     end
   end
-  trans = solver.transaction
-  solver = nil
-  if trans.isempty?
-    puts "Nothing to do."
-    exit
-  end
-  puts "\nTransaction summary:\n"
-  for cl in trans.classify()
-    if cl.type == Solv::Transaction::SOLVER_TRANSACTION_ERASE
-      puts "#{cl.count} erased packages:"
-    elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_INSTALL
-      puts "#{cl.count} installed packages:"
-    elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_REINSTALLED
-      puts "#{cl.count} reinstalled packages:"
-    elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
-      puts "#{cl.count} downgraded packages:"
-    elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_CHANGED
-      puts "#{cl.count} changed packages:"
-    elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED
-      puts "#{cl.count} upgraded packages:"
-    elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE
-      puts "#{cl.count} vendor changes from '#{cl.fromdep}' to '#{cl.todep}':"
-    elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE
-      puts "#{cl.count} arch changes from '#{cl.fromdep}' to '#{cl.todep}':"
+end
+
+trans = solver.transaction
+solver = nil
+if trans.isempty?
+  puts "Nothing to do."
+  exit
+end
+
+puts "\nTransaction summary:\n"
+for cl in trans.classify()
+  if cl.type == Solv::Transaction::SOLVER_TRANSACTION_ERASE
+    puts "#{cl.count} erased packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_INSTALL
+    puts "#{cl.count} installed packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_REINSTALLED
+    puts "#{cl.count} reinstalled packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
+    puts "#{cl.count} downgraded packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_CHANGED
+    puts "#{cl.count} changed packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED
+    puts "#{cl.count} upgraded packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE
+    puts "#{cl.count} vendor changes from '#{cl.fromdep}' to '#{cl.todep}':"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE
+    puts "#{cl.count} arch changes from '#{cl.fromdep}' to '#{cl.todep}':"
+  else
+    next
+  end
+  for p in cl.solvables
+    if cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED || cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
+      puts "  - #{p.str} -> #{trans.othersolvable(p).str}"
     else
-      next
+      puts "  - #{p.str}"
     end
-    for p in cl.solvables
-      if cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED || cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
-       puts "  - #{p.str} -> #{trans.othersolvable(p).str}"
-      else
-       puts "  - #{p.str}"
-      end
-    end
-    puts
   end
-  puts "install size change: #{trans.calc_installsizechange()} K\n\n"
-  while true:
-    print("OK to continue (y/n)? ")
-    STDOUT.flush
-    yn = STDIN.gets.strip
-    break if yn == 'y'
-    abort if yn == 'n'
-  end
-  newpkgs = trans.newpackages()
-  newpkgsfp = {}
-  if !newpkgs.empty?
-    downloadsize = 0
-    for p in newpkgs
-      downloadsize += p.lookup_num(Solv::SOLVABLE_DOWNLOADSIZE)
-    end
-    puts "Downloading #{newpkgs.length} packages, #{downloadsize} K"
-    for p in newpkgs
-      repo = p.repo.appdata
-      location, medianr = p.lookup_location()
-      next unless location
-      location = repo.packagespath + location
-      chksum = p.lookup_checksum(Solv::SOLVABLE_CHECKSUM)
-      f = repo.download(location, false, chksum)
-      abort("\n#{@name}: #{location} not found in repository\n") unless f
-      newpkgsfp[p.id] = f
-      print "."
-      STDOUT.flush()
-    end
-    puts
-  end
-  puts "Committing transaction:"
   puts
-  trans.order(0)
-  for p in trans.steps
-    steptype = trans.steptype(p, Solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY)
-    if steptype == Solv::Transaction::SOLVER_TRANSACTION_ERASE
-      puts "erase #{p.str}"
-      next unless p.lookup_num(Solv::RPM_RPMDBID)
-      evr = p.evr.sub(/^[0-9]+:/, '')
-      system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "#{p.name}-#{evr}.#{p.arch}") || abort("rpm failed: #{$? >> 8}") 
-    elsif (steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL || steptype == Solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL)
-      puts "install #{p.str}"
-      f = newpkgsfp.delete(p.id)
-      next unless f
-      mode = steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i'
-      system('rpm', mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/#{f.fileno().to_s}") || abort("rpm failed: #{$? >> 8}")
-      f.close
-    end
+end
+puts "install size change: #{trans.calc_installsizechange()} K\n\n"
+
+while true:
+  print("OK to continue (y/n)? ")
+  STDOUT.flush
+  yn = STDIN.gets.strip
+  break if yn == 'y'
+  abort if yn == 'n'
+end
+
+newpkgs = trans.newpackages()
+newpkgsfp = {}
+if !newpkgs.empty?
+  downloadsize = 0
+  for p in newpkgs
+    downloadsize += p.lookup_num(Solv::SOLVABLE_DOWNLOADSIZE)
+  end
+  puts "Downloading #{newpkgs.length} packages, #{downloadsize} K"
+  for p in newpkgs
+    repo = p.repo.appdata
+    location, medianr = p.lookup_location()
+    next unless location
+    location = repo.packagespath + location
+    chksum = p.lookup_checksum(Solv::SOLVABLE_CHECKSUM)
+    f = repo.download(location, false, chksum)
+    abort("\n#{@name}: #{location} not found in repository\n") unless f
+    newpkgsfp[p.id] = f
+    print "."
+    STDOUT.flush()
+  end
+  puts
+end
+
+puts "Committing transaction:"
+puts
+trans.order(0)
+for p in trans.steps
+  steptype = trans.steptype(p, Solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY)
+  if steptype == Solv::Transaction::SOLVER_TRANSACTION_ERASE
+    puts "erase #{p.str}"
+    next unless p.lookup_num(Solv::RPM_RPMDBID)
+    evr = p.evr.sub(/^[0-9]+:/, '')
+    system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "#{p.name}-#{evr}.#{p.arch}") || abort("rpm failed: #{$? >> 8}") 
+  elsif (steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL || steptype == Solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL)
+    puts "install #{p.str}"
+    f = newpkgsfp.delete(p.id)
+    next unless f
+    mode = steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i'
+    system('rpm', mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/#{f.fileno().to_s}") || abort("rpm failed: #{$? >> 8}")
+    f.close
   end
 end