Skip to content

Commit

Permalink
Add --resolve-script callback - to handle cases where file path
Browse files Browse the repository at this point in the history
munging is more complicated than simple regexp substituion can
easily handle.

Signed-off-by:  Henry Cox <[email protected]>
  • Loading branch information
henry2cox committed Oct 19, 2023
1 parent 59f24d0 commit 663f0bc
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 38 deletions.
15 changes: 6 additions & 9 deletions bin/genhtml
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,10 @@ sub checkCoverageCriteria
'\' ' . $self->type() . ' \'' . $json . '\'';
# command: script name (top|dir|file) jsonString args..
lcovutil::info(1, "criteria: '$cmd'\n");
if (open(HANDLE, "-|", $cmd)) {
if (open(HANDLE, "-|", @coverageCriteriaScript,
$self->type() eq 'top' ? 'top' : $self->name(),
$self->type(), $json
)) {
my @msg;
while (my $line = <HANDLE>) {
chomp $line;
Expand Down Expand Up @@ -4355,7 +4358,7 @@ sub _load
lcovutil::info(1, "annotate: '$cmd'\n");
my $found; # check that either all lines are annotated or none are
local *HANDLE;
if (open(HANDLE, "-|", $cmd)) {
if (open(HANDLE, "-|", @annotateScript, $repo_path)) {
while (my $line = <HANDLE>) {
chomp $line;
$line =~ s/\r//g; # remove CR from line-end
Expand Down Expand Up @@ -5447,13 +5450,6 @@ foreach my $data (['criteria_callback_levels', \@criteriaCallbackLevels,
}
}

foreach my $d (@ReadCurrentSource::source_directories) {
if (!-d $d) {
lcovutil::ignorable_error($lcovutil::ERROR_SOURCE,
"--source-directory '$d' not found");
}
}

# Merge sort options
$sort = 0
if ($no_sort);
Expand Down Expand Up @@ -5801,6 +5797,7 @@ OPERATION
--criteria-script SCRIPT Use SCRIPT to check for acceptance criteria
--version-script SCRIPT Use SCRIPT to check for compatibility of
source code and coverage data
--resolve-script SCRIPT Call script to find source file frpm path
--(no-)checksum Compare (ignore) source line checksum
--diff-file UDIFF Unified diff file UDIFF describes source
code changes between baseline and current
Expand Down
14 changes: 11 additions & 3 deletions bin/geninfo
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,8 @@ if (!lcovutil::parseOptions(\%geninfo_rc_opts, \%geninfo_opts)) {
}

$buildDirSearchPath =
SearchPath->new(@build_directory ? @build_directory : @rc_build_dir);
SearchPath->new('build directory',
@build_directory ? @build_directory : @rc_build_dir);

# Check regexp
if (defined($rc_adjust_src_path)) {
Expand Down Expand Up @@ -722,6 +723,7 @@ OPTIONS
--forget-test-names Merge data for all tests names
--version-script SCRIPTNAME Call script to find revison control version
ID of source file
--resolve-script SCRIPTNAME Call script to find source file frpm path
-j, --parallel [N] Use parallel processing with at most N jobs
--memory MB Use at most MB memory in parallel processing
--profile [FILENAME] Write performance statistics to FILENAME
Expand Down Expand Up @@ -1219,6 +1221,13 @@ sub gen_info(@)
}
} # foreach build_directory

if (@lcovutil::resolveCallback) {
$gcno_file = File::Spec->catfile($d, $name . ".gcno");

$gcno_file = SearchPath::resolveCallback($gcno_file, 1);
last GCNO if (-f $gcno_file || -l $gcno_file);
}

# skip the .gcda file if there is no .gcno

lcovutil::ignorable_error(
Expand Down Expand Up @@ -2371,8 +2380,7 @@ sub read_intermediate_text($$)
if ($line =~ /^file:(.*)$/) {
$filename = $1;
$filename =~ s/[\r\n]$//g;
# adjust filename...
$filename = ReadCurrentSource::resolve_path($filename, 1);
#filename will be simplified/sustituted in 'adjust_source_filenames'
} elsif (defined($filename)) {
$data->{$filename} .= $line;
}
Expand Down
4 changes: 4 additions & 0 deletions bin/lcov
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ OPTIONS
coverage is less than MIN (summary option)
--version-script SCRIPTNAME Call script to find revison control version
ID of source file
--resolve-script SCRIPTNAME Call script to find source file frpm path
-j, --parallel [NUM] Use parallel processing with at most NUM jobs
--memory MB Use at most MB memory in parallel processing
--profile [FILENAME] Write performance statistics to FILENAME
Expand Down Expand Up @@ -929,6 +930,9 @@ sub lcov_geninfo(@)
foreach my $seg (@lcovutil::extractVersionScript) {
push(@param, "--version-script", $seg);
}
foreach my $seg (@lcovutil::resolveCallback) {
push(@param, "--resolve-script", $seg);
}
foreach (@lcovutil::file_subst_patterns) {
push(@param, "--substitute", $_);
}
Expand Down
3 changes: 3 additions & 0 deletions lcovrc
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@ branch_coverage = 0
# specify path to version identification script
#version_script = path_to_my_executable

# specify path to file pathname resolution script
#resolve_script = path_to_my_executable

# Specify JSON module to use, or choose best available if set to auto
lcov_json_module = auto

Expand Down
130 changes: 106 additions & 24 deletions lib/lcovutil.pm
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,13 @@ our $opt_no_external;

# filename substitutions
our @file_subst_patterns;
# resolve callback
our @resolveCallback;
our %resolveCache;

# C++ demangling
our @cpp_demangle; # the options passed in
our $demangle_cpp_cmd; # the computed command string
our @cpp_demangle; # the options passed in
our $demangle_cpp_cmd; # the computed command string
# deprecated: demangler for C++ function names is c++filt
our $cpp_demangle_tool;
# Deprecated: prefer -Xlinker approach with @cpp_dmangle_tool
Expand Down Expand Up @@ -649,9 +652,12 @@ sub merge_child_profile($)
} else {
# 'total' key appears in genhtml report
# the others in geninfo.
if (exists($lcovutil::profileData{$key}{$f}) &&
grep(/^$key$/, ('version', 'parse', 'append', 'total')))
{
if (exists($lcovutil::profileData{$key}{$f})
&&
grep(/^$key$/,
( 'version', 'parse', 'append', 'total',
'resolve'))
) {
$lcovutil::profileData{$key}{$f} += $t;
} else {
lcovutil::ignorable_error($lcovutil::ERROR_INTERNAL,
Expand Down Expand Up @@ -896,8 +902,8 @@ my (@rc_filter, @rc_ignore, @rc_exclude_patterns,
@rc_include_patterns, @rc_subst_patterns, @rc_omit_patterns,
@rc_erase_patterns, @rc_version_script, @unsupported_config,
@rc_source_directories, %unsupported_rc, $keepGoing,
$help, $rc_no_branch_coverage, $rc_no_func_coverage,
$rc_no_checksum, $version);
@rc_resolveCallback, $help, $rc_no_branch_coverage,
$rc_no_func_coverage, $rc_no_checksum, $version);
my $quiet = 0;
my $tempdirname;

Expand Down Expand Up @@ -962,6 +968,7 @@ my %rc_common = (
'omit_lines' => \@rc_omit_patterns,
'erase_functions' => \@rc_erase_patterns,
"version_script" => \@rc_version_script,
'resolve_script' => \@rc_resolveCallback,
"checksum" => \$lcovutil::verify_checksum,
"case_insensitive" => \$lcovutil::case_insensitive,
"forget_testcase_names" => \$TraceFile::ignore_testcase_name,
Expand Down Expand Up @@ -994,6 +1001,7 @@ our %argCommon = ("tempdir=s" => \$tempdirname,
'source-directory=s' =>
\@ReadCurrentSource::source_directories,

'resolve-script=s' => \@lcovutil::resolveCallback,
"filter=s" => \@opt_filter,
"demangle-cpp:s" => \@lcovutil::cpp_demangle,
"ignore-errors=s" => \@opt_ignore_errors,
Expand Down Expand Up @@ -1134,8 +1142,11 @@ sub parseOptions

@ReadCurrentSource::source_directories = @rc_source_directories
unless @ReadCurrentSource::source_directories;
@lcovutil::resolveCallback = @rc_resolveCallback
unless @lcovutil::resolveCallback;
$ReadCurrentSource::searchPath =
SearchPath->new(@ReadCurrentSource::source_directories);
SearchPath->new('source directory',
@ReadCurrentSource::source_directories);

$lcovutil::stop_on_error = 0
if (defined $keepGoing);
Expand Down Expand Up @@ -1525,14 +1536,14 @@ sub initial_state
}
}

return Storable::dclone([\@message_count, \%versionCache]);
return Storable::dclone([\@message_count, \%versionCache, \%resolveCache]);
}

sub compute_update
{
my $state = shift;
my @new_count;
my ($initialCount, $initialVersionCache) = @$state;
my ($initialCount, $initialVersionCache, $initialResolveCache) = @$state;
my $id = 0;
foreach my $count (@message_count) {
my $v = $count - $initialCount->[$id++];
Expand All @@ -1543,8 +1554,14 @@ sub compute_update
$versionUpdate{$f} = $v
unless exists($initialVersionCache->{$f});
}
my %resolveUpdate;
while (my ($f, $v) = each(%resolveCache)) {
$resolveUpdate{$f} = $v
unless exists($initialResolveCache->{$f});
}
my @rtn = (\@new_count,
\%versionUpdate,
\%resolveUpdate,
\%message_types,
$ReadCurrentSource::searchPath->current_count(),
\%lcovutil::profileData,
Expand Down Expand Up @@ -1579,6 +1596,13 @@ sub update_state
if exists($versionCache{$f}) && !$versionCache{$f} eq $v;
$versionCache{$f} = $v;
}
my $updateResolveCache = shift;
while (my ($f, $v) = each(%$updateResolveCache)) {
lcovutil::ignorable_error($lcovutil::ERROR_INTERNAL,
"unexpected resolve entry")
if exists($resolveCache{$f}) && !$resolveCache{$f} eq $v;
$resolveCache{$f} = $v;
}
my $msgTypes = shift;
while (my ($type, $h) = each(%$msgTypes)) {
while (my ($err, $count) = each(%$h)) {
Expand Down Expand Up @@ -2059,11 +2083,13 @@ sub extractFileVersion
# unless -f $filename;
my $version;
my $cmd = join(' ', @extractVersionScript) . " '$filename'";
lcovutil::debug(1, "extractFileVersion: $cmd\n");
if (open(VERS, "-|", $cmd) &&
lcovutil::info(1, "extractFileVersion: $cmd\n");

if (open(VERS, "-|", @extractVersionScript, $filename) &&
($version = <VERS>)) {
chomp($version);
$version =~ s/\r//;
lcovutil::info(1, " version: $version\n");
close(VERS);
my $status = $? >> 8;
0 == $status
Expand Down Expand Up @@ -2393,11 +2419,17 @@ package SearchPath;

sub new
{
my $class = shift;
my $self = [];
my $class = shift;
my $option = shift;
my $self = [];
bless $self, $class;
foreach my $p (@_) {
push(@$self, [$p, 0]);
if (-d $p) {
push(@$self, [$p, 0]);
} else {
lcovutil::ignorable_error($lcovutil::ERROR_PATH,
"$option '$p' is not a directory");
}
}
return $self;
}
Expand All @@ -2412,13 +2444,59 @@ sub resolve
{
my ($self, $filename, $applySubstitutions) = @_;
$filename = lcovutil::subst_file_name($filename) if $applySubstitutions;
foreach my $d (@$self) {
my $path = File::Spec->catfile($d->[0], $filename);
if (-e $path) {
lcovutil::info(1, "found $filename at $path\n");
++$d->[1];
return $path;
return $filename if -e $filename;
if (!File::Spec->file_name_is_absolute($filename)) {
foreach my $d (@$self) {
my $path = File::Spec->catfile($d->[0], $filename);
if (-e $path) {
lcovutil::info(1, "found $filename at $path\n");
++$d->[1];
return $path;
}
}
}
return resolveCallback($filename, 0);
}

sub resolveCallback
{
my ($filename, $applySubstitutions) = @_;
$filename = lcovutil::subst_file_name($filename) if $applySubstitutions;

if (@lcovutil::resolveCallback) {
return $lcovutil::resolveCache{$filename}
if exists($lcovutil::resolveCache{$filename});
my $start = Time::HiRes::gettimeofday();
my $cmd = join(' ', @lcovutil::resolveCallback) . " '$filename'";
lcovutil::info(1, "resolveCallback: $cmd\n");
my $path;
if (open(VERS, "-|", @lcovutil::resolveCallback, $filename) &&
($path = <VERS>)) {
chomp($path);
$path =~ s/\r//;
close(VERS);
lcovutil::info(1, " path: $path\n");
my $status = $? >> 8;
0 == $status
or
lcovutil::ignorable_error($lcovutil::ERROR_CALLBACK,
"resolve-script '$cmd' returned non-zero exit code: '$!'");
} else {
lcovutil::ignorable_error($lcovutil::ERROR_CALLBACK,
"'open(-| $cmd)' failed: \"$!\"");
}
# look up particular path most once...
$lcovutil::resolveCache{$filename} = $path if $path;
my $cost = Time::HiRes::gettimeofday() - $start;
$path = $filename unless $path;
if (exists($lcovutil::profileData{resolve}) &&
exists($lcovutil::profileData{resolve}{$path})) {
# might see multiple aliases for the same source file
$lcovutil::profileData{resolve}{$path} += $cost;
} else {
$lcovutil::profileData{resolve}{$path} = $cost;
}
return $path;
}
return $filename;
}
Expand Down Expand Up @@ -4267,11 +4345,12 @@ sub resolve_path
$filename = lcovutil::subst_file_name($filename) if $applySubstitutions;
return $filename
if (-e $filename ||
File::Spec->file_name_is_absolute($filename) ||
0 == scalar(@source_directories));
(!@lcovutil::resolveCallback &&
(File::Spec->file_name_is_absolute($filename) ||
0 == scalar(@source_directories))));

# don't pass 'applySubstitutions' flag as we already did that, above
return $searchPath->resolve($filename);
return $searchPath->resolve($filename, 0);
}

sub warn_sourcedir_patterns
Expand Down Expand Up @@ -6582,6 +6661,9 @@ sub merge

my $total_trace = TraceFile->new();
my $readSourceFile = ReadCurrentSource->new();
if (!defined($lcovutil::maxParallelism)) {
lcovutil::init_parallel_params();
}
if (0 != $lcovutil::maxMemory &&
1 != $lcovutil::maxParallelism) {
# estimate the number of processes we think we can run..
Expand Down
Loading

0 comments on commit 663f0bc

Please sign in to comment.