Here's a second version that actually works with multiple parameters, is way more specific at telling you where badly-placed variables should be, and also knows a heck of a lot more about existing variables.
#! /usr/bin/perl # ex:ts=8 sw=4: # $OpenBSD$ # # Copyright (c) 2024 Marc Espie <es...@openbsd.org> # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use v5.36;
my $portsdir = $ENV{PORTSDIR} // '/usr/ports'; my $rc = 0; # all variables we know that don't appear in Makefile.template my @unreg = (qw(GH_ACCOUNT GH_COMMIT GH_PROJECT GH_TAGNAME V REVISION EPOCH REVISION-* EPOCH-* TEST_ENV FIX_EXTRACT_PERMISSIONS CFLAGS CXXFLAGS LDSTATIC PORTROACH MULTI_PACKAGES)); my $unreg = {map {($_, 1)} @unreg}; my @wantdash = (qw(BROKEN WANTLIB LIB_DEPENDS RUN_DEPENDS PERMIT_PACKAGE PKG_ARCH ONLY_FOR_ARCHS NOT_FOR_ARCHS)); my $wantdash = {map {($_, 1)} @wantdash}; sub read_order($file) { my @list; open my $f, "<", $file or return; while (<$f>) { chomp; if (m/^([A-Z0-9_]+(:?\-[a-zA-Z0-9_]*)?)\s*\+?\=/) { push(@list, $1); } elsif (m/^\#\s*([A-Z0-9_]+(:?\-[a-zA-Z0-9_]*)?)\s*\+?\=/) { push(@list, $1); } } for my $i (@list) { $i =~ s/\-.*/\-\*/; } return \@list; } sub find_closest($e, $seen, $ref) { my $f = 0; for my $i (@$ref) { if ($f == 0) { if ($i eq $e) { $f = 1; } } else { if ($seen->{$i}) { return " (should be before $i)"; } } } return ""; } # some variables don't appear with their '-' form in the template sub fix_template($ref) { my @list; for my $i (@$ref) { push(@list, $i); if ($wantdash->{$i}) { push(@list, "$i-*"); } } return \@list; } my $ref = read_order("${portsdir}/infrastructure/templates/Makefile.template"); if (!defined $ref) { say STDERR "Couldn't read reference template"; exit 2; } $ref = fix_template($ref); my $all = {}; for my $i (@$ref) { $all->{$i} = 1; } for my $name (@ARGV) { my $port = read_order($name); if (!defined $port) { say STDERR "$name: Couldn't read"; $rc = 2; next; } my @new = @$ref; my $old = {}; my $seen = {}; while (my $e = shift @$port) { $seen->{$e} = 1; if (!$all->{$e}) { if ($unreg->{$e}) { next; } say "$name: $e unknown"; next; } if ($old->{$e}) { say "$name: $e late". find_closest($e, $seen, $ref); $rc = 1; next; } while ($e ne $new[0]) { $old->{$new[0]} = 1; shift @new; if (@new == 0) { say "$name: $e ? (unknown error)"; last; $rc = 1; } } } } exit $rc;