On 04/11/07 at 23:44 +0100, Luk Claes wrote:
> Lucas Nussbaum wrote:
> > On 03/11/07 at 15:55 +0100, Luk Claes wrote:
> >> Hi
> >>
> >> Attached my first version at a conversion to perl. Note that it is *NOT*
> >> tested very well. Please don't hesitate to report any issue you find
> >> with it (to this bug report?).
> > 
> > Hi Luk,
> > 
> > it seems that there's a problem with the scope of $datadir (and maybe
> > also of $dist) in subs. I can't get chdist apt-get sid update to work,
> > for example.
> 
> No, other causes, though tnx for a sample command to test things a bit
> more :-)
> 
> Attached an updated version with quite some mistakes fixed. Now that I
> have a clearer idea about what it's supposed to do I could fix some
> trivial and not so trivial mistakes. There will probably more bugs, so
> please test it some more before I add it to the repository...

Ok, looks better!

Attached is an updated version with some fixes (`` -> system mostly).
There's still a problem I don't understand in compare_packages:
chdist compare-packages sid hardy
should display a list of packages, but this part seems to be broken:
sub dist_compare(\@;$) {
  my (@argv, $do_compare) = @_;
  $do_compare = 0 if $do_compare eq 'false';
  my @dists;
  my $n = 0;
  # read params
  foreach my $a (@argv) {
    # lucas 05/11
    print $a;
    $dists[$n] = $a;
    dist_check($dists[$n]);
    $n += 1;
  }

- Lucas
#!/usr/bin/perl

# Debian GNU/Linux chdist.  Copyright (C) 2007 Lucas Nussbaum and Luk Claes.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

use Getopt::Long;

my $datadir = $ENV{'HOME'} . '/.chdist';

sub usage {
  return <<EOF;
Usage: chdist [options] [command] [command parameters]

Options:
    -h, --help                       Show this help
    -d, --data-dir DIR               Choose data directory (default: 
\$HOME/.chdist/

Commands:
  create DIST : prepare a new tree named DIST
  apt-get DIST (update|source|...) : run apt-get inside DIST
  apt-cache DIST (show|showsrc|...) : run apt-cache inside DIST
  apt-rdepends DIST [...] : run apt-rdepends inside DIST
  src2bin DIST PKG : get binary packages for a source package in DIST
  bin2src DIST PKG : get source package for a binary package in DIST
  compare-packages DIST1 DIST2 [DIST3, ...] : list versions of packages in
      several DISTributions
  compare-versions DIST1 DIST2 : same as compare-packages, but also run
      dpkg --compare-versions and display where the package is newer
  grep-dctrl-packages DIST [...] : run grep-dctrl on *_Packages inside DIST
  grep-dctrl-sources DIST [...] : run grep-dctrl on *_Sources inside DIST
EOF
}

# specify the options we accept and initialize
# the option parser
my $help     = '';
GetOptions(
  "help"       => \$help,
  "data-dir=s" => \$datadir,
);

if ($help) {
  print usage(0);
  exit;
}

########################################################
sub dist_check {
  my $dist = $_;
  my $dir  = $datadir . '/' . $dist;
  return 0 if (-d $dir);
  print "Could not find $dist in $datadir. Exiting.\n";
  exit(1);
}

sub aptopts {
  my $dist = @_[0];
  return "-o Dir=$datadir/$dist -o 
Dir::State::status=$datadir/$dist/var/lib/dpkg/status";
}

sub compare_versions {
  my $va = $_[0];
  my $vb = $_[1];
  return `dpkg --compare-versions $va lt $vb; echo $?`;
}

###

sub aptcache {
  my @args = @_;
  my $dist = shift @args;
  dist_check($dist);
  my $args = aptopts($dist) . " @args";
  system("/usr/bin/apt-cache $args");
}

sub aptget {
  my @args = @_;
  my $dist = shift @args;
  dist_check($dist);
  my $args = aptopts($dist) . " @args";
  system("/usr/bin/apt-get $args");
}

sub aptrdepends {
  my @args = @_;
  my $dist = shift @args;
  dist_check($dist);
  my $args = aptopts($dist) . " @args";
  system("/usr/bin/apt-rdepends $args");
}

sub bin2src {
  my @args = @_;
  my $dist = $args[0];
  dist_check($dist);
  my $args = aptopts($dist) . " show $args[1]";
  my $source = `/usr/bin/apt-cache $args|grep '^Source:'`;
  exit($?) if($? != 0);
  $source =~ s/Source: (.*)/$1/;
  print $args[1] if($source eq '');
  print $source if($source ne '');
}

sub src2bin {
  my @argv = @_;
  my $dist = $argv[0];
  dist_check($dist);
  my $args = aptopts($dist) . " showsrc $argv[1]";
  my $bins = `/usr/bin/apt-cache $args|sed 's/\(Package: .*\)\n/\(Binary: 
.*\)/\1\t\2/'|grep "Package: $argv[1]"|sed 's/.*Binary: \(.*\)\n/\1/'`;
  exit($?) if ($? != 0);
  my @bins = split /, /, $bins;
  print join "\n", @bins;
}

sub dist_create {
  my @argv = @_;
  my $dist = $argv[0];
  my $dir  = $datadir . '/' . $dist;
  if (-d $dir) {
    print "$dir already exists, exiting.\n";
    exit(1);
  }
  if (! -d $datadir) {
    mkdir($datadir);
  }
  mkdir($dir);
  foreach $d (('/etc/apt', '/var/lib/apt/lists/partial', '/var/lib/dpkg', 
'/var/cache/apt/archives/partial')) {
    my @temp = split /\//, $d;
    my $tres = $dir;
    foreach my $piece (@temp) {
      $tres .= "/$piece";
      mkdir($tres);
    }
  }
  open(FH, ">$dir/etc/apt/sources.list");
  print FH <<EOF;
#deb http://ftp.debian.org/debian/ unstable main contrib non-free
#deb-src http://ftp.debian.org/debian/ unstable main contrib non-free

#deb http://archive.ubuntu.com/ubuntu dapper main restricted
#deb http://archive.ubuntu.com/ubuntu dapper universe multiverse
#deb-src http://archive.ubuntu.com/ubuntu dapper main restricted
#deb-src http://archive.ubuntu.com/ubuntu dapper universe multiverse
EOF
  close FH;
  open(FH, ">$dir/var/lib/dpkg/status");
  close FH; #empty file
  print "Now edit $dir/etc/apt/sources.list\n";
  print "Then run chdist apt-get $dist update\n";
  print "And enjoy.\n";
}

sub dist_compare(\@;$) {
  my (@argv, $do_compare) = @_;
  $do_compare = 0 if $do_compare eq 'false';
  my @dists;
  my $n = 0;
  # read params
  foreach my $a (@argv) {
    # lucas 05/11
    print $a;
    $dists[$n] = $a;
    dist_check($dists[$n]);
    $n += 1;
  }
  if ($do_compare && $n != 2) {
    print "Can only compare if there are two distros.\n";
    exit(1);
  }
  # read Sources
  my %packages;
  foreach my $dist (@dists) {
    foreach $f (glob($datadir . '/' . $dist . "/var/lib/apt/lists/*_Sources")) {
      my $pkg;
      foreach my $l (<$f>) {
        if ($l =~ /^Package: /) {
          (my $ign, $pkg) = split /: /, $l;
        }
        elsif ($l =~ /^Version: /) {
          (my $ign, $packages{$dist}{$pkg}) = split /: /, $l;
        }
      }
    }
  }
  # output packages list
  #dists.inject([]) { |tot, d| tot += packages[d].keys }.sort.uniq.each do |pkg|
  my @tot = ();
  my %hash = $packages{$dist};
  foreach $dist (@dists) {
        push @tot, keys %hash;
  }
  # @out contains the uniq elements of @tot
  my %saw;
  @[EMAIL PROTECTED] = ();
  my @out = keys %saw;
  foreach my $pkg (@out) {  
    my $str = "$pkg";
    foreach $dist (@dists) {
      if ($packages{$dist}{$pkg}) {
        $str .= " $packages{$dist}{$pkg}";
      }
      else {
        $str .= " UNAVAIL";
      }
    }
    if ($do_compare) {
      # compare versions if run as compare-versions
      if (! $packages{$dists[0]}{$pkg}) {
        $dist = $dists[0];
        $str .= " not_in_$dist";
      }
      elsif (! $packages{$dists[1]}{$pkg}) {
        $dist = $dists[1];
        $str .= " not_in_$dist";
      }
      elsif ($packages{$dists[0]}{$pkg} eq $packages{$dists[1]}{$pkg}) {
        $str .= " same_version";
      }
      elsif (compare_versions($packages{$dists[0]}{$pkg}, 
$packages{$dists[1]}{$pkg})) {
        $dist = $dists[0];
        $str .= " newer_in_$dist";
      }
      else {
        $dist = $dists[1];
        $str .= " newer_in_$dist";
      }
    }
    print "$str\n";
  }
}

sub grep_file {
  my (@argv, $file) = @_;
  $dist = shift @argv;
  dist_check($dist);
  $f = glob($datadir . '/' . $dist . "/var/lib/apt/lists/*_$file");
  # FIXME avoid shell invoc, potential quoting problems here
  system("cat $f | grep-dctrl @argv");
}

########################################################
# Command parsing

my $command = shift @ARGV;
if ($command eq 'create') {
  dist_create(@ARGV);
}
elsif ($command eq 'apt-get') {
  aptget(@ARGV);
}
elsif ($command eq 'apt-cache') {
  aptcache(@ARGV);
}
elsif ($command eq 'apt-rdepends') {
  aptrdepends(@ARGV);
}
elsif ($command eq 'bin2src') {
  bin2src(@ARGV);
}
elsif ($command eq 'src2bin') {
  src2bin(@ARGV);
}
elsif ($command eq 'compare-packages') {
  dist_compare(@ARGV);
}
elsif ($command eq 'compare-versions') {
  dist_compare(@ARGV, 1);
}
elsif ($command eq 'grep-dctrl-packages') {
  grep_file(@ARGV, 'Packages');
}
elsif ($command eq 'grep-dctrl-sources') {
  grep_file(@ARGV, 'Sources');
}
else {
  print "Command unknown. Try $0 -h\n";
  exit(1);
}

Reply via email to