#!/usr/bin/perl -w
#
# revtool -- Source Code Revision Control Tool
# 
# 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: revtool,v 1.93 2006/06/06 01:29:58 mej Exp $
#

use strict;
use Getopt::Long;
use Mezzanine::Util;
#use Mezzanine::RevCtl;
use Mezzanine::SCM;
use Mezzanine::Config;

my $config;

# 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:   $PROGNAME [ options ] [ files ]\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 "    -g --get                 Download and/or merge the current sources from the master tree\n";
    print "    -p --put                 Upload new changes to the master tree\n";
    print "    -a --add                 Mark new files for addition into the master tree\n";
    print "    -r --remove              Delete files and mark them for deletion in the master tree\n";
    print "    -R --recurse             Operate recursively (this is the default for some commands)\n";
    print "    -i --import              Import a new set of sources, or update the vendor branch for a package\n";
    print "    -t --tag <tag>           Specify a symbolic tag for an operation, or tag local sources\n";
    print "    -T --ttag <tag>          Specify the target tag for a diff/merge\n";
    print "    -I --info --query        Obtain information about file(s) in SCM.\n";
    print "       --diff                Generate a diff (diff -Nu format) between files/revisions/dates\n";
    print "       --stat --status       Display working copy status information\n";
    print "       --log                 Display SCM log\n";
    print "       --annotate --blame    Display annotated source code\n";
    print "       --init                Initialize the SCM repository\n";
    print "    -b --branch              When performing a tag, make it a branch tag\n";
    print "       --merge               Merge specified revisions/branches/dates during \"get\"\n";
    print "    -l --login               Perform a login to the repository\n";
    print "    -D --dir                 Specify an alternative repository (\$REPOSITORY)\n";
    print "    -P --protocol <scm>      Force use of the specified SCM mechanism (e.g., CVS)\n";
    print "    -m --message             Provide a ChangeLog message (will not prompt for edit)\n";
    print "    -k --keyword <type>      Specify the type of keyword expansion to use (e.g., \"source\")\n";
    print "    -x --exclusive           Only commit specified file(s) (or, with no args, don't append ChangeLog)\n";
    print "       --reset               Reset sticky tags, dates, etc. in the current module\n";
    print "       --blind               Do not update before committing (may result in conflicts, use carefully)\n";
    print "    -L --local               Do not interact with the repository (local mode)\n";
    print "       --savecfg             Save configuration settings for future use\n";
    print "\n";
    exit(0);
}

# main() here is basically the same as main() in C
sub
main
{
    my ($scm, $mode, $retval);

    &mezz_init("revtool", "3.0", "help|h", "version|v", "debug|d!",
               "get|g", "put|p", "add|a", "remove|r", "recurse|R!",
               "tag|source-tag|t=s", "import|i", "info|query|I",
               "diff", "stat|status", "log", "annotate|ann|blame",
               "keyword|k=s", "dir|D=s", "exclusive|x!", "init",
               "ttag|target-tag|T=s", "login|l!", "branch|b!",
               "reset!", "blind!", "merge", "message|m=s",
               "protocol|P=s", "init", "savecfg!", "local|L!");

    if ($OPTION{"version"}) {
        &print_version($PROGNAME, $VERSION, "Michael Jennings <mej\@eterm.org>",
                       'CVS Revision $Revision: 1.93 $ created on $Date: 2006/06/06 01:29:58 $ by $Author: mej $ ');
    }
    if ($OPTION{"help"}) {
	&print_usage_info();
    }
    open(STDERR, ">&STDOUT");
    $config = Mezzanine::Config->new("scm/config");
    if (!scalar($config->keys())) {
        $OPTION{"savecfg"} = 1;
    }

    # Set basic options
    if (defined($OPTION{"debug"}) && !($OPTION{"debug"})) {
        &debug_set($config->set("DEBUG", 0));
    } else {
        &debug_set($config->set("DEBUG", $OPTION{"debug"} || $config->get("DEBUG") || 0));
    }
    $config->set("PROTOCOL", $OPTION{"protocol"} || $config->get("PROTOCOL"));
    if ($config->get("PROTOCOL")) {
        $scm = Mezzanine::SCM::new($config->get("PROTOCOL"));
    } elsif (scalar(@ARGV) && -d $ARGV[0]) {
        $scm = Mezzanine::SCM::auto_detect($ARGV[0]);
    } else {
        $scm = Mezzanine::SCM::auto_detect('.');
    }

    # Set the mode, first based on executable name...
    if ($0 =~ /(get|co|checkout)$/) {
        $mode = "get";
        $OPTION{"get"} = 1;
    } elsif ($0 =~ /(put|ci|commit|checkin)$/) {
        $mode = "put";
        $OPTION{"put"} = 1;
    } elsif ($0 =~ /import$/) {
        $mode = "import";
    } elsif ($0 =~ /(ask|query|info)$/) {
        $mode = "info";
    } elsif ($0 =~ /diff$/) {
	$mode = "diff";
    } elsif ($0 =~ /stat(us)?$/) {
	$mode = "status";
    } elsif ($0 =~ /log$/) {
	$mode = "log";
    } elsif ($0 =~ /(ann|annotate|blame)$/) {
	$mode = "annotate";
    } elsif ($0 =~ /(add|new)$/) {
        $mode = "add";
        $OPTION{"add"} = 1;
    } elsif ($0 =~ /(rm|remove|kill|nuke|purge)$/) {
        $mode = "remove";
        $OPTION{"remove"} = 1;
    } elsif ($0 =~ /(tag|label|mark)$/) {
        $mode = "tag";
    } elsif ($0 =~ /reset$/) {
        $mode = "reset";
        $OPTION{"reset"} = 1;
    } elsif ($0 =~ /init$/) {
        $mode = "init";
    } elsif ($0 =~ /login$/) {
        $mode = "login";
    # ...then on command line options
    } elsif ($OPTION{"import"}) {
        $mode = "import";
    } elsif ($OPTION{"put"}) {
        $mode = "put";
    } elsif ($OPTION{"get"}) {
        $mode = "get";
    } elsif ($OPTION{"add"}) {
        $mode = "add";
    } elsif ($OPTION{"remove"}) {
        $mode = "remove";
    } elsif ($OPTION{"diff"}) {
        $mode = "diff";
    } elsif ($OPTION{"info"}) {
        $mode = "info";
    } elsif ($OPTION{"stat"}) {
        $mode = "stat";
    } elsif ($OPTION{"log"}) {
        $mode = "log";
    } elsif ($OPTION{"annotate"}) {
        $mode = "annotate";
    } elsif ($OPTION{"tag"}) {
        $mode = "tag";
    } elsif ($OPTION{"merge"}) {
        $mode = "merge";
    } elsif ($OPTION{"branch"}) {
        $mode = "tag";
    } elsif ($OPTION{"reset"}) {
        $mode = "reset";
    } elsif ($OPTION{"init"}) {
        $mode = "init";
    } elsif ($OPTION{"login"}) {
        $mode = "login";
    }

    # Support common aliases for keyword modes.
    if (! $OPTION{"keyword"}) {
        $OPTION{"keyword"} = "auto";
    } elsif ($OPTION{"keyword"} eq "s") {
        $OPTION{"keyword"} = "source";
    } elsif ($OPTION{"keyword"} eq "b") {
        $OPTION{"keyword"} = "binary";
    } elsif ($OPTION{"keyword"} eq "kv") {
        $OPTION{"keyword"} = "source";
    } elsif ($OPTION{"keyword"} eq "n") {
        $OPTION{"keyword"} = "none";
    } elsif ($OPTION{"keyword"} eq "o") {
        $OPTION{"keyword"} = "none";
    } elsif ($OPTION{"keyword"} eq "d") {
        $OPTION{"keyword"} = "default";
    }

    $scm->scmobj_propset(
                         "repository" => $OPTION{"dir"},
                         "keyword_expansion" => $OPTION{"keyword"},
                         "recursion" => $OPTION{"recurse"},
                         "reset" => $OPTION{"reset"},
                         "source_tag" => $OPTION{"tag"},
                         "target_tag" => $OPTION{"ttag"},
                         "local_mode" => $OPTION{"local"},
                         "changelog_message" => $OPTION{"message"}
                        );
    if (defined($OPTION{"exclusive"})) {
        if ($mode eq "import") {
            $scm->scmobj_propset("use_standard_ignore", !$OPTION{"exclusive"});
        } elsif (scalar(@ARGV)) {
            $scm->scmobj_propset("args_only", $OPTION{"exclusive"});
        } else {
            $scm->scmobj_propset("update_changelog", !$OPTION{"exclusive"});
        }
    }

    if ($OPTION{"login"}) {
        $scm->login();
        return MEZZANINE_SUCCESS if ($mode eq "login");
    }
    if ($mode eq "import") {
        $scm->imprt(@ARGV);
    } elsif ($mode eq "diff") {
        $scm->diff(@ARGV);
    } elsif ($mode eq "annotate") {
        $scm->annotate(@ARGV);
    } elsif ($mode eq "info") {
        $scm->info(@ARGV);
    } elsif ($mode eq "status") {
        $scm->status(@ARGV);
    } elsif ($mode eq "log") {
        $scm->log(@ARGV);
    } elsif ($mode eq "tag") {
        if ((! $scm->scmobj_propget("source_tag")) || (!length($scm->scmobj_propget("source_tag")))) {
            $scm->scmobj_propset("source_tag", (shift @ARGV));
        }
        if ($OPTION{"branch"}) {
            $retval = $scm->branch(@ARGV);
        } else {
            $retval = $scm->tag(@ARGV);
        }
    } else {
        if ($OPTION{"add"}) {
            $retval = $scm->add(@ARGV);
            if (! $OPTION{"exclusive"}) {
                @ARGV = ();
            }
        } elsif ($OPTION{"remove"}) {
            $retval = $scm->remove(@ARGV);
            if (! $OPTION{"exclusive"}) {
                @ARGV = ();
            }
        }
        if (($mode eq "get") || ($mode eq "merge") || ($scm->scmobj_propget("reset"))) {
            if ($OPTION{"merge"}) {
                $retval = $scm->merge(@ARGV);
            } else {
                $retval = $scm->get(@ARGV);
            }
        } elsif ($mode eq "put") {
            if (! $OPTION{"blind"}) {
                $retval = $scm->get(@ARGV);
                if ($retval != MEZZANINE_SUCCESS) {
                    eprint "Get failed; aborting put process.\n";
                    return $retval;
                }
            }
            $retval = $scm->put(@ARGV);
        }
    }
    return $retval;
}

exit &main();
