blob: 4a9fdd179fc56c0484faa04d6b6fc51f553766a7 [file] [log] [blame]
Reid Spencer4dd4e6a2005-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.*/);
Reid Spencer4dd4e6a2005-05-16 18:30:38 +0000136 return 0 if ($d =~ /.*docs\/CommandGuide\/html.*/);
137 return 0 if ($d =~ /.*docs\/CommandGuide\/man.*/);
138 return 0 if ($d =~ /.*docs\/CommandGuide\/ps.*/);
139 return 0 if ($d =~ /.*docs\/CommandGuide\/man.*/);
140 return 0 if ($d =~ /.*docs\/HistoricalNotes.*/);
141 return 0 if ($d =~ /.*docs\/img.*/);
142 return 0 if ($d =~ /.*bzip2.*/);
143 return 1 if ($d =~ /.*projects\/Stacker.*/);
144 return 1 if ($d =~ /.*projects\/sample.*/);
145 return 0 if ($d =~ /.*projects\/llvm-.*/);
146 return 0 if ($d =~ /.*win32.*/);
147 return 1;
148}
149
150my $RowCount = 0;
151sub printStats
152{
153 my $dir = $_[0];
154 my $hash = $_[1];
155 my $user;
156 my $total = 0;
157
158 if ($RowCount % 10 == 0)
159 {
160 print " <tr><th style=\"text-align:left\">Directory</th>\n";
Reid Spencer74b0f112005-05-16 19:33:21 +0000161 foreach $user (sort keys %Stats)
Reid Spencer4dd4e6a2005-05-16 18:30:38 +0000162 {
Reid Spencerbfb7ca92005-05-16 18:52:57 +0000163 print "<th style=\"text-align:right\">",$user,"</th>\n";
Reid Spencer4dd4e6a2005-05-16 18:30:38 +0000164 }
Reid Spencerbfb7ca92005-05-16 18:52:57 +0000165 print "</tr>\n";
Reid Spencer4dd4e6a2005-05-16 18:30:38 +0000166 }
167
168 $RowCount++;
169
Reid Spencer4dd4e6a2005-05-16 18:30:38 +0000170 if ($html)
171 { print "<tr><td style=\"text-align:left\">",$dir,"</td>"; }
172 else
173 { print $dir,"\n"; }
174
Reid Spencerbfb7ca92005-05-16 18:52:57 +0000175 foreach $user (keys %{$hash}) { $total += $hash->{$user}; }
176
Reid Spencer4dd4e6a2005-05-16 18:30:38 +0000177 foreach $user ( sort keys %Stats )
178 {
179 my $v = $hash->{$user};
180 if (defined($v))
181 {
182 if ($html)
183 {
184 printf "<td style=\"text-align:right\">%d<br/>(%2.1f%%)</td>", $v,
185 (100.0/$total)*$v;
186 }
187 else
188 {
189 printf "%8d (%4.1f%%): %s\n", $v, (100.0/$total)*$v, $user;
190 }
191 }
192 elsif ($html)
193 {
194 print "<td style=\"text-align:right\">-&nbsp;</td>";
195 }
196 }
197 print "</tr>\n" if ($html);
198}
199
200my @ALLDIRS = @ARGV;
201
202if ($recurse)
203{
204 $Dirs = join(" ", @ARGV);
205 $Dirs = `find $Dirs -type d \! -name CVS -print`;
206 @ALLDIRS = split(' ',$Dirs);
207}
208
209if ($html)
210{
211print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n";
212print "<html>\n<head>\n";
213print " <title>LLVM LOC Based On CVS Annotation</title>\n";
214print " <link rel=\"stylesheet\" href=\"llvm.css\" type=\"text/css\"/>\n";
215print "</head>\n";
216print "<body><div class=\"doc_title\">LLVM LOC Based On CVS Annotation</div>\n";
217print "<p>This document shows the total lines of code per user in each\n";
218print "LLVM directory. Lines of code are attributed by the user that last\n";
219print "committed the line. This does not necessarily reflect authorship.</p>\n";
220print "<p>The following directories were skipped:</p>\n";
221print "<ol>\n";
222}
223
224for $Dir (@ALLDIRS)
225{
226 if ( -d "$Dir" && -d "$Dir/CVS" && ValidateDirectory($Dir) )
227 {
228 ScanDir($Dir);
229 }
230 elsif ($html)
231 {
232 print "<li>$Dir</li>\n";
233 }
234}
235
236if ($html)
237{
238 print "</ol>\n";
239 print "<table>\n";
240}
241
242if ($details)
243{
244 foreach $dir (sort keys %StatsDetails)
245 {
246 printStats($dir,$StatsDetails{$dir});
247 }
248}
249
250printStats("Total",\%Stats);
251
252
253if ($html)
254{
255 print "</table></body></html>\n";
256}
257