#!/usr/bin/perl
use strict;
use warnings;
use YAML::Tiny();
use Archive::Tar;
use Cwd 'abs_path';

sub LoadManifest {
    my $dir = shift;
    my $modman;
    die "Not a module directory '$dir'\n"
	unless -d $dir and ($modman) = glob("$dir/*.gjm");
    my($Manifest, $meta) = @{YAML::Tiny->read($modman)};
    return $Manifest;
}

sub PackageAll {
    my ($Manifest, $dir) = @_;
    $dir = abs_path($dir);
    my $tar = Archive::Tar->new();
    # Add manifest file first
    $tar->add_files("$dir/$Manifest->{Package}.gjm");
    # Add all Modules
    for(sort keys %{$Manifest->{Modules}}) {
	if(/^\.$/) { # The 'plib'
	    $tar->add_files("$dir/plib");
	    next;
	}
	$tar->add_files("$dir/plib/$_");
    }
    # add all Library files
    for(sort keys %{$Manifest->{Library}}) {
	my $lp = "lib/$Manifest->{Package}";
	if(/^\.$/) { # The 'lib'
	    $tar->add_files("$dir/lib", "$dir/$lp");
	    next;
	}
	if(/^lib\//) { # "Extra" lib files
	    $tar->add_files("$dir/$_");
	} else {
	    $tar->add_files("$dir/$lp/$_");
	}
    }
    # Add conf files
    for(sort keys %{$Manifest->{Conf}}) {
	if(/^\.$/) { # The conf
	    $tar->add_files("$dir/conf");
	    next;
	}
	$tar->add_files("$dir/conf/$_");
    }
    # Add bin files, not in manifest
    opendir(my $dh, "$dir/bin");
    if($dh) {
	$tar->add_files("$dir/bin");
	while(readdir $dh) {
	    next if /^\./;
	    $tar->add_files("$dir/bin/$_");
	}
    }
    # Calculate prefix 
    my $prefix = do {
	my $version = $Manifest->{Version};
	my @vc = split(/\./,$version);
	$version = join('.',@vc[0..2]);
	my $rdir = (split('/',$dir))[-1];
	"$rdir-$version";
    };
    $tar->{myprefix} = $prefix;
    # Adjust all files to prefix
    for($tar->get_files()) {
	$_->{prefix} =~ s/^$dir/$prefix/;
	$_->{uname} = $_->{gname} = 'root';
    }
    return $tar;
}

sub WriteTar {
    my $Manifest = shift;
    my $tar = shift;
    my $dest = shift;
    my $prefix = $tar->{myprefix};
    warn "Packaging $Manifest->{Package} v$Manifest->{Version} as $prefix to $dest\n";
    my $tarfile = "$dest/$prefix.tar";
    # Write the tar
    $tar->write($tarfile);
    system('gzip', '-9', $tarfile);
}

my $dir = shift or die "usage: gjtar <DIR> [DEST]\n";
my $dest = shift || ($dir eq '.' ? '..' : '.');
die "Destination '$dest' not exists!\n" unless -d $dest;
my $Manifest = LoadManifest($dir);

die "Manifest of $Manifest->{Package} not signed!\n" unless $Manifest->{Signed};

my $tar = PackageAll($Manifest, $dir);
WriteTar($Manifest, $tar, $dest);
warn "Done.\n";


