Tue Aug 9 19:42:47 2022 UTC ()
lintpkgsrc: fix search path for .include directives

Previously, the search path was in pseudo-random order.


(rillig)
diff -r1.61 -r1.62 pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl

cvs diff -r1.61 -r1.62 pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl (expand / switch to unified diff)

--- pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl 2022/08/09 19:31:57 1.61
+++ pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl 2022/08/09 19:42:46 1.62
@@ -1,16 +1,16 @@ @@ -1,16 +1,16 @@
1#!@PERL5@ 1#!@PERL5@
2 2
3# $NetBSD: lintpkgsrc.pl,v 1.61 2022/08/09 19:31:57 rillig Exp $ 3# $NetBSD: lintpkgsrc.pl,v 1.62 2022/08/09 19:42:46 rillig Exp $
4 4
5# Written by David Brownlee <abs@netbsd.org>. 5# Written by David Brownlee <abs@netbsd.org>.
6# 6#
7# Caveats: 7# Caveats:
8# The 'Makefile parsing' algorithm used to obtain package versions and 8# The 'Makefile parsing' algorithm used to obtain package versions and
9# DEPENDS information is geared towards speed rather than perfection, 9# DEPENDS information is geared towards speed rather than perfection,
10# though it has gotten somewhat better over time, it only parses the 10# though it has gotten somewhat better over time, it only parses the
11# simpler Makefile conditionals. 11# simpler Makefile conditionals.
12# 12#
13# TODO: Handle fun DEPENDS like avifile-devel with 13# TODO: Handle fun DEPENDS like avifile-devel with
14# {qt2-designer>=2.2.4,qt2-designer-kde>=2.3.1nb1} 14# {qt2-designer>=2.2.4,qt2-designer-kde>=2.3.1nb1}
15 15
16use locale; 16use locale;
@@ -429,106 +429,106 @@ sub parse_makefile_line_include($$$$$$)  @@ -429,106 +429,106 @@ sub parse_makefile_line_include($$$$$$)
429 # At this point just skip any includes which we were 429 # At this point just skip any includes which we were
430 # not able to fully expand. 430 # not able to fully expand.
431 if ($incfile =~ m#/mk/bsd# 431 if ($incfile =~ m#/mk/bsd#
432 || $incfile =~ /$magic_undefined/ 432 || $incfile =~ /$magic_undefined/
433 || $incfile =~ /\$\{/ 433 || $incfile =~ /\$\{/
434 || (!$opt{d} && $incfile =~ m#/(buildlink[^/]*\.mk)#)) { 434 || (!$opt{d} && $incfile =~ m#/(buildlink[^/]*\.mk)#)) {
435 debug("$file: .include \"$incfile\" skipped\n"); 435 debug("$file: .include \"$incfile\" skipped\n");
436 return; 436 return;
437 } 437 }
438 438
439 debug("$file: .include \"$incfile\"\n"); 439 debug("$file: .include \"$incfile\"\n");
440 440
441 if (substr($incfile, 0, 1) ne '/') { 441 if (substr($incfile, 0, 1) ne '/') {
442 foreach my $dir (keys %$incdirs) { 442 foreach my $dir (reverse @$incdirs) {
443 if (-f "$dir/$incfile") { 443 if (-f "$dir/$incfile") {
444 $incfile = "$dir/$incfile"; 444 $incfile = "$dir/$incfile";
445 last; 445 last;
446 } 446 }
447 } 447 }
448 } 448 }
449 449
450 # perl 5.6.1 realpath() cannot handle files, only directories. 450 # perl 5.6.1 realpath() cannot handle files, only directories.
451 # If the last component is a symlink, this will give a false 451 # If the last component is a symlink, this will give a false
452 # negative, but that is not a problem, as the duplicate check 452 # negative, but that is not a problem, as the duplicate check
453 # is for performance. 453 # is for performance.
454 $incfile =~ m#^(.+)(/[^/]+)$#; 454 $incfile =~ m#^(.+)(/[^/]+)$#;
455 455
456 if (!-f $incfile) { 456 if (!-f $incfile) {
457 $opt{L} or verbose("\n"); 457 $opt{L} or verbose("\n");
458 458
459 my $dirs = join(' ', sort keys %$incdirs); 459 my $dirs = join(' ', @$incdirs);
460 verbose("$file: Cannot locate $incfile in $dirs\n"); 460 verbose("$file: Cannot locate $incfile in $dirs\n");
461 return; 461 return;
462 } 462 }
463 463
464 $incfile = realpath($1) . $2; 464 $incfile = realpath($1) . $2;
465 return if $included->{$incfile}; 465 return if $included->{$incfile};
466 466
467 $opt{L} and print "inc $incfile\n"; 467 $opt{L} and print "inc $incfile\n";
468 $included->{$incfile} = 1; 468 $included->{$incfile} = 1;
469 469
470 if (!open(FILE, $incfile)) { 470 if (!open(FILE, $incfile)) {
471 verbose("Cannot open '$incfile' (from $file): $_ $!\n"); 471 verbose("Cannot open '$incfile' (from $file): $_ $!\n");
472 return; 472 return;
473 } 473 }
474 474
475 my $NEWCURDIR = $incfile; 475 my $NEWCURDIR = $incfile;
476 $NEWCURDIR =~ s#/[^/]*$##; 476 $NEWCURDIR =~ s#/[^/]*$##;
477 $incdirs->{$NEWCURDIR} = 1; 477 push(@$incdirs, $NEWCURDIR)
 478 unless grep { $_ eq $NEWCURDIR } @$incdirs;
478 unshift(@$lines, ".CURDIR=" . $vars->{'.CURDIR'}); 479 unshift(@$lines, ".CURDIR=" . $vars->{'.CURDIR'});
479 chomp(my @inc_lines = <FILE>); 480 chomp(my @inc_lines = <FILE>);
480 unshift(@$lines, @inc_lines); 481 unshift(@$lines, @inc_lines);
481 unshift(@$lines, ".CURDIR=$NEWCURDIR"); 482 unshift(@$lines, ".CURDIR=$NEWCURDIR");
482 close(FILE); 483 close(FILE);
483} 484}
484 485
485# Extract variable assignments from Makefile 486# Extract variable assignments from Makefile
486# Much unpalatable magic to avoid having to use make (all for speed) 487# Much unpalatable magic to avoid having to use make (all for speed)
487# 488#
488sub parse_makefile_vars($$) { 489sub parse_makefile_vars($$) {
489 my ($file, $cwd) = @_; 490 my ($file, $cwd) = @_;
490 my ( 491
491 %vars, $plus, $value, 492 my %vars;
492 %incfiles, # Cache of previously included fils 493 my %incfiles; # Cache of previously included files
493 %incdirs, # Directories in which to check for includes 494 my @incdirs; # Directories in which to check for includes
494 @if_false 495 my @if_false; # 0:true 1:false 2:nested-false&nomore-elsif
495 ); # 0:true 1:false 2:nested-false&nomore-elsif 
496 my @lines; 496 my @lines;
497 497
498 open(FILE, $file) or return undef; 498 open(FILE, $file) or return undef;
499 chomp(@lines = <FILE>); 499 chomp(@lines = <FILE>);
500 close(FILE); 500 close(FILE);
501 501
502 $incdirs{'.'} = 1; 502 push(@incdirs, '.');
503 $incdirs{dirname($file)} = 1; 503 push(@incdirs, dirname($file));
504 504
505 # Some Makefiles depend on these being set 505 # Some Makefiles depend on these being set
506 if ($file eq '/etc/mk.conf') { 506 if ($file eq '/etc/mk.conf') {
507 $vars{LINTPKGSRC} = 'YES'; 507 $vars{LINTPKGSRC} = 'YES';
508 } else { 508 } else {
509 %vars = %{$default_vars}; 509 %vars = %{$default_vars};
510 } 510 }
511 $vars{BSD_PKG_MK} = 'YES'; 511 $vars{BSD_PKG_MK} = 'YES';
512 512
513 if ($cwd) { 513 if ($cwd) {
514 $vars{'.CURDIR'} = $cwd; 514 $vars{'.CURDIR'} = $cwd;
515 } elsif ($file =~ m#(.*)/#) { 515 } elsif ($file =~ m#(.*)/#) {
516 $vars{'.CURDIR'} = $1; 516 $vars{'.CURDIR'} = $1;
517 } else { 517 } else {
518 $vars{'.CURDIR'} = getcwd; 518 $vars{'.CURDIR'} = getcwd;
519 } 519 }
520 520
521 $incdirs{$vars{'.CURDIR'}} = 1; 521 push(@incdirs, $vars{'.CURDIR'});
522 if ($opt{L}) { 522 if ($opt{L}) {
523 print "$file\n"; 523 print "$file\n";
524 } 524 }
525 525
526 while (defined($_ = shift(@lines))) { 526 while (defined($_ = shift(@lines))) {
527 s/\s*[^\\]#.*//; 527 s/\s*[^\\]#.*//;
528 528
529 # Continuation lines 529 # Continuation lines
530 # 530 #
531 while (substr($_, -1) eq "\\" && @lines > 0) { 531 while (substr($_, -1) eq "\\" && @lines > 0) {
532 substr($_, -2) = shift @lines; 532 substr($_, -2) = shift @lines;
533 } 533 }
534 534
@@ -575,36 +575,32 @@ sub parse_makefile_vars($$) { @@ -575,36 +575,32 @@ sub parse_makefile_vars($$) {
575 575
576 if (m#^\.\s*endif\b#) { 576 if (m#^\.\s*endif\b#) {
577 pop(@if_false); 577 pop(@if_false);
578 debug("$file: .endif (! @if_false)\n"); 578 debug("$file: .endif (! @if_false)\n");
579 next; 579 next;
580 } 580 }
581 581
582 $if_false[$#if_false] && next; 582 $if_false[$#if_false] && next;
583 583
584 if (m#^\.\s*include\s+"([^"]+)"#) { 584 if (m#^\.\s*include\s+"([^"]+)"#) {
585 my $incfile = parse_expand_vars($1, \%vars); 585 my $incfile = parse_expand_vars($1, \%vars);
586 586
587 parse_makefile_line_include($file, $incfile, 587 parse_makefile_line_include($file, $incfile,
588 \%incdirs, \%incfiles, \@lines, \%vars); 588 \@incdirs, \%incfiles, \@lines, \%vars);
589 next; 589 next;
590 } 590 }
591 591
592 if (/^ *([-\w\.]+)\s*([:+?]?)=\s*(.*)/) { 592 if (/^ *([-\w\.]+)\s*([:+?]?)=\s*(.*)/) {
593 my ($key); 593 my ($key, $plus, $value) = ($1, $2, $3);
594 
595 $key = $1; 
596 $plus = $2; 
597 $value = $3; 
598 594
599 if ($plus eq ':') { 595 if ($plus eq ':') {
600 $vars{$key} = parse_expand_vars($value, \%vars); 596 $vars{$key} = parse_expand_vars($value, \%vars);
601 } elsif ($plus eq '+' && defined $vars{$key}) { 597 } elsif ($plus eq '+' && defined $vars{$key}) {
602 $vars{$key} .= " $value"; 598 $vars{$key} .= " $value";
603 } elsif ($plus ne '?' || !defined $vars{$key}) { 599 } elsif ($plus ne '?' || !defined $vars{$key}) {
604 $vars{$key} = $value; 600 $vars{$key} = $value;
605 } 601 }
606 debug("assignment: $key$plus=[$value] ($vars{$key})\n"); 602 debug("assignment: $key$plus=[$value] ($vars{$key})\n");
607 603
608 # Give python a little hand (XXX - do we wanna consider actually 604 # Give python a little hand (XXX - do we wanna consider actually
609 # implementing make .for loops, etc? 605 # implementing make .for loops, etc?
610 # 606 #