| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Eshu; |
|
2
|
|
|
|
|
|
|
|
|
3
|
62
|
|
|
62
|
|
6159950
|
use 5.008003; |
|
|
62
|
|
|
|
|
195
|
|
|
4
|
62
|
|
|
62
|
|
303
|
use strict; |
|
|
62
|
|
|
|
|
110
|
|
|
|
62
|
|
|
|
|
1844
|
|
|
5
|
62
|
|
|
62
|
|
251
|
use warnings; |
|
|
62
|
|
|
|
|
95
|
|
|
|
62
|
|
|
|
|
5402
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
require XSLoader; |
|
10
|
|
|
|
|
|
|
XSLoader::load('Eshu', $VERSION); |
|
11
|
|
|
|
|
|
|
|
|
12
|
62
|
|
|
62
|
|
317
|
use File::Find (); |
|
|
62
|
|
|
|
|
149
|
|
|
|
62
|
|
|
|
|
1065
|
|
|
13
|
62
|
|
|
62
|
|
242
|
use File::Spec (); |
|
|
62
|
|
|
|
|
79
|
|
|
|
62
|
|
|
|
|
83060
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my $MAX_FILE_SIZE = 1_048_576; # 1MB |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub indent_file { |
|
18
|
39
|
|
|
39
|
0
|
96
|
my ($class, $path, %opts) = @_; |
|
19
|
|
|
|
|
|
|
|
|
20
|
39
|
|
|
|
|
101
|
my $result = { |
|
21
|
|
|
|
|
|
|
file => $path, |
|
22
|
|
|
|
|
|
|
status => 'unchanged', |
|
23
|
|
|
|
|
|
|
}; |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# Check file exists and is readable |
|
26
|
39
|
50
|
33
|
|
|
767
|
unless (-f $path && -r _) { |
|
27
|
0
|
|
|
|
|
0
|
$result->{status} = 'error'; |
|
28
|
0
|
|
|
|
|
0
|
$result->{error} = 'not a readable file'; |
|
29
|
0
|
|
|
|
|
0
|
return $result; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# Check file size |
|
33
|
39
|
|
|
|
|
298
|
my $size = -s $path; |
|
34
|
39
|
50
|
|
|
|
78
|
if ($size > $MAX_FILE_SIZE) { |
|
35
|
0
|
|
|
|
|
0
|
$result->{status} = 'skipped'; |
|
36
|
0
|
|
|
|
|
0
|
$result->{reason} = 'file too large'; |
|
37
|
0
|
|
|
|
|
0
|
return $result; |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# Read file |
|
41
|
39
|
50
|
|
|
|
1186
|
open my $fh, '<', $path or do { |
|
42
|
0
|
|
|
|
|
0
|
$result->{status} = 'error'; |
|
43
|
0
|
|
|
|
|
0
|
$result->{error} = "cannot open: $!"; |
|
44
|
0
|
|
|
|
|
0
|
return $result; |
|
45
|
|
|
|
|
|
|
}; |
|
46
|
39
|
|
|
|
|
93
|
my $src = do { local $/; <$fh> }; |
|
|
39
|
|
|
|
|
179
|
|
|
|
39
|
|
|
|
|
1107
|
|
|
47
|
39
|
|
|
|
|
320
|
close $fh; |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# Binary detection: NUL in first 8KB |
|
50
|
39
|
50
|
|
|
|
130
|
if (length($src) > 0) { |
|
51
|
39
|
|
|
|
|
85
|
my $sample = substr($src, 0, 8192); |
|
52
|
39
|
100
|
|
|
|
114
|
if ($sample =~ /\0/) { |
|
53
|
1
|
|
|
|
|
4
|
$result->{status} = 'skipped'; |
|
54
|
1
|
|
|
|
|
3
|
$result->{reason} = 'binary file'; |
|
55
|
1
|
|
|
|
|
7
|
return $result; |
|
56
|
|
|
|
|
|
|
} |
|
57
|
|
|
|
|
|
|
} |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# Detect language |
|
60
|
38
|
|
66
|
|
|
470
|
my $lang = $opts{lang} || $class->detect_lang($path); |
|
61
|
38
|
100
|
|
|
|
95
|
unless (defined $lang) { |
|
62
|
2
|
|
|
|
|
4
|
$result->{status} = 'skipped'; |
|
63
|
2
|
|
|
|
|
3
|
$result->{reason} = 'unrecognised extension'; |
|
64
|
2
|
|
|
|
|
6
|
return $result; |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# Build indent options |
|
68
|
36
|
|
|
|
|
115
|
my %indent_opts = (lang => $lang); |
|
69
|
36
|
|
|
|
|
69
|
for my $k (qw(indent_char indent_width indent_pp range_start range_end)) { |
|
70
|
180
|
50
|
|
|
|
292
|
$indent_opts{$k} = $opts{$k} if exists $opts{$k}; |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# Indent |
|
74
|
36
|
|
|
|
|
297
|
my $fixed = $class->indent_string($src, %indent_opts); |
|
75
|
|
|
|
|
|
|
|
|
76
|
36
|
100
|
|
|
|
87
|
if ($fixed eq $src) { |
|
77
|
2
|
|
|
|
|
6
|
$result->{status} = 'unchanged'; |
|
78
|
|
|
|
|
|
|
} else { |
|
79
|
34
|
100
|
|
|
|
88
|
$result->{status} = $opts{fix} ? 'changed' : 'needs_fixing'; |
|
80
|
34
|
100
|
|
|
|
62
|
if ($opts{fix}) { |
|
81
|
12
|
50
|
|
|
|
990
|
open my $out, '>', $path or do { |
|
82
|
0
|
|
|
|
|
0
|
$result->{status} = 'error'; |
|
83
|
0
|
|
|
|
|
0
|
$result->{error} = "cannot write: $!"; |
|
84
|
0
|
|
|
|
|
0
|
return $result; |
|
85
|
|
|
|
|
|
|
}; |
|
86
|
12
|
|
|
|
|
51
|
print $out $fixed; |
|
87
|
12
|
|
|
|
|
942
|
close $out; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
34
|
100
|
|
|
|
83
|
$result->{diff} = _simple_diff($path, $src, $fixed) if $opts{diff}; |
|
90
|
|
|
|
|
|
|
} |
|
91
|
36
|
|
|
|
|
70
|
$result->{lang} = $lang; |
|
92
|
36
|
|
|
|
|
160
|
return $result; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub indent_dir { |
|
96
|
16
|
|
|
16
|
0
|
29436
|
my ($class, $path, %opts) = @_; |
|
97
|
|
|
|
|
|
|
|
|
98
|
16
|
100
|
|
|
|
68
|
my $recursive = exists $opts{recursive} ? $opts{recursive} : 1; |
|
99
|
16
|
|
|
|
|
30
|
my $exclude = $opts{exclude}; |
|
100
|
16
|
|
|
|
|
28
|
my $include = $opts{include}; |
|
101
|
|
|
|
|
|
|
|
|
102
|
16
|
|
|
|
|
26
|
my @files; |
|
103
|
|
|
|
|
|
|
|
|
104
|
16
|
50
|
|
|
|
390
|
if (-f $path) { |
|
|
|
50
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
0
|
push @files, $path; |
|
106
|
|
|
|
|
|
|
} elsif (-d $path) { |
|
107
|
16
|
100
|
|
|
|
41
|
if ($recursive) { |
|
108
|
|
|
|
|
|
|
File::Find::find({ |
|
109
|
|
|
|
|
|
|
wanted => sub { |
|
110
|
68
|
100
|
|
68
|
|
2953
|
return unless -f $_; |
|
111
|
45
|
50
|
33
|
|
|
290
|
return if -l $File::Find::dir && $File::Find::dir ne $path; |
|
112
|
45
|
|
|
|
|
563
|
push @files, $File::Find::name; |
|
113
|
|
|
|
|
|
|
}, |
|
114
|
15
|
|
|
|
|
1447
|
follow_skip => 2, |
|
115
|
|
|
|
|
|
|
no_chdir => 1, |
|
116
|
|
|
|
|
|
|
}, $path); |
|
117
|
|
|
|
|
|
|
} else { |
|
118
|
1
|
50
|
|
|
|
70
|
opendir my $dh, $path or die "Eshu: cannot opendir '$path': $!\n"; |
|
119
|
1
|
|
|
|
|
25
|
while (my $entry = readdir $dh) { |
|
120
|
4
|
100
|
|
|
|
11
|
next if $entry =~ /^\./; |
|
121
|
2
|
|
|
|
|
17
|
my $full = File::Spec->catfile($path, $entry); |
|
122
|
2
|
100
|
|
|
|
30
|
push @files, $full if -f $full; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
1
|
|
|
|
|
10
|
closedir $dh; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
} else { |
|
127
|
0
|
|
|
|
|
0
|
die "Eshu: '$path' is not a file or directory\n"; |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
|
|
130
|
16
|
|
|
|
|
119
|
@files = sort @files; |
|
131
|
|
|
|
|
|
|
|
|
132
|
16
|
|
|
|
|
89
|
my $report = { |
|
133
|
|
|
|
|
|
|
files_checked => 0, |
|
134
|
|
|
|
|
|
|
files_changed => 0, |
|
135
|
|
|
|
|
|
|
files_skipped => 0, |
|
136
|
|
|
|
|
|
|
files_errored => 0, |
|
137
|
|
|
|
|
|
|
changes => [], |
|
138
|
|
|
|
|
|
|
}; |
|
139
|
|
|
|
|
|
|
|
|
140
|
16
|
|
|
|
|
30
|
for my $file (@files) { |
|
141
|
|
|
|
|
|
|
# Apply exclude filter |
|
142
|
46
|
100
|
|
|
|
90
|
if (defined $exclude) { |
|
143
|
12
|
100
|
|
|
|
25
|
my @pats = ref $exclude eq 'ARRAY' ? @$exclude : ($exclude); |
|
144
|
12
|
|
|
|
|
12
|
my $skip = 0; |
|
145
|
12
|
|
|
|
|
13
|
for my $pat (@pats) { |
|
146
|
15
|
100
|
|
|
|
54
|
if ($file =~ $pat) { $skip = 1; last; } |
|
|
4
|
|
|
|
|
4
|
|
|
|
4
|
|
|
|
|
6
|
|
|
147
|
|
|
|
|
|
|
} |
|
148
|
12
|
100
|
|
|
|
18
|
if ($skip) { |
|
149
|
4
|
|
|
|
|
4
|
$report->{files_skipped}++; |
|
150
|
4
|
|
|
|
|
4
|
push @{$report->{changes}}, { file => $file, status => 'skipped', reason => 'excluded' }; |
|
|
4
|
|
|
|
|
11
|
|
|
151
|
4
|
|
|
|
|
5
|
next; |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# Apply include filter |
|
156
|
42
|
100
|
|
|
|
72
|
if (defined $include) { |
|
157
|
7
|
50
|
|
|
|
44
|
my @pats = ref $include eq 'ARRAY' ? @$include : ($include); |
|
158
|
7
|
|
|
|
|
11
|
my $match = 0; |
|
159
|
7
|
|
|
|
|
9
|
for my $pat (@pats) { |
|
160
|
7
|
100
|
|
|
|
35
|
if ($file =~ $pat) { $match = 1; last; } |
|
|
4
|
|
|
|
|
3
|
|
|
|
4
|
|
|
|
|
6
|
|
|
161
|
|
|
|
|
|
|
} |
|
162
|
7
|
100
|
|
|
|
17
|
unless ($match) { |
|
163
|
3
|
|
|
|
|
7
|
$report->{files_skipped}++; |
|
164
|
3
|
|
|
|
|
4
|
push @{$report->{changes}}, { file => $file, status => 'skipped', reason => 'not included' }; |
|
|
3
|
|
|
|
|
10
|
|
|
165
|
3
|
|
|
|
|
7
|
next; |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
39
|
|
|
|
|
145
|
my $result = $class->indent_file($file, %opts); |
|
170
|
39
|
|
|
|
|
57
|
push @{$report->{changes}}, $result; |
|
|
39
|
|
|
|
|
81
|
|
|
171
|
|
|
|
|
|
|
|
|
172
|
39
|
100
|
100
|
|
|
168
|
if ($result->{status} eq 'changed' || $result->{status} eq 'needs_fixing') { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
173
|
34
|
|
|
|
|
50
|
$report->{files_changed}++; |
|
174
|
34
|
|
|
|
|
67
|
$report->{files_checked}++; |
|
175
|
|
|
|
|
|
|
} elsif ($result->{status} eq 'unchanged') { |
|
176
|
2
|
|
|
|
|
4
|
$report->{files_checked}++; |
|
177
|
|
|
|
|
|
|
} elsif ($result->{status} eq 'skipped') { |
|
178
|
3
|
|
|
|
|
23
|
$report->{files_skipped}++; |
|
179
|
|
|
|
|
|
|
} elsif ($result->{status} eq 'error') { |
|
180
|
0
|
|
|
|
|
0
|
$report->{files_errored}++; |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
} |
|
183
|
|
|
|
|
|
|
|
|
184
|
16
|
|
|
|
|
87
|
return $report; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub _simple_diff { |
|
188
|
1
|
|
|
1
|
|
2
|
my ($label, $old, $new) = @_; |
|
189
|
1
|
|
|
|
|
3
|
my @old_lines = split /^/m, $old; |
|
190
|
1
|
|
|
|
|
3
|
my @new_lines = split /^/m, $new; |
|
191
|
1
|
|
|
|
|
2
|
my $out = "--- a/$label\n+++ b/$label\n"; |
|
192
|
1
|
50
|
|
|
|
3
|
my $max = @old_lines > @new_lines ? scalar @old_lines : scalar @new_lines; |
|
193
|
1
|
|
|
|
|
1
|
my $hunk_start = -1; |
|
194
|
1
|
|
|
|
|
2
|
my (@hunk_old, @hunk_new); |
|
195
|
|
|
|
|
|
|
|
|
196
|
1
|
|
|
|
|
2
|
for (my $i = 0; $i <= $max; $i++) { |
|
197
|
4
|
100
|
|
|
|
5
|
my $ol = $i < @old_lines ? $old_lines[$i] : undef; |
|
198
|
4
|
100
|
|
|
|
6
|
my $nl = $i < @new_lines ? $new_lines[$i] : undef; |
|
199
|
4
|
|
100
|
|
|
11
|
my $same = defined $ol && defined $nl && $ol eq $nl; |
|
200
|
|
|
|
|
|
|
|
|
201
|
4
|
100
|
66
|
|
|
9
|
if (!$same && $hunk_start < 0) { |
|
202
|
2
|
|
|
|
|
2
|
$hunk_start = $i; |
|
203
|
2
|
|
|
|
|
2
|
@hunk_old = (); |
|
204
|
2
|
|
|
|
|
6
|
@hunk_new = (); |
|
205
|
|
|
|
|
|
|
} |
|
206
|
4
|
100
|
100
|
|
|
9
|
if ($hunk_start >= 0 && !$same) { |
|
207
|
2
|
100
|
|
|
|
3
|
push @hunk_old, $ol if defined $ol; |
|
208
|
2
|
100
|
|
|
|
3
|
push @hunk_new, $nl if defined $nl; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
4
|
100
|
100
|
|
|
8
|
if ($same || $i == $max) { |
|
211
|
3
|
100
|
|
|
|
5
|
if ($hunk_start >= 0) { |
|
212
|
2
|
|
|
|
|
6
|
$out .= sprintf "@@ -%d,%d +%d,%d @@\n", |
|
213
|
|
|
|
|
|
|
$hunk_start + 1, scalar @hunk_old, |
|
214
|
|
|
|
|
|
|
$hunk_start + 1, scalar @hunk_new; |
|
215
|
2
|
|
|
|
|
3
|
for my $l (@hunk_old) { |
|
216
|
1
|
50
|
|
|
|
4
|
$l = "$l\n" unless $l =~ /\n$/; |
|
217
|
1
|
|
|
|
|
1
|
$out .= "-$l"; |
|
218
|
|
|
|
|
|
|
} |
|
219
|
2
|
|
|
|
|
2
|
for my $l (@hunk_new) { |
|
220
|
1
|
50
|
|
|
|
2
|
$l = "$l\n" unless $l =~ /\n$/; |
|
221
|
1
|
|
|
|
|
2
|
$out .= "+$l"; |
|
222
|
|
|
|
|
|
|
} |
|
223
|
2
|
|
|
|
|
3
|
$hunk_start = -1; |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
} |
|
226
|
|
|
|
|
|
|
} |
|
227
|
1
|
|
|
|
|
3
|
return $out; |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
1; |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
__END__ |