1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +02:00
pgbackrest/lib/BackRest/Config/ConfigHelp.pm
David Steele ac3c0d43ab Implemented issue #132: Improved command-line help.
Implemented issue #133: Dynamic module loading where possible.
2015-09-08 07:31:24 -04:00

381 lines
13 KiB
Perl

####################################################################################################################################
# CONFIG HELP MODULE
####################################################################################################################################
package BackRest::Config::Config::ConfigHelp;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use Exporter qw(import);
our @EXPORT = qw();
use File::Basename qw(dirname);
use lib dirname($0) . '/../lib';
use BackRest::Common::Exception;
use BackRest::Common::Log;
use BackRest::Common::String;
use BackRest::Config::Config;
####################################################################################################################################
# Help types
####################################################################################################################################
use constant CONFIG_HELP_COMMAND => 'command';
push @EXPORT, qw(CONFIG_HELP_COMMAND);
use constant CONFIG_HELP_CURRENT => 'current';
push @EXPORT, qw(CONFIG_HELP_CURRENT);
use constant CONFIG_HELP_DEFAULT => 'default';
push @EXPORT, qw(CONFIG_HELP_DEFAULT);
use constant CONFIG_HELP_DESCRIPTION => 'description';
push @EXPORT, qw(CONFIG_HELP_DESCRIPTION);
use constant CONFIG_HELP_OPTION => 'option';
push @EXPORT, qw(CONFIG_HELP_OPTION);
use constant CONFIG_HELP_SECTION => 'section';
push @EXPORT, qw(CONFIG_HELP_SECTION);
use constant CONFIG_HELP_SUMMARY => 'summary';
push @EXPORT, qw(CONFIG_HELP_SUMMARY);
use constant CONFIG_HELP_SOURCE => 'source';
push @EXPORT, qw(CONFIG_HELP_SOURCE);
use constant CONFIG_HELP_SOURCE_DEFAULT => 'default';
push @EXPORT, qw(CONFIG_HELP_SOURCE_DEFAULT);
use constant CONFIG_HELP_SOURCE_SECTION => CONFIG_HELP_SECTION;
push @EXPORT, qw(CONFIG_HELP_SOURCE_SECTION);
use constant CONFIG_HELP_SOURCE_COMMAND => CONFIG_HELP_COMMAND;
push @EXPORT, qw(CONFIG_HELP_SOURCE_COMMAND);
####################################################################################################################################
# configHelp
#
# Display command-line help.
####################################################################################################################################
sub configHelp
{
my $strCommand = shift;
my $strOption = shift;
# Load module dynamically
require BackRest::Config::Config::ConfigHelpData;
BackRest::Config::Config::ConfigHelpData->import();
# Get config data
my $oCommandHash = commandHashGet();
my $oOptionRule = optionRuleGet();
my $oConfigHelpData = configHelpDataGet();
# Build the title
my $strTitle;
my $strHelp;
# Since there's no command this will be general help
if (!defined($strCommand))
{
$strTitle = "General"
}
# Else check the command
else
{
$strCommand = lc($strCommand);
if (defined($$oCommandHash{$strCommand}))
{
$strTitle = "'${strCommand}' command";
# And check the option
if (defined($strOption))
{
$strOption = lc($strOption);
if (defined($$oConfigHelpData{&CONFIG_HELP_COMMAND}{$strCommand}{&CONFIG_HELP_OPTION}{$strOption}))
{
$strTitle .= " - '${strOption}' option";
}
else
{
$strHelp = "Invalid option '${strOption}' for command '${strCommand}'";
}
}
}
else
{
$strHelp = "Invalid command '${strCommand}'";
}
}
# Internal text format function to make output look good on a console
sub formatText
{
my $strTextIn = shift;
my $iIndent = shift;
my $bIndentFirst = shift;
my $iLength = shift;
my @stryText = split("\n", trim($strTextIn));
my $strText;
my $iIndex = 0;
foreach my $strLine (@stryText)
{
if (defined($strText))
{
$strText .= "\n";
}
my $strPart;
my $bFirst = true;
do
{
($strPart, $strLine) = stringSplit($strLine, ' ', $iLength - $iIndent);
if (!$bFirst || $bIndentFirst)
{
if (!$bFirst)
{
$strText .= "\n";
}
$strText .= ' ' x $iIndent;
}
$strText .= trim($strPart);
$bFirst = false;
}
while (defined($strLine));
$iIndex++;
}
return $strText;
}
# Internal option find function
#
# The option may be stored with the command or in the option list depending on whether it's generic or command-specific
sub optionFind
{
my $oConfigHelpData = shift;
my $oOptionRule = shift;
my $strCommand = shift;
my $strOption = shift;
my $strSection = CONFIG_HELP_COMMAND;
my $oOption = $$oConfigHelpData{&CONFIG_HELP_COMMAND}{$strCommand}{&CONFIG_HELP_OPTION}{$strOption};
if (ref(\$oOption) eq 'SCALAR')
{
$oOption = $$oConfigHelpData{&CONFIG_HELP_OPTION}{$strOption};
if (defined($$oOption{&CONFIG_HELP_SECTION}))
{
$strSection = $$oOption{&CONFIG_HELP_SECTION};
if ($strSection eq CONFIG_SECTION_COMMAND)
{
$strSection = CONFIG_SECTION_GENERAL;
}
}
else
{
$strSection = CONFIG_SECTION_GENERAL;
}
if (($strSection ne CONFIG_SECTION_GENERAL && $strSection ne CONFIG_SECTION_LOG &&
$strSection ne CONFIG_SECTION_STANZA && $strSection ne CONFIG_SECTION_EXPIRE) ||
$strSection eq $strCommand)
{
$strSection = CONFIG_HELP_COMMAND;
}
}
if (defined(optionDefault($strOption, $strCommand)))
{
if ($$oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq &OPTION_TYPE_BOOLEAN)
{
$$oOption{&CONFIG_HELP_DEFAULT} = optionDefault($strOption, $strCommand) ? 'y' : 'n';
}
else
{
$$oOption{&CONFIG_HELP_DEFAULT} = optionDefault($strOption, $strCommand);
}
}
if (optionTest($strOption) && optionSource($strOption) ne CONFIG_HELP_SOURCE_DEFAULT)
{
if ($$oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq &OPTION_TYPE_BOOLEAN)
{
$$oOption{&CONFIG_HELP_CURRENT} = optionGet($strOption) ? 'y' : 'n';
}
else
{
$$oOption{&CONFIG_HELP_CURRENT} = optionGet($strOption);
}
}
return $oOption, $strSection;
}
# Build the help
my $strMore;
if (!defined($strHelp))
{
my $iScreenWidth = 80;
# General help
if (!defined($strCommand))
{
$strHelp =
"Usage:\n" .
" " . BACKREST_EXE . " [options] [command]\n\n" .
"Commands:\n";
# Find longest command length
my $iCommandLength = 0;
foreach my $strCommand (sort(keys($$oConfigHelpData{&CONFIG_HELP_COMMAND})))
{
if (length($strCommand) > $iCommandLength)
{
$iCommandLength = length($strCommand);
}
}
# Output commands
foreach my $strCommand (sort(keys($$oConfigHelpData{&CONFIG_HELP_COMMAND})))
{
my $oCommand = $$oConfigHelpData{&CONFIG_HELP_COMMAND}{$strCommand};
$strHelp .= " ${strCommand}" . (' ' x ($iCommandLength - length($strCommand)));
$strHelp .=
' ' . formatText($$oCommand{&CONFIG_HELP_SUMMARY}, 4 + $iCommandLength + 2, false, $iScreenWidth + 1) .
"\n";
}
$strMore = '[command]';
}
# Else command help
elsif (!defined($strOption))
{
my $oCommand = $$oConfigHelpData{&CONFIG_HELP_COMMAND}{$strCommand};
$strHelp =
formatText($$oCommand{&CONFIG_HELP_SUMMARY} . "\n\n" .
$$oCommand{&CONFIG_HELP_DESCRIPTION}, 0, true, $iScreenWidth + 1);
# Find longest option length and unique list of sections
my $iOptionLength = 0;
my $oSection = {};
if (defined($$oCommand{&CONFIG_HELP_OPTION}))
{
foreach my $strOption (sort(keys($$oCommand{&CONFIG_HELP_OPTION})))
{
if (length($strOption) > $iOptionLength)
{
$iOptionLength = length($strOption);
}
my ($oOption, $strSection) = optionFind($oConfigHelpData, $oOptionRule, $strCommand, $strOption);
$$oSection{$strSection}{$strOption} = $oOption;
}
# Iterate sections
foreach my $strSection (sort(keys($oSection)))
{
$strHelp .=
"\n\n" . ucfirst($strSection) . " Options:\n";
# Iterate options
foreach my $strOption (sort(keys($$oSection{$strSection})))
{
$strHelp .= "\n";
my $iIndent = 4 + $iOptionLength + 2;
my $oOption = $$oSection{$strSection}{$strOption};
# Set current and default values
my $strDefault = '';
if ($$oOption{&CONFIG_HELP_CURRENT} || $$oOption{&CONFIG_HELP_DEFAULT})
{
$strDefault = undef;
if ($$oOption{&CONFIG_HELP_CURRENT})
{
$strDefault .= 'current=' . $$oOption{&CONFIG_HELP_CURRENT};
}
if ($$oOption{&CONFIG_HELP_DEFAULT})
{
if (defined($strDefault))
{
$strDefault .= ', ';
}
$strDefault .= 'default=' . $$oOption{&CONFIG_HELP_DEFAULT};
}
$strDefault = " [${strDefault}]";
}
# Output help
$strHelp .= " --${strOption}" . (' ' x ($iOptionLength - length($strOption)));
$strHelp .= ' ' . formatText(lcfirst(substr($$oOption{&CONFIG_HELP_SUMMARY}, 0,
length($$oOption{&CONFIG_HELP_SUMMARY}) - 1)) .
$strDefault, $iIndent, false, $iScreenWidth + 1);
}
}
$strMore = "${strCommand} [option]";
$strHelp .= "\n";
}
}
# Else option help
else
{
my ($oOption) = optionFind($oConfigHelpData, $oOptionRule, $strCommand, $strOption);
# Set current and default values
my $strDefault = '';
if ($$oOption{&CONFIG_HELP_CURRENT} || $$oOption{&CONFIG_HELP_DEFAULT})
{
$strDefault = undef;
if ($$oOption{&CONFIG_HELP_CURRENT})
{
$strDefault = 'current: ' . $$oOption{&CONFIG_HELP_CURRENT};
}
if ($$oOption{&CONFIG_HELP_DEFAULT})
{
if (defined($strDefault))
{
$strDefault .= "\n";
}
$strDefault .= 'default: ' . $$oOption{&CONFIG_HELP_DEFAULT};
}
$strDefault = "\n\n${strDefault}";
}
# Output help
$strHelp =
formatText($$oOption{&CONFIG_HELP_SUMMARY} . "\n\n" . $$oOption{&CONFIG_HELP_DESCRIPTION} .
$strDefault, 0, true, $iScreenWidth + 1);
}
}
# Output help
syswrite(*STDOUT, ' -' . (defined($strTitle) ? " ${strTitle}" : '') . " help\n\n${strHelp}\n" .
(defined($strMore) ? 'Use \'' . BACKREST_EXE . " help ${strMore}' for more information.\n" : ''));
}
push @EXPORT, qw(configHelp);
1;