Chmod +x.
[git2cl.git] / git2cl
blobaa204f5b091b03ab0cc903aabc55324fab8dfa26
1 #!/usr/bin/perl
3 # Copyright (C) 2007 Simon Josefsson.
5 # The functions mywrap, last_line_len, wrap_log_entry are derived from
6 # the cvs2cl tool, see <http://www.red-bean.com/cvs2cl/>:
7 # Copyright (C) 2001,2002,2003,2004 Martyn J. Pearce <fluffy@cpan.org>
8 # Copyright (C) 1999 Karl Fogel <kfogel@red-bean.com>
10 # git2cl is free software; you can redistribute it and/or modify it
11 # under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2, or (at your option)
13 # any later version.
15 # git2cl is distributed in the hope that it will be useful, but
16 # WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 # General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with git2cl; see the file COPYING. If not, write to the Free
22 # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 # 02111-1307, USA.
25 use strict;
26 use Date::Parse qw(strptime);
27 use POSIX qw(strftime);
28 use Text::Wrap qw(wrap);
30 use constant EMPTY_LOG_MESSAGE => '*** empty log message ***';
32 sub mywrap {
33 my ($indent1, $indent2, @text) = @_;
34 # If incoming text looks preformatted, don't get clever
35 my $text = Text::Wrap::wrap($indent1, $indent2, @text);
36 if ( grep /^\s+/m, @text ) {
37 return $text;
39 my @lines = split /\n/, $text;
40 $indent2 =~ s!^((?: {8})+)!"\t" x (length($1)/8)!e;
41 $lines[0] =~ s/^$indent1\s+/$indent1/;
42 s/^$indent2\s+/$indent2/
43 for @lines[1..$#lines];
44 my $newtext = join "\n", @lines;
45 $newtext .= "\n"
46 if substr($text, -1) eq "\n";
47 return $newtext;
50 sub last_line_len {
51 my $files_list = shift;
52 my @lines = split (/\n/, $files_list);
53 my $last_line = pop (@lines);
54 return length ($last_line);
57 # A custom wrap function, sensitive to some common constructs used in
58 # log entries.
59 sub wrap_log_entry {
60 my $text = shift; # The text to wrap.
61 my $left_pad_str = shift; # String to pad with on the left.
63 # These do NOT take left_pad_str into account:
64 my $length_remaining = shift; # Amount left on current line.
65 my $max_line_length = shift; # Amount left for a blank line.
67 my $wrapped_text = ''; # The accumulating wrapped entry.
68 my $user_indent = ''; # Inherited user_indent from prev line.
70 my $first_time = 1; # First iteration of the loop?
71 my $suppress_line_start_match = 0; # Set to disable line start checks.
73 my @lines = split (/\n/, $text);
74 while (@lines) # Don't use `foreach' here, it won't work.
76 my $this_line = shift (@lines);
77 chomp $this_line;
79 if ($this_line =~ /^(\s+)/) {
80 $user_indent = $1;
82 else {
83 $user_indent = '';
86 # If it matches any of the line-start regexps, print a newline now...
87 if ($suppress_line_start_match)
89 $suppress_line_start_match = 0;
91 elsif (($this_line =~ /^(\s*)\*\s+[a-zA-Z0-9]/)
92 || ($this_line =~ /^(\s*)\* [a-zA-Z0-9_\.\/\+-]+/)
93 || ($this_line =~ /^(\s*)\([a-zA-Z0-9_\.\/\+-]+(\)|,\s*)/)
94 || ($this_line =~ /^(\s+)(\S+)/)
95 || ($this_line =~ /^(\s*)- +/)
96 || ($this_line =~ /^()\s*$/)
97 || ($this_line =~ /^(\s*)\*\) +/)
98 || ($this_line =~ /^(\s*)[a-zA-Z0-9](\)|\.|\:) +/))
100 $length_remaining = $max_line_length - (length ($user_indent));
103 # Now that any user_indent has been preserved, strip off leading
104 # whitespace, so up-folding has no ugly side-effects.
105 $this_line =~ s/^\s*//;
107 # Accumulate the line, and adjust parameters for next line.
108 my $this_len = length ($this_line);
109 if ($this_len == 0)
111 # Blank lines should cancel any user_indent level.
112 $user_indent = '';
113 $length_remaining = $max_line_length;
115 elsif ($this_len >= $length_remaining) # Line too long, try breaking it.
117 # Walk backwards from the end. At first acceptable spot, break
118 # a new line.
119 my $idx = $length_remaining - 1;
120 if ($idx < 0) { $idx = 0 };
121 while ($idx > 0)
123 if (substr ($this_line, $idx, 1) =~ /\s/)
125 my $line_now = substr ($this_line, 0, $idx);
126 my $next_line = substr ($this_line, $idx);
127 $this_line = $line_now;
129 # Clean whitespace off the end.
130 chomp $this_line;
132 # The current line is ready to be printed.
133 $this_line .= "\n${left_pad_str}";
135 # Make sure the next line is allowed full room.
136 $length_remaining = $max_line_length - (length ($user_indent));
138 # Strip next_line, but then preserve any user_indent.
139 $next_line =~ s/^\s*//;
141 # Sneak a peek at the user_indent of the upcoming line, so
142 # $next_line (which will now precede it) can inherit that
143 # indent level. Otherwise, use whatever user_indent level
144 # we currently have, which might be none.
145 my $next_next_line = shift (@lines);
146 if ((defined ($next_next_line)) && ($next_next_line =~ /^(\s+)/)) {
147 $next_line = $1 . $next_line if (defined ($1));
148 # $length_remaining = $max_line_length - (length ($1));
149 $next_next_line =~ s/^\s*//;
151 else {
152 $next_line = $user_indent . $next_line;
154 if (defined ($next_next_line)) {
155 unshift (@lines, $next_next_line);
157 unshift (@lines, $next_line);
159 # Our new next line might, coincidentally, begin with one of
160 # the line-start regexps, so we temporarily turn off
161 # sensitivity to that until we're past the line.
162 $suppress_line_start_match = 1;
164 last;
166 else
168 $idx--;
172 if ($idx == 0)
174 # We bottomed out because the line is longer than the
175 # available space. But that could be because the space is
176 # small, or because the line is longer than even the maximum
177 # possible space. Handle both cases below.
179 if ($length_remaining == ($max_line_length - (length ($user_indent))))
181 # The line is simply too long -- there is no hope of ever
182 # breaking it nicely, so just insert it verbatim, with
183 # appropriate padding.
184 $this_line = "\n${left_pad_str}${this_line}";
186 else
188 # Can't break it here, but may be able to on the next round...
189 unshift (@lines, $this_line);
190 $length_remaining = $max_line_length - (length ($user_indent));
191 $this_line = "\n${left_pad_str}";
195 else # $this_len < $length_remaining, so tack on what we can.
197 # Leave a note for the next iteration.
198 $length_remaining = $length_remaining - $this_len;
200 if ($this_line =~ /\.$/)
202 $this_line .= " ";
203 $length_remaining -= 2;
205 else # not a sentence end
207 $this_line .= " ";
208 $length_remaining -= 1;
212 # Unconditionally indicate that loop has run at least once.
213 $first_time = 0;
215 $wrapped_text .= "${user_indent}${this_line}";
218 # One last bit of padding.
219 $wrapped_text .= "\n";
221 return $wrapped_text;
224 # main
226 my @date;
227 my $author;
228 my @files;
229 my $comment;
231 my $state; # 0-header 1-comment 2-files
232 my $done = 0;
234 $state = 0;
236 while (<>) {
237 if ($state == 0) {
238 if (m,^Author: (.*),) {
239 $author = $1;
241 if (m,^Date: (.*),) {
242 @date = strptime($1);
244 $state = 1 if (m,^$,);
245 } elsif ($state == 1) {
246 $state = 2 if (m,^$,);
247 s/^ //g;
248 s/\n/ /g;
249 $comment = $comment . $_;
250 } elsif ($state == 2) {
251 if (m,^([0-9]+)\t([0-9]+)\t(.*)$,) {
252 push @files, $3;
253 } elsif (m,^[^ ],) {
254 # No file changes.
255 $done = 1;
257 $done = 1 if (m,^$,);
260 if ($done && @date == ()) {
261 print STDERR "warning: could not parse entry\n";
262 } elsif ($done) {
263 print (strftime "%Y-%m-%d $author\n\n", @date);
265 my $files = join (", ", @files);
266 $files = mywrap ("\t", "\t", "* $files"), ": ";
268 if (index($comment, EMPTY_LOG_MESSAGE) > -1 ) {
269 $comment = "[no log message]\n";
272 my $files_last_line_len = 0;
273 $files_last_line_len = last_line_len($files) + 1;
274 my $msg = wrap_log_entry($comment, "\t", 69-$files_last_line_len, 69);
276 $msg =~ s/[ \t]+\n/\n/g;
278 print "$files: $msg\n";
280 @date = ();
281 $author = "";
282 @files = ();
283 $comment = "";
285 $state = 0;
286 $done = 0;
290 print (strftime "%Y-%m-%d $author\n\n", @date);
291 my $msg = wrap_log_entry($comment, "\t", 69, 69);
292 $msg =~ s/[ \t]+\n/\n/g;
293 print "\t* $msg\n";