search-svnlog.pl 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #!/usr/bin/perl -w
  2. # ====================================================================
  3. # Show log messages matching a certain pattern. Usage:
  4. #
  5. # search-svnlog.pl [-v] [-f LOGFILE] REGEXP
  6. #
  7. # See &usage() for details.
  8. #
  9. # ====================================================================
  10. # Copyright (c) 2000-2004 CollabNet. All rights reserved.
  11. #
  12. # This software is licensed as described in the file COPYING, which
  13. # you should have received as part of this distribution. The terms
  14. # are also available at http://subversion.tigris.org/license-1.html.
  15. # If newer versions of this license are posted there, you may use a
  16. # newer version instead, at your option.
  17. #
  18. # This software consists of voluntary contributions made by many
  19. # individuals. For exact contribution history, see the revision
  20. # history and logs, available at http://subversion.tigris.org/.
  21. # ====================================================================
  22. use strict;
  23. use Getopt::Long;
  24. my $log_file;
  25. my $invert = 0;
  26. my $caseless = 0;
  27. GetOptions('f|file=s' => \$log_file,
  28. 'v|invert' => \$invert,
  29. 'i|caseinsensitive' => \$caseless) or &usage;
  30. &usage("$0: too few arguments") unless @ARGV;
  31. &usage("$0: too many arguments") if @ARGV > 1;
  32. my $filter = shift;
  33. $filter = '(?i)' . $filter if $caseless;
  34. my $log_cmd = "svn log -v";
  35. my $log_separator = '-' x 72 . "\n";
  36. my $open_string = defined $log_file ? $log_file : "$log_cmd |";
  37. open(LOGDATA, $open_string) or
  38. die "$0: cannot open `$open_string' for reading: $!\n";
  39. my $this_entry_accum = "";
  40. my $this_rev = -1;
  41. my $this_lines = 0;
  42. my $seen_blank_line; # A blank line separates headers from body.
  43. while (<LOGDATA>)
  44. {
  45. if (/^r([0-9]+) \| [^\|]* \| [^\|]* \| ([0-9]+) (line|lines)$/)
  46. {
  47. $this_rev = $1;
  48. $this_lines = $2 + 1; # Compensate for blank line preceding body.
  49. $this_entry_accum .= $_;
  50. }
  51. elsif ($this_lines == 0) # Reached end of msg. Looking at log separator?
  52. {
  53. if (! ($_ eq $log_separator))
  54. {
  55. die "$0: wrong number of lines for log message!\n${this_entry_accum}\n";
  56. }
  57. if ($this_entry_accum =~ /$filter/og ^ $invert)
  58. {
  59. print "${this_entry_accum}${log_separator}";
  60. }
  61. # Reset accumulators.
  62. $seen_blank_line = 0;
  63. $this_entry_accum = "";
  64. $this_rev = -1;
  65. }
  66. elsif ($this_lines < 0)
  67. {
  68. die "$0: line weirdness parsing log.\n";
  69. }
  70. else # Just continue accumulating.
  71. {
  72. $this_entry_accum .= $_;
  73. if ($seen_blank_line)
  74. {
  75. $this_lines--;
  76. }
  77. elsif (/^$/)
  78. {
  79. $seen_blank_line = 1;
  80. $this_lines--;
  81. }
  82. }
  83. }
  84. close(LOGDATA) or
  85. die "$0: closing `$open_string' failed: $!\n";
  86. exit 0;
  87. sub usage {
  88. warn "@_\n" if @_;
  89. die "usage: $0: [-v] [-i] [-f LOGFILE] REGEXP\n",
  90. "\n",
  91. "Print only log messages matching REGEXP, either by running 'svn log'\n",
  92. "in the current working directory, or if '-f LOGFILE' is passed, then\n",
  93. "read the log data from LOGFILE (which should be in the same format\n",
  94. "as the output of 'svn log').\n",
  95. "\n",
  96. "If '-v' is given, the matching is inverted (like 'grep -v').\n",
  97. "\n",
  98. "If '-i' is given, the matching is case-insensitive (like 'grep -i').\n";
  99. }