1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +02:00
pgbackrest/build/lib/pgBackRestBuild/Config/BuildParse.pm

265 lines
10 KiB
Perl
Raw Normal View History

2017-11-29 04:44:05 +02:00
####################################################################################################################################
# Auto-Generate Option Definition for Parsing with getopt_long().
####################################################################################################################################
package pgBackRestBuild::Config::BuildParse;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use Cwd qw(abs_path);
use Exporter qw(import);
our @EXPORT = qw();
use File::Basename qw(dirname);
use Storable qw(dclone);
use pgBackRest::Common::Log;
use pgBackRest::Common::String;
use pgBackRest::Version;
use pgBackRestBuild::Build::Common;
use pgBackRestBuild::Config::Build;
use pgBackRestBuild::Config::Data;
####################################################################################################################################
# Constants
####################################################################################################################################
use constant BLDLCL_FILE_DEFINE => 'parse';
use constant BLDLCL_DATA_OPTION => '01-dataOption';
use constant BLDLCL_DATA_OPTION_RESOLVE => '01-dataOptionResolve';
2017-11-29 04:44:05 +02:00
####################################################################################################################################
# Definitions for constants and data to build
####################################################################################################################################
my $strSummary = 'Option Parse Definition';
my $rhBuild =
{
&BLD_FILE =>
{
&BLDLCL_FILE_DEFINE =>
{
&BLD_SUMMARY => $strSummary,
&BLD_DATA =>
{
&BLDLCL_DATA_OPTION =>
{
&BLD_SUMMARY => 'Option parse data',
},
&BLDLCL_DATA_OPTION_RESOLVE =>
{
&BLD_SUMMARY => 'Order for option parse resolution',
},
2017-11-29 04:44:05 +02:00
},
},
},
};
####################################################################################################################################
# Build configuration constants and data
####################################################################################################################################
sub buildConfigParse
{
# Build option parse list
#-------------------------------------------------------------------------------------------------------------------------------
my $rhConfigDefine = cfgDefine();
my $strBuildSource =
"static const struct option optionList[] =\n" .
"{";
2017-11-29 04:44:05 +02:00
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
{
my $rhOption = $rhConfigDefine->{$strOption};
my $strOptionEnum = buildConfigOptionEnum($strOption);
my $strOptionArg = ($rhOption->{&CFGDEF_TYPE} ne CFGDEF_TYPE_BOOLEAN ? " .has_arg = required_argument,\n" : '');
my $strOptionPrefix = $rhConfigDefine->{$strOption}{&CFGDEF_PREFIX};
my @stryOptionName = ($strOption);
if (defined($rhOption->{&CFGDEF_NAME_ALT}))
{
foreach my $strOptionNameAlt (sort(keys(%{$rhOption->{&CFGDEF_NAME_ALT}})))
{
push(@stryOptionName, $strOptionNameAlt);
}
}
$strBuildSource .=
"\n" .
" // ${strOption} option" . (@stryOptionName > 1 ? ' and deprecations' : '') . "\n" .
" // " . (qw{-} x 125) . "\n";
for (my $iOptionIdx = 1; $iOptionIdx <= $rhOption->{&CFGDEF_INDEX_TOTAL}; $iOptionIdx++)
2017-11-29 04:44:05 +02:00
{
for (my $iOptionNameIdx = 0; $iOptionNameIdx < @stryOptionName; $iOptionNameIdx++)
{
my $strOptionName = $stryOptionName[$iOptionNameIdx];
my $rhNameAlt = $rhOption->{&CFGDEF_NAME_ALT}{$strOptionName};
2017-11-29 04:44:05 +02:00
# Skip alt name if it is not valid for this option index
if ($iOptionNameIdx > 0 && defined($rhNameAlt->{&CFGDEF_INDEX}) && $rhNameAlt->{&CFGDEF_INDEX} != $iOptionIdx)
{
next;
}
2017-11-29 04:44:05 +02:00
# Generate output name
my $strOptionNameOut = $strOptionName;
my $strOptionConst;
if (defined($strOptionPrefix))
{
if ($iOptionNameIdx == 0)
{
$strOptionNameOut =
"${strOptionPrefix}${iOptionIdx}-" . substr($strOptionName, length($strOptionPrefix) + 1);
}
else
{
$strOptionNameOut =~ s/\?/$iOptionIdx/g;
}
}
# Generate option value used for parsing (offset is added so options don't conflict with getopt_long return values)
my $strOptionFlag = 'PARSE_OPTION_FLAG |';
# Build option constant name if this is the current name for the option
if ($iOptionNameIdx == 0)
{
$strOptionConst = "CFGOPT_" . uc($strOptionNameOut);
$strOptionConst =~ s/\-/_/g;
}
# Else use bare string and mark as deprecated
else
{
$strOptionFlag .= ' PARSE_DEPRECATE_FLAG |';
}
2017-11-29 04:44:05 +02:00
my $strOptionVal =
($iOptionIdx > 1 ? "(" : '') . $strOptionEnum . ($iOptionIdx > 1 ? " + " . ($iOptionIdx - 1) . ')' : '');
2017-11-29 04:44:05 +02:00
# Add option
2017-11-29 04:44:05 +02:00
$strBuildSource .=
" {\n" .
" .name = " . (defined($strOptionConst) ? $strOptionConst : "\"${strOptionNameOut}\"") . ",\n" .
$strOptionArg .
" .val = ${strOptionFlag} ${strOptionVal},\n" .
2017-11-29 04:44:05 +02:00
" },\n";
# Add negation when defined
if ($rhOption->{&CFGDEF_NEGATE} &&
!($iOptionNameIdx > 0 && defined($rhNameAlt->{&CFGDEF_NEGATE}) && !$rhNameAlt->{&CFGDEF_NEGATE}))
{
$strBuildSource .=
" {\n" .
" .name = \"no-" .
(defined($strOptionConst) ? "\" ${strOptionConst}" : "${strOptionNameOut}\"") . ",\n" .
" .val = ${strOptionFlag} PARSE_NEGATE_FLAG | ${strOptionVal},\n" .
" },\n";
}
# Add reset when defined
if ($rhOption->{&CFGDEF_RESET} &&
!($iOptionNameIdx > 0 && defined($rhNameAlt->{&CFGDEF_RESET}) && !$rhNameAlt->{&CFGDEF_RESET}))
{
$strBuildSource .=
" {\n" .
" .name = \"reset-" .
(defined($strOptionConst) ? "\" ${strOptionConst}" : "${strOptionNameOut}\"") . ",\n" .
" .val = ${strOptionFlag} PARSE_RESET_FLAG | ${strOptionVal},\n" .
" },\n";
}
2017-11-29 04:44:05 +02:00
}
}
}
# The option list needs to be terminated or getopt_long will just keep on reading
$strBuildSource .=
" // Terminate option list\n" .
" {\n" .
" .name = NULL\n" .
" }\n" .
"};\n";
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION}{&BLD_SOURCE} = $strBuildSource;
# Build option resolve order list. This allows the option validation in C to take place in a single pass.
#
# Always process the stanza option first since confusing error message are produced if it is missing.
#-------------------------------------------------------------------------------------------------------------------------------
my @stryResolveOrder = (buildConfigOptionEnum(CFGOPT_STANZA));
my $rhResolved = {&CFGOPT_STANZA => true};
my $bAllResolved;
do
{
# Assume that we will finish on this loop
$bAllResolved = true;
# Loop through all options
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
{
my $bSkip = false;
# Check the default depend
my $strOptionDepend =
ref($rhConfigDefine->{$strOption}{&CFGDEF_DEPEND}) eq 'HASH' ?
$rhConfigDefine->{$strOption}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION} :
$rhConfigDefine->{$strOption}{&CFGDEF_DEPEND};
if (defined($strOptionDepend) && !$rhResolved->{$strOptionDepend})
{
# &log(WARN, "$strOptionDepend is not resolved");
$bSkip = true;
}
# Check the command depends
foreach my $strCommand (sort(keys(%{$rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}})))
{
my $strOptionDepend =
ref($rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_DEPEND}) eq 'HASH' ?
$rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION} :
$rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_DEPEND};
if (defined($strOptionDepend) && !$rhResolved->{$strOptionDepend})
{
$bSkip = true;
}
}
# If dependency was not found try again on the next loop
if ($bSkip)
{
$bAllResolved = false;
}
# Else add option to resolve order list
elsif (!$rhResolved->{$strOption})
{
$rhResolved->{$strOption} = true;
for (my $iIndex = 0; $iIndex < $rhConfigDefine->{$strOption}{&CFGDEF_INDEX_TOTAL}; $iIndex++)
{
push(@stryResolveOrder, buildConfigOptionEnum($strOption) . ($iIndex == 0 ? '' : " + $iIndex"));
}
}
}
}
while (!$bAllResolved);
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION_RESOLVE}{&BLD_SOURCE} =
"static const ConfigOption optionResolveOrder[] =\n" .
"{\n" .
" " . join(",\n ", @stryResolveOrder) . ",\n" .
"};\n";
2017-11-29 04:44:05 +02:00
return $rhBuild;
}
push @EXPORT, qw(buildConfigParse);
1;