Index: /tools/trunk/MANIFEST
===================================================================
--- /tools/trunk/MANIFEST	(revision 311)
+++ /tools/trunk/MANIFEST	(revision 312)
@@ -5,2 +5,3 @@
 bin/sophie-rpm
 lib/Sophie/Client.pm
+lib/Sophie/Client/Transaction.pm
Index: /tools/trunk/bin/sophie-rpm
===================================================================
--- /tools/trunk/bin/sophie-rpm	(revision 311)
+++ /tools/trunk/bin/sophie-rpm	(revision 312)
@@ -136,124 +136,29 @@
 $sc->login;
 
-my %rpmid;
+my $ts = $sc->ts($distrib);
+
 foreach my $rpm (@ARGV) {
-    my $string = `rpm -qp --qf '[%{*:xml}\n]' $rpm`;
-    $string =~ s:<rpmTag name="Changelogname">(.*?)</rpmTag>::sm;
-    $string =~ s:<rpmTag name="Changelogtext">(.*?)</rpmTag>::sm;
-    $string =~ s:<rpmTag name="Changelogtime">(.*?)</rpmTag>::sm;
-    warn "Loading $rpm\n";
-
-    my $res = $sc->send_request('user.folder.load_rpm',
-        RPC::XML::base64->new($string));
-    if (ref $res && ! $res->is_fault) {
-        $rpmid{$res->value} = $rpm;
-    } else {
-        die((ref $res ? $res->string : $res) . "\n");
-    }
+    $ts->add_rpm($rpm) or die "Cannot add $rpm";
 }
 
-my %pool;
-{
-    foreach (@{ $sc->send_request('user.folder.list')->value }) {
-        $pool{$_->{id}} = $_->{name} . '-' . $_->{evr}; 
-    }
-}
-
-my @unresolved;
-my @dirnotfound;
-foreach my $rpmid (keys %rpmid) {
-    warn "Analysing $rpmid{$rpmid}\n";
-    my $analyse = $sc->send_request('analysis.find_requirements',
-        $distrib,
-        $rpmid,
-        [ keys %rpmid ],
-    );
-    if (ref $analyse && !$analyse->is_fault) {
-        my $result = $analyse->value;
-        if ($verbose) {
-            print "\nPackage requirements\n";
-            foreach my $dep (keys %{ $result->{bydep} }) {
-                print $dep . ":\n";
-                foreach (@{ $result->{bydep}{$dep}{pkg} || []}) {
-                    print "    " . $sc->send_request('rpms.basicinfo', $_)->value->{filename};
-                    print "\n";
-                }
-                foreach (@{ $result->{bydep}{$dep}{pool} || [] }) {
-                    print "  * " . $pool{$_} . "\n";
-                }
-            }
-        }
-        if (@{ $result->{unresolved} || []}) {
-            push(@unresolved, @{ $result->{unresolved} });
-            print "\nAre unresolved:\n";
-            print  map { " $_\n" }  @{ $result->{unresolved} };
-        }
-    }
-    my $diranalyse = $sc->send_request('analysis.parentdir',
-        $distrib,
-        $rpmid,
-        [ keys %rpmid ],
-    );
-    if (ref $diranalyse && !$diranalyse->is_fault) {
-        my $result = $diranalyse->value;
-        if ($verbose) {
-            print "\nParent directories:\n";
-            foreach my $dir (sort keys %{ $result->{bydir} }) {
-                print $dir . ":\n";
-                if (@{ $result->{bydir}{$dir}{pkg} || []} > 3) {
-                    print "    " . scalar(@{ $result->{bydir}{$dir}{pkg} || []}) .
-                    " results in the distribution...\n";
-                } else {
-                    foreach (@{ $result->{bydir}{$dir}{pkg} || []}) {
-                        print "    " . $sc->send_request('rpms.basicinfo', $_)->value->{filename};
-                        print "\n";
-                    }
-                }
-                foreach (@{ $result->{bydir}{$dir}{pool} || [] }) {
-                    print "  * " . $pool{$_} . "\n";
-                }
-            }
-        }
-        if (@{ $result->{notfound} || []}) {
-            push(@dirnotfound, @{ $result->{notfound} });
-            print "\nUnowned directories:\n";
-            print  map { " $_\n" }  @{ $result->{notfound} };
-        }
-    }
-    print "\n";
-}
-
-$sc->send_request('user.folder.clear');
-
-if (@dirnotfound) {
-    print "Warning, this directory are not owned by any package:\n";
-    print map { " $_\n" } @dirnotfound;
-    print "\n";
-}
-if (@unresolved) {
-    print "Error, unresolved:\n";
-    print  map { " $_\n" }  @unresolved;
-    print "\n";
-    if ($search) {
-        print "\nSearching depedencies in sophie\n";
-        foreach my $dep (@unresolved) {
-            my $res = $sc->send_request(
-                'search.rpm.bydep', $searchsp, 'P', split(' ', $dep)
-            );
-            if (ref $res && !$res->is_fault) {
-                print "$dep: " . $res->value->{total_entries} . " results\n";
-                foreach (@{ $res->value->{results} }) {
-                    print "    " . $sc->send_request('rpms.basicinfo', $_)->value->{filename};
-                    print "\n";
-                }
+my $res = $ts->run;
+$ts->summary if (@ARGV > 1);
+print "\nThis transaction would failed\n" if(!$res);
+if ($search) {
+    print "\nSearching depedencies in sophie\n";
+    foreach my $dep (@{ $ts->{unresolved}} ) {
+        my $res = $sc->send_request(
+            'search.rpm.bydep', $searchsp, 'P', split(' ', $dep)
+        );
+        if (ref $res && !$res->is_fault) {
+            print "$dep: " . $res->value->{total_entries} . " results\n";
+            foreach (@{ $res->value->{results} }) {
+                print "    " . $sc->send_request('rpms.basicinfo', $_)->value->{filename};
+                print "\n";
             }
         }
     }
-    exit(1);
-} else {
-    print "No Error found\n";
-    exit(0);
 }
-
+exit($res ? 0 : 1);
 
 =head1 AUTHOR
Index: /tools/trunk/lib/Sophie/Client.pm
===================================================================
--- /tools/trunk/lib/Sophie/Client.pm	(revision 311)
+++ /tools/trunk/lib/Sophie/Client.pm	(revision 312)
@@ -6,4 +6,5 @@
 use RPC::XML;
 use base qw(RPC::XML::Client);
+use Sophie::Client::Transaction;
 $RPC::XML::FORCE_STRING_ENCODING = 1;
 
@@ -56,4 +57,8 @@
 }
 
+sub ts {
+    my ($self, $distrib) = @_;
+    return Sophie::Client::Transaction->new($self, $distrib);
+}
 
 1;
Index: /tools/trunk/lib/Sophie/Client/Transaction.pm
===================================================================
--- /tools/trunk/lib/Sophie/Client/Transaction.pm	(revision 312)
+++ /tools/trunk/lib/Sophie/Client/Transaction.pm	(revision 312)
@@ -0,0 +1,287 @@
+package Sophie::Client::Transaction;
+
+use strict;
+use warnings;
+
+sub new {
+    my ($class, $client, $distrib) = @_;
+
+    bless(
+        { 
+            client => $client,
+            distrib => $distrib || {},
+        }, 
+        $class
+    );
+}
+
+sub DESTROY {
+    my ($self) = @_;
+    #$self->client->send_request('user.folder.clear');
+}
+
+sub client { $_[0]->{client} }
+sub distrib { $_[0]->{distrib} }
+sub rpmid { sort keys %{ $_[0]->{rpms} || {} } }
+
+sub add_rpm {
+    my ($self, $rpm) = @_;
+
+    my $string = `rpm -qp --qf '[%{*:xml}\n]' $rpm`;
+    if ($?) {
+        warn "$!\n";
+        return;
+    }
+    $string =~ s:<rpmTag name="Changelogname">(.*?)</rpmTag>::sm;
+    $string =~ s:<rpmTag name="Changelogtext">(.*?)</rpmTag>::sm;
+    $string =~ s:<rpmTag name="Changelogtime">(.*?)</rpmTag>::sm;
+
+    my $res = $self->client->send_request(
+        'user.folder.load_rpm',
+        RPC::XML::base64->new($string));
+    if (ref $res && ! $res->is_fault) {
+        $self->{rpms}{$res->value} = $rpm;
+        return 1;
+    } else {
+        warn((ref $res ? $res->string : $res) . "\n");
+        return;
+    }
+}
+
+sub show_pkg {
+    my ($self, $pkgid) = @_;
+
+    if ($self->{_cache}{pkg}{$pkgid}) {
+        return $self->{_cache}{pkg}{$pkgid};
+    } else {
+        return
+        $self->{_cache}{pkg}{$pkgid} = $self->client->send_request(
+            'rpms.basicinfo', $_)
+            ->value->{filename};
+    }
+}
+
+sub check_obsoleted {
+    my ($self, $rpmid) = @_;
+
+    my $res = $self->client->send_request(
+        'analysis.is_obsoleted',
+        $self->distrib,
+        $rpmid,
+        $self->rpmid
+    );
+    if (ref $res && !$res->is_fault) {
+        foreach(@{ $res->value->{pkg} || []}) {
+            warn sprintf("%s is obsoleted by %s\n",
+                $self->{rpms}{$rpmid},
+                $self->show_pkg($_)
+            );
+            push(@{$self->{obsoleted}}, $self->{rpms}{$rpmid});
+            $self->{error} = 1;
+        }
+        foreach($res->value->{pool}) {
+        }
+    }
+}
+
+sub is_updated {
+    my ($self, $rpmid) = @_;
+    my $res = $self->client->send_request(
+        'analysis.is_updated',
+        $self->distrib,
+        $rpmid,
+        $self->rpmid
+    );
+    if (ref $res && !$res->is_fault) {
+        foreach(@{ $res->value->{pkg} || []}) {
+            warn sprintf("%s has lesser version than %s\n",
+                $self->{rpms}{$rpmid},
+                $self->show_pkg($_)
+            );
+            $self->{removed}{pkg}{$_} = 1;
+            push(@{$self->{obsoleted}}, $self->{rpms}{$rpmid});
+            $self->{error} = 1;
+        }
+        foreach($res->value->{pool}) {
+        }
+    }
+}
+
+sub check_conflicts {
+    my ($self, $rpmid) = @_;
+    my $res = $self->client->send_request(
+        'analysis.find_conflicts',
+        $self->distrib,
+        $rpmid,
+        $self->rpmid
+    );
+    if (ref $res && !$res->is_fault) {
+        foreach(@{ $res->value->{pkg} || []}) {
+            $self->{removed}{pkg}{$_} = 1;
+        }
+        foreach(@{ $res->value->{pool} || []}) {
+            $self->{removed}{pool}{$_} = 1;
+        }
+    }
+}
+
+sub find_requirements {
+    my ($self, $rpmid) = @_;
+    my $res = $self->client->send_request(
+        'analysis.find_requirements',
+        $self->distrib,
+        $rpmid,
+        $self->rpmid
+    );
+    if (ref $res && !$res->is_fault) {
+        my $result = $res->value;
+        my @unresolved = @{ $result->{unresolved} || []};
+
+        foreach my $dep (keys %{ $result->{bydep} }) {
+            my @needs;
+            foreach my $pkgid (@{ $result->{bydep}{$dep}{pkg} || []}) {
+                if (exists($self->{removed}{pkg}{$pkgid})) {
+                    next;
+                }
+                push(@needs, $pkgid);
+            }
+            foreach (@{ $result->{bydep}{$dep}{pool} || [] }) {
+                if (exists($self->{removed}{pool}{$_})) {
+                    next;
+                }
+                push(@needs, $_);
+            }
+            if (!@needs) {
+                push(@unresolved, $dep) if (!grep { $dep eq $_ } @unresolved);
+                $self->{error} = 1;
+            }
+        }
+        if (@unresolved) {
+            print $self->{rpms}{$rpmid} . " have missing dependencies:\n";
+            print map { "  $_\n" } @unresolved;
+        }
+        push(@{$self->{unresolved}}, @unresolved);
+    }
+}
+
+sub unowned_directories {
+    my ($self, $rpmid) = @_;
+
+    my $res = $self->client->send_request(
+        'analysis.parentdir',
+        $self->distrib,
+        $rpmid,
+        $self->rpmid
+    );
+    if (ref $res && !$res->is_fault) {
+        my $result = $res->value;
+        my @noparent = @{ $result->{notfound} || []};
+
+        foreach my $dir (keys %{ $result->{bydir} }) {
+            my @needs;
+            foreach my $pkgid (@{ $result->{bydir}{$dir}{pkg} || []}) {
+                if (exists($self->{removed}{pkg}{$pkgid})) {
+                    next;
+                }
+                push(@needs, $pkgid);
+            }
+            foreach (@{ $result->{bydep}{$dir}{pool} || [] }) {
+                if (exists($self->{removed}{pool}{$_})) {
+                    next;
+                }
+                push(@needs, $_);
+            }
+            if (!@needs) {
+                push(@noparent, $dir) if (!grep { $dir eq $_ } @noparent);
+            }
+        }
+        if (@noparent) {
+            print $self->{rpms}{$rpmid} .
+                " have files in non existent directories\n";
+            print map { "  $_\n" } sort @noparent;
+        }
+        push(@{$self->{noparent}}, @noparent);
+    }
+
+}
+
+sub files_conflicts {
+    my ($self, $rpmid) = @_;
+
+    my $res = $self->client->send_request(
+        'analysis.files_conflicts',
+        $self->distrib,
+        $rpmid,
+        $self->rpmid
+    );
+    my @conflicts;
+    if (ref $res && !$res->is_fault) {
+        my $result = $res->value;
+        foreach my $file (keys %{ $result->{byfile} }) {
+            foreach (@{ $result->{byfile}{$file} }) {
+                exists($self->{removed}{pkg}{$_}) and next;
+                push(@conflicts, $file);
+            }
+        }
+        if (@conflicts) {
+            print $self->{rpms}{$rpmid} .
+                " have potential file conflicts\n";
+            print map { "  $_\n" } sort @conflicts;
+        }
+    }
+}
+
+sub run {
+    my ($self, %options) = @_;
+
+    warn "Checking rpm are not obsoleted\n";
+    foreach ($self->rpmid) {
+        $self->is_updated($_);
+        $self->check_obsoleted($_);
+    }
+
+    warn "Checking conflicts\n";
+    foreach ($self->rpmid) {
+        $self->check_conflicts($_);
+    }
+
+    warn "Checking requirements\n";
+    foreach ($self->rpmid) {
+        $self->find_requirements($_);
+    }
+
+    warn "Checking files conflicts\n";
+    foreach ($self->rpmid) {
+        $self->files_conflicts($_);
+    }
+
+    warn "Checking parent directory\n";
+    foreach ($self->rpmid) {
+        $self->unowned_directories($_);
+    }
+
+
+    return $self->{error} ? 0 : 1;
+}
+
+sub results {
+    my ($self) = @_;
+
+    if (@{$self->{noparent}}) {
+        print "This directories are not provided\n";
+        print map { "  $_\n" } sort @{$self->{noparent}};
+    }
+
+    if (@{$self->{obsoleted}}) {
+        print "This packaged will obsoleted by others\n";
+        print map { "  $_\n" } @{$self->{obsoleted}};
+    }
+
+    if (@{$self->{unresolved}}) {
+        print "This dependencies are unresolved:\n";
+        print map { "  $_\n" } @{$self->{unresolved}};
+    }
+    return $self->{error} ? 0 : 1;
+}
+
+1;
