For PR678:
[oota-llvm.git] / utils / userloc.pl
1 #!/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
24 die "Usage userloc.pl [-details|-recurse|-tag=tag|-html] <directories>..." 
25   if ($#ARGV < 0);
26
27 my $tag = "";
28 my $details = 0;
29 my $recurse = 0;
30 my $html = 0;
31 while ( 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
57 die "Usage userloc.pl [-details|-recurse|-tag=tag|-html] <directories>..." 
58   if ($#ARGV < 0);
59
60 my %Stats;
61 my %StatsDetails;
62
63 sub 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
79 sub 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
98 my $annotate = "cvs annotate -lf ";
99 if (length($tag) > 0)
100 {
101   $annotate = $annotate . " -r " . $tag;
102 }
103
104 sub 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
129 sub 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
151 my $RowCount = 0;
152 sub 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 (sort keys %Stats)
163     {
164       print "<th style=\"text-align:right\">",$user,"</th>\n";
165     }
166     print "</tr>\n";
167   }
168
169   $RowCount++;
170
171   if ($html)
172     { print "<tr><td style=\"text-align:left\">",$dir,"</td>"; }
173   else
174     { print $dir,"\n"; }
175
176   foreach $user (keys %{$hash}) { $total += $hash->{$user}; }
177
178   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
201 my @ALLDIRS = @ARGV;
202
203 if ($recurse)
204 {
205   $Dirs = join(" ", @ARGV);
206   $Dirs = `find $Dirs -type d \! -name CVS -print`;
207   @ALLDIRS = split(' ',$Dirs);
208 }
209
210 if ($html)
211 {
212 print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n";
213 print "<html>\n<head>\n";
214 print "  <title>LLVM LOC Based On CVS Annotation</title>\n";
215 print "  <link rel=\"stylesheet\" href=\"llvm.css\" type=\"text/css\"/>\n";
216 print "</head>\n";
217 print "<body><div class=\"doc_title\">LLVM LOC Based On CVS Annotation</div>\n";
218 print "<p>This document shows the total lines of code per user in each\n";
219 print "LLVM directory. Lines of code are attributed by the user that last\n";
220 print "committed the line. This does not necessarily reflect authorship.</p>\n";
221 print "<p>The following directories were skipped:</p>\n";
222 print "<ol>\n";
223 }
224
225 for $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
237 if ($html)
238 {
239   print "</ol>\n";
240   print "<table>\n";
241 }
242
243 if ($details)
244 {
245   foreach $dir (sort keys %StatsDetails)
246   {
247     printStats($dir,$StatsDetails{$dir});
248   }
249 }
250
251 printStats("Total",\%Stats);
252
253
254 if ($html)
255 {
256   print "</table></body></html>\n";
257 }
258