File common_tree of Package openSUSE-images

#! /usr/bin/perl

use Getopt::Long;
use Digest::MD5;
use Fcntl ':mode';

sub add_md5;
sub sub_dirs;
sub del_dups;
sub copy_files;
sub remove_files;
sub new_tmp_file;
sub cleanup;

END { cleanup }     
$SIG{INT} = \&cleanup;
$SIG{TERM} = \&cleanup;

GetOptions(
  'dst=s'    => \$opt_dst,
  'prim=s'   => \$opt_primary,
  'sec=s'    => \$opt_secondary,
  'verbose+' => \$opt_verbose,
);

die "usage: common_tree --dst dst_dir --prim src_1 --sec src_2 \n" unless $opt_dst;
die "error: \"$opt_dst\" already exists; please delete\n" if -e $opt_dst;
die "$opt_dst: $!\n" unless mkdir $opt_dst, 0755;

for (`find '$opt_primary'`) {
    chomp;
    my $prim_file = $_;
    s,^$opt_primary/,,;
    my $secu_file = "$opt_secondary/$_";
    ($mode1, $uid1, $gid1, $size1) = (lstat $prim_file)[2,4,5,7];
    ($mode2, $uid2, $gid2, $size2) = (lstat $secu_file)[2,4,5,7];
    next if (!defined $mode2 || $mode1 != $mode2 || $size1 != $size2 || $uid1 != $uid2 || $gid1 != $gid2 );
    if ( S_ISREG $mode1  )
    {
       open F, $prim_file;
       $md5_1 = Digest::MD5->new->addfile(*F)->hexdigest;    
       close F;
       open F, $secu_file;
       $md5_2 = Digest::MD5->new->addfile(*F)->hexdigest;
       close F;
       if ($md5_1 ne $md5_2)
       {
	  print "$prim_file $md5_1 $md5_2\n";
          next;
       }
       push @$common, sub_dirs($_);
       push @$common, $_;
    }
  }

del_dups $common;

if($opt_verbose) {
  $dir = $dir_list[0];
  for (@$common) {
    print "c: $dir $_: $l->{$dir}{$_}\n";
  }

}

copy_files $common, $opt_primary, "$opt_dst";
remove_files $common, $opt_primary;
remove_files $common, $opt_secondary;

sub add_md5
{
  local $_;
  my $file = shift;
  my ($dir, $md5);


  return if $have_md5->{$file};

  $have_md5->{$file} = 1;

  for $dir (@dir_list) {
    if(exists($l->{$dir}{$file}) && $l->{$dir}{$file} =~ /^f:/) {
      die "$dir/$file: $!\n"unless open F, "$dir/$file";
      $md5 = Digest::MD5->new->addfile(*F)->hexdigest;
      close F;
      $l->{$dir}{$file} .= ":$md5";
    }
  }
}


sub sub_dirs
{
  local $_;
  my $file = shift;
  my (@dirs);

  # print ">$file: ";

  unshift @dirs, $file while $file =~ s#/[^/]*$##;

  # print join(',', @dirs), "<\n";

  return @dirs;
}


sub del_dups
{
  local $_;
  my %x;

  $_[0] = [ grep { !$x{$_}++ } @{$_[0]} ];
}


sub copy_files
{
  local $_;
  my ($files, $src, $dst, $tmp);

  ($files, $src, $dst) = @_;

  if($dst !~ /^\//) {
    chomp($_ = `pwd`);
    $dst = "$_/$dst";
  }

  $tmp = new_tmp_file;

  open F, "|cd $src ; cpio --quiet -pm $dst 2>$tmp";
  print F "$_\n" for (@$files);
  close F;

  if(-s $tmp) {
    print STDERR scalar(`cat $tmp`);
    die "error copying files\n";
  }
}

sub remove_files
{
  local $_;
  my ($files, $src);

  ($files, $src) = @_;

  for (@$files) {
     unlink "$src/$_";
  }
}


sub new_tmp_file
{
  local $_;

  chomp ($_ = `mktemp /tmp/common_tree.XXXXXXXXXX`);
  die "error: mktemp failed\n" if $?;

  push @tmp_files, $_;

  return $_;
}


sub cleanup
{
  unlink @tmp_files;
  undef @tmp_files;
}


openSUSE Build Service is sponsored by