git-list (5173B)
1 #!/usr/bin/perl 2 # vim: sts=4 sw=4 ts=4 expandtab: 3 # gl - List files from .git/gitids.txt 4 5 use strict; 6 use warnings; 7 use File::Spec; 8 use Cwd qw/getcwd abs_path/; 9 10 =pod 11 12 =head1 NAME 13 14 git-list 15 16 =head1 SYNOPSIS 17 18 git-list [-h] [number pattern] 19 20 =head1 DESCRIPTION 21 22 git-list lists the corresponding filenames given their numbers that was 23 previously assigned by git-id. It lists one filename per line of output. Any 24 other argument or numbers that has no filenames associated with it will be 25 printed as is. 26 27 [number pattern] can either be a single number or a range: 28 29 git-list 1 5-6 30 31 =head1 OPTIONS 32 33 -h Show this help message 34 35 =head1 SEE ALSO 36 37 git-number(1), git-id(1) 38 39 =cut 40 41 if (defined $ARGV[0] && $ARGV[0] eq '-h') { 42 system(qq[perldoc $0]); 43 exit 0; 44 } 45 46 my $wanted_ids = explode_args(@ARGV); 47 48 if (ref $wanted_ids eq 'ARRAY') { 49 my $file_for = get_file_ids(); 50 foreach my $id (@$wanted_ids) { 51 if (defined $file_for->{$id}) { 52 print $file_for->{$id}; 53 } else { 54 print $id; 55 } 56 print "\n"; 57 } 58 } elsif ($wanted_ids eq 'all') { 59 my @file_list = get_file_list(); 60 foreach my $entry (@file_list) { 61 print $entry->{filename} . "\n"; 62 } 63 } 64 exit 0; 65 # Add subs below this line 66 67 sub get_file_list { 68 my $git_dir = `git rev-parse --git-dir`; 69 chomp $git_dir; 70 71 my $gitids = "$git_dir/gitids.txt"; 72 if (! -f $gitids) { 73 print "Please run git-number first\n"; 74 exit 1; 75 } 76 77 open my $cache, "<$gitids" or die "Error: $!"; 78 79 my $headers = read_headers($cache); 80 my $cwd = getcwd(); 81 my $needfixdir = 0; 82 if ($headers->{cwd} ne $cwd) { 83 $needfixdir = 1; 84 $cwd = abs_path($cwd); 85 } 86 my @file_list; 87 my $status_processor_for = { 88 '' => sub { 89 while (my $line = <$cache>) { 90 next if $line !~ /^#?[0-9]+\t/; 91 chomp $line; 92 if (my ($number, $status, $filename) 93 = $line =~ /^#?([0-9]+)\t([^:]+:\s+)?(.*)/) { 94 95 96 97 if ($filename =~ / \(.*\)$/ && ! -e $filename) { 98 # Looks like a submodule status, see if it really is a submodule 99 my ($dir) = $filename =~ /(.*) \(.*\)$/; 100 if (-d $dir && -e "$dir/.git") { 101 $filename = $dir; 102 } 103 } 104 105 if ($needfixdir) { 106 $filename = fixdir($filename, $headers->{cwd}, $cwd); 107 } 108 push @file_list, { 109 number => $number, 110 status => $status, 111 filename => $filename, 112 }; 113 } 114 } 115 }, 116 '--short' => sub { 117 while (my $line = <$cache>) { 118 next if $line !~ /^[0-9]+\s/; 119 chomp $line; 120 if (my ($number, $status, $filename) 121 = $line =~ /^([0-9]+)\s+([^ ]+)\s+(.*)/) { 122 123 if ($needfixdir) { 124 $filename = fixdir($filename, $headers->{cwd}, $cwd); 125 } 126 push @file_list, { 127 number => $number, 128 status => $status, 129 filename => $filename, 130 }; 131 } 132 } 133 }, 134 }; 135 136 my $status_format = $headers->{'status-format'}; 137 $status_processor_for->{$status_format}->(); 138 close $cache; 139 return @file_list; 140 } 141 142 sub read_headers { 143 my ($cache) = @_; 144 my %headers; 145 while (my $line = <$cache>) { 146 chomp $line; 147 last if length $line == 0; 148 my ($field, $value) = split(/:\s*/, $line, 2); 149 $headers{$field} = $value; 150 } 151 return \%headers; 152 } 153 154 sub get_file_ids { 155 my @file_list = get_file_list(); 156 157 my %file_for; 158 foreach my $entry (@file_list) { 159 my $filename = $entry->{filename}; 160 # First we escape characters that need escaping 161 if ($filename =~ /[`\$"]/) { 162 $filename =~ s/([`\$"])/\\$1/g; 163 } 164 # Then we double-quote the name if necessary 165 if ($filename =~ /[ '\[\]()&]/) { 166 $filename = '"' . $filename . '"'; 167 } 168 $file_for{$entry->{number}} = $filename; 169 } 170 return \%file_for; 171 } 172 173 sub explode_args { 174 my (@ARGV) = @_; 175 if (scalar @ARGV == 0) { 176 return 'all'; 177 } 178 my @wanted_ids; 179 foreach my $arg (@ARGV) { 180 if ($arg =~ m/^[0-9]+$/) { 181 push @wanted_ids, $arg; 182 } elsif ($arg =~ m/^([0-9]+)-([0-9]+)/) { 183 my $a = $1; 184 my $b = $2; 185 if ($a > $b) { 186 $a = $b; 187 $b = $1; 188 } 189 push @wanted_ids, $a..$b; 190 } else { 191 push @wanted_ids, $arg; 192 } 193 } 194 return \@wanted_ids; 195 } 196 197 sub fixdir { 198 my ($filename, $orig_cwd, $cwd) = @_; 199 my $abspath = File::Spec->catfile($orig_cwd, $filename); 200 $abspath = abs_path($abspath); 201 return File::Spec->abs2rel($abspath, $cwd); 202 }