blob: e9e4b9062ad0434938376116660c67dca90aae68 [file] [log] [blame]
Reid Spencer8dd91272005-05-16 18:30:38 +00001#!/usr/bin/perl -w
2#
3# Program: userloc.pl
4#
5# Synopsis: This program uses "cvs annotate" to get a summary of how many lines
6# of code the various developres are responsible for. It takes one
7# argument, the directory to process. If the argument is not specified
8# then the cwd is used. The directory must be an LLVM tree checked out
9# from cvs.
10#
11# Syntax: userloc.pl [-details|-recurse|-tag=tag|-html... <directory>...
12#
13# Options:
14# -details
15# Print detailed per-directory information.
16# -recurse
17# Recurse through sub directories. Without this, only the
18# specified directory is examined
19# -tag=tag
20# Use "tag" to select the revision (as per cvs -r option)
21# -html
22# Generate HTML output instead of text output
23
24die "Usage userloc.pl [-details|-recurse|-tag=tag|-html] <directories>..."
25 if ($#ARGV < 0);
26
27my $tag = "";
28my $details = 0;
29my $recurse = 0;
30my $html = 0;
31while ( substr($ARGV[0],0,1) eq '-' )
32{
33 if ($ARGV[0] eq "-details")
34 {
35 $details = 1 ;
36 }
37 elsif ($ARGV[0] eq "-recurse")
38 {
39 $recurse = 1;
40 }
41 elsif ($ARGV[0] =~ /-tag=.*/)
42 {
43 $tag = $ARGV[0];
44 $tag =~ s#-tag=(.*)#$1#;
45 }
46 elsif ($ARGV[0] eq "-html")
47 {
48 $html = 1;
49 }
50 else
51 {
52 die "Invalid option: $ARGV[0]";
53 }
54 shift;
55}
56
57die "Usage userloc.pl [-details|-recurse|-tag=tag|-html] <directories>..."
58 if ($#ARGV < 0);
59
60my %Stats;
61my %StatsDetails;
62
63sub ValidateFile
64{
65 my $f = $_[0];
66 my $d = $_[1];
67
68 return 0 if ( "$f" eq "configure");
69 if ( $d =~ ".*autoconf.*")
70 {
71 return 1 if ($f eq "configure.ac");
72 return 1 if ($f eq "AutoRegen.sh");
73 return 0;
74 }
75
76 return 1;
77}
78
79sub GetCVSFiles
80{
81 my $d = $_[0];
82 my $files ="";
83 open STATUS, "cvs -nfz6 status $d -l 2>/dev/null |"
84 || die "Can't 'cvs status'";
85 while ( defined($line = <STATUS>) )
86 {
87 if ( $line =~ /^File:.*/ )
88 {
89 chomp($line);
90 $line =~ s#^File: ([A-Za-z0-9._-]*)[ \t]*Status:.*#$1#;
91 $files = "$files $d/$line" if (ValidateFile($line,$d));
92 }
93
94 }
95 return $files;
96}
97
98my $annotate = "cvs annotate -lf ";
99if (length($tag) > 0)
100{
101 $annotate = $annotate . " -r " . $tag;
102}
103
104sub ScanDir
105{
106 my $Dir = $_[0];
107 my $files = GetCVSFiles($Dir);
108
109 open (DATA,"$annotate $files 2>/dev/null |")
110 || die "Can't read cvs annotation data";
111
112 my %st;
113 while ( defined($line = <DATA>) )
114 {
115 if ($line =~ /^[0-9.]*[ \t]*\(/)
116 {
117 $line =~ s#^[0-9.]*[ \t]*\(([a-zA-Z0-9_.-]*).*#$1#;
118 chomp($line);
119 $st{$line}++;
120 $Stats{$line}++;
121 }
122 }
123
124 $StatsDetails{$Dir} = { %st };
125
126 close DATA;
127}
128
129sub ValidateDirectory
130{
131 my $d = $_[0];
132 return 0 if ($d =~ /.*CVS.*/);
133 return 0 if ($d =~ /.*Debug.*/);
134 return 0 if ($d =~ /.*Release.*/);
135 return 0 if ($d =~ /.*Profile.*/);
136 return 0 if ($d =~ /.*utils\/Burg.*/);
137 return 0 if ($d =~ /.*docs\/CommandGuide\/html.*/);
138 return 0 if ($d =~ /.*docs\/CommandGuide\/man.*/);
139 return 0 if ($d =~ /.*docs\/CommandGuide\/ps.*/);
140 return 0 if ($d =~ /.*docs\/CommandGuide\/man.*/);
141 return 0 if ($d =~ /.*docs\/HistoricalNotes.*/);
142 return 0 if ($d =~ /.*docs\/img.*/);
143 return 0 if ($d =~ /.*bzip2.*/);
144 return 1 if ($d =~ /.*projects\/Stacker.*/);
145 return 1 if ($d =~ /.*projects\/sample.*/);
146 return 0 if ($d =~ /.*projects\/llvm-.*/);
147 return 0 if ($d =~ /.*win32.*/);
148 return 1;
149}
150
151my $RowCount = 0;
152sub printStats
153{
154 my $dir = $_[0];
155 my $hash = $_[1];
156 my $user;
157 my $total = 0;
158
159 if ($RowCount % 10 == 0)
160 {
161 print " <tr><th style=\"text-align:left\">Directory</th>\n";
162 foreach $user (keys %Stats)
163 {
Reid Spencer5a685662005-05-16 18:52:57 +0000164 print "<th style=\"text-align:right\">",$user,"</th>\n";
Reid Spencer8dd91272005-05-16 18:30:38 +0000165 }
Reid Spencer5a685662005-05-16 18:52:57 +0000166 print "</tr>\n";
Reid Spencer8dd91272005-05-16 18:30:38 +0000167 }
168
169 $RowCount++;
170
Reid Spencer8dd91272005-05-16 18:30:38 +0000171 if ($html)
172 { print "<tr><td style=\"text-align:left\">",$dir,"</td>"; }
173 else
174 { print $dir,"\n"; }
175
Reid Spencer5a685662005-05-16 18:52:57 +0000176 foreach $user (keys %{$hash}) { $total += $hash->{$user}; }
177
Reid Spencer8dd91272005-05-16 18:30:38 +0000178 foreach $user ( sort keys %Stats )
179 {
180 my $v = $hash->{$user};
181 if (defined($v))
182 {
183 if ($html)
184 {
185 printf "<td style=\"text-align:right\">%d<br/>(%2.1f%%)</td>", $v,
186 (100.0/$total)*$v;
187 }
188 else
189 {
190 printf "%8d (%4.1f%%): %s\n", $v, (100.0/$total)*$v, $user;
191 }
192 }
193 elsif ($html)
194 {
195 print "<td style=\"text-align:right\">-&nbsp;</td>";
196 }
197 }
198 print "</tr>\n" if ($html);
199}
200
201my @ALLDIRS = @ARGV;
202
203if ($recurse)
204{
205 $Dirs = join(" ", @ARGV);
206 $Dirs = `find $Dirs -type d \! -name CVS -print`;
207 @ALLDIRS = split(' ',$Dirs);
208}
209
210if ($html)
211{
212print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n";
213print "<html>\n<head>\n";
214print " <title>LLVM LOC Based On CVS Annotation</title>\n";
215print " <link rel=\"stylesheet\" href=\"llvm.css\" type=\"text/css\"/>\n";
216print "</head>\n";
217print "<body><div class=\"doc_title\">LLVM LOC Based On CVS Annotation</div>\n";
218print "<p>This document shows the total lines of code per user in each\n";
219print "LLVM directory. Lines of code are attributed by the user that last\n";
220print "committed the line. This does not necessarily reflect authorship.</p>\n";
221print "<p>The following directories were skipped:</p>\n";
222print "<ol>\n";
223}
224
225for $Dir (@ALLDIRS)
226{
227 if ( -d "$Dir" && -d "$Dir/CVS" && ValidateDirectory($Dir) )
228 {
229 ScanDir($Dir);
230 }
231 elsif ($html)
232 {
233 print "<li>$Dir</li>\n";
234 }
235}
236
237if ($html)
238{
239 print "</ol>\n";
240 print "<table>\n";
241}
242
243if ($details)
244{
245 foreach $dir (sort keys %StatsDetails)
246 {
247 printStats($dir,$StatsDetails{$dir});
248 }
249}
250
251printStats("Total",\%Stats);
252
253
254if ($html)
255{
256 print "</table></body></html>\n";
257}
258