#!/usr/bin/perl -w
#
# pkgtool -- Tool for generating source/patch files from a source code repository
# 
# Copyright (C) 2001, Michael Jennings
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies of the Software, its documentation and marketing & publicity
# materials, and acknowledgment shall be given in the documentation, materials
# and software packages that this Software was used.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# $Id: pkgtool,v 1.69 2005/10/17 20:01:55 mej Exp $
#

use strict;

# Include the Perl Modules we need
use POSIX;
use Mezzanine::Util;
use Mezzanine::Config;
use Mezzanine::PkgVars;
use Mezzanine::Pkg;
use Mezzanine::RPM;
use Mezzanine::Deb;
use Mezzanine::Tar;
use Mezzanine::Build;

# Configuration data.
my $config;
my @config_vars = ("DEBUG", "TARGET", "CLEAN", "LOGFILE", "HINTS",
                   "DEP_INSTALLER", "LOCATIONS", "BUILDUSER",
                   "INSTROOT", "BUILDROOT", "TMPDIR", "MAKE",
                   "MFLAGS", "CFLAGS", "PATH", "ALLOW_EPOCH");

# Print usage information
sub
print_usage_info
{
    my ($leader, $underbar);

    print "\n";
    $leader = "$PROGNAME $VERSION Usage Information";
    $underbar = $leader;
    $underbar =~ s/./-/g;
    print "$leader\n$underbar\n";
    print "\n";
    print "  Syntax:   pkgtool [ options ]\n";
    print "\n";
    print "    -h --help                        Show this usage information\n";
    print "    -d --debug                       Turn on debugging\n";
    print "    -v --version                     Show version and copyright\n";
    print "    -b --build                       Build a package\n";
    print "    -i --install                     Install (unarchive) a package\n";
    print "    -c --contents                    Check the contents of a package\n";
    print "    -q --query <type>                Query attributes of a package\n";
    print "    -o --sources [srcs]              Specify the sources to generate\n";
    print "    -p --package <file>              Specify the package filename\n";
    print "    -s --specfile --scripts <path>   Specify the spec file (or debian script directory) to use\n";
    print "    -m --module <name>               Specify the module name\n";
    print "    -t --target <type>               Specify the package target type\n";
    print "    -a --arch <architecture>         Specify the architecture(s) for which to build\n";
    print "    -P --program <cmd>               Specify the package management program to be used\n";
    print "    -A --args <arg>                  Specify additional options to pass to program\n";
    print "    -R --rcfile <rcfile>             Specify an alternate rpmrc file\n";
    print "    -D --dir <directory>             Specify \"directory\" as the full path to the module\n";
    print "    -r --root <dir>                  Specify the build/install root (depending on mode)\n";
    print "    -H --hints <file_or_dir>         Specify location of pre-build hints or hint files\n";
    print "    -u --user <userid>               Build as <userid> rather than the current user\n";
    print "       --di --dep-installer <prog>   Specify the mechanism used to install build dependencies\n";
    print "       --tar <tarcmd>                Use <tarcmd> as the \"tar\" command\n";
    print "       --zip <zipcmd>                Use <zipcmd> as the compression program\n";
    print "       --allow-epoch                 Allow Epoch in spec file (prepend \"no\" to disallow)\n";
    print "\n";
    exit(MEZZANINE_SUCCESS);
}

# main() here is basically the same as main() in C
sub
main
{
    my ($err, $msg, $outfiles, $pkg_file, $mode, $query_type, $pkg_name);

    &mezz_init("pkgtool", "2.2", "help|h", "version|v", "debug|d!",
               "build|b", "install|i", "contents|c", "query|q=s",
               "sources|o:s", "package|p=s", "specfile|s|scripts=s",
               "module|m=s", "target|t=s", "arch|a=s", "program|P=s",
               "rcfile|R=s", "tar=s", "zip=s", "destdir|D=s",
               "root|r=s", "hints|H=s", "args|A=s@",
               "depinstaller|dep-installer|hint-installer|hi|di=s",
               "user|u=s", "allow-epoch!", "savecfg|save-config");

    if ($OPTION{"version"}) {
        # Do not edit this.  It is updated automatically by CVS when you commit.
        &print_version($PROGNAME, $VERSION, "Michael Jennings",
                       'CVS Revision $Revision: 1.69 $ created on $Date: 2005/10/17 20:01:55 $ by $Author: mej $ ');
    } elsif ($OPTION{"help"} || (!scalar(@ARGV) && !scalar(%OPTION) && &basename($0) !~ /^mz/)) {
        &print_usage_info();
    }
    $config = Mezzanine::Config->new("build/config");
    if (!scalar($config->keys())) {
        $OPTION{"savecfg"} = 1;
    }

    if (defined($OPTION{"debug"}) && !($OPTION{"debug"})) {
        &debug_set($config->set("DEBUG", 0));
    } else {
        &debug_set($config->set("DEBUG", $OPTION{"debug"} || $config->get("DEBUG") || 0));
    }

    &pkgvar_srcs($OPTION{"sources"});
    $pkg_name = &pkgvar_filename($OPTION{"package"});
    &pkgvar_command($OPTION{"program"});
    &pkgvar_instructions($OPTION{"specfile"});

    if ($0 =~ /build$/) {
        $mode = "build";
    } elsif ($0 =~ /inst(all)?$/) {
        $mode = "install";
    } elsif ($OPTION{"build"}) {
        $mode = "build";
    } elsif ($OPTION{"install"}) {
        $mode = "install";
    } elsif ($OPTION{"contents"}) {
        $mode = "contents";
    } elsif ($OPTION{"query"}) {
        $mode = "query";
        $query_type = $OPTION{"query"};
    } else {
        &fatal_error("Nothing to do!\n");
    }

    if ($OPTION{"module"}) {
        if ($pkg_file) {
            $pkg_file = &pkgvar_filename($OPTION{"module"}, $pkg_file);
        } else {
            $pkg_file = &pkgvar_filename($OPTION{"module"});
        }
        &pkgvar_topdir($OPTION{"module"});
    }
    if ($OPTION{"args"} && (ref($OPTION{"args"}) eq "ARRAY")) {
        &pkgvar_parameters(join(' ', @{$OPTION{"args"}}));
    }
    &pkgvar_architecture($OPTION{"arch"});
    $config->set("TARGET", &pkgvar_target($OPTION{"target"} || $config->get("TARGET") || ""));
    &pkgvar_rcfile($OPTION{"rcfile"});
    &pkgvar_tar($OPTION{"tar"});
    &pkgvar_zip($OPTION{"zip"});
    &pkgvar_topdir($OPTION{"destdir"});
    $config->set("INSTROOT", &pkgvar_instroot((($OPTION{"root"} && $OPTION{"root"} eq "none") ? ("") : ($OPTION{"root"})) || $config->get("INSTROOT") || ""));
    if ($config->set("BUILDUSER", &pkgvar_set("builduser", $OPTION{"user"} || $config->get("BUILDUSER") || ""))) {
        &file_owner(&pkgvar_get("builduser"), "", &pkgvar_instroot());
    }

    if (!&pkgvar_filename()) {
        if (scalar(@ARGV)) {
            &pkgvar_filename(shift @ARGV);
        } else {
            &pkgvar_filename(".");
        }
    }

    if ((! -e &pkgvar_filename()) || (index(&pkgvar_filename(), "://") >= 0)) {
        my $fname = &pkgvar_filename();
        my $tmp;

        # It's a URL, so download it.
        print "Downloading $fname";
        $tmp = &fetch_url($fname);
        if (-e $tmp) {
            &pkgvar_filename($tmp);
        } else {
            &fatal_error("Unable to fetch $fname -- $tmp\n");
        }
    }

    # Epoch toggle
    if (defined($OPTION{"allow-epoch"})) {
        &pkgvar_set("allow_epoch", $OPTION{"allow-epoch"});
    } elsif (defined($config->get("ALLOW_EPOCH"))) {
        &pkgvar_set("allow_epoch", $config->get("ALLOW_EPOCH"));
    }
    $config->set("ALLOW_EPOCH", &pkgvar_get("allow_epoch"));

    # Handle hint file/directory specification
    $config->set("HINTS", $OPTION{"hints"} || $config->get("HINTS") || $ENV{"MEZZANINE_HINTS"} || "");
    $config->set("DEP_INSTALLER", $OPTION{"depinstaller"} || $config->get("DEP_INSTALLER") || "false");
    if ($config->get("HINTS")) {
        if ($config->get("DEP_INSTALLER")) {
            &set_hints_info(sprintf("%s%%%s", $config->get("DEP_INSTALLER"), $config->get("HINTS")));
        } else {
            &set_hints_info($config->get("HINTS"));
        }
    } elsif ($config->get("DEP_INSTALLER")) {
        &set_hints_info($config->get("DEP_INSTALLER") . '%');
    }

    $ENV{"MAKE"} = $config->set("MAKE", $config->get("MAKE") || $ENV{"MEZZANINE_MAKE"} || "make");
    $ENV{"CFLAGS"} = $config->set("CFLAGS", $OPTION{"cflags"} || $config->get("CFLAGS") || $ENV{"MEZZANINE_CFLAGS"} || "-O2");
    $ENV{"PATH"} = $config->set("PATH", $config->get("PATH") || $ENV{"MEZZANINE_PATH"}
                                || "/usr/build/bin:/usr/local/build/bin:/usr/lib/qt-1.45/bin:/usr/lib/qt-2.1.0/bin"
                                . ":/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/kerberos/sbin"
                                . ":/usr/kerberos/bin:.");
    # Don't hard code any RPATH's into binaries
    delete $ENV{"LD_RUN_PATH"};
    delete $ENV{"LD_LIBRARY_PATH"};

    # Save configuration if needed.
    if ($OPTION{"savecfg"}) {
        $config->save();
    }
    
    if ($mode eq "build") {
        my ($pkg, $topdir, $buildroot);

        &pkgvar_cleanup("all");
        if ((-e &pkgvar_instructions()) && (! &pkgvar_filename())) {
            &prepare_build_tree();
            ($err, $msg, $outfiles) = &build_topdir();
        } else {
            ($err, $msg, $outfiles) = &build_package();
        }
        if ($err != MEZZANINE_SUCCESS) {
            eprint "Package build failed:  $msg\n";
            return $err;
        }
        print "Package build succeeded.  Output files are:\n\n";
        foreach my $f (split(' ', $outfiles)) {
            my $instroot = &pkgvar_instroot();

            if ($instroot && -e "$instroot$f") {
                $f = $instroot . $f;
            }
            if (&copy_files($f, ".")) {
                print &basename($f);
            } else {
                print $f;
                $err = 1;
            }
            print "\n";
        }
        print "\n";
        &pkgvar_cleanup("temp") if ($err);
        &cleanup_build_tree();
    } elsif ($mode eq "install") {
        my $msg;

        ($err, $msg) = &package_install();
        if ($err != MEZZANINE_SUCCESS) {
            eprint "Unable to install package -- $msg.\n";
        } else {
            print "$msg.\n";
        }
    } elsif ($mode eq "contents") {
        my @results;

        @results = &package_show_contents();
        if (($err = shift @results) != MEZZANINE_SUCCESS) {
            eprint "Unable to examine contents of package.\n";
        }
        print join("", @results), "\n";
    } elsif ($mode eq "query") {
        my @results;

        @results = &package_query($query_type);
        if (($err = shift @results) != MEZZANINE_SUCCESS) {
            eprint "Unable to query package.\n";
        }
        print join("", @results), "\n";
    }
    return $err;
}

exit &main();
