File Coverage

perllib/Arch/DiffParser.pm
Criterion Covered Total %
statement 89 94 94.6
branch 21 30 70.0
condition n/a
subroutine 21 22 95.4
pod 12 12 100.0
total 143 158 90.5


line stmt bran cond sub pod time code
1             # Arch Perl library, Copyright (C) 2005 Mikhael Goikhman
2             #
3             # This program is free software; you can redistribute it and/or modify
4             # it under the terms of the GNU General Public License as published by
5             # the Free Software Foundation; either version 2 of the License, or
6             # (at your option) any later version.
7             #
8             # This program is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11             # GNU General Public License for more details.
12             #
13             # You should have received a copy of the GNU General Public License
14             # along with this program; if not, write to the Free Software
15             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16              
17 3     3   79 use 5.005;
  3         10  
  3         156  
18 3     3   20 use strict;
  3         5  
  3         157  
19              
20             package Arch::DiffParser;
21              
22 3     3   1206 use Arch::Util qw(load_file);
  3         8  
  3         442  
23              
24             my $FILE1_PREFIX = '--- ';
25             my $FILE2_PREFIX = '+++ ';
26             my $HUNK_PREFIX = '@@ ';
27             my $UNMOD_PREFIX = ' ';
28             my $DEL_PREFIX = '-';
29             my $ADD_PREFIX = '+';
30             my $NOEOL_PREFIX = '\ No newline at end of file';
31              
32 3     3   23 use constant FILE1_LINE => 1 << 1;
  3         5  
  3         206  
33 3     3   14 use constant FILE2_LINE => 1 << 2;
  3         5  
  3         117  
34 3     3   15 use constant HUNK_LINE => 1 << 3;
  3         5  
  3         124  
35 3     3   14 use constant UNMOD_LINE => 1 << 4;
  3         5  
  3         117  
36 3     3   22 use constant DEL_LINE => 1 << 5;
  3         6  
  3         128  
37 3     3   15 use constant ADD_LINE => 1 << 6;
  3         3  
  3         112  
38 3     3   13 use constant NOEOL_LINE => 1 << 7;
  3         5  
  3         3282  
39              
40             sub new ($) {
41 2     2 1 4 my $class = shift;
42              
43 2         7 my $self = {
44             data => undef,
45             };
46 2         9 return bless $self, $class;
47             }
48              
49             sub parse ($$) {
50 2     2 1 3 my $self = shift;
51 2         13 my $content = $self->{content} = shift;
52 2 50       10 die "Arch::DiffParser::parse: no diff content\n" unless $content;
53              
54 2         47 my @lines = $content =~ /(.*\n)/g;
55 2         6 my $hunks = [];
56 2         5 my $changes = [];
57              
58 2 50       61 $lines[0] =~ /^\Q$FILE1_PREFIX\E(.+?)(?:\t(.+))?$/o
59             or die "Unexpected line 1: $lines[0]";
60 2         12 my ($filename1, $mtime1) = ($1, $2);
61 2 50       40 $lines[1] =~ /^\Q$FILE2_PREFIX\E(.+?)(?:\t(.+))?$/o
62             or die "Unexpected line 2: $lines[1]";
63 2         7 my ($filename2, $mtime2) = ($1, $2);
64              
65 2         3 my $last_line = FILE2_LINE;
66 2         3 my $ln1 = 0;
67 2         4 my $ln2 = 0;
68              
69 2         8 for (my $i = 2; $i < @lines; $i++) {
70 18 100       169 if ($lines[$i] =~ /^\Q$HUNK_PREFIX\E-(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))?/o) {
    100          
    100          
    100          
    50          
71 2 100       16 push @$hunks, [ $1, defined $2? $2: 1, $3, defined $4? $4: 1, $i ];
    50          
72 2         4 $last_line = HUNK_LINE;
73 2         4 $ln1 = $1; $ln2 = $3;
  2         8  
74             } elsif ($lines[$i] =~ /^\Q$DEL_PREFIX\E/o) {
75 4 50       11 die if $last_line == ADD_LINE;
76 4 100       15 push @$changes, [ $ln1, 0, $ln2, 0, $i ]
77             unless $last_line == DEL_LINE;
78 4         7 $changes->[-1][1]++;
79 4         4 $last_line = DEL_LINE;
80 4         14 $ln1++;
81             } elsif ($lines[$i] =~ /^\Q$ADD_PREFIX\E/o) {
82 4 100       16 push @$changes, [ $ln1, 0, $ln2, 0, $i ]
83             unless $last_line & (DEL_LINE | ADD_LINE | NOEOL_LINE);
84 4         5 $changes->[-1][3]++;
85 4         5 $last_line = ADD_LINE;
86 4         12 $ln2++;
87             } elsif ($lines[$i] =~ /^\Q$UNMOD_PREFIX\E/o) {
88 6         6 $last_line = UNMOD_LINE;
89 6         7 $ln1++; $ln2++;
  6         15  
90             } elsif ($lines[$i] =~ /^\Q$NOEOL_PREFIX\E/o) {
91 2         7 $last_line = NOEOL_LINE;
92             } else {
93 0         0 die "Unrecognized diff line #" . ($i + 1) . ":\n$lines[$i]";
94             }
95             }
96              
97 2         14 $self->{data} = {
98             lines => \@lines,
99             filename1 => $filename1,
100             filename2 => $filename2,
101             mtime1 => $mtime1,
102             mtime2 => $mtime2,
103             hunks => $hunks,
104             changes => $changes,
105             };
106 2         15 return $self;
107             }
108              
109             sub parse_file ($$) {
110 0     0 1 0 my $self = shift;
111 0         0 my $file_name = shift;
112 0 0       0 die "Arch::DiffParser::parse_file: no diff file name\n"
113             unless $file_name;
114              
115 0         0 return $self->parse(load_file($file_name));
116             }
117              
118             sub diff_data ($) {
119 20     20 1 34 my $self = shift;
120              
121 20         33 my $data = $self->{data};
122 20 50       57 die "Arch::DiffParser::info: no last diff info, perform parse first\n"
123             unless $data;
124 20         117 return $data;
125             }
126              
127             sub content ($%) {
128 2     2 1 5 my $self = shift;
129 2         6 my %args = @_;
130              
131 2         4 return join("", @{$self->diff_data->{lines}});
  2         6  
132             }
133              
134             sub lines ($) {
135 2     2 1 4 my $self = shift;
136 2         7 return $self->diff_data->{lines};
137             }
138              
139             sub filename1 ($) {
140 4     4 1 8 my $self = shift;
141 4         10 return $self->diff_data->{filename1};
142             }
143              
144             sub filename2 ($) {
145 2     2 1 6 my $self = shift;
146 2         6 return $self->diff_data->{filename2};
147             }
148              
149             sub mtime1 ($) {
150 2     2 1 5 my $self = shift;
151 2         8 return $self->diff_data->{mtime1};
152             }
153              
154             sub mtime2 ($) {
155 2     2 1 6 my $self = shift;
156 2         7 return $self->diff_data->{mtime2};
157             }
158              
159             sub hunks ($) {
160 2     2 1 6 my $self = shift;
161 2         7 return $self->diff_data->{hunks};
162             }
163              
164             sub changes ($) {
165 2     2 1 6 my $self = shift;
166 2         7 return $self->diff_data->{changes};
167             }
168              
169             1;
170              
171             __END__