From f23620aebf1c2f404ec5c848bb87fdfe8caeec36 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sun, 5 Jul 2026 14:26:35 +0200 Subject: [PATCH] Fix APT package arch normalization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⓘ Normalize APT install-result names like `libtinfo6:amd64` to `libtinfo6` so scheduled updates can correctly detect dependency-updated packages and avoid false failure reports. https://github.com/virtualmin/virtualmin-gpl/issues/1247 --- software/apt-lib.pl | 13 ++++++- t/software-apt.t | 82 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 t/software-apt.t diff --git a/software/apt-lib.pl b/software/apt-lib.pl index 36e3cf513..e0f9f5add 100755 --- a/software/apt-lib.pl +++ b/software/apt-lib.pl @@ -11,6 +11,15 @@ sub list_update_system_commands return ($apt_get_command, $apt_search_command); } +# strip_apt_package_arch(package) +# Returns an APT package name without any Debian architecture suffix. +sub strip_apt_package_arch +{ +my ($name) = @_; +$name =~ s/:[A-Za-z0-9][A-Za-z0-9._-]*$//; +return $name; +} + # update_system_install([package], [&in], [no-force]) # Install some package with apt sub update_system_install @@ -47,7 +56,7 @@ foreach (0..100) { &open_execute_command(CMD, "$cmd <".quotemeta($yesfile), 2); while() { if (/setting\s+up\s+(\S+)/i && !/as\s+MDA/i) { - push(@rv, $1); + push(@rv, &strip_apt_package_arch($1)); } elsif (/packages\s+will\s+be\s+upgraded/i || /new\s+packages\s+will\s+be\s+installed/i) { @@ -94,6 +103,7 @@ foreach my $l (split(/\r?\n/, $out)) { if ($pkg->{'version'} =~ s/^(\S+)://) { $pkg->{'epoch'} = $1; } + $pkg->{'name'} = &strip_apt_package_arch($pkg->{'name'}); push(@rv, $pkg); } elsif ($l =~ /Inst\s+(\S+)\s+\(([^ \)]+)/) { @@ -103,6 +113,7 @@ foreach my $l (split(/\r?\n/, $out)) { if ($pkg->{'version'} =~ s/^(\S+)://) { $pkg->{'epoch'} = $1; } + $pkg->{'name'} = &strip_apt_package_arch($pkg->{'name'}); push(@rv, $pkg); } } diff --git a/t/software-apt.t b/t/software-apt.t new file mode 100644 index 000000000..1d91f976a --- /dev/null +++ b/t/software-apt.t @@ -0,0 +1,82 @@ +#!/usr/local/bin/perl + +use strict; +use warnings; +use Test::More; +use File::Basename qw(dirname); +use File::Spec; +use Cwd qw(abs_path); + +our %config; + +my $root = abs_path(File::Spec->catdir(dirname(__FILE__), '..')); +chdir($root) or die "chdir($root): $!"; + +do './software/apt-lib.pl' or die $@ || $!; + +is(strip_apt_package_arch('libtinfo6:amd64'), 'libtinfo6', + 'strips native Debian architecture suffix'); +is(strip_apt_package_arch('libgomp1:i386'), 'libgomp1', + 'strips foreign Debian architecture suffix'); +is(strip_apt_package_arch('ncurses-base'), 'ncurses-base', + 'leaves unqualified package names unchanged'); + +{ +no warnings qw(once redefine); +local *backquote_command = sub { + return "Inst libtinfo6:amd64 [6.3-2ubuntu0.1] ". + "(6.3-2ubuntu0.2 Ubuntu:22.04/jammy-updates [amd64])\n"; + }; +local *clean_language = sub { }; +local *reset_environment = sub { }; + +my @ops = update_system_operations('libtinfo6'); +is($ops[0]->{'name'}, 'libtinfo6', + 'normalizes package names from simulated APT operations'); +} + +{ +no warnings qw(once redefine); +my $apt_output = "Setting up libtinfo6:amd64 (6.3-2ubuntu0.2) ...\n"; +my $yes_input = ""; +local *additional_log = sub { }; +local *backquote_logged = sub { return ""; }; +local *clean_language = sub { }; +local *html_escape = sub { return $_[0]; }; +local *reset_environment = sub { }; +local *text = sub { return $_[0]; }; +local *transname = sub { return "/tmp/software-apt-test-yes"; }; +local *open_tempfile = sub { + my ($fh) = @_; + no strict 'refs'; + open(ref($fh) ? $fh : \*{$fh}, ">", \$yes_input) + or die "open temp input: $!"; + }; +local *print_tempfile = sub { + my ($fh, @text) = @_; + no strict 'refs'; + my $handle = ref($fh) ? $fh : \*{$fh}; + print $handle @text; + }; +local *close_tempfile = sub { + my ($fh) = @_; + no strict 'refs'; + close(ref($fh) ? $fh : \*{$fh}); + }; +local *open_execute_command = sub { + my ($fh) = @_; + no strict 'refs'; + open(ref($fh) ? $fh : \*{$fh}, "<", \$apt_output) + or die "open simulated apt output: $!"; + }; +local $config{'package_system'} = 'debian'; + +my $printed = ""; +open(my $stdout, ">", \$printed) or die "open captured stdout: $!"; +local *STDOUT = $stdout; +my @installed = update_system_install('libtinfo6', undef, 1); +is_deeply(\@installed, [ 'libtinfo6' ], + 'normalizes package names returned by apt install output'); +} + +done_testing();