123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- package SimplyGit::Git;
- use strict;
- use warnings;
- use Log::Log4perl qw(:easy);
- use lib "/usr/local/lib/";
- use Shellex::Shellex qw(shellex findBin);
- use Exporter qw(import);
- our @EXPORT_OK = qw(
- readConfig getStatus returnState addFiles
- commitChanges pushChanges stashAndReset resetFromUpstream
- updateGitIgnore appendRepoUserConfig parseSGConfig
- warnOnUser basicClone basicPull knocker
- );
- # TODO: Add info/debug logging for all subroutines
- sub knocker($$$) {
- my $target = shift;
- my $portRef = shift;
- my $logger = shift;
- my $nmapCmd = findBin("nmap",$logger);
- foreach my $port (@$portRef) {
- print "Knocking at $port\r";
- shellex("$nmapCmd -Pn --host_timeout 201 --max-retries 0 -p $port $target > /dev/null",$logger);
- }
- # So we don't have random chars potentially on the line after using \r
- print "\n";
- }
- sub checkPath($$) {
- my $path = shift;
- my $logger = shift;
- if ( ! -d $path ) {
- $logger->error("$path doesn't look like a dir, exiting...");
- exit 1;
- }
- }
- sub warnOnUser($$$) {
- my $user = shift;
- my $email = shift;
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- my $configuredUser = shellex("$gitCmd config --get user.name",$logger);
- my $configuredEmail = shellex("$gitCmd config --get user.email",$logger);
- if ( $configuredUser ne $user || $configuredEmail ne $email ) {
- print "***************\n";
- print "Your configured user/email don't match what you declared in the config file!\n";
- print "Desired User: $user\nConfigured User: $configuredUser\nDesired Email: $email\nConfigured Email: $configuredEmail\n";
- print "***************\n";
- }
- }
- # https://perlmaven.com/trim
- sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s };
- sub parseSGConfig($$) {
- my $config = shift;
- my $logger = shift;
- if ( ! -e $config ) {
- $logger->error("$config doesn't look like a regular file, exiting...");
- exit 1;
- }
- my $catCmd = findBin("cat",$logger);
- my @configLines = split("\n",shellex("$catCmd $config",$logger));
- my %configHash;
- foreach my $line ( @configLines ) {
- chomp $line;
- if ( $line =~ m/^(.*)\ =\ "(.*)"$/ ) {
- $configHash{$1} = $2;
- }
- if ( $line =~ m/^(.*)\ =\ \[(.*)\]/ ) {
- my @trimmedPorts;
- my @ports = split(",",$2);
- foreach my $port (@ports) {
- $port =~ /(\d{1,5})/;
- push(@trimmedPorts,trim($1));
- }
- $configHash{$1} = \@trimmedPorts;
- }
- }
- return %configHash;
- }
- sub returnConfigPath($$) {
- my $path = shift;
- my $logger = shift;
- checkPath($path,$logger);
- my $gitConfigPath = $path . "/" . ".git/config";
- return $gitConfigPath;
- }
-
- sub readConfig($$) {
- # This sub is probably not really needed for what I'm trying to do
- # git itself already parses this config...but an interesting exercise non the less
- # and may be useful later
- my $path = shift;
- my $logger = shift;
- my $gitConfigPath = returnConfigPath($path,$logger);
- my $catCmd = findBin("cat",$logger);
- my @configLines = split("\n",shellex("$catCmd $gitConfigPath",$logger));
- # Key is config header, value is hash ref containing config values
- my %gitConfig;
- my @valueLines;
- my $lineCounter = 0;
- foreach my $line ( @configLines ) {
- $lineCounter++;
- #if ( $line =~ m/\[(.*)\]/ ) {
- if ( $line =~ m/\[(.*)\]/ ) {
- #$valueLine =~ /\t(.*)\ =\ (.*)$/;
- $gitConfig{$1} = "";
- }
- }
- # Tag each line with it's heading
- # Only way I could think of that worked to solve how this
- # There are almost certainly better ways
- my @taggedLines;
- my $tag = "NULLTAG";
- foreach my $line ( @configLines ) {
- if ( $line =~ m/\[(.*)\]/ ) {
- $tag = $1;
- } else {
- my $newLine = $tag . $line;
- push(@taggedLines,$newLine);
- }
- }
- # Get all of the tagged lines into a hash structure.
- foreach my $key ( keys %gitConfig ) {
- my %stash;
- foreach my $tl ( @taggedLines ) {
- if ( $tl =~ m/^($key)/ ) {
- $tl =~ s/^($key)//g;
- $tl =~ m/^\t(.*)\ \=\ (.*)$/;
- my $confKey = $1;
- my $confVal = $2;
- $stash{$confKey} = $confVal;
- }
- }
- $gitConfig{$key} = \%stash;
- }
- return %gitConfig;
- }
- sub getStatus($) {
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- my $status = shellex("$gitCmd status -uall --porcelain",$logger);
- chomp $status;
- return $status;
- }
- sub returnState($) {
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- my $currentStatus = getStatus($logger);
- my @statusLines = split("\n", $currentStatus);
- my @untracked;
- my @modified;
- my @added;
- my @deleted;
- foreach my $file ( @statusLines ) {
- $file =~ m/^\ {0,1}([A-Z?]{1,2})\ {1,2}(.*)/;
- my $fileAttrs = $1;
- my $filename = $2;
- my @attrs = split("",$fileAttrs);
- foreach my $attr ( @attrs ) {
- if ( $attr =~ m/\?/ ) {
- push(@untracked, $filename) unless grep $_ eq $filename, @untracked;
- }
-
- if ( $attr =~ m/[M]/ ) {
- push(@modified, $filename) unless grep $_ eq $filename, @modified;
- }
-
- if ( $attr =~ m/[A]/ ) {
- push(@added, $filename) unless grep $_ eq $filename, @added;
- }
- if ( $attr =~ m/[D]/ ) {
- push(@deleted, $filename) unless grep $_ eq $filename, @deleted;
- }
- }
- }
- return ( \@untracked, \@modified, \@added, \@deleted );
- }
- sub addFiles($$) {
- my $filesToAddRef = shift;
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- foreach my $file ( @$filesToAddRef ) {
- shellex("$gitCmd add $file",$logger);
- }
- }
- sub commitChanges($$) {
- my $commitMsg = shift;
- chomp $commitMsg;
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- shellex("$gitCmd commit -m \"$commitMsg\"",$logger);
- }
- sub pushChanges($) {
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- my $output = shellex("$gitCmd push",$logger);
- }
- sub dropStash($) {
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- my @stashList = split("\n", shellex("$gitCmd stash list",$logger));
- my $stashCount = scalar @stashList;
- # TODO: Don't need $stashCount, should just be able to iterate over @stashList
- if ( scalar @stashList == 0 ) {
- print "Stash is empty so not dropping\n";
- } else {
- foreach my $stashNum ( 1..$stashCount ) {
- shellex("$gitCmd stash drop 0",$logger);
- }
- }
- }
- sub stashAndReset($) {
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- shellex("$gitCmd stash",$logger);
- dropStash($logger);
- shellex("$gitCmd rebase",$logger);
- }
- sub resetFromUpstream($) {
- # git stash and git reset --hard and git pull ? I think
- # git reset upstream/master; git stash
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- my $upstream = shellex("$gitCmd config --get remote.upstream.url",$logger);
- if ( $upstream eq "" || ! defined $upstream ) {
- print "Upstream not configured, exiting\n";
- exit 1;
- }
- shellex("$gitCmd reset upstream/master",$logger);
- shellex("$gitCmd stash",$logger);
- dropStash($logger);
- print "Successful reset from upstream\n";
- print "Changes have not been pushed, run \'$gitCmd pull\' to revert\n";
- }
- sub updateGitIgnore($$$) {
- my $path = shift;
- # Maybe better to accept an array of values
- my $ignoreValue = shift;
- my $logger = shift;
- checkPath($path,$logger);
- my $filename = $path . "/" . ".gitignore";
- # Make sure we're not appending/writing if entry already exists in gitignore
- if ( -f $filename ) {
- my $catCmd = findBin("cat",$logger);
- my @ignoreLines = split("\n",shellex("$catCmd $filename",$logger));
- if ( ! grep( /^$ignoreValue$/, @ignoreLines ) ) {
- open(my $fh, ">>", $filename) or die $logger->error("Couldn't open $filename, exiting...");
- chomp $ignoreValue;
- print $fh "$ignoreValue\n";
- close $fh;
- }
- } else {
- open(my $fh, ">", $filename) or die $logger->error("Couldn't open $filename, exiting...");
- chomp $ignoreValue;
- print $fh "$ignoreValue\n";
- close $fh;
- }
- }
- sub appendRepoUserConfig($$$) {
- my $desiredName = shift;
- my $desiredEmail = shift;
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- my $currentName = shellex("$gitCmd config --get user.name",$logger);
- chomp $currentName;
- my $currentEmail = shellex("$gitCmd config --get user.email",$logger);
- chomp $currentEmail;
- if ( $currentName eq $desiredName ) {
- print "Already have $desiredName configured\n";
- } else {
- shellex("$gitCmd config user.name \"$desiredName\"",$logger);
- print "Set $desiredName successfully\n";
- }
- if ( $currentEmail eq $desiredEmail ) {
- print "Already have $desiredEmail configured\n";
- } else {
- shellex("$gitCmd config user.email \"$desiredEmail\"",$logger);
- print "Set $desiredEmail successfully\n";
- }
- }
- sub basicClone($$) {
- my $cloneTarget = shift;
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- shellex("$gitCmd clone $cloneTarget",$logger);
- print "Successfully cloned $cloneTarget\n";
- }
- sub basicPull($) {
- my $logger = shift;
- my $gitCmd = findBin("git",$logger);
- my $gitPullReturn = shellex("$gitCmd pull",$logger);
- print "git pull returned:\n$gitPullReturn\n";
- }
|