#! /usr/bin/perl # ex:ts=8 sw=4: # $OpenBSD: pkg_check-version,v 1.6 2023/05/30 05:38:52 espie Exp $ # # Copyright (c) 2021 Marc Espie # # 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; package OpenBSD::VersionCheck::State; our @ISA = qw(OpenBSD::State); use OpenBSD::State; sub handle_options($state) { $state->SUPER::handle_options('Hv', '[-Hv] pkg-name ...'); if (@ARGV == 0) { $state->usage; } } package OpenBSD::PackageName::dewey; sub human_print($self, $state) { $state->say("\tversion (split): #1", join(' ', @{$self->{deweys}})); if ($self->{suffix} eq '') { $state->say("\tno suffix"); } else { $state->say("\twith suffix: #1 #2", $self->{suffix}, $self->{suffix_value}); } } package OpenBSD::PackageName::version; sub human_print($self, $state) { $self->{dewey}->human_print($state); if (defined $self->{p}) { $state->say("\tREVISION: #1", $self->{p}); } else { $state->say("\tno REVISION"); } if (defined $self->{v}) { $state->say("\tEPOCH: #1", $self->{v}); } else { $state->say("\tno EPOCH"); } } package OpenBSD::PackageName::Name; sub human_print($self, $state) { $state->say("\tstem: #1", $self->{stem}); $self->{version}->human_print($state); $state->say("\tflavors: #1", join(' ', (sort keys %{$self->{flavors}}))); } sub add_to_stems($self, $h) { # XXX note that we use "to_pattern", so the "stem" includes flavors" push(@{$h->{$self->to_pattern}}, $self); } package OpenBSD::PackageName::Stem; sub human_print($self, $state) { $state->say("\tstem = #1", $self->{stem}); } sub add_to_stems($, $) { # nothing to do for "pure stems" } package OpenBSD::VersionCheck; use OpenBSD::PackageName; sub parse_and_run($self) { my $rc = 0; my $state = OpenBSD::VersionCheck::State->new('pkg_check-version'); $state->handle_options; my $by_stem = {}; for my $name (@ARGV) { my $v = OpenBSD::PackageName->from_string($name); if ($state->opt('H')) { $state->say("#1:", $name); $v->human_print($state); } my @issues = $v->has_issues; if (@issues > 0) { for my $s (@issues) { $state->errsay("#1: #2", $name, $s); $rc = 1; } } elsif ($state->opt('v')) { $state->errsay("#1 has no issues", $name); } $v->add_to_stems($by_stem); } for my $stem (sort keys %$by_stem) { my $list = $by_stem->{$stem}; if (@$list == 1 && !$state->opt('v')) { next; } my $h = $state->opt('v') ? "#1 sorts as (older to newer): #2" : "#1 sorted: #2"; # XXX some versions are actually not comparable (compare # will return undef). Sort will try to do "something" anyway. my @sorted = sort {$a->compare($b)} @$list; $state->say($h, $stem, join(' ', map {$_->to_string} @sorted)); # but the ordering relation is still a valid order through # partial, so we can check the result on adjacent pairs ! # (so it's still linear) # if we don't find any discrepancy, then we found a total # ordering for our list ! my ($older, $newer); while (@sorted != 0) { $older //= $newer; $newer = shift @sorted; next if !defined $older; my $r = $older->compare($newer); next if defined $r; $state->errsay( "WARNING: #1 and #2 are actually not comparable", $older->to_string, $newer->to_string); $rc = 1; } } return $rc; } exit(__PACKAGE__->parse_and_run);