raylu 7 жил өмнө
parent
commit
7b74ec7ac9
3 өөрчлөгдсөн 550 нэмэгдсэн , 0 устгасан
  1. 187 0
      git-id
  2. 202 0
      git-list
  3. 161 0
      git-number

+ 187 - 0
git-id

@@ -0,0 +1,187 @@
+#!/usr/bin/perl
+# vim: sts=4 sw=4 ts=4 expandtab:
+=pod
+
+=head1 NAME
+
+git-id
+
+=head1 SYNOPSIS
+
+    git-id
+
+=head1 DESCRIPTION
+
+Runs git-status and prepends numeric ids to filenames.
+
+=head1 OPTIONS
+
+=over 4
+
+=item -h
+
+Show this help message
+
+=item -s
+
+=item --column
+
+=item -u(no|normal|all)
+
+=item --color=(always|auto|never)
+
+These options are similar to git-status'.
+
+=back
+
+=head1 SEE ALSO
+
+    git-number(1), git-list(1)
+
+=cut
+
+use strict;
+use warnings;
+use Cwd;
+
+my $red = "\e[31m";
+my $normal = "\e[0m";
+my $git_dir = `git rev-parse --git-dir`;
+chomp $git_dir;
+
+my $gitids = "$git_dir/gitids.txt";
+
+my $color = 'always';
+my $STATUS_DEFAULT = 0;
+my $STATUS_SHORT = 1;
+my $status_style = $STATUS_DEFAULT;
+my $status_opt = '';
+
+my $untracked_in_columns = 0;
+while (scalar @ARGV && $ARGV[0] =~ /^-/) {
+    my $option = shift @ARGV;
+    last if $option eq '--';
+    if ($option =~ /--color=(always|auto|never)/) {
+        $color = $1;
+        if ($color =~ /never/) {
+            $red = $normal = '';
+        }
+    } elsif ($option eq '--short') {
+        $status_style = $STATUS_SHORT;
+    } elsif ($option =~ m{^-u(no|normal|all)$}) {
+        $status_opt .= " $option";
+    } elsif ($option =~ /^--column/) {
+        if ($option eq '--column=never' || ($option =~ /--column(=auto)?$/ && ! -t STDOUT)) {
+            $untracked_in_columns = 0;
+        } else {
+            $untracked_in_columns = 1;
+        }
+        $status_opt .= " $option";
+    } else {
+        print "Unknown option: $option\n";
+        exit 1;
+    }
+}
+
+if (! $untracked_in_columns) {
+    $status_opt .= " --column=never";
+}
+
+my @status_option_for = ( '', '--short' );
+my $status_format = $status_option_for[$status_style];
+my $git_cmd = "git -c color.status=$color status $status_opt $status_format "
+              . join(' ', @ARGV);
+open my $git_status, "$git_cmd|"
+    or die "Error: $!";
+
+open my $cache, ">$gitids"
+    or die "Error: $!";
+
+# Headers
+print $cache "cwd: " . getcwd . "\n";
+print $cache "status-format: $status_format\n";
+print $cache "\n";
+
+my $seen_untracked = 0;
+my @untracked;
+my $c = 1;
+while (my $line = <$git_status>) {
+    if ($line =~ /Untracked files:/) {
+        $seen_untracked = 1;
+    }
+
+    if ($status_style == $STATUS_DEFAULT) {
+        if ($seen_untracked && $line =~ /\t/ && $untracked_in_columns) {
+            push @untracked, $line;
+            last;
+        }
+
+        if ($line =~ /#\t/) {
+            $line =~ s/#\t/#$c\t/;
+            $c += 1;
+        } elsif ($line =~ /\t/) {
+            $line =~ s/\t/$c\t/;
+            $c += 1;
+        }
+    } elsif ($status_style == $STATUS_SHORT) {
+        if ($line !~ /^#/) {
+            $line =~ s/^/$c /;
+            $c += 1;
+        }
+    }
+    show_and_cache($line);
+}
+
+if ($untracked_in_columns) {
+    my $seen_files = 0;
+    my @the_rest;
+    while (my $line = <$git_status>) {
+        if ($line =~ /\t/) {
+            $seen_files = 1;
+            push @untracked, $line;
+        } else {
+            push @the_rest, $line;
+        }
+    }
+
+    my $rows = @untracked;
+    foreach my $line (@untracked) {
+        my $id = $c;
+        $line =~ s/([\t ])(\S)/add_number(\$id, $1, $2, $rows)/ge;
+        $line =~ s/^ +//;
+        show_and_cache($line);
+        $c += 1;
+    }
+    print join "", @the_rest;
+}
+
+close $git_status;
+close $cache;
+exit 0;
+
+sub show_and_cache {
+    my ($line) = @_;
+    my $tocache = $line;
+    $tocache =~ s/{(\d+)}[\t ]{1,2}/\n$1\t/g;
+    $line =~ s/{(\d+)}/$1/g;
+    print $line;
+    $tocache =~ s/\e\[(\d*(;\d*)*)m//g;
+    if ($untracked_in_columns) {
+        $tocache =~ s/\s*\n/\n/gms; # Trailing spaces from columnar formatting
+    }
+    print $cache $tocache;
+}
+
+sub add_number {
+    my ($nref, $space, $first_char, $incr) = @_;
+
+    my $num = $$nref;
+    if ($num < 10 && $space eq ' ') {
+        $num = "{$num} ";
+    } else {
+        $num = "{$num}";
+    }
+    my $str = "$normal$num$space$red$first_char";
+    $$nref += $incr;
+    return $str;
+}

+ 202 - 0
git-list

@@ -0,0 +1,202 @@
+#!/usr/bin/perl
+# vim: sts=4 sw=4 ts=4 expandtab:
+# gl - List files from .git/gitids.txt
+
+use strict;
+use warnings;
+use File::Spec;
+use Cwd qw/getcwd abs_path/;
+
+=pod
+
+=head1 NAME
+
+git-list
+
+=head1 SYNOPSIS
+
+    git-list [-h] [number pattern]
+
+=head1 DESCRIPTION
+
+git-list lists the corresponding filenames given their numbers that was
+previously assigned by git-id. It lists one filename per line of output. Any
+other argument or numbers that has no filenames associated with it will be
+printed as is.
+
+[number pattern] can either be a single number or a range:
+
+    git-list 1 5-6
+
+=head1 OPTIONS
+
+    -h         Show this help message
+
+=head1 SEE ALSO
+
+    git-number(1), git-id(1)
+
+=cut
+
+if (defined $ARGV[0] && $ARGV[0] eq '-h') {
+    system(qq[perldoc $0]);
+    exit 0;
+}
+
+my $wanted_ids = explode_args(@ARGV);
+
+if (ref $wanted_ids eq 'ARRAY') {
+    my $file_for = get_file_ids();
+    foreach my $id (@$wanted_ids) {
+        if (defined $file_for->{$id}) {
+            print $file_for->{$id};
+        } else {
+            print $id;
+        }
+        print "\n";
+    }
+} elsif ($wanted_ids eq 'all') {
+    my @file_list = get_file_list();
+    foreach my $entry (@file_list) {
+        print  $entry->{filename} . "\n";
+    }
+}
+exit 0;
+# Add subs below this line
+
+sub get_file_list {
+    my $git_dir = `git rev-parse --git-dir`;
+    chomp $git_dir;
+
+    my $gitids = "$git_dir/gitids.txt";
+    if (! -f $gitids) {
+        print "Please run git-number first\n";
+        exit 1;
+    }
+
+    open my $cache, "<$gitids" or die "Error: $!";
+
+    my $headers = read_headers($cache);
+    my $cwd = getcwd();
+    my $needfixdir = 0;
+    if ($headers->{cwd} ne $cwd) {
+        $needfixdir = 1;
+        $cwd = abs_path($cwd);
+    }
+    my @file_list;
+    my $status_processor_for = {
+        '' => sub {
+            while (my $line = <$cache>) {
+                next if $line !~ /^#?[0-9]+\t/;
+                chomp $line;
+                if (my ($number, $status, $filename)
+                        = $line =~ /^#?([0-9]+)\t([^:]+:\s+)?(.*)/) {
+
+
+
+                    if ($filename =~ / \(.*\)$/ && ! -e $filename) {
+                        # Looks like a submodule status, see if it really is a submodule
+                        my ($dir) = $filename =~ /(.*) \(.*\)$/;
+                        if (-d $dir && -e "$dir/.git") {
+                                $filename = $dir;
+                        }
+                    }
+
+                    if ($needfixdir) {
+                        $filename = fixdir($filename, $headers->{cwd}, $cwd);
+                    }
+                    push @file_list, {
+                            number => $number,
+                            status => $status,
+                            filename => $filename,
+                        };
+                }
+            }
+        },
+        '--short' => sub {
+            while (my $line = <$cache>) {
+                next if $line !~ /^[0-9]+\s/;
+                chomp $line;
+                if (my ($number, $status, $filename)
+                        = $line =~ /^([0-9]+)\s+([^ ]+)\s+(.*)/) {
+
+                    if ($needfixdir) {
+                        $filename = fixdir($filename, $headers->{cwd}, $cwd);
+                    }
+                    push @file_list, {
+                            number => $number,
+                            status => $status,
+                            filename => $filename,
+                        };
+                }
+            }
+        },
+    };
+
+    my $status_format = $headers->{'status-format'};
+    $status_processor_for->{$status_format}->();
+    close $cache;
+    return @file_list;
+}
+
+sub read_headers {
+    my ($cache) = @_;
+    my %headers;
+    while (my $line = <$cache>) {
+        chomp $line;
+        last if length $line == 0;
+        my ($field, $value) = split(/:\s*/, $line, 2);
+        $headers{$field} = $value;
+    }
+    return \%headers;
+}
+
+sub get_file_ids {
+    my @file_list = get_file_list();
+
+    my %file_for;
+    foreach my $entry (@file_list) {
+        my $filename = $entry->{filename};
+        # First we escape characters that need escaping
+        if ($filename =~ /[`\$"]/) {
+            $filename =~ s/([`\$"])/\\$1/g;
+        }
+        # Then we double-quote the name if necessary
+        if ($filename =~ /[ '\[\]()&]/) {
+            $filename = '"' . $filename . '"';
+        }
+        $file_for{$entry->{number}} = $filename;
+    }
+    return \%file_for;
+}
+
+sub explode_args {
+    my (@ARGV) = @_;
+    if (scalar @ARGV == 0) {
+        return 'all';
+    }
+    my @wanted_ids;
+    foreach my $arg (@ARGV) {
+        if ($arg =~ m/^[0-9]+$/) {
+            push @wanted_ids, $arg;
+        } elsif ($arg =~ m/^([0-9]+)-([0-9]+)/) {
+            my $a = $1;
+            my $b = $2;
+            if ($a > $b) {
+                $a = $b;
+                $b = $1;
+            }
+            push @wanted_ids, $a..$b;
+        } else {
+            push @wanted_ids, $arg;
+        }
+    }
+    return \@wanted_ids;
+}
+
+sub fixdir {
+    my ($filename, $orig_cwd, $cwd) = @_;
+    my $abspath = File::Spec->catfile($orig_cwd, $filename);
+    $abspath = abs_path($abspath);
+    return File::Spec->abs2rel($abspath, $cwd);
+}

+ 161 - 0
git-number

@@ -0,0 +1,161 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use File::Basename;
+
+# git-number:
+#
+
+=pod
+
+=head1 NAME
+
+git-number
+
+=head1 SYNOPSIS
+
+    git-number [-h|--color=<when>|-s] [<git-cmd|-c <cmd>> [git-or-cmd-options] [files or numbers]] [-- ...]
+
+=head1 DESCRIPTION
+
+When run without arguments, runs git-status and assign numeric ids to filenames shown by git-status.
+
+When run with arguments, runs <git-cmd> or <cmd>, and replaces any number in
+the arguments with the corresponding filename from the previous run of
+git-number.
+
+Any args given after `--' are passed to the underlying command verbatim.
+
+=head1 OPTIONS
+
+=over 4
+
+=item -c <cmd>
+
+Runs I<E<lt>cmdE<gt>> instead of git on the given arguments.
+All arguments that follows <cmd> will be passed on to <cmd>.
+
+=item -v
+
+Show version information
+
+=item -h
+
+Show this help message
+
+=item -s
+
+=item --column
+
+=item -u(no|normal|all)
+
+=item --color=(always|auto|never)
+
+These options are similar to git-status'.
+
+=back
+
+=head1 SEE ALSO
+
+    git-id(1), git-list(1)
+
+=head1 VERSION
+
+1.0.1
+=cut
+my $VERSION = '1.0.1'; # Don't forget to update the one in pod!
+
+my $me = basename(__FILE__);
+sub show_usage_and_exit {
+    my ($exit_value) = @_;
+    $exit_value = 0 if ! defined $exit_value;
+    system(qq[perldoc "$0"]);
+    exit $exit_value;
+}
+
+sub run_cmd {
+    my ($cmd) = @_;
+    system($cmd);
+    if ($? == -1) {
+        print STDERR "$me: $!\n";
+        return 1;
+    }
+    return $? >> 8;
+}
+
+my $run = 'git';
+my $color = 'always';
+my $status_opt = '';
+my $passthru_args = '';
+if (grep(/^--$/, @ARGV) == 0 && $ARGV[-1] && $ARGV[-1] eq '.') {
+    $ARGV[-1] = '--';
+    push @ARGV, '.';
+}
+while (scalar @ARGV && $ARGV[0] =~ /^-/) {
+    my $option = shift @ARGV;
+    if ($option eq '--') {
+        $passthru_args = join(' ', @ARGV);
+        @ARGV = ();
+        last;
+    }
+    if ($option eq '-h') {
+        show_usage_and_exit();
+    } elsif ($option eq '-v') {
+        print "$VERSION\n";
+        exit 0;
+    } elsif ($option eq '-c') {
+        $run = shift @ARGV;
+        last;
+    } elsif ($option =~ m{--color=(always|auto|never)}) {
+        $color = $1;
+    } elsif ($option eq '-s') {
+        $status_opt .= " --short";
+    } elsif ($option =~ m{^-u(no|normal|all)$}) {
+        $status_opt .= " $option";
+    } elsif ($option =~ m{^--column}) {
+        $status_opt .= " $option";
+    } else {
+        print "Unknown option: $option\n";
+        exit 1;
+    }
+}
+
+if ($run eq 'git' && scalar @ARGV == 0) {
+    my $cmd = join(' ',
+            "git-id",
+            "--color=$color",
+            "$status_opt",
+            "-- $passthru_args",
+        );
+    exit run_cmd($cmd);
+}
+
+my @args;
+
+my $converted=0;
+while (scalar @ARGV) {
+    my $arg = shift @ARGV;
+    if ($arg eq '--') {
+        push(@args, @ARGV);
+        last;
+    }
+
+    if ( $arg =~ m/^[0-9][0-9]*$/ ) {
+        push @args, split("\n", `git-list $arg`);
+        $converted=1;
+    } elsif ( $arg =~ m/^[0-9][0-9]*-[0-9][0-9]*$/ ) {
+        push @args, split("\n", `git-list $arg`);
+        $converted=1;
+    } else {
+        if (index($arg, ' ') != -1) {
+            $arg = "\"$arg\"";
+        }
+        push @args, $arg;
+    }
+}
+
+my $cmd = "$run " . join(' ', @args);
+if (-t STDOUT && $converted) {
+    print $cmd . "\n";
+}
+exit run_cmd($cmd);