#!/usr/bin/perl
#---------------------------------------------------------------
# Project         : Linux-Mandrake
# Module          : spec-helper
# File            : compress_files
# Version         : $Id: compress_files 33293 2004-08-02 04:35:24Z tvignaud $
# Author          : Frederic Lepied
# Created On      : Thu Feb 10 08:04:11 2000
# Purpose         : compress man and info pages.
#---------------------------------------------------------------

use Cwd;
use File::Find;

################################################################################
# Returns the basename of the argument passed to it.
sub basename {
    my $fn = shift;
    $fn =~ s!^.*/(.*?)$!$1!;
    return $fn;
}

################################################################################
# Returns the directory name of the argument passed to it.
sub dirname {
    my $fn=shift;
    $fn =~ s!^(.*)/.*?$!$1!;
    return $fn;
}

################################################################################
# Run a command that may have a huge number of arguments, like xargs does.
# Pass in a reference to an array containing the arguments, and then other
# parameters that are the command and any parameters that should be passed to
# it each time.
sub xargs {
    my $args=shift;

    # The kernel can accept command lines up to 20k worth of characters.
    my $command_max=20000;

    # Figure out length of static portion of command.
    my $static_length=0;
    foreach (@_) {
	$static_length+=length($_)+1;
    }
    
    my @collect;
    my $length=$static_length;
    foreach (@$args) {
	if (length($_) + 1 + $static_length > $command_max) {
	    error(qq(This command is greater than the maximum command size allowed by the kernel, and cannot be split up further. What on earth are you doing? "@_ $_"));
	}
	$length+=length($_) + 1;
	if ($length < $command_max) {
	    push @collect, $_;
	}
	else {
	    system(@_,@collect) if $#collect > -1;
	    @collect = $_;
	    $length=$static_length + length($_) + 1;
	}
    }
    system(@_,@collect) if $#collect > -1;
}

################################################################################
# Check if a file is a .so man page, for use by File::Find.
my @sofiles;
my @sodests;
sub find_so_man() {
    local $_ = $_;
    # The -s test is becuase a .so file tends to be small. We don't want
    # to open every man page. 1024 is arbitrary.
    if (! -f $_ || -s $_ > 1024) {
	return;
    }

    # Test first line of file for the .so thing.
    my $SOTEST;
    open($SOTEST, $_);
    my $l=<$SOTEST>;
    close $SOTEST;
    if ($l =~ m/\.so\s+(.*)/) {
	my $solink=$1;
	# This test is here to prevent links like ... man8/../man8/foo.8
	if (basename($File::Find::dir) eq dirname($solink)) {
	    $solink=basename($solink);
	}
	else {
	    $solink="../$solink";
	}
	
	push @sofiles, "$File::Find::dir/$_";
	push @sodests, $solink;
    }
}

################################################################################
my $RPM_BUILD_ROOT = $ENV{RPM_BUILD_ROOT};
chdir($RPM_BUILD_ROOT) or die "Can't cd to $ENV{RPM_BUILD_ROOT}: $!";

# Now the .so conversion.
@sofiles = @sodests = ();
foreach my $dir (qw{usr/man usr/X11R6/man usr/lib/perl5/man}) {
    find(\&find_so_man, $dir) if -e $dir;
}
foreach my $sofile (@sofiles) {
    my $sodest = shift(@sodests);
    system "rm", "-f",$sofile;
    system "ln", "-sf",$sodest,$sofile;
}

my @files = split(/\n/, `find usr/info usr/share/info usr/man usr/share/man usr/X11*/man usr/lib/perl5/man -type f ! -name "*.gz" -a ! -name "*.bz2" ! -name 'dir' ! -name 'whatis' 2>/dev/null || true`);

my @gz_files = split(/\n/, `find usr/info usr/share/info usr/man usr/share/man usr/X11*/man usr/lib/perl5/man -type f -name "*.gz" 2>/dev/null || true`);
if (@gz_files) { xargs(\@gz_files, "gzip", "-d"); $? ? die "Something wrong with the decompression of the gzip man/info file, fix this ASAP" : exec($0) }

# Exclude files from compression.
if (@files && defined($ENV{EXCLUDE_FROM_COMPRESS})) {
    my @new;
    foreach (@files) {
	my $ok = 1;
	foreach my $x (split(' ', $ENV{EXCLUDE_FROM_COMPRESS})) {
	    if (/\Q$x\E/) {
		$ok='';
		last;
	    }
	}
	push @new,$_ if $ok;
    }
    @files=@new;
}
	
# Look for files with hard links. If we are going to compress both,
# we can preserve the hard link across the compression and save
# space in the end.
my @f;
my (%hardlinks, %seen);
foreach (@files) {
    my ($dev, $inode, undef, $nlink)=stat($_);
    if ($nlink > 1) {
	if (! $seen{"$inode.$dev"}) {
	    $seen{"$inode.$dev"} = $_;
	    push @f, $_;
	}
	else {
	    # This is a hardlink.
	    $hardlinks{$_} = $seen{"$inode.$dev"};
	}
    }
    else {
	push @f, $_;
    }
}

if (@f) {
    # Make executables not be anymore.
    xargs(\@f, "chmod", "a-x");
    
    xargs(\@f, "bzip2", "-9f");
}

	
# Now change over any files we can that used to be hard links so
# they are again.
foreach (keys %hardlinks) {
    # Remove old file.
    system("rm", "-f", $_);
    # Make new hardlink.
    system("ln", "$hardlinks{$_}.bz2", "$_.bz2");
}

# Fix up symlinks that were pointing to the uncompressed files.
my $FIND;
open($FIND, "find $RPM_BUILD_ROOT -type l |");
while (<$FIND>) {
    local $_ = $_;
    chomp;
    my ($directory) = m!(.*)/!;
    my $linkval = readlink($_);
    if (! -e "$directory/$linkval" && -e "$directory/$linkval.bz2") {
	system("rm", "-f", $_);
	system("ln", "-sf", "$linkval.bz2", "$_.bz2");
    } elsif (! -e "$directory/$linkval" && ! -e "$directory/linkval.bz2" && $directory =~ m|man/|)  {
		#Bad link go on nowhere (any better idea) ?
		unlink($_);
    }
	
}

# compress_files ends here
