#!/usr/bin/perl use strict; use warnings; use Getopt::Long qw(GetOptions); use Log::Log4perl qw(:easy); # TODO: This needs to be scoped properly use lib "/usr/local/lib"; use Shellex::Shellex qw(shellex findBin); use SimplyGit::Git qw( readConfig getStatus returnState addFiles commitChanges pushChanges stashAndReset resetFromUpstream updateGitIgnore appendRepoUserConfig parseSGConfig warnOnUser basicClone basicPull knocker ); sub initSG($) { my $sgDir = shift; my $homeDir = shellex("echo \$HOME"); chomp $homeDir; my $path = $homeDir . "/" . $sgDir; my $logFile = $homeDir . "/" . $sgDir . "/" . "sgLog.txt"; my $configFile = $homeDir . "/" . $sgDir . "/" . "sg.config"; if ( ! -d $path ) { print "Creating $path\n"; shellex("mkdir $path"); } if ( ! -f $logFile ) { print "Creating $logFile\n"; shellex("touch $logFile"); } if ( ! -f $configFile ) { print "Creating $configFile\n"; shellex("touch $configFile"); } return ( $path, $logFile, $configFile ); } my ( $sgPath, $sgLogFile, $sgConfigFile ) = initSG(".sg"); sub getLogName { return $sgLogFile; }; my $log_conf = q( log4perl.rootLogger = ERROR, LOG1, screen log4perl.appender.LOG1 = Log::Log4perl::Appender::File log4perl.appender.LOG1.filename = sub { getLogName(); } log4perl.appender.LOG1.mode = append log4perl.appender.LOG1.layout = Log::Log4perl::Layout::PatternLayout log4perl.appender.LOG1.layout.ConversionPattern = %d %p >> %m %n log4perl.appender.screen = Log::Log4perl::Appender::Screen log4perl.appender.screen.stderr = 0 log4perl.appender.screen.layout = PatternLayout log4perl.appender.screen.layout.ConversionPattern = %d %p >> %m %n ); Log::Log4perl::init(\$log_conf); my $logger = get_logger(); my $gitCmd = findBin("git",$logger); # Removed .sg from repo dir to home, don't need this sub right now # updateGitIgnore(".","/.sg",$logger); my %args; GetOptions( \%args, 'push-all', 'interactive', 'view', 'reset-from-master', 'reset-from-upstream', 'upstream-url=s', 'commit-msg=s', 'dump-config', 'configure-local-user', 'user=s', 'email=s', 'config-file=s', 'knock', 'knock-clone=s', 'help', 'knock-pull', ); # TODO: This should maybe be more robust? if ( ! -d ".git" && ( ! defined $args{'knock-clone'} && ! defined $args{'knock'} && ! defined $args{'help'} ) ) { print "Not a git dir, exiting...\n"; exit 1; } sub printHelp { my $help = < 1 ) { print "Can't pass other args with --view\n"; exit 1; } if ( defined $args{'dump-config'} && scalar keys %args > 1 ) { print "Can't pass other args with --dump-config\n"; exit 1; } if ( defined $args{'reset-from-master'} && scalar keys %args > 1 ) { print "Can't pass other args with --reset-from-master\n"; exit 1; } if ( defined $args{'push-all'} ) { foreach my $arg ( keys %args ) { if ( $arg eq "interactive" || $arg eq "commit-msg" || $arg eq "push-all" || $arg eq "knock" ) { next; } else { print "Can only pass --interactive and --commit-msg with --push-all\n"; exit 1; } } } if ( defined $args{'configure-local-user'} ) { if ( scalar keys %args < 2 ) { print "Must pass either --interactive or --user AND --email to --configure-local-user\n"; exit 1; } foreach my $arg ( keys %args ) { if ( $arg eq "interactive" || $arg eq "user" || $arg eq "email" || $arg eq "configure-local-user" ) { next; } else { print "Must/can only pass --interactive, OR --user AND --email with --configure-local-user\n"; exit 1; } } if ( ! defined $args{'interactive'} && ! defined $args{'user'} || ! defined $args{'interactive'} && ! defined $args{'email'} ) { print "If not using --interactive with --configure-local-user, --user and --email MUST be defined\n"; exit 1; } } if ( defined $args{'reset-from-upstream'} ) { if ( scalar keys %args > 2 ) { print "Can only pass --upstream-url with --reset-from-upstream\n"; exit 1; } foreach my $arg ( keys %args ) { if ( $arg eq "reset-from-upstream" || $arg eq "upstream-url" ) { next; } else { print "Can only pass --upstream-url with --reset-from-upstream\n"; exit 1; } } } if ( ! defined $args{'config-file'} ) { $args{'config-file'} = $sgConfigFile; } if ( defined $args{'knock-clone'} ) { if ( scalar keys %args > 2 ) { print "--knock-clone accepts no other args\n"; exit 1; } } if ( defined $args{'knock-pull'} ) { if ( scalar keys %args > 2 ) { print "--knock-pull accepts no other args\n"; exit 1; } } } sub color_print($$) { #echo -e "\033[0mNC (No color)" #echo -e "\033[1;37mWHITE\t\033[0;30mBLACK" #echo -e "\033[0;34mBLUE\t\033[1;34mLIGHT_BLUE" #echo -e "\033[0;32mGREEN\t\033[1;32mLIGHT_GREEN" #echo -e "\033[0;36mCYAN\t\033[1;36mLIGHT_CYAN" #echo -e "\033[0;31mRED\t\033[1;31mLIGHT_RED" #echo -e "\033[0;35mPURPLE\t\033[1;35mLIGHT_PURPLE" #echo -e "\033[0;33mYELLOW\t\033[1;33mLIGHT_YELLOW" #echo -e "\033[1;30mGRAY\t\033[0;37mLIGHT_GRAY" # # Doing it this way likely hurts portability but # it's better than nothing which is what I'm currently doing # and would like to avoid additional module deps, as this # isn't too hard to implement my $print_string = shift; my $color = shift; if ( $color ne "BLUE" && $color ne "GREEN" && $color ne "RED" ) { $logger->error("Bad color passed to color_print"); exit 1; } my %color_map = ( BLUE => "\033[0;34m", GREEN => "\033[0;32m", RED => "\033[0;31m", RESET => "\033[0m", ); printf "$color_map{$color}$print_string$color_map{'RESET'}"; } parseArgs(); my %sgConfig = parseSGConfig($args{'config-file'},$logger); if ( defined $sgConfig{'UserWarn'} && -d ".git" ) { warnOnUser($sgConfig{'user.name'},$sgConfig{'user.email'},$logger); } sub knock() { if ( defined $sgConfig{'Knock'} && ( defined $args{'knock'} || defined $args{'knock-clone'} || defined $args{'knock-pull'} ) ) { knocker($sgConfig{'knock.target'},$sgConfig{'ports'},$logger); } } if ( defined $args{'knock'} && scalar keys %args == 2 ) { print "Just knocking then exiting...\n"; knock(); exit 1; } # TODO: This sub could be more concise with a sub to print array refs if ( defined $args{'view'} ) { my ( $untrackedRef, $modifiedRef, $addedRef, $deletedRef ) = returnState($logger); #my $refs = shellex("$gitCmd show-ref",$logger); my $branch = shellex("$gitCmd show-branch",$logger); my $name = shellex("$gitCmd config --get user.name",$logger); chomp $name; my $email = shellex("$gitCmd config --get user.email",$logger); chomp $email; color_print("-->Username: $name\n-->Email: $email\n","BLUE"); print "Branches:\n"; color_print("$branch\n","GREEN"); #print "$refs\n"; print "Files:\n"; my $swpWarning = "\t# Likely a Vi .swp file"; my $untrackedTotal = scalar @$untrackedRef; print "* $untrackedTotal untracked file(s):\n"; foreach my $file ( @$untrackedRef ) { if ( $file =~ m/.swp/ ) { color_print("\t$file $swpWarning\n","GREEN"); } else { color_print("\t$file\n","GREEN"); } } my $modifiedTotal = scalar @$modifiedRef; print "* $modifiedTotal modified file(s):\n"; foreach my $file ( @$modifiedRef ) { if ( $file =~ m/.swp/ ) { color_print("\t$file $swpWarning\n","GREEN"); } else { color_print("\t$file\n","GREEN"); } } my $commitTotal = scalar @$addedRef; print "* $commitTotal file(s) added to commit:\n"; foreach my $file ( @$addedRef ) { if ( $file =~ m/.swp/ ) { print "\t$file $swpWarning\n"; } else { print "\t$file\n"; } } my $deletedTotal = scalar @$deletedRef; print "* $deletedTotal file(s) to be deleted from commit:\n"; foreach my $file ( @$deletedRef ) { if ( $file =~ m/.swp/ ) { color_print("\t$file $swpWarning\n","RED"); } else { color_print("\t$file\n","RED"); } } } if ( defined $args{'push-all'} ) { my ( $untrackedRef, $modifiedRef ) = returnState($logger); my @files; push(@files,@$untrackedRef); push(@files,@$modifiedRef); my @filesToCommit; if ( defined $args{'interactive'} ) { foreach my $file ( @files ) { print "Add $file to commit (y/n): "; my $input = ; chomp $input; if ( $input =~ m/^Y|^y/ ) { push(@filesToCommit,$file); } else { next; } } } else { @filesToCommit = @files; } print "Commiting the following files:\n"; foreach my $file ( @filesToCommit ) { print "\t$file\n"; } if ( defined $args{'interactive'} ) { print "Does this look correct (y/n) : "; my $input = ; chomp $input; if ( $input !~ m/^Y|^y/ ) { print "Canceling...\n"; exit 1; } } addFiles(\@filesToCommit,$logger); if ( defined $args{'interactive'} && ! defined $args{'commit-msg'}) { print "Enter a commit message: "; my $input = ; chomp $input; commitChanges($input,$logger); } elsif ( defined $args{'commit-msg'} ) { my $commitMsg = "$args{'commit-msg'}"; commitChanges($commitMsg,$logger); } else { my $epoch = time(); my $commitMsg = "Generic Commit at $epoch"; commitChanges($commitMsg,$logger); } if ( defined $args{'interactive'} ) { print "Push changes? (y/n): "; my $input = ; chomp $input; if ( $input !~ m/^Y|^y/ ) { # TODO: Unstage changes? print "Canceling...\n"; exit 1; } knock(); my $gitOutput = pushChanges($logger); print "Git returned:\n$gitOutput\n"; } else { knock(); pushChanges($logger); my $gitOutput = pushChanges($logger); print "Git returned:\n$gitOutput\n"; } } if ( defined $args{'reset-from-master'} ) { knock(); stashAndReset($logger); } if ( defined $args{'reset-from-upstream'} ) { if ( defined $args{'upstream-url'} ) { print "Setting upstream to $args{'upstream-url'}\n"; chomp $args{'upstream-url'}; shellex("$gitCmd remote add upstream $args{'upstream-url'}",$logger); shellex("$gitCmd fetch upstream",$logger); knock(); resetFromUpstream($logger); } else { knock(); resetFromUpstream($logger); } } if ( defined $args{'dump-config'} ) { my %configHash = readConfig(".",$logger); foreach my $key ( keys %configHash ) { my $hRef = $configHash{$key}; print "[$key]\n"; foreach my $ckey ( keys %$hRef ) { print "\t$ckey = ${$hRef}{$ckey}\n"; } } } if ( defined $args{'configure-local-user'} ) { if ( defined $args{'interactive'} ) { print "Enter user to set: "; my $desiredName = ; chomp $desiredName; print "Enter email to set: "; my $desiredEmail = ; chomp $desiredEmail; appendRepoUserConfig($desiredName,$desiredEmail,$logger); } else { appendRepoUserConfig($args{'user'},$args{'email'},$logger); } } if ( defined $args{'knock-clone'} ) { knock(); basicClone($args{'knock-clone'},$logger); } if ( defined $args{'knock-pull'} ) { knock(); basicPull($logger); }