mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-14 10:13:05 +02:00
44da314adb
The prior range checking was done based on the valid values for gz. While this worked it was a subset of what is available for lz4 and zst. Allow the range to be specified for each compress-type. Adding this functionality to the parse module would be a better solution but that is a bigger project than this fix deserves, at least for now.
558 lines
25 KiB
Perl
558 lines
25 KiB
Perl
####################################################################################################################################
|
|
# Configuration Definition Data
|
|
#
|
|
# The configuration is defined in src/build/config/config.yaml, which also contains the documentation.
|
|
####################################################################################################################################
|
|
package pgBackRestDoc::Custom::DocConfigData;
|
|
|
|
use strict;
|
|
use warnings FATAL => qw(all);
|
|
use Carp qw(confess);
|
|
|
|
use Cwd qw(abs_path);
|
|
use Exporter qw(import);
|
|
our @EXPORT = qw();
|
|
use File::Basename qw(dirname basename);
|
|
use Getopt::Long qw(GetOptions);
|
|
use Storable qw(dclone);
|
|
|
|
use pgBackRestDoc::Common::Exception;
|
|
use pgBackRestDoc::Common::Log;
|
|
use pgBackRestDoc::ProjectInfo;
|
|
|
|
use pgBackRestTest::Common::Wait;
|
|
|
|
####################################################################################################################################
|
|
# Command constants
|
|
####################################################################################################################################
|
|
use constant CFGCMD_BACKUP => 'backup';
|
|
push @EXPORT, qw(CFGCMD_BACKUP);
|
|
use constant CFGCMD_HELP => 'help';
|
|
push @EXPORT, qw(CFGCMD_HELP);
|
|
use constant CFGCMD_INFO => 'info';
|
|
push @EXPORT, qw(CFGCMD_INFO);
|
|
use constant CFGCMD_VERSION => 'version';
|
|
|
|
####################################################################################################################################
|
|
# Command role constants - roles allowed for each command. Commands may have multiple processes that work together to implement
|
|
# their functionality. These roles allow each process to know what it is supposed to do.
|
|
####################################################################################################################################
|
|
# Called directly by the user. This is the main process of the command that may or may not spawn other command roles.
|
|
use constant CFGCMD_ROLE_MAIN => 'main';
|
|
push @EXPORT, qw(CFGCMD_ROLE_MAIN);
|
|
|
|
# Async worker that is spawned so the main process can return a result while work continues. An async worker may spawn local or
|
|
# remote workers.
|
|
use constant CFGCMD_ROLE_ASYNC => 'async';
|
|
push @EXPORT, qw(CFGCMD_ROLE_ASYNC);
|
|
|
|
# Local worker for parallelizing jobs. A local work may spawn a remote worker.
|
|
use constant CFGCMD_ROLE_LOCAL => 'local';
|
|
push @EXPORT, qw(CFGCMD_ROLE_LOCAL);
|
|
|
|
# Remote worker for accessing resources on another host
|
|
use constant CFGCMD_ROLE_REMOTE => 'remote';
|
|
push @EXPORT, qw(CFGCMD_ROLE_REMOTE);
|
|
|
|
####################################################################################################################################
|
|
# Option constants - options that are allowed for commands
|
|
####################################################################################################################################
|
|
|
|
# Command-line only options
|
|
#-----------------------------------------------------------------------------------------------------------------------------------
|
|
use constant CFGOPT_CONFIG => 'config';
|
|
push @EXPORT, qw(CFGOPT_CONFIG);
|
|
use constant CFGOPT_STANZA => 'stanza';
|
|
push @EXPORT, qw(CFGOPT_STANZA);
|
|
|
|
# Command-line only local/remote options
|
|
#-----------------------------------------------------------------------------------------------------------------------------------
|
|
# Paths
|
|
use constant CFGOPT_LOCK_PATH => 'lock-path';
|
|
push @EXPORT, qw(CFGOPT_LOCK_PATH);
|
|
use constant CFGOPT_LOG_PATH => 'log-path';
|
|
push @EXPORT, qw(CFGOPT_LOG_PATH);
|
|
use constant CFGOPT_SPOOL_PATH => 'spool-path';
|
|
push @EXPORT, qw(CFGOPT_SPOOL_PATH);
|
|
|
|
# Logging
|
|
use constant CFGOPT_LOG_LEVEL_STDERR => 'log-level-stderr';
|
|
push @EXPORT, qw(CFGOPT_LOG_LEVEL_STDERR);
|
|
use constant CFGOPT_LOG_TIMESTAMP => 'log-timestamp';
|
|
push @EXPORT, qw(CFGOPT_LOG_TIMESTAMP);
|
|
|
|
# Repository options
|
|
#-----------------------------------------------------------------------------------------------------------------------------------
|
|
# Prefix that must be used by all repo options that allow multiple configurations
|
|
use constant CFGDEF_PREFIX_REPO => 'repo';
|
|
|
|
# Repository General
|
|
use constant CFGOPT_REPO_PATH => CFGDEF_PREFIX_REPO . '-path';
|
|
push @EXPORT, qw(CFGOPT_REPO_PATH);
|
|
|
|
# Repository Host
|
|
use constant CFGOPT_REPO_HOST => CFGDEF_PREFIX_REPO . '-host';
|
|
use constant CFGOPT_REPO_HOST_CMD => CFGOPT_REPO_HOST . '-cmd';
|
|
push @EXPORT, qw(CFGOPT_REPO_HOST_CMD);
|
|
|
|
# Stanza options
|
|
#-----------------------------------------------------------------------------------------------------------------------------------
|
|
# Determines how many databases can be configured
|
|
use constant CFGDEF_INDEX_PG => 8;
|
|
push @EXPORT, qw(CFGDEF_INDEX_PG);
|
|
|
|
# Prefix that must be used by all db options that allow multiple configurations
|
|
use constant CFGDEF_PREFIX_PG => 'pg';
|
|
push @EXPORT, qw(CFGDEF_PREFIX_PG);
|
|
|
|
# Set default PostgreSQL cluster
|
|
use constant CFGOPT_PG_HOST => CFGDEF_PREFIX_PG . '-host';
|
|
use constant CFGOPT_PG_HOST_CMD => CFGOPT_PG_HOST . '-cmd';
|
|
push @EXPORT, qw(CFGOPT_PG_HOST_CMD);
|
|
|
|
####################################################################################################################################
|
|
# Option definition constants - defines, types, sections, etc.
|
|
####################################################################################################################################
|
|
|
|
# Command defines
|
|
#-----------------------------------------------------------------------------------------------------------------------------------
|
|
use constant CFGDEF_LOG_FILE => 'log-file';
|
|
push @EXPORT, qw(CFGDEF_LOG_FILE);
|
|
use constant CFGDEF_LOG_LEVEL_DEFAULT => 'log-level-default';
|
|
push @EXPORT, qw(CFGDEF_LOG_LEVEL_DEFAULT);
|
|
use constant CFGDEF_LOCK_REQUIRED => 'lock-required';
|
|
push @EXPORT, qw(CFGDEF_LOCK_REQUIRED);
|
|
use constant CFGDEF_LOCK_REMOTE_REQUIRED => 'lock-remote-required';
|
|
push @EXPORT, qw(CFGDEF_LOCK_REMOTE_REQUIRED);
|
|
|
|
use constant CFGDEF_LOCK_TYPE => 'lock-type';
|
|
push @EXPORT, qw(CFGDEF_LOCK_TYPE);
|
|
use constant CFGDEF_LOCK_TYPE_NONE => 'none';
|
|
|
|
use constant CFGDEF_PARAMETER_ALLOWED => 'parameter-allowed';
|
|
push @EXPORT, qw(CFGDEF_PARAMETER_ALLOWED);
|
|
|
|
# Option defines
|
|
#-----------------------------------------------------------------------------------------------------------------------------------
|
|
use constant CFGDEF_ALLOW_LIST => 'allow-list';
|
|
push @EXPORT, qw(CFGDEF_ALLOW_LIST);
|
|
use constant CFGDEF_ALLOW_RANGE => 'allow-range';
|
|
push @EXPORT, qw(CFGDEF_ALLOW_RANGE);
|
|
use constant CFGDEF_DEFAULT => 'default';
|
|
push @EXPORT, qw(CFGDEF_DEFAULT);
|
|
use constant CFGDEF_DEFAULT_LITERAL => 'default-literal';
|
|
push @EXPORT, qw(CFGDEF_DEFAULT_LITERAL);
|
|
|
|
# Group options together to share common configuration
|
|
use constant CFGDEF_GROUP => 'group';
|
|
push @EXPORT, qw(CFGDEF_GROUP);
|
|
|
|
use constant CFGDEF_INDEX => 'index';
|
|
push @EXPORT, qw(CFGDEF_INDEX);
|
|
use constant CFGDEF_INHERIT => 'inherit';
|
|
push @EXPORT, qw(CFGDEF_INHERIT);
|
|
use constant CFGDEF_INTERNAL => 'internal';
|
|
push @EXPORT, qw(CFGDEF_INTERNAL);
|
|
use constant CFGDEF_DEPRECATE => 'deprecate';
|
|
push @EXPORT, qw(CFGDEF_DEPRECATE);
|
|
use constant CFGDEF_NEGATE => 'negate';
|
|
push @EXPORT, qw(CFGDEF_NEGATE);
|
|
use constant CFGDEF_COMMAND => 'command';
|
|
push @EXPORT, qw(CFGDEF_COMMAND);
|
|
use constant CFGDEF_COMMAND_ROLE => 'command-role';
|
|
push @EXPORT, qw(CFGDEF_COMMAND_ROLE);
|
|
use constant CFGDEF_REQUIRED => 'required';
|
|
push @EXPORT, qw(CFGDEF_REQUIRED);
|
|
use constant CFGDEF_RESET => 'reset';
|
|
push @EXPORT, qw(CFGDEF_RESET);
|
|
use constant CFGDEF_SECTION => 'section';
|
|
push @EXPORT, qw(CFGDEF_SECTION);
|
|
use constant CFGDEF_SECURE => 'secure';
|
|
push @EXPORT, qw(CFGDEF_SECURE);
|
|
use constant CFGDEF_TYPE => 'type';
|
|
push @EXPORT, qw(CFGDEF_TYPE);
|
|
|
|
# Option types
|
|
#-----------------------------------------------------------------------------------------------------------------------------------
|
|
use constant CFGDEF_TYPE_BOOLEAN => 'boolean';
|
|
push @EXPORT, qw(CFGDEF_TYPE_BOOLEAN);
|
|
use constant CFGDEF_TYPE_HASH => 'hash';
|
|
push @EXPORT, qw(CFGDEF_TYPE_HASH);
|
|
use constant CFGDEF_TYPE_INTEGER => 'integer';
|
|
push @EXPORT, qw(CFGDEF_TYPE_INTEGER);
|
|
use constant CFGDEF_TYPE_LIST => 'list';
|
|
push @EXPORT, qw(CFGDEF_TYPE_LIST);
|
|
use constant CFGDEF_TYPE_PATH => 'path';
|
|
push @EXPORT, qw(CFGDEF_TYPE_PATH);
|
|
use constant CFGDEF_TYPE_STRING => 'string';
|
|
push @EXPORT, qw(CFGDEF_TYPE_STRING);
|
|
use constant CFGDEF_TYPE_SIZE => 'size';
|
|
push @EXPORT, qw(CFGDEF_TYPE_SIZE);
|
|
use constant CFGDEF_TYPE_TIME => 'time';
|
|
push @EXPORT, qw(CFGDEF_TYPE_TIME);
|
|
|
|
# Option config sections
|
|
#-----------------------------------------------------------------------------------------------------------------------------------
|
|
use constant CFGDEF_SECTION_GLOBAL => 'global';
|
|
push @EXPORT, qw(CFGDEF_SECTION_GLOBAL);
|
|
use constant CFGDEF_SECTION_STANZA => 'stanza';
|
|
push @EXPORT, qw(CFGDEF_SECTION_STANZA);
|
|
|
|
####################################################################################################################################
|
|
# Load configuration
|
|
####################################################################################################################################
|
|
use YAML::XS qw(LoadFile);
|
|
|
|
# Required so booleans are not read-only
|
|
local $YAML::XS::Boolean = "JSON::PP";
|
|
|
|
my $rhConfig = LoadFile(dirname(dirname($0)) . '/src/build/config/config.yaml');
|
|
my $rhCommandDefine = $rhConfig->{'command'};
|
|
my $rhOptionGroupDefine = $rhConfig->{'optionGroup'};
|
|
my $rhConfigDefine = $rhConfig->{'option'};
|
|
|
|
####################################################################################################################################
|
|
# Fix errors introduced by YAML::XS::LoadFile. This is typically fixed by setting local $YAML::XS::Boolean = "JSON::PP", but older
|
|
# Debian/Ubuntu versions do not support this fix. Some booleans get set read only and others also end up as empty strings. There is
|
|
# no apparent pattern to what gets broken so it is important to be on the lookout for strange output when adding new options.
|
|
#
|
|
# ??? For now this code is commented out since packages for older Debians can be built using backports. It is being preserved just
|
|
# in case it is needed before the migration to C is complete.
|
|
####################################################################################################################################
|
|
# sub optionDefineFixup
|
|
# {
|
|
# my $strKey = shift;
|
|
# my $rhDefine = shift;
|
|
#
|
|
# # Fix read-only required values so they are writable
|
|
# if (defined($rhDefine->{&CFGDEF_REQUIRED}))
|
|
# {
|
|
# my $value = $rhDefine->{&CFGDEF_REQUIRED} ? true : false;
|
|
# delete($rhDefine->{&CFGDEF_REQUIRED});
|
|
# $rhDefine->{&CFGDEF_REQUIRED} = $value;
|
|
# }
|
|
#
|
|
# # If the default is an empty string set to false. This must be a mangled boolean since empty strings are not valid defaults.
|
|
# if (defined($rhDefine->{&CFGDEF_DEFAULT}) && $rhDefine->{&CFGDEF_DEFAULT} eq '')
|
|
# {
|
|
# delete($rhDefine->{&CFGDEF_DEFAULT});
|
|
# $rhDefine->{&CFGDEF_DEFAULT} = false;
|
|
# }
|
|
# }
|
|
#
|
|
# # Fix all options
|
|
# foreach my $strKey (sort(keys(%{$rhConfigDefine})))
|
|
# {
|
|
# my $rhOption = $rhConfigDefine->{$strKey};
|
|
# optionDefineFixup($strKey, $rhOption);
|
|
#
|
|
# # Fix all option commands
|
|
# if (ref($rhOption->{&CFGDEF_COMMAND}))
|
|
# {
|
|
# foreach my $strCommand (sort(keys(%{$rhOption->{&CFGDEF_COMMAND}})))
|
|
# {
|
|
# optionDefineFixup("$strKey-$strCommand", $rhOption->{&CFGDEF_COMMAND}{$strCommand});
|
|
# }
|
|
# }
|
|
# }
|
|
|
|
####################################################################################################################################
|
|
# Process command define defaults
|
|
####################################################################################################################################
|
|
foreach my $strCommand (sort(keys(%{$rhCommandDefine})))
|
|
{
|
|
# Commands are external by default
|
|
if (!defined($rhCommandDefine->{$strCommand}{&CFGDEF_INTERNAL}))
|
|
{
|
|
$rhCommandDefine->{$strCommand}{&CFGDEF_INTERNAL} = false;
|
|
}
|
|
|
|
# Log files are created by default
|
|
if (!defined($rhCommandDefine->{$strCommand}{&CFGDEF_LOG_FILE}))
|
|
{
|
|
$rhCommandDefine->{$strCommand}{&CFGDEF_LOG_FILE} = true;
|
|
}
|
|
|
|
# Default log level is INFO
|
|
if (!defined($rhCommandDefine->{$strCommand}{&CFGDEF_LOG_LEVEL_DEFAULT}))
|
|
{
|
|
$rhCommandDefine->{$strCommand}{&CFGDEF_LOG_LEVEL_DEFAULT} = INFO;
|
|
}
|
|
|
|
# Default lock required is false
|
|
if (!defined($rhCommandDefine->{$strCommand}{&CFGDEF_LOCK_REQUIRED}))
|
|
{
|
|
$rhCommandDefine->{$strCommand}{&CFGDEF_LOCK_REQUIRED} = false;
|
|
}
|
|
|
|
# Default lock remote required is false
|
|
if (!defined($rhCommandDefine->{$strCommand}{&CFGDEF_LOCK_REMOTE_REQUIRED}))
|
|
{
|
|
$rhCommandDefine->{$strCommand}{&CFGDEF_LOCK_REMOTE_REQUIRED} = false;
|
|
}
|
|
|
|
# Lock type must be set if a lock is required
|
|
if (!defined($rhCommandDefine->{$strCommand}{&CFGDEF_LOCK_TYPE}))
|
|
{
|
|
# Is a lock type required?
|
|
if ($rhCommandDefine->{$strCommand}{&CFGDEF_LOCK_REQUIRED})
|
|
{
|
|
confess &log(ERROR, "lock type is required for command '${strCommand}'");
|
|
}
|
|
|
|
$rhCommandDefine->{$strCommand}{&CFGDEF_LOCK_TYPE} = CFGDEF_LOCK_TYPE_NONE;
|
|
}
|
|
else
|
|
{
|
|
if ($rhCommandDefine->{$strCommand}{&CFGDEF_LOCK_REQUIRED} &&
|
|
$rhCommandDefine->{$strCommand}{&CFGDEF_LOCK_TYPE} eq CFGDEF_LOCK_TYPE_NONE)
|
|
{
|
|
confess &log(ERROR, "lock type is required for command '${strCommand}' and cannot be 'none'");
|
|
}
|
|
}
|
|
|
|
# Default parameter allowed is false
|
|
if (!defined($rhCommandDefine->{$strCommand}{&CFGDEF_PARAMETER_ALLOWED}))
|
|
{
|
|
$rhCommandDefine->{$strCommand}{&CFGDEF_PARAMETER_ALLOWED} = false;
|
|
}
|
|
|
|
# All commands have the default role
|
|
if (!defined($rhCommandDefine->{$strCommand}{&CFGDEF_COMMAND_ROLE}{&CFGCMD_ROLE_MAIN}))
|
|
{
|
|
$rhCommandDefine->{$strCommand}{&CFGDEF_COMMAND_ROLE}{&CFGCMD_ROLE_MAIN} = {};
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# Process option define defaults
|
|
####################################################################################################################################
|
|
foreach my $strKey (sort(keys(%{$rhConfigDefine})))
|
|
{
|
|
my $rhOption = $rhConfigDefine->{$strKey};
|
|
|
|
# If the define is a scalar then copy the entire define from the referenced option
|
|
if (defined($rhConfigDefine->{$strKey}{&CFGDEF_INHERIT}))
|
|
{
|
|
# Make a copy in case there are overrides that need to be applied after inheriting
|
|
my $hConfigDefineOverride = dclone($rhConfigDefine->{$strKey});
|
|
|
|
# Copy the option being inherited from
|
|
$rhConfigDefine->{$strKey} = dclone($rhConfigDefine->{$rhConfigDefine->{$strKey}{&CFGDEF_INHERIT}});
|
|
|
|
# No need to copy the inheritance key
|
|
delete($rhConfigDefine->{$strKey}{&CFGDEF_INHERIT});
|
|
|
|
# It makes no sense to inherit deprecations - they must be specified for each option
|
|
delete($rhConfigDefine->{$strKey}{&CFGDEF_DEPRECATE});
|
|
|
|
# Apply overrides
|
|
foreach my $strOptionDef (sort(keys(%{$hConfigDefineOverride})))
|
|
{
|
|
$rhConfigDefine->{$strKey}{$strOptionDef} = $hConfigDefineOverride->{$strOptionDef};
|
|
}
|
|
|
|
# Update option variable with new hash reference
|
|
$rhOption = $rhConfigDefine->{$strKey}
|
|
}
|
|
|
|
# If command is not specified then the option is valid for all commands except version and help
|
|
if (!defined($rhOption->{&CFGDEF_COMMAND}))
|
|
{
|
|
foreach my $strCommand (sort(keys(%{$rhCommandDefine})))
|
|
{
|
|
next if $strCommand eq CFGCMD_HELP || $strCommand eq CFGCMD_VERSION;
|
|
|
|
$rhOption->{&CFGDEF_COMMAND}{$strCommand} = {};
|
|
}
|
|
}
|
|
# Else if the command section is a scalar then copy the section from the referenced option
|
|
elsif (defined($rhConfigDefine->{$strKey}{&CFGDEF_COMMAND}) && !ref($rhConfigDefine->{$strKey}{&CFGDEF_COMMAND}))
|
|
{
|
|
$rhConfigDefine->{$strKey}{&CFGDEF_COMMAND} =
|
|
dclone($rhConfigDefine->{$rhConfigDefine->{$strKey}{&CFGDEF_COMMAND}}{&CFGDEF_COMMAND});
|
|
}
|
|
|
|
# If the allow list is a scalar then copy the list from the referenced option
|
|
if (defined($rhConfigDefine->{$strKey}{&CFGDEF_ALLOW_LIST}) && !ref($rhConfigDefine->{$strKey}{&CFGDEF_ALLOW_LIST}))
|
|
{
|
|
$rhConfigDefine->{$strKey}{&CFGDEF_ALLOW_LIST} =
|
|
dclone($rhConfigDefine->{$rhConfigDefine->{$strKey}{&CFGDEF_ALLOW_LIST}}{&CFGDEF_ALLOW_LIST});
|
|
}
|
|
|
|
# Default type is string
|
|
if (!defined($rhConfigDefine->{$strKey}{&CFGDEF_TYPE}))
|
|
{
|
|
&log(ASSERT, "type is required for option '${strKey}'");
|
|
}
|
|
|
|
# Default required is true
|
|
if (!defined($rhConfigDefine->{$strKey}{&CFGDEF_REQUIRED}))
|
|
{
|
|
$rhConfigDefine->{$strKey}{&CFGDEF_REQUIRED} = true;
|
|
}
|
|
|
|
# Default internal is false
|
|
if (!defined($rhConfigDefine->{$strKey}{&CFGDEF_INTERNAL}))
|
|
{
|
|
$rhConfigDefine->{$strKey}{&CFGDEF_INTERNAL} = false;
|
|
}
|
|
|
|
# All boolean config options can be negated. Boolean command-line options must be marked for negation individually.
|
|
if ($rhConfigDefine->{$strKey}{&CFGDEF_TYPE} eq CFGDEF_TYPE_BOOLEAN && defined($rhConfigDefine->{$strKey}{&CFGDEF_SECTION}))
|
|
{
|
|
$rhConfigDefine->{$strKey}{&CFGDEF_NEGATE} = true;
|
|
}
|
|
|
|
# Default for negation is false
|
|
if (!defined($rhConfigDefine->{$strKey}{&CFGDEF_NEGATE}))
|
|
{
|
|
$rhConfigDefine->{$strKey}{&CFGDEF_NEGATE} = false;
|
|
}
|
|
|
|
# All config options can be reset
|
|
if (defined($rhConfigDefine->{$strKey}{&CFGDEF_SECTION}))
|
|
{
|
|
$rhConfigDefine->{$strKey}{&CFGDEF_RESET} = true;
|
|
}
|
|
elsif (!defined($rhConfigDefine->{$strKey}{&CFGDEF_RESET}))
|
|
{
|
|
$rhConfigDefine->{$strKey}{&CFGDEF_RESET} = false;
|
|
}
|
|
|
|
# By default options are not secure
|
|
if (!defined($rhConfigDefine->{$strKey}{&CFGDEF_SECURE}))
|
|
{
|
|
$rhConfigDefine->{$strKey}{&CFGDEF_SECURE} = false;
|
|
}
|
|
|
|
# All size and time options must have an allow range
|
|
if (($rhConfigDefine->{$strKey}{&CFGDEF_TYPE} eq CFGDEF_TYPE_TIME ||
|
|
$rhConfigDefine->{$strKey}{&CFGDEF_TYPE} eq CFGDEF_TYPE_SIZE) &&
|
|
!(defined($rhConfigDefine->{$strKey}{&CFGDEF_ALLOW_RANGE}) || defined($rhConfigDefine->{$strKey}{&CFGDEF_ALLOW_LIST})))
|
|
{
|
|
confess &log(ASSERT, "int/size/time option '${strKey}' must have allow range or list");
|
|
}
|
|
|
|
# Ensure all commands are valid
|
|
foreach my $strCommand (sort(keys(%{$rhConfigDefine->{$strKey}{&CFGDEF_COMMAND}})))
|
|
{
|
|
if (!defined($rhCommandDefine->{$strCommand}))
|
|
{
|
|
confess &log(ASSERT, "invalid command '${strCommand}'");
|
|
}
|
|
}
|
|
}
|
|
|
|
# Generate valid command roles for each option
|
|
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
|
|
{
|
|
my $rhOption = $rhConfigDefine->{$strOption};
|
|
|
|
# Generate valid command roles for each command in the option
|
|
foreach my $strCommand (sort(keys(%{$rhOption->{&CFGDEF_COMMAND}})))
|
|
{
|
|
# If command roles are defined in the option command override then check that they are valid
|
|
if (defined($rhOption->{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_COMMAND_ROLE}))
|
|
{
|
|
foreach my $strCommandRole (sort(keys(%{$rhOption->{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_COMMAND_ROLE}})))
|
|
{
|
|
if (!defined($rhCommandDefine->{$strCommand}{&CFGDEF_COMMAND_ROLE}{$strCommandRole}))
|
|
{
|
|
confess &log(
|
|
ASSERT, "option '${strOption}', command '${strCommand}' has invalid command role '${strCommandRole}'");
|
|
}
|
|
}
|
|
}
|
|
# Else if the option has command roles defined then use the intersection of command roles with the command
|
|
elsif (defined($rhOption->{&CFGDEF_COMMAND_ROLE}))
|
|
{
|
|
foreach my $strCommandRole (sort(keys(%{$rhOption->{&CFGDEF_COMMAND_ROLE}})))
|
|
{
|
|
if (defined($rhCommandDefine->{$strCommand}{&CFGDEF_COMMAND_ROLE}{$strCommandRole}))
|
|
{
|
|
$rhOption->{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_COMMAND_ROLE}{$strCommandRole} = {};
|
|
}
|
|
}
|
|
}
|
|
# Else copy the command roles from the command
|
|
else
|
|
{
|
|
foreach my $strCommandRole (sort(keys(%{$rhCommandDefine->{$strCommand}{&CFGDEF_COMMAND_ROLE}})))
|
|
{
|
|
$rhOption->{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_COMMAND_ROLE}{$strCommandRole} = {};
|
|
}
|
|
}
|
|
}
|
|
|
|
# Remove option command roles so they don't accidentally get used in processing (since they were copied to option commands)
|
|
delete($rhOption->{&CFGDEF_COMMAND_ROLE});
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# Get option definition
|
|
####################################################################################################################################
|
|
sub cfgDefine
|
|
{
|
|
return dclone($rhConfigDefine);
|
|
}
|
|
|
|
push @EXPORT, qw(cfgDefine);
|
|
|
|
####################################################################################################################################
|
|
# Get command definition
|
|
####################################################################################################################################
|
|
sub cfgDefineCommand
|
|
{
|
|
return dclone($rhCommandDefine);
|
|
}
|
|
|
|
push @EXPORT, qw(cfgDefineCommand);
|
|
|
|
####################################################################################################################################
|
|
# Get option group definition
|
|
####################################################################################################################################
|
|
sub cfgDefineOptionGroup
|
|
{
|
|
return dclone($rhOptionGroupDefine);
|
|
}
|
|
|
|
push @EXPORT, qw(cfgDefineOptionGroup);
|
|
|
|
####################################################################################################################################
|
|
# Get list of all commands
|
|
####################################################################################################################################
|
|
sub cfgDefineCommandList
|
|
{
|
|
# Return sorted list
|
|
return (sort(keys(%{$rhCommandDefine})));
|
|
}
|
|
|
|
push @EXPORT, qw(cfgDefineCommandList);
|
|
|
|
####################################################################################################################################
|
|
# Get list of all option types
|
|
####################################################################################################################################
|
|
sub cfgDefineOptionTypeList
|
|
{
|
|
my $rhOptionTypeMap;
|
|
|
|
# Get unique list of types
|
|
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
|
|
{
|
|
my $strOptionType = $rhConfigDefine->{$strOption}{&CFGDEF_TYPE};
|
|
|
|
if (!defined($rhOptionTypeMap->{$strOptionType}))
|
|
{
|
|
$rhOptionTypeMap->{$strOptionType} = true;
|
|
}
|
|
};
|
|
|
|
# Return sorted list
|
|
return (sort(keys(%{$rhOptionTypeMap})));
|
|
}
|
|
|
|
push @EXPORT, qw(cfgDefineOptionTypeList);
|
|
|
|
1;
|