1 # Tags -- Perl tags functions for lintian
4 # Copyright (C) 1998-2004 Various authors
5 # Copyright (C) 2005 Frank Lichtenheld <frank@lichtenheld.de>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, you can find it on the World Wide
19 # Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
20 # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
28 our @ISA = qw(Exporter);
29 our @EXPORT = qw(tag);
31 # support for ANSI color output via colored()
34 # Quiet "Name "main::LINTIAN_ROOT" used only once"
35 # The variables comes from 'lintian'
36 () = ($main::verbose, $main::debug);
38 # configuration variables and defaults
39 our $verbose = $::verbose;
40 our $debug = $::debug;
42 our $show_experimental = 0;
43 our $show_overrides = 0;
44 our $output_formatter = \&print_tag;
45 our $min_severity = 1;
46 our $max_severity = 99;
47 our $min_significance = 1;
48 our $max_significance = 99;
51 # The master hash with all tag info. Key is the tag name, value another hash
52 # with the following keys:
54 # - type: error/warning/info/experimental
55 # - info: Description in HTML
56 # - ref: Any references
57 # - experimental: experimental status (possibly undef)
60 # Statistics per file. Key is the filename, value another hash with the
68 # Info about a specific file. Key is the the filename, value another hash
69 # with the following keys:
71 # - version: package version
72 # - arch: package architecture
73 # - type: one of 'binary', 'udeb' or 'source'
74 # - overrides: hash with all overrides for this file as keys
77 # Currently selected file (not package!)
81 my %codes = ( 'error' => 'E' , 'warning' => 'W' , 'info' => 'I' );
82 our %type_to_sev = ( error => 4, warning => 2, info => 0 );
83 our @sev_to_type = qw( info warning warning error error );
85 my @sig_to_qualifier = ( '??', '?', '', '!' );
86 my @sev_to_code = qw( I W W E E );
87 my @sev_to_color = ( 'cyan', 'yellow', 'yellow', 'red', 'red' );
89 # Add a new tag, supplied as a hash reference
92 if (exists $tags{$newtag->{tag}}) {
93 warn "Duplicate tag: $newtag->{tag}\n";
98 $newtag->{type} = $sev_to_type[$newtag->{severity}]
99 unless $newtag->{type};
100 $newtag->{significance} = 2 unless exists $newtag->{significance};
101 $newtag->{severity} = $type_to_sev{$newtag->{type}}
102 unless exists $newtag->{severity};
103 $tags{$newtag->{'tag'}} = $newtag;
107 # Add another file, will fail if there is already stored info about
110 my ( $file, $pkg, $version, $arch, $type ) = @_;
112 if (exists $info{$file}) {
113 warn "File $file was already processed earlier\n";
135 # select another file as 'current' without deleting or adding any information
136 # the file must have been added with add_pkg
140 unless (exists $info{$file}) {
141 warn "Can't select package $file";
149 # only delete the value of 'current' without deleting any stored information
155 # delete all the stored information (including tags)
164 # Add an override. If you specifiy two arguments, the first will be taken
165 # as file to add the override to, otherwise 'current' will be assumed
167 my ($tag, $file) = ( "", "" );
171 ($file, $tag) = ($current, @_);
175 warn "Don't know which package to add override $tag to";
179 $info{$file}{overrides}{$tag} = 0;
188 warn "Don't know which package to get overrides from";
192 return $info{$file}{overrides};
195 # Get the info hash for a tag back as a reference. The hash will be
196 # copied first so that you can edit it safely
199 return { %{$tags{$tag}} } if exists $tags{$tag};
204 my ( $x, $min, $max ) = @_;
206 return -1 if $x < $min;
207 return 1 if $x > $max;
211 # check if a certain tag has a override for the 'current' package
212 sub check_overrides {
213 my ( $tag_info, $information ) = @_;
216 $extra = " @$information" if @$information;
217 $extra = '' if $extra eq ' ';
218 if( exists $info{$current}{overrides}{$tag_info->{tag}}) {
219 $info{$current}{overrides}{$tag_info->{tag}}++;
220 return $tag_info->{tag};
221 } elsif( exists $info{$current}{overrides}{"$tag_info->{tag}$extra"} ) {
222 $info{$current}{overrides}{"$tag_info->{tag}$extra"}++;
223 return "$tag_info->{tag}$extra";
229 # sets all the overridden fields of a tag_info hash correctly
230 sub check_need_to_show {
231 my ( $tag_info, $information ) = @_;
232 $tag_info->{overridden}{override} = check_overrides( $tag_info,
234 my $min_sev = $show_info ? 0 : $min_severity; # compat hack
235 $tag_info->{overridden}{severity} = check_range( $tag_info->{severity},
238 $tag_info->{overridden}{significance} = check_range( $tag_info->{significance},
243 # records the stats for a given tag_info hash
245 my ( $tag_info ) = @_;
247 for my $k (qw( severity significance tag )) {
248 $stats{$current}{$k}{$tag_info->{$k}}++
249 unless $tag_info->{overridden}{override}
250 || $tag_info->{overridden}{severity}
251 || $tag_info->{overridden}{significance};
253 for my $k (qw( severity significance override )) {
254 $stats{$current}{overrides}{$k}{$tag_info->{overridden}{$k}}++
255 if $tag_info->{overridden}{$k};
257 if ($tag_info->{overridden}{override}) {
258 $stats{$current}{overrides}{by_severity}{$tag_info->{severity}}++;
262 # get the statistics for a file (one argument) or for all files (no argument)
266 return $stats{$file} if $file;
270 # Color tags with HTML. Takes the tag and the color name.
272 my ($tag, $color) = @_;
273 return qq(<span style="color: $color">$tag</span>);
277 my ( $pkg_info, $tag_info, $information ) = @_;
280 $extra = " @$information" if @$information;
281 $extra = '' if $extra eq ' ';
282 my $code = $codes{$tag_info->{type}};
283 my $severity = $type_to_sev{$tag_info->{type}};
284 $code = 'X' if exists $tag_info->{experimental};
285 $code = 'O' if $tag_info->{overridden}{override};
287 $type = " $pkg_info->{type}" if $pkg_info->{type} ne 'binary';
289 my $output = "$code: $pkg_info->{pkg}$type: ";
290 if ($color eq 'always' || ($color eq 'auto' && -t STDOUT)) {
291 $output .= colored($tag_info->{tag}, $sev_to_color[$severity]);
292 } elsif ($color eq 'html') {
293 $output .= colored_html($tag_info->{tag}, $sev_to_color[$severity]);
295 $output .= $tag_info->{tag};
297 $output .= "$extra\n";
303 my ( $pkg_info, $tag_info, $information ) = @_;
306 $extra = " @$information" if @$information;
307 $extra = '' if $extra eq ' ';
308 my $code = $sev_to_code[$tag_info->{severity}];
309 $code = 'X' if exists $tag_info->{experimental};
310 $code = 'O' if $tag_info->{overridden}{override};
311 my $qualifier = $sig_to_qualifier[$tag_info->{significance}];
312 $qualifier = '' if $code eq 'O';
314 $type = " $pkg_info->{type}" if $pkg_info->{type} ne 'binary';
316 my $output = "$code$qualifier: $pkg_info->{pkg}$type: ";
317 if ($color eq 'always' || ($color eq 'auto' && -t STDOUT)) {
318 $output .= colored($tag_info->{tag}, $sev_to_color[$tag_info->{severity}]);
320 $output .= $tag_info->{tag};
322 $output .= "$extra\n";
329 my ( $tag, @information ) = @_;
331 warn "Tried to issue tag $tag without setting package\n";
335 # Newlines in @information would cause problems, so replace them with \n.
336 @information = map { s,\n,\\n,; $_ } @information;
338 my $tag_info = get_tag_info( $tag );
340 warn "Tried to issue unknown tag $tag\n";
343 check_need_to_show( $tag_info, \@information );
345 record_stats( $tag_info );
348 exists $tag_info->{experimental} and !$show_experimental;
351 $tag_info->{overridden}{severity} != 0
352 || $tag_info->{overridden}{significance} != 0
353 || ( $tag_info->{overridden}{override} &&
356 &$output_formatter( $info{$current}, $tag_info, \@information );
363 # indent-tabs-mode: t
364 # cperl-indent-level: 4
366 # vim: ts=4 sw=4 noet