301 lines
7.1 KiB
Perl
301 lines
7.1 KiB
Perl
# needrestart - Restart daemons after library updates.
|
|
#
|
|
# Authors:
|
|
# Thomas Liske <thomas@fiasko-nw.net>
|
|
#
|
|
# Copyright Holder:
|
|
# 2013 - 2022 (C) Thomas Liske [http://fiasko-nw.net/~thomas/]
|
|
#
|
|
# License:
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this package; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
#
|
|
|
|
package NeedRestart::UI;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Text::Wrap qw(wrap);
|
|
use Term::ReadKey;
|
|
|
|
# NeedRestart::UI internals properties
|
|
# ====================================
|
|
#
|
|
# $self->{verbosity}: 1 if needrestart is in verbose mode, 0
|
|
# otherwise.
|
|
#
|
|
# $self->{progress}: if undef, disable the progress bar. Otherwise:
|
|
#
|
|
# $self->{progress}->{msg}: message to print (last message printed).
|
|
#
|
|
# $self->{progress}->{count}: current progress (number of steps done
|
|
# since the beginning).
|
|
#
|
|
# $self->{progress}->{max}: Expected total number of steps. If 0,
|
|
# the bar will always be at 0.
|
|
#
|
|
# $self->{fhin}, $self->{fhout}: original stdin/stdout filehandles.
|
|
# NeedRestart::UI may change the filehandles to ensure we have a
|
|
# terminal. The original filehandles are saved in these two
|
|
# attributes in progress_prep, and restored in progress_fin.
|
|
|
|
|
|
# my $ui = new NeedRestart::UI(VERBOSITY);
|
|
#
|
|
# VERBOSITY indicates whether needrestart is otherwise verbose (0 or
|
|
# 1). If VERBOSITY is 1, we disable the progress indicator:
|
|
# otherwise, the output would not be nice.
|
|
sub new {
|
|
my $class = shift;
|
|
my $verbosity = shift;
|
|
|
|
return bless {
|
|
verbosity => $verbosity,
|
|
progress => undef,
|
|
}, $class;
|
|
}
|
|
|
|
# my $nb_columns = _get_terminal_columns(FILEHANDLE);
|
|
# e.g.: my $nb_columns = _get_terminal_columns(\*STDOUT);
|
|
# => 103
|
|
#
|
|
# This is a wrapper for GetTerminalSize to cope with Debian
|
|
# Bug#824564.
|
|
sub _get_terminal_columns {
|
|
my ($filehandle) = @_;
|
|
# workaround Debian Bug#824564 in Term::ReadKey: pass filehandle
|
|
# twice
|
|
my ($columns) = GetTerminalSize($filehandle, $filehandle);
|
|
return $columns;
|
|
}
|
|
|
|
# my $columns = &_get_columns();
|
|
#
|
|
# Return the number of columns to use for output.
|
|
sub _get_columns {
|
|
my $default_columns = 80; # Sane default
|
|
if (-t *STDOUT) {
|
|
my ($columns) = _get_terminal_columns(\*STDOUT);
|
|
|
|
# Cope with 0-width terminals (see Debian bug #942759).
|
|
return $columns == 0? $default_columns: $columns;
|
|
}
|
|
else {
|
|
return $default_columns;
|
|
}
|
|
}
|
|
|
|
# $ui->wprint(FILEHANDLE, SP1, SP2, MESSAGE);
|
|
#
|
|
# Print the MESSAGE to the given FILEHANDLE, wrapping text if we can get
|
|
# the number of columns.
|
|
#
|
|
# SP1 and SP2 are resp. Text::Wrap::wrap's $initial_tab and
|
|
# $subsequent_tab.
|
|
sub wprint {
|
|
my $self = shift;
|
|
my $fh = shift;
|
|
my $sp1 = shift;
|
|
my $sp2 = shift;
|
|
my $message = shift;
|
|
|
|
# only wrap output if it is a terminal
|
|
if (-t $fh) {
|
|
my ($cols) = _get_terminal_columns($fh, $fh);
|
|
$Text::Wrap::columns = $cols? $cols: 80;
|
|
|
|
print $fh wrap($sp1, $sp2, $message);
|
|
}
|
|
else {
|
|
print $fh "$sp1$message";
|
|
}
|
|
}
|
|
|
|
# $ui->progress_prep(MAX, OUT);
|
|
#
|
|
# Prepare for displaying a new progress bar.
|
|
#
|
|
# Disable the progress bar if we don't have a terminal. Restore the
|
|
# terminal if necessary. Reset the progress counter. Print the
|
|
# initial line.
|
|
#
|
|
# MAX: expected total number of steps.
|
|
#
|
|
# OUT: the message, e.g. "Scanning processes..."
|
|
sub progress_prep($$$) {
|
|
my $self = shift;
|
|
my ($max, $out) = @_;
|
|
|
|
unless(($self->{verbosity} != 1) || !(-t *STDERR)) {
|
|
# restore terminal if required (debconf)
|
|
unless(-t *STDIN) {
|
|
open($self->{fhin}, '<&', \*STDIN) || die "Can't dup stdin: $!\n";
|
|
open(STDIN, '< /dev/tty') || open(STDIN, '<&1');
|
|
}
|
|
unless(-t *STDOUT) {
|
|
open($self->{fhout}, '>&', \*STDOUT) || die "Can't dup stdout: $!\n";
|
|
open(STDOUT, '> /dev/tty') || open(STDOUT, '>&2');
|
|
}
|
|
|
|
$self->{progress} = {
|
|
count => 0,
|
|
max => $max,
|
|
};
|
|
}
|
|
else {
|
|
# disable progress indicator while being verbose
|
|
$self->{progress} = undef;
|
|
}
|
|
|
|
$self->_progress_msg($out);
|
|
}
|
|
|
|
# $ui->progress_step();
|
|
#
|
|
# Add one step to the progress and update the display.
|
|
sub progress_step($) {
|
|
my $self = shift;
|
|
|
|
return unless defined($self->{progress});
|
|
|
|
$self->_progress_inc();
|
|
|
|
1;
|
|
}
|
|
|
|
# $ui->progress_fin();
|
|
#
|
|
# Restore stdin/out as they were before the preparation.
|
|
sub progress_fin($) {
|
|
my $self = shift;
|
|
|
|
return unless defined($self->{progress});
|
|
|
|
$self->_progress_fin();
|
|
|
|
# restore STDIN/STDOUT if required (debconf)
|
|
open(STDIN, '<&', \*{$self->{fhin}}) || die "Can't dup stdin: $!\n"
|
|
if($self->{fhin});
|
|
open(STDOUT, '>&', \*{$self->{fhout}}) || die "Can't dup stdout: $!\n"
|
|
if($self->{fhout});
|
|
}
|
|
|
|
# $ui->_progress_msg(MESSAGE);
|
|
#
|
|
# Set the current MESSAGE and update the display.
|
|
sub _progress_msg {
|
|
my $self = shift;
|
|
|
|
return unless defined($self->{progress});
|
|
|
|
$self->{progress}->{msg} = shift;
|
|
$self->_progress_out();
|
|
}
|
|
|
|
# $ui->_progress_inc();
|
|
#
|
|
# Increase progress by one step and redisplay.
|
|
sub _progress_inc {
|
|
my $self = shift;
|
|
|
|
$self->{progress}->{count}++;
|
|
$self->_progress_out();
|
|
}
|
|
|
|
# $ui->_progress_out();
|
|
#
|
|
# Print the current message and progress bar.
|
|
sub _progress_out {
|
|
my $self = shift;
|
|
|
|
my $msg = $self->{progress}->{msg};
|
|
my $max = $self->{progress}->{max};
|
|
my $count = $self->{progress}->{count};
|
|
|
|
# The line looks like this:
|
|
# my message [==== ]
|
|
# <- wmsg ->..<---- wbar -------->.
|
|
|
|
# 3 columns are preassigned (the space and the square brackets);
|
|
# we need to split the remaining space between the message and the
|
|
# bar itself.
|
|
my $remaining_space = _get_columns() - 3;
|
|
|
|
# We use 70% max of the remaining space.
|
|
my $wmsg = int($remaining_space * 0.7);
|
|
# Shrink if the message is actually shorter.
|
|
$wmsg = length($msg) if(length($msg) < $wmsg);
|
|
|
|
my $wbar = $remaining_space - $wmsg;
|
|
|
|
my $bar = '=' x ($wbar*( $max > 0 ? $count/$max : 0 ));
|
|
printf("%-${wmsg}s [%-${wbar}s]\r", substr($msg, 0, $wmsg), $bar);
|
|
}
|
|
|
|
# $ui->_progress_fin();
|
|
#
|
|
# Finish the progress. Redisplay the line, removing the bar.
|
|
sub _progress_fin {
|
|
my $self = shift;
|
|
my $columns = _get_columns;
|
|
|
|
$self->{progress}->{count} = 0;
|
|
|
|
print $self->{progress}->{msg}, ' ' x ($columns - length($self->{progress}->{msg})), "\n";
|
|
}
|
|
|
|
sub announce_abi {
|
|
}
|
|
|
|
|
|
sub announce_ver {
|
|
}
|
|
|
|
|
|
sub announce_ucode {
|
|
}
|
|
|
|
|
|
sub notice($$) {
|
|
}
|
|
|
|
sub vspace {
|
|
my $self = shift;
|
|
my $fh = shift;
|
|
|
|
print $fh "\n" if(defined($fh));
|
|
}
|
|
|
|
sub command() {
|
|
my $self = shift;
|
|
|
|
$self->notice(@_);
|
|
}
|
|
|
|
|
|
sub query_pkgs($$$$$) {
|
|
}
|
|
|
|
sub query_conts($$$$$) {
|
|
}
|
|
|
|
sub runcmd {
|
|
my $self = shift;
|
|
my $cb = shift;
|
|
|
|
&$cb;
|
|
}
|
|
|
|
1;
|