Follow-up to r29036: Now that the "mergeinfo" transaction file is no
[svn.git] / contrib / client-side / svn_all_diffs.pl
blob47ef43a516c72e1bd628bfe928f1f4f3a2b8c13b
1 #!/usr/bin/perl -w
3 # $HeadURL$
4 # $LastChangedDate$
5 # $LastChangedBy$
6 # $LastChangedRevision$
8 use strict;
9 use Carp;
10 use Getopt::Long 2.25;
12 # Process the command line options.
14 # Print the log message along with the modifications made in a
15 # particular revision.
16 my $opt_print_log_message;
18 GetOptions('log' => \$opt_print_log_message)
19 or &usage;
21 &usage("$0: too many arguments") if @ARGV > 1;
23 # If there is no file or directory specified on the command line, use
24 # the current working directory as a default path.
25 my $file_or_dir = @ARGV ? shift : '.';
27 unless (-e $file_or_dir)
29 die "$0: file or directory `$file_or_dir' does not exist.\n";
32 # Get the entire log for this file or directory. Parse the log into
33 # two separate lists. The first is a list of the revision numbers
34 # when this file or directory was modified. The second is a hash of
35 # log messages for each revision.
36 my @revisions;
37 my %log_messages;
39 my $current_revision;
40 foreach my $log_line (read_from_process('svn', 'log', $file_or_dir))
42 # Ignore any of the lines containing only -'s.
43 next if $log_line =~ /^-+$/;
45 if (my ($r) = $log_line =~ /^r(\d+)/)
47 $current_revision = $r;
48 $log_messages{$current_revision} = "";
49 push(@revisions, $r);
52 if (defined $current_revision)
54 $log_messages{$current_revision} .= "$log_line\n";
59 # Run all the diffs.
60 while (@revisions > 1)
62 my $new_rev = shift @revisions;
63 my $old_rev = $revisions[0];
65 &print_revision($new_rev);
67 my @diff = read_from_process('svn', 'diff',
68 "-r$old_rev:$new_rev", $file_or_dir);
70 if ($opt_print_log_message)
72 print $log_messages{$new_rev};
74 print join("\n", @diff, "\n");
77 # Print the log message for the last revision. There is no diff for
78 # this revision, because according to svn log, the file or directory
79 # did not exist previously.
81 my $last_revision = shift @revisions;
82 if ($opt_print_log_message)
84 &print_revision($last_revision);
85 print $log_messages{$last_revision};
89 exit 0;
91 sub usage
93 warn "@_\n" if @_;
94 die "usage: $0 [options] [file_or_dir]\n",
95 "Valid options:\n",
96 " -l [--log] : also show the log messages\n";
99 sub print_revision
101 my $revision = shift;
103 print "\n\n\nRevision $revision\n";
106 # Start a child process safely without using /bin/sh.
107 sub safe_read_from_pipe
109 unless (@_)
111 croak "$0: safe_read_from_pipe passed no arguments.\n";
113 print "Running @_\n";
114 my $pid = open(SAFE_READ, '-|');
115 unless (defined $pid)
117 die "$0: cannot fork: $!\n";
119 unless ($pid)
121 open(STDERR, ">&STDOUT")
122 or die "$0: cannot dup STDOUT: $!\n";
123 exec(@_)
124 or die "$0: cannot exec `@_': $!\n";
126 my @output;
127 while (<SAFE_READ>)
129 chomp;
130 push(@output, $_);
132 close(SAFE_READ);
133 my $result = $?;
134 my $exit = $result >> 8;
135 my $signal = $result & 127;
136 my $cd = $result & 128 ? "with core dump" : "";
137 if ($signal or $cd)
139 warn "$0: pipe from `@_' failed $cd: exit=$exit signal=$signal\n";
141 if (wantarray)
143 return ($result, @output);
145 else
147 return $result;
151 # Use safe_read_from_pipe to start a child process safely and exit the
152 # script if the child failed for whatever reason.
153 sub read_from_process
155 unless (@_)
157 croak "$0: read_from_process passed no arguments.\n";
159 my ($status, @output) = &safe_read_from_pipe(@_);
160 if ($status)
162 die "$0: @_ failed with this output:\n", join("\n", @output), "\n";
164 else
166 return @output;