git-list 5.1 KB

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