#!/usr/bin/perl

# Author: Kevin K.M. Chiu
# Copyright 2001, Cobalt Networks.  All rights reserved.
# $Id: makePkg 3 2003-07-17 15:19:15Z will $

# This script is used by module.mk to make a PKG file from a module.
#
# There is no need to specify RPM fields in <module>/pkg_packing_list.
# All RPMs under <module>/rpms are included in the final packing_list.
# We intentionally do not sweep <module>/as_rpms here because that directory
# may contain host-global build artifacts from the shared packaging toolchain.

# 2012-08-07 (mstauber): Added optional sorting of RPMs. Not perfect yet, 
#			 but it is a start.

use strict;
use Cwd;
use Getopt::Std;

# get options
getopts('a:l:n:r:s:v:');
use vars qw($opt_a $opt_l $opt_n $opt_r $opt_s $opt_v);

# commands
my $cp = '/bin/cp';
my $mkdir = '/bin/mkdir';
my $msgfmt = '/usr/bin/msgfmt';
my $rm = '/bin/rm';
my $tar = '/bin/tar';

# this is the root of the module
my $moduleDir = cwd();

# path constants
my $redhatRpmsDir = '/usr/src/redhat/RPMS';
my $tmpDir = '/tmp';
my $tmpTarDir = "$tmpDir/pkg$$";
my $origPackingList = "$moduleDir/pkg_packing_list";

# read parameters
my @locales = split /\s/, $opt_l;
my $vendor = $opt_v;
my $service = $opt_s;
my $version = $opt_n;
my $release = $opt_r;
my $arch = $opt_a;

# crucial parameters must exist
if($vendor eq '' || $service eq '' || $version eq '' || $release eq '') {
    die "ERROR: Insufficient parameters to $0";
}

# packing list must exist
if(! -f $origPackingList) {
    die "ERROR: $origPackingList does not exist";
}

# make the tar directory
`$mkdir -p $tmpTarDir`;

# copy the whole scripts directory if it exists
if(-d "$moduleDir/scripts") {
    `$cp -r $moduleDir/scripts $tmpTarDir`;
}

# copy the whole scripts directory if it exists
if(-d "$moduleDir/scripts") {
    `$cp -r $moduleDir/scripts $tmpTarDir`;
}

# copy the whole pkginfo directory if it exists
if(-d "$moduleDir/pkginfo") {
    `$cp -r $moduleDir/pkginfo $tmpTarDir`;

    # locale directory will be handled later separately, so we clean it up here
    my $tarLocaleDir = "$tmpTarDir/pkginfo/locale";
    if(-d $tarLocaleDir) {
	`rm -r $tarLocaleDir`;
    }
}

# compile .po files if they exist
# we compile all the .po files instead of following the locale list supplied
# as script parameter because that list is for the data in the PKG, but we're
# dealing with the meta data of the PKG here.
my $localeDir = "$moduleDir/pkginfo/locale";
if(-d $localeDir) {
    # read all the locales
    opendir(DIR, $localeDir)
	|| die "ERROR: Cannot open directory $localeDir";
    my @pkgLocales = readdir(DIR);
    closedir(DIR);

    # remove hidden files
    @pkgLocales = grep !/^\./, @pkgLocales;

    # loop through all the locales
    my $pkgLocale;
    foreach $pkgLocale (@pkgLocales) {
	my $poDir = "$localeDir/$pkgLocale";

	# get all .po files
	opendir(DIR, $poDir);
	my @poFiles = readdir(DIR);
	closedir(DIR);

	# filter out hidden files or non-.po files
	@poFiles = grep /^[^\.].+\.po$/i, @poFiles;

	# compile all the .po files
	my $poFile;
	foreach $poFile (@poFiles) {
	    # get .mo file name
	    my $moFile = $poFile;
	    $moFile =~ s/\.po$/.mo/i;

	    `$mkdir -p $tmpTarDir/pkginfo/locale/$pkgLocale`;
	    `$msgfmt -o $tmpTarDir/pkginfo/locale/$pkgLocale/$moFile $poDir/$poFile`;
	}
    }
}

# the list of RPMs in the PKG
my @rpms = ();
my @dirRpms = ();

# include RPMs under as_rpms first; fall back to rpms only when a module
# does not populate the normal shared build output directory.
my $rpmsDir = "$moduleDir/as_rpms";
if(!-d $rpmsDir) {
    $rpmsDir = "$moduleDir/rpms";
}
if(-d $rpmsDir) {
    opendir(DIR, $rpmsDir)
	|| die "ERROR: Cannot open directory $rpmsDir";
    @rpms = readdir(DIR);
    closedir(DIR);

    # filter away hidden files or non-rpm files
    @rpms = grep /^[^\.].+\.rpm$/i, @rpms;
    @dirRpms = @rpms;

    # make directory to hold RPMs
    if($#rpms >= 0) {
	`$mkdir -p $tmpTarDir/RPMS`;
    }

    # copy RPMs to the directory
    my $rpm;
    foreach $rpm (@rpms) {
	`$cp $rpmsDir/$rpm $tmpTarDir/RPMS/`;
    }
}

# build the packing list
open(IN, $origPackingList)
    || die "ERROR: Cannot open file $origPackingList";
open(OUT, ">$tmpTarDir/packing_list")
    || die "ERROR: Cannot open file $tmpTarDir/packing_list";
my $line;
while($line = <IN>) {
    # discard all the RPM fields
    if($line =~ /^\s*RPM:\s+(.*)$/) {
	next;
    }

    if (!-f "/usr/sausalito/devel/.pkgsort") {
      # Dump list of RPMs into a sorted fashion:
      # put in RPM list before the end
      if($line =~ /^\s*\[\/Package\]/) {
        my $inrpms = `/usr/sausalito/bin/rpmsorter.sh $rpmsDir`;
        my @sortedRpms = split /\s+/, $inrpms;
        if ($#sortedRpms < 0) {
            @sortedRpms = fallback_sort_rpms(@dirRpms);
        }
        else {
            @sortedRpms = fallback_sort_rpms(@sortedRpms);
        }
	my $rpm;
	foreach $rpm (@sortedRpms) {
	    print OUT "RPM: $rpm\n";
	}
      }
    }
    else {
      ### Start: Sort very basically
      # Sort RPMs in a fashion that doesn't resolve dependencies yet, but at least maintain
      # the bare neccessities: locate, ui, glue and capstone get installed in that order.
      # But only after anything else has been installed.
      if($line =~ /^\s*\[\/Package\]/) {
	my %HoA = ('capstone' => [], 'locale' => [], 'glue' => [], 'ui' => [], 'other' => []);
	my $line;
	my $i;
	foreach $line (@rpms) {
            my $rpmname = $line;
            if ($rpmname =~ m/-capstone-/g) {
                push(@{$HoA{'capstone'}}, $rpmname);
            }
            elsif ($rpmname =~ m/-locale-/g) {
                push(@{$HoA{'locale'}}, $rpmname);
            }
            elsif ($rpmname =~ m/-glue-/g) {
                push(@{$HoA{'glue'}}, $rpmname);
            }
            elsif ($rpmname =~ m/-ui-/g) {
                push(@{$HoA{'ui'}}, $rpmname);
            }
            elsif ($rpmname =~ m/\.rpm/g) {
                push(@{$HoA{'other'}}, $rpmname);
            }
	}

	$i = 0;
	foreach $line (@{$HoA{'other'}}) {
	  print OUT "RPM: " . $HoA{'other'}->[$i] . "\n"; 
	  $i++;
	}
	$i = 0;
	foreach $line (@{$HoA{'locale'}}) {
	  print OUT "RPM: " . $HoA{'locale'}->[$i] . "\n"; 
	  $i++;
	}
	$i = 0;
	foreach $line (@{$HoA{'locale'}}) {
	  print OUT "RPM: " . $HoA{'locale'}->[$i] . "\n"; 
	  $i++;
	}
	$i = 0;
	foreach $line (@{$HoA{'ui'}}) {
	  print OUT "RPM: " . $HoA{'ui'}->[$i] . "\n"; 
	  $i++;
	}
	$i = 0;
	foreach $line (@{$HoA{'glue'}}) {
	  print OUT "RPM: " . $HoA{'glue'}->[$i] . "\n"; 
	  $i++;
	}
	$i = 0;
	foreach $line (@{$HoA{'capstone'}}) {
	  print OUT "RPM: " . $HoA{'capstone'}->[$i] . "\n"; 
	  $i++;
	}
      }
    }
    ### End: Sort

    # print to target
    print OUT $line;
}

sub fallback_sort_rpms {
    my @input = @_;
    my %groups = (
        other    => [],
        locale   => [],
        ui       => [],
        glue     => [],
        capstone => [],
    );

    foreach my $rpm (@input) {
        if ($rpm =~ m/-capstone-/i) {
            push(@{$groups{capstone}}, $rpm);
        }
        elsif ($rpm =~ m/-locale-/i) {
            push(@{$groups{locale}}, $rpm);
        }
        elsif ($rpm =~ m/-glue-/i) {
            push(@{$groups{glue}}, $rpm);
        }
        elsif ($rpm =~ m/-ui-/i) {
            push(@{$groups{ui}}, $rpm);
        }
        else {
            push(@{$groups{other}}, $rpm);
        }
    }

    return (
        @{$groups{other}},
        @{$groups{locale}},
        @{$groups{ui}},
        @{$groups{glue}},
        @{$groups{capstone}},
    );
}
close(IN);
close(OUT);

# tar up the PKG
`cd $tmpTarDir; $tar --exclude '.svn' -czf $moduleDir/$vendor-$service-$version-$release.pkg .`;

# clean up
`$rm -r $tmpTarDir`;

exit;
