Implemented feature to generate sub-reports for missing libraries in la_filter.pl
authorMaciej Seroka <maciejs@symbian.org>
Fri, 16 Apr 2010 12:56:17 +0100
changeset 240 e662a2267ea5
parent 239 d57b367400c0
child 241 b7a101a82e4b
Implemented feature to generate sub-reports for missing libraries in la_filter.pl
bc_tools/la_filter.pl
--- a/bc_tools/la_filter.pl	Wed Apr 14 12:58:22 2010 +0100
+++ b/bc_tools/la_filter.pl	Fri Apr 16 12:56:17 2010 +0100
@@ -14,15 +14,15 @@
 #   This is a tool for filtering static BC libraries reports.
 
 use strict;
+use Getopt::Long;
 use XML::Simple;
-use File::Copy;
 use Tie::File;
-use Data::Dumper;
 
 my $report;
 my $xref_file;
 my $destfile;
 my $missing_destfile;
+my $pkg_destfile;
 my @lines;
 my $line;
 my $n;
@@ -33,27 +33,57 @@
 my $gen_missing_report = 1; # This variable determines whether to produce report for missing libraries.
 my $issues_num;
 my $issue_name;
-my $xref_name;
-my $xref_type;
-my $xref_line;
-my $xref_hdr;
-my $xref_def;
+my ($xref_name, $xref_type, $xref_line, $xref_hdr, $xref_def);
 my $delete_node;
 my @non_public_list;
 my $current_item;
 my $check_against_xref;
 my $temp_lib_num;
 my $temp_counter;
+my $sub_reports = 1; # This variable determines whether to generate sub-reports per package.
+my @lines_to_ignore = ("\\\\build\\\\", "\\\\compsupp\\\\", "\\\\uc_dll."); # This is the list of key words based on which a line potentially containing a package name will be ignored (skipped).
+my @pkgs;
+my $baselinedlldir;
+my $lib_name;
+my $map_name;
+my $map_found;
+my ($layer_name, $package_name);
+my $pkg_found;
+my $pkgs_num;
+my $add_pkg;
+my $nomap;
+my $help;
 
-if ($ARGV[1]) {
-	$report = $ARGV[0];
-	$xref_file = $ARGV[1];
-	$destfile = "filtered_" . $report;
-	$missing_destfile = "missing_" . $report;
-} else { 
-	die "Missing parameter(s). For example: la_filter.pl libraries_report.xml my_xref_file.txt"; 
+sub usage($);
+sub help();
+sub usage_error();
+
+my %optmap = (  'libraries-report' => \$report,
+			    'xref-file' => \$xref_file,
+			    'baseline-dll-dir' => \$baselinedlldir,
+				'help' => \$help);
+
+GetOptions(\%optmap,
+          'libraries-report=s',
+          'xref-file=s',
+          'baseline-dll-dir=s',
+		  'help!') 
+          or usage_error();
+
+if ($help) {
+	help();
 }
 
+# --libraries-report is mandatory.
+usage_error(), unless (defined($report));
+
+# --xref-file is mandatory.
+usage_error(), unless (defined($xref_file));
+
+# Define output files based on the libraries report name.
+$destfile = "filtered_" . $report;
+$missing_destfile = "missing_" . $report;
+
 # Parse the input XMLs into hashrefs.
 print "Parsing " . $report . "... ";
 my $current_report = XMLin("./$report", keeproot => 1,
@@ -198,6 +228,9 @@
 print OUT XMLout($current_report, keeproot => 1);
 close OUT;
 
+# Free up memory resources.
+$current_report = ();
+
 # Insert:	<?xml version="1.0" encoding="ASCII" standalone="no" ?>
 #			<?xml-stylesheet type="text/xsl" href="BBCResults.xsl"?>
 tie @lines, 'Tie::File', $destfile or die ("Cannot tie file \"$destfile\". $!\n");
@@ -255,4 +288,204 @@
 	unshift @lines, "<?xml-stylesheet type=\"text/xsl\" href=\"BBCResults.xsl\"?>";
 	unshift @lines, "<?xml version=\"1.0\" encoding=\"ASCII\" standalone=\"no\" ?>";
 	untie @lines;
-}
\ No newline at end of file
+}
+
+if (($sub_reports) && ($gen_missing_report)) { # Generate sub-reports per package.
+	# Parse the input XMLs into hashrefs again.
+	print "Parsing " . $missing_destfile . "... ";
+	my $current_report = XMLin("./$missing_destfile", keeproot => 1,
+		forcearray => [ 'header', 'baselineversion', 'currentversion', 'timestamp', 'day', 'month', 'year', 'hour', 'minute', 'second', #
+		'laversion', 'formatversion', 'cmdlineparms', 'parm', 'pname', 'pvalue', 'knownissuesversion', 'os', 'version', 'buildweek', 'issuelist',#
+		'library', 'name', 'comparefilename', 'shortname', 'baseplatform', 'currentplatform', 'issue', 'typeinfo', 'typeid', 'funcname', 'newfuncname', 'newfuncpos', #
+		'bc_severity', 'sc_severity', 'status', 'funcpos' ], keyattr => [] );
+	print "complete \n";
+	$lib_num = @{$current_report->{'bbcresults'}->{'issuelist'}->[0]->{'library'}};
+	if (!defined($baselinedlldir)) { # Define baselinedlldir.
+		$n = 0;
+		foreach (@{$current_report->{'bbcresults'}->{'header'}->[0]->{'cmdlineparms'}->[0]->{'parm'}}) { # Find baselinedlldir.
+			if ($current_report->{'bbcresults'}->{'header'}->[0]->{'cmdlineparms'}->[0]->{'parm'}->[$n]->{'pname'}->[0] eq "baselinedlldir") {
+				$baselinedlldir = $current_report->{'bbcresults'}->{'header'}->[0]->{'cmdlineparms'}->[0]->{'parm'}->[$n]->{'pvalue'}->[0];
+				last;
+			}
+			$n++;
+		}
+	}
+	print "baselinedlldir: $baselinedlldir\n";
+	# Create the list of packages that link to missing libraries and generate sub-report for no-map file libraries.
+	$nomap = 0;
+	$n = 0;
+	while ($n < $lib_num) {
+		$lib_name = $current_report->{'bbcresults'}->{'issuelist'}->[0]->{'library'}->[$n]->{'shortname'}->[0];
+		$map_name = $baselinedlldir . "\\" . $lib_name . ".map";
+		$map_found = 1;
+		# Find and open corresponding map file (.map or .dll.map).
+		open (FILE, "<$map_name") or $map_name = $baselinedlldir . "\\" . $lib_name . ".dll.map" and open (FILE, "<$map_name") or print "No map file found for $lib_name\n" and $map_found = 0;
+		if ($map_found) { 
+#			print "Found: $map_name for $lib_name\n";
+			$pkg_found = 0;
+			while ($line = <FILE>)
+			{
+				chomp $line;
+				# Get rid of spaces at the beginning.
+				$line =~ s/^\s+//;
+				if ($line =~ m/\\sf\\/) {
+					$pkg_found = 1; # Package potentially found.
+					# Check against lines_to_ignore.
+					foreach $current_item (@lines_to_ignore) {
+						if ($line =~ m/($current_item)/) { # Skip the line.
+							$pkg_found = 0; # Change it back to not found.
+							last;
+						}
+					}
+				}
+				if ($pkg_found) {
+					# Get rid of \sf\ and the part it follows.
+					$line =~ s/^.*\\sf\\//;
+					# Get only the package name (in between \ and \).
+					($layer_name, $package_name) = split /\\/,$line;
+					print "Package: $package_name found for: $lib_name (based on $map_name)\n";
+					$pkgs_num = @pkgs;
+					if ($pkgs_num == 0) { # Add the first package name by default.
+						push @pkgs, $package_name;
+					} else {
+						$add_pkg = 1;
+						$m = 0;
+						while ($m < $pkgs_num) {
+							if ($package_name eq @pkgs[$m]) { # Do not add a new package name.
+								$add_pkg = 0;
+							}
+							$m++;
+						}
+						if ($add_pkg) { # Add the new package name.
+							push @pkgs, $package_name;
+						}
+					}
+					last;
+				}
+			}
+			close FILE;
+			# Delete the node (to generate sub-report for libraries with no map file.
+			splice(@{$current_report->{'bbcresults'}->{'issuelist'}->[0]->{'library'}},$n, 1);
+			$lib_num--;					
+		} else {
+			$nomap++;
+			$n++;
+		}
+	}
+	print "Number of libraries with no map file (most likely not a part of Public API): " . $nomap . "\n";
+	if ($nomap > 0) { # Save sub-report for no-map file libraries.
+		# Write new XML to dest file.
+		$pkg_destfile = "missing_with_no_map_file_" . $report;
+		open OUT,">$pkg_destfile" or die("Cannot open file \"$pkg_destfile\" for writing. $!\n");
+		print OUT XMLout($current_report, keeproot => 1);
+		close OUT;
+		# Insert:	<?xml version="1.0" encoding="ASCII" standalone="no" ?>
+		#			<?xml-stylesheet type="text/xsl" href="BBCResults.xsl"?>
+		tie @lines, 'Tie::File', $pkg_destfile or die ("Cannot tie file \"$pkg_destfile\". $!\n");
+		unshift @lines, "<?xml-stylesheet type=\"text/xsl\" href=\"BBCResults.xsl\"?>";
+		unshift @lines, "<?xml version=\"1.0\" encoding=\"ASCII\" standalone=\"no\" ?>";
+		untie @lines;
+	}
+	print "Number of packages: " . @pkgs . "\n";
+	# Generate sub reports for all packages.
+	foreach $current_item (@pkgs) {
+	# Parse the input XMLs into hashrefs again.
+		print "Parsing " . $missing_destfile . "... ";
+		my $current_report = XMLin("./$missing_destfile", keeproot => 1,
+			forcearray => [ 'header', 'baselineversion', 'currentversion', 'timestamp', 'day', 'month', 'year', 'hour', 'minute', 'second', #
+			'laversion', 'formatversion', 'cmdlineparms', 'parm', 'pname', 'pvalue', 'knownissuesversion', 'os', 'version', 'buildweek', 'issuelist',#
+			'library', 'name', 'comparefilename', 'shortname', 'baseplatform', 'currentplatform', 'issue', 'typeinfo', 'typeid', 'funcname', 'newfuncname', 'newfuncpos', #
+			'bc_severity', 'sc_severity', 'status', 'funcpos' ], keyattr => [] );
+		print "complete \n";
+		$lib_num = @{$current_report->{'bbcresults'}->{'issuelist'}->[0]->{'library'}};
+		$n = 0;
+		print "Processing libraries for $current_item... ";
+		while ($n < $lib_num) {
+			$lib_name = $current_report->{'bbcresults'}->{'issuelist'}->[0]->{'library'}->[$n]->{'shortname'}->[0];
+			$map_name = $baselinedlldir . "\\" . $lib_name . ".map";
+			$map_found = 1;
+			# Find and open corresponding map file (.map or .dll.map).
+			open (FILE, "<$map_name") or $map_name = $baselinedlldir . "\\" . $lib_name . ".dll.map" and open (FILE, "<$map_name") or $map_found = 0;
+			if ($map_found) { 
+				$pkg_found = 0;
+				while ($line = <FILE>)
+				{
+					chomp $line;
+					# Get rid of spaces at the beginning.
+					$line =~ s/^\s+//;
+					if ($line =~ m/\\sf\\/) {
+						$pkg_found = 1; # Package potentially found.
+						# Check against lines_to_ignore.
+						foreach $current_item (@lines_to_ignore) {
+							if ($line =~ m/($current_item)/) { # Skip the line.
+								$pkg_found = 0; # Change it back to not found.
+								last;
+							}
+						}
+					}
+					if ($pkg_found) {
+						# Get rid of \sf\ and the part it follows.
+						$line =~ s/^.*\\sf\\//;
+						# Get only the package name (in between \ and \).
+						($layer_name, $package_name) = split /\\/,$line;
+						last;
+					}
+				}
+				close FILE;
+				if ($package_name ne $current_item) { # Remove the node from the report for the current package.
+					splice(@{$current_report->{'bbcresults'}->{'issuelist'}->[0]->{'library'}},$n, 1);
+					$lib_num--;					
+				} else {
+					$n++;
+				}
+			} else { # Delete the node (library with no-map file).
+				splice(@{$current_report->{'bbcresults'}->{'issuelist'}->[0]->{'library'}},$n, 1);
+				$lib_num--;					
+			}
+		}
+		# Write new XML to dest file.
+		$pkg_destfile = $current_item . "_" . $missing_destfile;
+		open OUT,">$pkg_destfile" or die("Cannot open file \"$pkg_destfile\" for writing. $!\n");
+		print OUT XMLout($current_report, keeproot => 1);
+		close OUT;
+		# Insert:	<?xml version="1.0" encoding="ASCII" standalone="no" ?>
+		#			<?xml-stylesheet type="text/xsl" href="BBCResults.xsl"?>
+		tie @lines, 'Tie::File', $pkg_destfile or die ("Cannot tie file \"$pkg_destfile\". $!\n");
+		unshift @lines, "<?xml-stylesheet type=\"text/xsl\" href=\"BBCResults.xsl\"?>";
+		unshift @lines, "<?xml version=\"1.0\" encoding=\"ASCII\" standalone=\"no\" ?>";
+		untie @lines;
+		print "complete \n";
+		$lib_num = @{$current_report->{'bbcresults'}->{'issuelist'}->[0]->{'library'}};
+		print "Number of missing libraries in $current_item package: $lib_num\n";
+	}
+}
+
+exit 0;
+
+sub usage($)
+{
+    my $error = shift;
+    my $fh = $error == 0 ? *STDOUT : *STDERR;
+    print $fh "la_filter.pl\n" .
+            "Specify the libraries report and xref file\n" .
+            "synopsis:\n" .
+            "  la_filter.pl --help\n" .
+            "  la_filter.pl [--libraries-report=XML_FILE] [--xref-file=TXT_FILE] [--baseline-dll-dir=PATH] \n" .
+            "options:\n" .
+            "  --help                        Display this help and exit.\n" .
+            "  --libraries-report=XML_FILE   XML_FILE is the name of the libraries report xml file.\n" .
+            "  --xref-file=TXT_FILE          TXT_FILE is the file containing the index of source code definitions generated by Ctags.\n" .
+            "  --baseline-dll-dir=PATH       PATH is the full path to the directory containing map files (e.g. \\epoc32\\release\\armv5\\urel).\n" .
+			"                                If not specified then the baselinedlldir param from the libraries report will be used.\n";
+    exit $error;            
+}
+
+sub help()
+{
+    usage(0);
+}
+
+sub usage_error()
+{
+    usage(1);
+}