You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-07-15 01:04:37 +02:00
Config parsing implemented in C.
This commit is contained in:
@ -138,6 +138,6 @@ Subsequent code that is uncoverable for the same reason is marked with `// {+unc
|
|||||||
|
|
||||||
Marks code that is not tested for one reason or another. This should be kept to a minimum and an excuse given for each instance.
|
Marks code that is not tested for one reason or another. This should be kept to a minimum and an excuse given for each instance.
|
||||||
```
|
```
|
||||||
exit(EXIT_FAILURE); // {uncoverable - test harness does not support non-zero exit}
|
exit(EXIT_FAILURE); // {uncovered - test harness does not support non-zero exit}
|
||||||
```
|
```
|
||||||
Subsequent code that is uncovered for the same reason is marked with `// {+uncovered}`.
|
Subsequent code that is uncovered for the same reason is marked with `// {+uncovered}`.
|
||||||
|
@ -146,6 +146,7 @@ sub buildConfig
|
|||||||
|
|
||||||
# Add "none" command that is used to initialize the current command before anything is parsed
|
# Add "none" command that is used to initialize the current command before anything is parsed
|
||||||
push(@{$rhEnum->{&BLD_LIST}}, buildConfigCommandEnum('none'));
|
push(@{$rhEnum->{&BLD_LIST}}, buildConfigCommandEnum('none'));
|
||||||
|
$iCommandTotal++;
|
||||||
|
|
||||||
$strBuildSource .=
|
$strBuildSource .=
|
||||||
")\n";
|
")\n";
|
||||||
|
@ -108,15 +108,6 @@ sub buildConfigParse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Perl options passed to the C binary should be ignored (unless calling Perl which is done elsewhere)
|
|
||||||
$strBuildSource .=
|
|
||||||
" // Perl option is ignored by normal config parsing\n" .
|
|
||||||
" {\n" .
|
|
||||||
" .name = \"perl-option\",\n" .
|
|
||||||
" .has_arg = required_argument,\n" .
|
|
||||||
" .val = 0,\n" .
|
|
||||||
" },\n";
|
|
||||||
|
|
||||||
# The option list needs to be terminated or getopt_long will just keep on reading
|
# The option list needs to be terminated or getopt_long will just keep on reading
|
||||||
$strBuildSource .=
|
$strBuildSource .=
|
||||||
" // Terminate option list\n" .
|
" // Terminate option list\n" .
|
||||||
|
@ -182,6 +182,10 @@ use constant CFGOPT_LOG_PATH => 'log-path
|
|||||||
use constant CFGOPT_SPOOL_PATH => 'spool-path';
|
use constant CFGOPT_SPOOL_PATH => 'spool-path';
|
||||||
push @EXPORT, qw(CFGOPT_SPOOL_PATH);
|
push @EXPORT, qw(CFGOPT_SPOOL_PATH);
|
||||||
|
|
||||||
|
# Perl
|
||||||
|
use constant CFGOPT_PERL_OPTION => 'perl-option';
|
||||||
|
push @EXPORT, qw(CFGOPT_PERL_OPTION);
|
||||||
|
|
||||||
# Repository
|
# Repository
|
||||||
use constant CFGOPT_REPO_PATH => 'repo-path';
|
use constant CFGOPT_REPO_PATH => 'repo-path';
|
||||||
push @EXPORT, qw(CFGOPT_REPO_PATH);
|
push @EXPORT, qw(CFGOPT_REPO_PATH);
|
||||||
@ -1050,6 +1054,30 @@ my %hConfigDefine =
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
&CFGOPT_PERL_OPTION =>
|
||||||
|
{
|
||||||
|
&CFGDEF_SECTION => CFGDEF_SECTION_GLOBAL,
|
||||||
|
&CFGDEF_TYPE => CFGDEF_TYPE_LIST,
|
||||||
|
&CFGDEF_REQUIRED => false,
|
||||||
|
&CFGDEF_INTERNAL => true,
|
||||||
|
&CFGDEF_COMMAND =>
|
||||||
|
{
|
||||||
|
&CFGCMD_ARCHIVE_GET => {},
|
||||||
|
&CFGCMD_ARCHIVE_PUSH => {},
|
||||||
|
&CFGCMD_BACKUP => {},
|
||||||
|
&CFGCMD_CHECK => {},
|
||||||
|
&CFGCMD_EXPIRE => {},
|
||||||
|
&CFGCMD_INFO => {},
|
||||||
|
&CFGCMD_LOCAL => {},
|
||||||
|
&CFGCMD_REMOTE => {},
|
||||||
|
&CFGCMD_RESTORE => {},
|
||||||
|
&CFGCMD_STANZA_CREATE => {},
|
||||||
|
&CFGCMD_STANZA_UPGRADE => {},
|
||||||
|
&CFGCMD_START => {},
|
||||||
|
&CFGCMD_STOP => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
&CFGOPT_PROTOCOL_TIMEOUT =>
|
&CFGOPT_PROTOCOL_TIMEOUT =>
|
||||||
{
|
{
|
||||||
&CFGDEF_SECTION => CFGDEF_SECTION_GLOBAL,
|
&CFGDEF_SECTION => CFGDEF_SECTION_GLOBAL,
|
||||||
|
@ -192,7 +192,7 @@ if (condition)
|
|||||||
<p>Marks code that is not tested for one reason or another. This should be kept to a minimum and an excuse given for each instance.</p>
|
<p>Marks code that is not tested for one reason or another. This should be kept to a minimum and an excuse given for each instance.</p>
|
||||||
|
|
||||||
<code-block>
|
<code-block>
|
||||||
exit(EXIT_FAILURE); // {uncoverable - test harness does not support non-zero exit}
|
exit(EXIT_FAILURE); // {uncovered - test harness does not support non-zero exit}
|
||||||
</code-block>
|
</code-block>
|
||||||
|
|
||||||
<p>Subsequent code that is uncovered for the same reason is marked with `// {+uncovered}`.</p>
|
<p>Subsequent code that is uncovered for the same reason is marked with `// {+uncovered}`.</p>
|
||||||
|
@ -41,6 +41,10 @@
|
|||||||
<p>Implement <cmd>version</cmd> command in C.</p>
|
<p>Implement <cmd>version</cmd> command in C.</p>
|
||||||
</release-item>
|
</release-item>
|
||||||
|
|
||||||
|
<release-item>
|
||||||
|
<p>Config parsing implemented in C.</p>
|
||||||
|
</release-item>
|
||||||
|
|
||||||
<release-item>
|
<release-item>
|
||||||
<p>Add <code>Buffer</code>, <code>Ini</code>, <code>KeyValue</code>, <code>List</code>, <code>Storage</code>, <code>String</code>, <code>StringList</code>, <code>Variant</code>, and <code>VariantList</code> objects.</p>
|
<p>Add <code>Buffer</code>, <code>Ini</code>, <code>KeyValue</code>, <code>List</code>, <code>Storage</code>, <code>String</code>, <code>StringList</code>, <code>Variant</code>, and <code>VariantList</code> objects.</p>
|
||||||
</release-item>
|
</release-item>
|
||||||
@ -65,10 +69,6 @@
|
|||||||
<p>Replace <code>cfgCommandTotal()</code>/<code>cfgOptionTotal()</code> functions with constants. The constants are applicable in more cases and allow the compiler to optimize certain loops more efficiently.</p>
|
<p>Replace <code>cfgCommandTotal()</code>/<code>cfgOptionTotal()</code> functions with constants. The constants are applicable in more cases and allow the compiler to optimize certain loops more efficiently.</p>
|
||||||
</release-item>
|
</release-item>
|
||||||
|
|
||||||
<release-item>
|
|
||||||
<p>More config parsing in C in preparation for all config parsing in C.</p>
|
|
||||||
</release-item>
|
|
||||||
|
|
||||||
<release-item>
|
<release-item>
|
||||||
<p>Refactor code to make valgrind happy.</p>
|
<p>Refactor code to make valgrind happy.</p>
|
||||||
</release-item>
|
</release-item>
|
||||||
|
@ -82,6 +82,13 @@ my @stryCFile =
|
|||||||
'common/error.c',
|
'common/error.c',
|
||||||
'common/errorType.c',
|
'common/errorType.c',
|
||||||
'common/memContext.c',
|
'common/memContext.c',
|
||||||
|
'common/type/buffer.c',
|
||||||
|
'common/type/keyValue.c',
|
||||||
|
'common/type/list.c',
|
||||||
|
'common/type/string.c',
|
||||||
|
'common/type/stringList.c',
|
||||||
|
'common/type/variant.c',
|
||||||
|
'common/type/variantList.c',
|
||||||
'config/config.c',
|
'config/config.c',
|
||||||
'config/define.c',
|
'config/define.c',
|
||||||
'postgres/pageChecksum.c',
|
'postgres/pageChecksum.c',
|
||||||
|
@ -159,6 +159,7 @@ sub libcAutoExportTag
|
|||||||
'CFGOPT_NEUTRAL_UMASK',
|
'CFGOPT_NEUTRAL_UMASK',
|
||||||
'CFGOPT_ONLINE',
|
'CFGOPT_ONLINE',
|
||||||
'CFGOPT_OUTPUT',
|
'CFGOPT_OUTPUT',
|
||||||
|
'CFGOPT_PERL_OPTION',
|
||||||
'CFGOPT_PROCESS',
|
'CFGOPT_PROCESS',
|
||||||
'CFGOPT_PROCESS_MAX',
|
'CFGOPT_PROCESS_MAX',
|
||||||
'CFGOPT_PROTOCOL_TIMEOUT',
|
'CFGOPT_PROTOCOL_TIMEOUT',
|
||||||
|
@ -73,6 +73,7 @@ Option constants
|
|||||||
#define CFGOPT_NEUTRAL_UMASK cfgOptNeutralUmask
|
#define CFGOPT_NEUTRAL_UMASK cfgOptNeutralUmask
|
||||||
#define CFGOPT_ONLINE cfgOptOnline
|
#define CFGOPT_ONLINE cfgOptOnline
|
||||||
#define CFGOPT_OUTPUT cfgOptOutput
|
#define CFGOPT_OUTPUT cfgOptOutput
|
||||||
|
#define CFGOPT_PERL_OPTION cfgOptPerlOption
|
||||||
#define CFGOPT_PROCESS cfgOptProcess
|
#define CFGOPT_PROCESS cfgOptProcess
|
||||||
#define CFGOPT_PROCESS_MAX cfgOptProcessMax
|
#define CFGOPT_PROCESS_MAX cfgOptProcessMax
|
||||||
#define CFGOPT_PROTOCOL_TIMEOUT cfgOptProtocolTimeout
|
#define CFGOPT_PROTOCOL_TIMEOUT cfgOptProtocolTimeout
|
||||||
|
@ -32,10 +32,12 @@ ERROR_DEFINE(ERROR_CODE_MIN, AssertError, RuntimeError);
|
|||||||
|
|
||||||
ERROR_DEFINE(ERROR_CODE_MIN + 04, FormatError, RuntimeError);
|
ERROR_DEFINE(ERROR_CODE_MIN + 04, FormatError, RuntimeError);
|
||||||
ERROR_DEFINE(ERROR_CODE_MIN + 05, CommandRequiredError, FormatError);
|
ERROR_DEFINE(ERROR_CODE_MIN + 05, CommandRequiredError, FormatError);
|
||||||
|
ERROR_DEFINE(ERROR_CODE_MIN + 06, OptionInvalidError, RuntimeError);
|
||||||
|
ERROR_DEFINE(ERROR_CODE_MIN + 07, OptionInvalidValueError, RuntimeError);
|
||||||
|
ERROR_DEFINE(ERROR_CODE_MIN + 12, OptionRequiredError, RuntimeError);
|
||||||
ERROR_DEFINE(ERROR_CODE_MIN + 16, FileOpenError, RuntimeError);
|
ERROR_DEFINE(ERROR_CODE_MIN + 16, FileOpenError, RuntimeError);
|
||||||
ERROR_DEFINE(ERROR_CODE_MIN + 17, FileReadError, RuntimeError);
|
ERROR_DEFINE(ERROR_CODE_MIN + 17, FileReadError, RuntimeError);
|
||||||
ERROR_DEFINE(ERROR_CODE_MIN + 23, CommandInvalidError, FormatError);
|
ERROR_DEFINE(ERROR_CODE_MIN + 23, CommandInvalidError, FormatError);
|
||||||
ERROR_DEFINE(ERROR_CODE_MIN + 31, OptionInvalidError, FormatError);
|
|
||||||
ERROR_DEFINE(ERROR_CODE_MIN + 39, FileWriteError, RuntimeError);
|
ERROR_DEFINE(ERROR_CODE_MIN + 39, FileWriteError, RuntimeError);
|
||||||
ERROR_DEFINE(ERROR_CODE_MIN + 69, MemoryError, RuntimeError);
|
ERROR_DEFINE(ERROR_CODE_MIN + 69, MemoryError, RuntimeError);
|
||||||
ERROR_DEFINE(ERROR_CODE_MIN + 70, CipherError, FormatError);
|
ERROR_DEFINE(ERROR_CODE_MIN + 70, CipherError, FormatError);
|
||||||
|
@ -18,10 +18,12 @@ ERROR_DECLARE(AssertError);
|
|||||||
|
|
||||||
ERROR_DECLARE(FormatError);
|
ERROR_DECLARE(FormatError);
|
||||||
ERROR_DECLARE(CommandRequiredError);
|
ERROR_DECLARE(CommandRequiredError);
|
||||||
ERROR_DECLARE(CommandInvalidError);
|
|
||||||
ERROR_DECLARE(OptionInvalidError);
|
ERROR_DECLARE(OptionInvalidError);
|
||||||
|
ERROR_DECLARE(OptionInvalidValueError);
|
||||||
|
ERROR_DECLARE(OptionRequiredError);
|
||||||
ERROR_DECLARE(FileOpenError);
|
ERROR_DECLARE(FileOpenError);
|
||||||
ERROR_DECLARE(FileReadError);
|
ERROR_DECLARE(FileReadError);
|
||||||
|
ERROR_DECLARE(CommandInvalidError);
|
||||||
ERROR_DECLARE(FileWriteError);
|
ERROR_DECLARE(FileWriteError);
|
||||||
ERROR_DECLARE(MemoryError);
|
ERROR_DECLARE(MemoryError);
|
||||||
ERROR_DECLARE(CipherError);
|
ERROR_DECLARE(CipherError);
|
||||||
|
@ -898,6 +898,14 @@ ConfigOptionData configOptionData[CFG_OPTION_TOTAL] = CONFIG_OPTION_LIST
|
|||||||
CONFIG_OPTION_DEFINE_ID(cfgDefOptOutput)
|
CONFIG_OPTION_DEFINE_ID(cfgDefOptOutput)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
CONFIG_OPTION
|
||||||
|
(
|
||||||
|
CONFIG_OPTION_NAME("perl-option")
|
||||||
|
CONFIG_OPTION_INDEX(0)
|
||||||
|
CONFIG_OPTION_DEFINE_ID(cfgDefOptPerlOption)
|
||||||
|
)
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
CONFIG_OPTION
|
CONFIG_OPTION
|
||||||
(
|
(
|
||||||
|
@ -9,12 +9,12 @@ Automatically generated by Build.pm -- do not modify directly.
|
|||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Command constants
|
Command constants
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
#define CFG_COMMAND_TOTAL 15
|
#define CFG_COMMAND_TOTAL 16
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Option constants
|
Option constants
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
#define CFG_OPTION_TOTAL 138
|
#define CFG_OPTION_TOTAL 139
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Command enum
|
Command enum
|
||||||
@ -89,6 +89,7 @@ typedef enum
|
|||||||
cfgOptNeutralUmask,
|
cfgOptNeutralUmask,
|
||||||
cfgOptOnline,
|
cfgOptOnline,
|
||||||
cfgOptOutput,
|
cfgOptOutput,
|
||||||
|
cfgOptPerlOption,
|
||||||
cfgOptProcess,
|
cfgOptProcess,
|
||||||
cfgOptProcessMax,
|
cfgOptProcessMax,
|
||||||
cfgOptProtocolTimeout,
|
cfgOptProtocolTimeout,
|
||||||
|
@ -4,6 +4,7 @@ Command and Option Configuration
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "common/error.h"
|
#include "common/error.h"
|
||||||
|
#include "common/memContext.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
@ -52,6 +53,11 @@ Include the automatically generated configuration data
|
|||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
#include "config.auto.c"
|
#include "config.auto.c"
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Store the config memory context
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
MemContext *configMemContext = NULL;
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Store the current command
|
Store the current command
|
||||||
|
|
||||||
@ -59,6 +65,67 @@ This is generally set by the command parser but can also be set by during execut
|
|||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
ConfigCommand command = cfgCmdNone;
|
ConfigCommand command = cfgCmdNone;
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Store the location of the executable
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
String *exe = NULL;
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Was help requested for the command?
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
bool help = false;
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Store the list of parameters passed to the command
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
StringList *paramList = NULL;
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Map options names and indexes to option definitions.
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
typedef struct ConfigOptionValue
|
||||||
|
{
|
||||||
|
bool valid:1;
|
||||||
|
bool negate:1;
|
||||||
|
unsigned int source:2;
|
||||||
|
|
||||||
|
Variant *value;
|
||||||
|
} ConfigOptionValue;
|
||||||
|
|
||||||
|
ConfigOptionValue configOptionValue[CFG_OPTION_TOTAL];
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Initialize or reinitialize the configuration data
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
void
|
||||||
|
cfgInit()
|
||||||
|
{
|
||||||
|
// Reset configuration
|
||||||
|
command = cfgCmdNone;
|
||||||
|
exe = NULL;
|
||||||
|
help = false;
|
||||||
|
paramList = NULL;
|
||||||
|
memset(&configOptionValue, 0, sizeof(configOptionValue));
|
||||||
|
|
||||||
|
// Free the old context
|
||||||
|
if (configMemContext != NULL)
|
||||||
|
{
|
||||||
|
memContextFree(configMemContext);
|
||||||
|
configMemContext = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate configuration context as a child of the top context
|
||||||
|
MEM_CONTEXT_BEGIN(memContextTop())
|
||||||
|
{
|
||||||
|
MEM_CONTEXT_NEW_BEGIN("configuration")
|
||||||
|
{
|
||||||
|
configMemContext = MEM_CONTEXT_NEW();
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_NEW_END();
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_END();
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Get the current command
|
Get the current command
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
@ -87,6 +154,21 @@ cfgCommandCheck(ConfigCommand commandId)
|
|||||||
THROW(AssertError, "command id %d invalid - must be >= 0 and < %d", commandId, CFG_COMMAND_TOTAL);
|
THROW(AssertError, "command id %d invalid - must be >= 0 and < %d", commandId, CFG_COMMAND_TOTAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Was help requested?
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
bool
|
||||||
|
cfgCommandHelp()
|
||||||
|
{
|
||||||
|
return help;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cfgCommandHelpSet(bool helpParam)
|
||||||
|
{
|
||||||
|
help = helpParam;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Get the define id for this command
|
Get the define id for this command
|
||||||
|
|
||||||
@ -108,11 +190,11 @@ cfgCommandId(const char *commandName)
|
|||||||
{
|
{
|
||||||
ConfigCommand commandId;
|
ConfigCommand commandId;
|
||||||
|
|
||||||
for (commandId = 0; commandId < CFG_COMMAND_TOTAL; commandId++)
|
for (commandId = 0; commandId < cfgCmdNone; commandId++)
|
||||||
if (strcmp(commandName, configCommandData[commandId].name) == 0)
|
if (strcmp(commandName, configCommandData[commandId].name) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (commandId == CFG_COMMAND_TOTAL)
|
if (commandId == cfgCmdNone)
|
||||||
THROW(AssertError, "invalid command '%s'", commandName);
|
THROW(AssertError, "invalid command '%s'", commandName);
|
||||||
|
|
||||||
return commandId;
|
return commandId;
|
||||||
@ -128,6 +210,54 @@ cfgCommandName(ConfigCommand commandId)
|
|||||||
return configCommandData[commandId].name;
|
return configCommandData[commandId].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Command parameters, if any
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
const StringList *
|
||||||
|
cfgCommandParam()
|
||||||
|
{
|
||||||
|
if (paramList == NULL)
|
||||||
|
{
|
||||||
|
MEM_CONTEXT_BEGIN(configMemContext)
|
||||||
|
{
|
||||||
|
paramList = strLstNew();
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
return paramList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cfgCommandParamSet(const StringList *param)
|
||||||
|
{
|
||||||
|
MEM_CONTEXT_BEGIN(configMemContext)
|
||||||
|
{
|
||||||
|
paramList = strLstDup(param);
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_END();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Command parameters, if any
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
const String *
|
||||||
|
cfgExe()
|
||||||
|
{
|
||||||
|
return exe;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cfgExeSet(const String *exeParam)
|
||||||
|
{
|
||||||
|
MEM_CONTEXT_BEGIN(configMemContext)
|
||||||
|
{
|
||||||
|
exe = strDup(exeParam);
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_END();
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Ensure that option id is valid
|
Ensure that option id is valid
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
@ -211,3 +341,224 @@ cfgOptionName(ConfigOption optionId)
|
|||||||
cfgOptionCheck(optionId);
|
cfgOptionCheck(optionId);
|
||||||
return configOptionData[optionId].name;
|
return configOptionData[optionId].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Was the option negated?
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
bool
|
||||||
|
cfgOptionNegate(ConfigOption optionId)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
return configOptionValue[optionId].negate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cfgOptionNegateSet(ConfigOption optionId, bool negate)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
|
||||||
|
configOptionValue[optionId].negate = negate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Get and set config options
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
const Variant *
|
||||||
|
cfgOption(ConfigSource optionId)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
return configOptionValue[optionId].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
cfgOptionBool(ConfigSource optionId)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
|
||||||
|
if (varType(configOptionValue[optionId].value) != varTypeBool)
|
||||||
|
THROW(AssertError, "option '%s' is not type 'bool'", cfgOptionName(optionId));
|
||||||
|
|
||||||
|
return varBool(configOptionValue[optionId].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
cfgOptionDbl(ConfigSource optionId)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
|
||||||
|
if (varType(configOptionValue[optionId].value) != varTypeDouble)
|
||||||
|
THROW(AssertError, "option '%s' is not type 'double'", cfgOptionName(optionId));
|
||||||
|
|
||||||
|
return varDbl(configOptionValue[optionId].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cfgOptionInt(ConfigSource optionId)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
|
||||||
|
if (varType(configOptionValue[optionId].value) != varTypeInt)
|
||||||
|
THROW(AssertError, "option '%s' is not type 'int'", cfgOptionName(optionId));
|
||||||
|
|
||||||
|
return varInt(configOptionValue[optionId].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const KeyValue *
|
||||||
|
cfgOptionKv(ConfigSource optionId)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
|
||||||
|
if (varType(configOptionValue[optionId].value) != varTypeKeyValue)
|
||||||
|
THROW(AssertError, "option '%s' is not type 'KeyValue'", cfgOptionName(optionId));
|
||||||
|
|
||||||
|
return varKv(configOptionValue[optionId].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VariantList *
|
||||||
|
cfgOptionLst(ConfigSource optionId)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
|
||||||
|
if (configOptionValue[optionId].value == NULL)
|
||||||
|
{
|
||||||
|
MEM_CONTEXT_BEGIN(configMemContext)
|
||||||
|
{
|
||||||
|
configOptionValue[optionId].value = varNewVarLst(varLstNew());
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_END();
|
||||||
|
}
|
||||||
|
else if (varType(configOptionValue[optionId].value) != varTypeVariantList)
|
||||||
|
THROW(AssertError, "option '%s' is not type 'VariantList'", cfgOptionName(optionId));
|
||||||
|
|
||||||
|
return varVarLst(configOptionValue[optionId].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const String *
|
||||||
|
cfgOptionStr(ConfigSource optionId)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
|
||||||
|
const String *result = NULL;
|
||||||
|
|
||||||
|
if (configOptionValue[optionId].value != NULL)
|
||||||
|
{
|
||||||
|
if (varType(configOptionValue[optionId].value) != varTypeString)
|
||||||
|
THROW(AssertError, "option '%s' is not type 'String'", cfgOptionName(optionId));
|
||||||
|
|
||||||
|
result = varStr(configOptionValue[optionId].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cfgOptionSet(ConfigOption optionId, ConfigSource source, const Variant *value)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
|
||||||
|
MEM_CONTEXT_BEGIN(configMemContext)
|
||||||
|
{
|
||||||
|
// Set the source
|
||||||
|
configOptionValue[optionId].source = source;
|
||||||
|
|
||||||
|
// Store old value
|
||||||
|
Variant *valueOld = configOptionValue[optionId].value;
|
||||||
|
|
||||||
|
// Only set value if it is not null
|
||||||
|
if (value != NULL)
|
||||||
|
{
|
||||||
|
switch (cfgDefOptionType(cfgOptionDefIdFromId(optionId)))
|
||||||
|
{
|
||||||
|
case cfgDefOptTypeBoolean:
|
||||||
|
{
|
||||||
|
if (varType(value) == varTypeBool)
|
||||||
|
configOptionValue[optionId].value = varDup(value);
|
||||||
|
else
|
||||||
|
configOptionValue[optionId].value = varNewBool(varBoolForce(value));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case cfgDefOptTypeFloat:
|
||||||
|
{
|
||||||
|
if (varType(value) == varTypeDouble)
|
||||||
|
configOptionValue[optionId].value = varDup(value);
|
||||||
|
else
|
||||||
|
configOptionValue[optionId].value = varNewDbl(varDblForce(value));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case cfgDefOptTypeInteger:
|
||||||
|
{
|
||||||
|
if (varType(value) == varTypeInt)
|
||||||
|
configOptionValue[optionId].value = varDup(value);
|
||||||
|
else
|
||||||
|
configOptionValue[optionId].value = varNewInt(varIntForce(value));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case cfgDefOptTypeHash:
|
||||||
|
{
|
||||||
|
if (varType(value) == varTypeKeyValue)
|
||||||
|
configOptionValue[optionId].value = varDup(value);
|
||||||
|
else
|
||||||
|
THROW(AssertError, "option '%s' must be set with KeyValue variant", cfgOptionName(optionId));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case cfgDefOptTypeList:
|
||||||
|
{
|
||||||
|
if (varType(value) == varTypeVariantList)
|
||||||
|
configOptionValue[optionId].value = varDup(value);
|
||||||
|
else
|
||||||
|
THROW(AssertError, "option '%s' must be set with VariantList variant", cfgOptionName(optionId));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case cfgDefOptTypeString:
|
||||||
|
if (varType(value) == varTypeString)
|
||||||
|
configOptionValue[optionId].value = varDup(value);
|
||||||
|
else
|
||||||
|
THROW(AssertError, "option '%s' must be set with String variant", cfgOptionName(optionId));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free old value
|
||||||
|
if (valueOld != NULL)
|
||||||
|
varFree(valueOld);
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
How was the option set (default, param, config)?
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
ConfigSource
|
||||||
|
cfgOptionSource(ConfigSource optionId)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
return configOptionValue[optionId].source;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Is the option valid for this command?
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
bool
|
||||||
|
cfgOptionValid(ConfigOption optionId)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
return configOptionValue[optionId].valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cfgOptionValidSet(ConfigOption optionId, bool valid)
|
||||||
|
{
|
||||||
|
cfgOptionCheck(optionId);
|
||||||
|
configOptionValue[optionId].valid = valid;
|
||||||
|
}
|
||||||
|
@ -9,20 +9,54 @@ Command and Option Configuration
|
|||||||
|
|
||||||
#include "config/config.auto.h"
|
#include "config/config.auto.h"
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Option source enum - defines where an option value came from
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
cfgSourceDefault, // Default value
|
||||||
|
cfgSourceParam, // Passed as command-line parameter
|
||||||
|
cfgSourceConfig, // From configuration file
|
||||||
|
} ConfigSource;
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Functions
|
Functions
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
|
void cfgInit();
|
||||||
|
|
||||||
ConfigCommand cfgCommand();
|
ConfigCommand cfgCommand();
|
||||||
|
bool cfgCommandHelp();
|
||||||
int cfgCommandId(const char *commandName);
|
int cfgCommandId(const char *commandName);
|
||||||
const char *cfgCommandName(ConfigCommand commandId);
|
const char *cfgCommandName(ConfigCommand commandId);
|
||||||
ConfigDefineCommand cfgCommandDefIdFromId(ConfigCommand commandId);
|
ConfigDefineCommand cfgCommandDefIdFromId(ConfigCommand commandId);
|
||||||
|
const StringList *cfgCommandParam();
|
||||||
|
|
||||||
|
void cfgCommandHelpSet(bool helpParam);
|
||||||
|
void cfgCommandParamSet(const StringList *param);
|
||||||
void cfgCommandSet(ConfigCommand commandParam);
|
void cfgCommandSet(ConfigCommand commandParam);
|
||||||
|
|
||||||
|
const String *cfgExe();
|
||||||
|
void cfgExeSet(const String *exeParam);
|
||||||
|
|
||||||
|
const Variant *cfgOption(ConfigSource optionId);
|
||||||
|
bool cfgOptionBool(ConfigSource optionId);
|
||||||
|
ConfigDefineOption cfgOptionDefIdFromId(ConfigOption optionId);
|
||||||
|
double cfgOptionDbl(ConfigSource optionId);
|
||||||
int cfgOptionId(const char *optionName);
|
int cfgOptionId(const char *optionName);
|
||||||
ConfigOption cfgOptionIdFromDefId(ConfigDefineOption optionDefId, int index);
|
ConfigOption cfgOptionIdFromDefId(ConfigDefineOption optionDefId, int index);
|
||||||
int cfgOptionIndex(ConfigOption optionId);
|
int cfgOptionIndex(ConfigOption optionId);
|
||||||
int cfgOptionIndexTotal(ConfigOption optionDefId);
|
int cfgOptionIndexTotal(ConfigOption optionDefId);
|
||||||
|
int cfgOptionInt(ConfigSource optionId);
|
||||||
|
const KeyValue *cfgOptionKv(ConfigSource optionId);
|
||||||
|
const VariantList *cfgOptionLst(ConfigSource optionId);
|
||||||
const char *cfgOptionName(ConfigOption optionId);
|
const char *cfgOptionName(ConfigOption optionId);
|
||||||
ConfigDefineOption cfgOptionDefIdFromId(ConfigOption optionId);
|
bool cfgOptionNegate(ConfigOption optionId);
|
||||||
|
ConfigSource cfgOptionSource(ConfigSource optionId);
|
||||||
|
const String *cfgOptionStr(ConfigSource optionId);
|
||||||
|
bool cfgOptionValid(ConfigOption optionId);
|
||||||
|
|
||||||
|
void cfgOptionNegateSet(ConfigOption optionId, bool negate);
|
||||||
|
void cfgOptionSet(ConfigOption optionId, ConfigSource source, const Variant *value);
|
||||||
|
void cfgOptionValidSet(ConfigOption optionId, bool valid);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1495,6 +1495,36 @@ ConfigDefineOptionData configDefineOptionData[] = CFGDEFDATA_OPTION_LIST
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------------------
|
||||||
|
CFGDEFDATA_OPTION
|
||||||
|
(
|
||||||
|
CFGDEFDATA_OPTION_NAME("perl-option")
|
||||||
|
CFGDEFDATA_OPTION_REQUIRED(false)
|
||||||
|
CFGDEFDATA_OPTION_SECTION(cfgDefSectionGlobal)
|
||||||
|
CFGDEFDATA_OPTION_TYPE(cfgDefOptTypeList)
|
||||||
|
|
||||||
|
CFGDEFDATA_OPTION_INDEX_TOTAL(1)
|
||||||
|
CFGDEFDATA_OPTION_NEGATE(true)
|
||||||
|
CFGDEFDATA_OPTION_SECURE(false)
|
||||||
|
|
||||||
|
CFGDEFDATA_OPTION_COMMAND_LIST
|
||||||
|
(
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdArchiveGet)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdArchivePush)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdBackup)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdCheck)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdExpire)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdInfo)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdLocal)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdRemote)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdRestore)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdStanzaCreate)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdStanzaUpgrade)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdStart)
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdStop)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------------------
|
||||||
CFGDEFDATA_OPTION
|
CFGDEFDATA_OPTION
|
||||||
(
|
(
|
||||||
|
@ -91,6 +91,7 @@ typedef enum
|
|||||||
cfgDefOptNeutralUmask,
|
cfgDefOptNeutralUmask,
|
||||||
cfgDefOptOnline,
|
cfgDefOptOnline,
|
||||||
cfgDefOptOutput,
|
cfgDefOptOutput,
|
||||||
|
cfgDefOptPerlOption,
|
||||||
cfgDefOptProcess,
|
cfgDefOptProcess,
|
||||||
cfgDefOptProcessMax,
|
cfgDefOptProcessMax,
|
||||||
cfgDefOptProtocolTimeout,
|
cfgDefOptProtocolTimeout,
|
||||||
|
@ -17,6 +17,11 @@ typedef enum
|
|||||||
cfgDefSectionStanza, // command-line of in any config stanza section
|
cfgDefSectionStanza, // command-line of in any config stanza section
|
||||||
} ConfigDefSection;
|
} ConfigDefSection;
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Define global section name
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
#define CFGDEF_SECTION_GLOBAL "global"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Functions
|
Functions
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
|
@ -957,6 +957,15 @@ static const struct option optionList[] =
|
|||||||
.has_arg = required_argument,
|
.has_arg = required_argument,
|
||||||
.val = PARSE_OPTION_FLAG | cfgOptOutput,
|
.val = PARSE_OPTION_FLAG | cfgOptOutput,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "perl-option",
|
||||||
|
.has_arg = required_argument,
|
||||||
|
.val = PARSE_OPTION_FLAG | cfgOptPerlOption,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "no-perl-option",
|
||||||
|
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptPerlOption,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "process",
|
.name = "process",
|
||||||
.has_arg = required_argument,
|
.has_arg = required_argument,
|
||||||
@ -1240,12 +1249,6 @@ static const struct option optionList[] =
|
|||||||
.has_arg = required_argument,
|
.has_arg = required_argument,
|
||||||
.val = PARSE_OPTION_FLAG | cfgOptType,
|
.val = PARSE_OPTION_FLAG | cfgOptType,
|
||||||
},
|
},
|
||||||
// Perl option is ignored by normal config parsing
|
|
||||||
{
|
|
||||||
.name = "perl-option",
|
|
||||||
.has_arg = required_argument,
|
|
||||||
.val = 0,
|
|
||||||
},
|
|
||||||
// Terminate option list
|
// Terminate option list
|
||||||
{
|
{
|
||||||
.name = NULL
|
.name = NULL
|
||||||
|
@ -4,13 +4,16 @@ Command and Option Parse
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
#include "common/error.h"
|
#include "common/error.h"
|
||||||
|
#include "common/ini.h"
|
||||||
#include "common/memContext.h"
|
#include "common/memContext.h"
|
||||||
#include "config/parse.h"
|
#include "config/parse.h"
|
||||||
|
#include "storage/storage.h"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Include the automatically generated configuration data
|
Parse option flags
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
// Offset the option values so they don't conflict with getopt_long return codes
|
// Offset the option values so they don't conflict with getopt_long return codes
|
||||||
#define PARSE_OPTION_FLAG (1 << 31)
|
#define PARSE_OPTION_FLAG (1 << 31)
|
||||||
@ -21,19 +24,44 @@ Include the automatically generated configuration data
|
|||||||
// Mask to exclude all flags and get at the actual option id (only 12 bits allowed for option id, the rest reserved for flags)
|
// Mask to exclude all flags and get at the actual option id (only 12 bits allowed for option id, the rest reserved for flags)
|
||||||
#define PARSE_OPTION_MASK 0xFFF
|
#define PARSE_OPTION_MASK 0xFFF
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Include automatically generated data structure for getopt_long()
|
||||||
|
***********************************************************************************************************************************/
|
||||||
#include "parse.auto.c"
|
#include "parse.auto.c"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Parse the command-line arguments and produce preliminary parse data
|
Struct to hold options parsed from the command line
|
||||||
|
|
||||||
This function only checks for obvious errors. Dependencies, types, etc, are checked later when data from the config file is
|
|
||||||
available.
|
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
ParseData *
|
typedef struct ParseOption
|
||||||
configParseArg(int argListSize, const char *argList[])
|
|
||||||
{
|
{
|
||||||
// Allocate memory for the parse data
|
bool found:1; // Was the option found on the command line?
|
||||||
ParseData *parseData = memNew(sizeof(ParseData));
|
bool negate:1; // Was the option negated on the command line?
|
||||||
|
unsigned int source:2; // Where was to option found?
|
||||||
|
StringList *valueList; // List of values found
|
||||||
|
} ParseOption;
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Parse the command-line arguments and config file to produce final config data
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
void
|
||||||
|
configParse(int argListSize, const char *argList[])
|
||||||
|
{
|
||||||
|
// Initialize configuration
|
||||||
|
cfgInit();
|
||||||
|
|
||||||
|
MEM_CONTEXT_TEMP_BEGIN()
|
||||||
|
{
|
||||||
|
// Set the exe
|
||||||
|
cfgExeSet(strNew(argList[0]));
|
||||||
|
|
||||||
|
// Phase 1: parse command line parameters
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
int option; // Code returned by getopt_long
|
||||||
|
int optionListIdx; // Index of option is list (if an option was returned)
|
||||||
|
ConfigOption optionId; // Option id extracted from option var
|
||||||
|
bool negate; // Option is being negated
|
||||||
|
bool argFound = false; // Track args found to decide on error or help at the end
|
||||||
|
StringList *commandParamList = NULL; // List of command parameters
|
||||||
|
|
||||||
// Reset optind to 1 in case getopt_long has been called before
|
// Reset optind to 1 in case getopt_long has been called before
|
||||||
optind = 1;
|
optind = 1;
|
||||||
@ -41,57 +69,52 @@ configParseArg(int argListSize, const char *argList[])
|
|||||||
// Don't error automatically on unknown options - they will be processed in the loop below
|
// Don't error automatically on unknown options - they will be processed in the loop below
|
||||||
opterr = false;
|
opterr = false;
|
||||||
|
|
||||||
|
// List of parsed options
|
||||||
|
ParseOption parseOptionList[CFG_OPTION_TOTAL];
|
||||||
|
memset(&parseOptionList, 0, sizeof(parseOptionList));
|
||||||
|
|
||||||
// Only the first non-option parameter should be treated as a command so track if the command has been set
|
// Only the first non-option parameter should be treated as a command so track if the command has been set
|
||||||
bool commandSet = false;
|
bool commandSet = false;
|
||||||
|
|
||||||
// Parse options
|
|
||||||
int option; // Code returned by getopt_long
|
|
||||||
int optionListIdx; // Index of option is list (if an option was returned)
|
|
||||||
ConfigOption optionId; // Option id extracted from option var
|
|
||||||
bool negate; // Option is being negated
|
|
||||||
bool argFound = false; // Track args found to decide on error or help at the end
|
|
||||||
|
|
||||||
while ((option = getopt_long(argListSize, (char **)argList, "-:", optionList, &optionListIdx)) != -1)
|
while ((option = getopt_long(argListSize, (char **)argList, "-:", optionList, &optionListIdx)) != -1)
|
||||||
{
|
{
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
// Add perl options (if any) to the list
|
|
||||||
case 0:
|
|
||||||
if (parseData->perlOptionList == NULL)
|
|
||||||
parseData->perlOptionList = strLstNew();
|
|
||||||
|
|
||||||
strLstAdd(parseData->perlOptionList, strNew(optarg));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Parse arguments that are not options, i.e. commands and parameters passed to commands
|
// Parse arguments that are not options, i.e. commands and parameters passed to commands
|
||||||
case 1:
|
case 1:
|
||||||
|
{
|
||||||
// The first argument should be the command
|
// The first argument should be the command
|
||||||
if (!commandSet)
|
if (!commandSet)
|
||||||
{
|
{
|
||||||
// Try getting the command from the valid command list
|
// Try getting the command from the valid command list
|
||||||
TRY_BEGIN()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
parseData->command = cfgCommandId(argList[optind - 1]);
|
cfgCommandSet(cfgCommandId(argList[optind - 1]));
|
||||||
}
|
}
|
||||||
// Assert error means the command does not exist, which is correct for all usages but this one (since we don't
|
// Assert error means the command does not exist, which is correct for all usages but this one (since we
|
||||||
// have any control over what the user passes), so modify the error code and message.
|
// don't have any control over what the user passes), so modify the error code and message.
|
||||||
CATCH(AssertError)
|
CATCH(AssertError)
|
||||||
{
|
{
|
||||||
THROW(CommandInvalidError, "invalid command '%s'", argList[optind - 1]);
|
THROW(CommandInvalidError, "invalid command '%s'", argList[optind - 1]);
|
||||||
}
|
}
|
||||||
TRY_END();
|
TRY_END();
|
||||||
|
|
||||||
|
if (cfgCommand() == cfgCmdHelp)
|
||||||
|
cfgCommandHelpSet(true);
|
||||||
|
else
|
||||||
|
commandSet = true;
|
||||||
}
|
}
|
||||||
// Additioal arguments are command arguments
|
// Additional arguments are command arguments
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (parseData->commandArgList == NULL)
|
if (commandParamList == NULL)
|
||||||
parseData->commandArgList = strLstNew();
|
commandParamList = strLstNew();
|
||||||
|
|
||||||
strLstAdd(parseData->commandArgList, strNew(argList[optind - 1]));
|
strLstAdd(commandParamList, strNew(argList[optind - 1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
commandSet = true;
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// If the option is unknown then error
|
// If the option is unknown then error
|
||||||
case '?':
|
case '?':
|
||||||
@ -113,27 +136,28 @@ configParseArg(int argListSize, const char *argList[])
|
|||||||
assert(optionId < CFG_OPTION_TOTAL);
|
assert(optionId < CFG_OPTION_TOTAL);
|
||||||
|
|
||||||
// If the the option has not been found yet then set it
|
// If the the option has not been found yet then set it
|
||||||
if (!parseData->parseOptionList[optionId].found)
|
if (!parseOptionList[optionId].found)
|
||||||
{
|
{
|
||||||
parseData->parseOptionList[optionId].found = true;
|
parseOptionList[optionId].found = true;
|
||||||
parseData->parseOptionList[optionId].negate = negate;
|
parseOptionList[optionId].negate = negate;
|
||||||
|
parseOptionList[optionId].source = cfgSourceParam;
|
||||||
|
|
||||||
// Only set the argument if the option requires one
|
// Only set the argument if the option requires one
|
||||||
if (optionList[optionListIdx].has_arg == required_argument)
|
if (optionList[optionListIdx].has_arg == required_argument)
|
||||||
parseData->parseOptionList[optionId].valueList = strLstAdd(strLstNew(), strNew(optarg));
|
parseOptionList[optionId].valueList = strLstAdd(strLstNew(), strNew(optarg));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Make sure option is not negated more than once. It probably wouldn't hurt anything to accept this case but
|
// Make sure option is not negated more than once. It probably wouldn't hurt anything to accept this case
|
||||||
// there's no point in allowing the user to be sloppy.
|
// but there's no point in allowing the user to be sloppy.
|
||||||
if (parseData->parseOptionList[optionId].negate && negate)
|
if (parseOptionList[optionId].negate && negate)
|
||||||
THROW(OptionInvalidError, "option '%s' is negated multiple times", cfgOptionName(optionId));
|
THROW(OptionInvalidError, "option '%s' is negated multiple times", cfgOptionName(optionId));
|
||||||
|
|
||||||
// Don't allow an option to be both set and negated
|
// Don't allow an option to be both set and negated
|
||||||
if (parseData->parseOptionList[optionId].negate != negate)
|
if (parseOptionList[optionId].negate != negate)
|
||||||
THROW(OptionInvalidError, "option '%s' cannot be set and negated", cfgOptionName(optionId));
|
THROW(OptionInvalidError, "option '%s' cannot be set and negated", cfgOptionName(optionId));
|
||||||
|
|
||||||
// Error if this option does not allow multiple arguments (!!! IMPLEMENT THIS IN DEFINE.C)
|
// Error if this option does not allow multiple arguments
|
||||||
if (!(cfgDefOptionType(cfgOptionDefIdFromId(optionId)) == cfgDefOptTypeHash ||
|
if (!(cfgDefOptionType(cfgOptionDefIdFromId(optionId)) == cfgDefOptTypeHash ||
|
||||||
cfgDefOptionType(cfgOptionDefIdFromId(optionId)) == cfgDefOptTypeList))
|
cfgDefOptionType(cfgOptionDefIdFromId(optionId)) == cfgDefOptTypeList))
|
||||||
{
|
{
|
||||||
@ -141,7 +165,7 @@ configParseArg(int argListSize, const char *argList[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the argument
|
// Add the argument
|
||||||
strLstAdd(parseData->parseOptionList[optionId].valueList, strNew(optarg));
|
strLstAdd(parseOptionList[optionId].valueList, strNew(optarg));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -152,32 +176,430 @@ configParseArg(int argListSize, const char *argList[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle command not found
|
// Handle command not found
|
||||||
if (!commandSet)
|
if (!commandSet && !cfgCommandHelp())
|
||||||
{
|
{
|
||||||
// If there are args then error
|
// If there are args then error
|
||||||
if (argFound)
|
if (argFound)
|
||||||
THROW(CommandRequiredError, "no command found");
|
THROW(CommandRequiredError, "no command found");
|
||||||
|
|
||||||
// Otherwise set the comand to help
|
// Otherwise set the comand to help
|
||||||
parseData->command = cfgCmdHelp;
|
cfgCommandHelpSet(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the parse data
|
// Set command params
|
||||||
return parseData;
|
if (commandParamList != NULL)
|
||||||
}
|
cfgCommandParamSet(commandParamList);
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
// Parse options from config file unless --no-config passed
|
||||||
Parse the command-line arguments and config file to produce final config data
|
if (cfgCommand() != cfgCmdNone &&
|
||||||
***********************************************************************************************************************************/
|
cfgCommand() != cfgCmdVersion &&
|
||||||
void
|
cfgCommand() != cfgCmdHelp)
|
||||||
configParse(int argListSize, const char *argList[])
|
{
|
||||||
{
|
// Get the command definition id
|
||||||
// Parse the command line
|
ConfigDefineCommand commandDefId = cfgCommandDefIdFromId(cfgCommand());
|
||||||
ParseData *parseData = configParseArg(argListSize, argList);
|
|
||||||
|
// Phase 2: parse config file
|
||||||
// Set the command
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
cfgCommandSet(parseData->command);
|
if (!parseOptionList[cfgOptConfig].negate)
|
||||||
|
{
|
||||||
// Free the parse data
|
// Get the config file name from the command-line if it exists else default
|
||||||
memFree(parseData);
|
const String *configFile = NULL;
|
||||||
|
|
||||||
|
if (parseOptionList[cfgOptConfig].found)
|
||||||
|
configFile = strLstGet(parseOptionList[cfgOptConfig].valueList, 0);
|
||||||
|
else
|
||||||
|
configFile = strNew(cfgDefOptionDefault(commandDefId, cfgOptionDefIdFromId(cfgOptConfig)));
|
||||||
|
|
||||||
|
// Load the ini file
|
||||||
|
Buffer *buffer = storageGet(storageLocal(), configFile, !parseOptionList[cfgOptConfig].found);
|
||||||
|
|
||||||
|
// Load the config file if it was found
|
||||||
|
if (buffer != NULL)
|
||||||
|
{
|
||||||
|
// Parse the ini file
|
||||||
|
Ini *config = iniNew();
|
||||||
|
iniParse(config, strNewBuf(buffer));
|
||||||
|
|
||||||
|
// Get the stanza name
|
||||||
|
String *stanza = NULL;
|
||||||
|
|
||||||
|
if (parseOptionList[cfgOptStanza].found)
|
||||||
|
stanza = strLstGet(parseOptionList[cfgOptStanza].valueList, 0);
|
||||||
|
|
||||||
|
// Build list of sections to search for options
|
||||||
|
StringList *sectionList = strLstNew();
|
||||||
|
|
||||||
|
if (stanza != NULL)
|
||||||
|
{
|
||||||
|
strLstAdd(sectionList, strNewFmt("%s:%s", strPtr(stanza), cfgCommandName(cfgCommand())));
|
||||||
|
strLstAdd(sectionList, stanza);
|
||||||
|
}
|
||||||
|
|
||||||
|
strLstAdd(sectionList, strNewFmt(CFGDEF_SECTION_GLOBAL ":%s", cfgCommandName(cfgCommand())));
|
||||||
|
strLstAdd(sectionList, strNew(CFGDEF_SECTION_GLOBAL));
|
||||||
|
|
||||||
|
// Loop through sections to search for options
|
||||||
|
for (unsigned int sectionIdx = 0; sectionIdx < strLstSize(sectionList); sectionIdx++)
|
||||||
|
{
|
||||||
|
String *section = strLstGet(sectionList, sectionIdx);
|
||||||
|
StringList *keyList = iniSectionKeyList(config, section);
|
||||||
|
|
||||||
|
// Loop through keys to search for options
|
||||||
|
for (unsigned int keyIdx = 0; keyIdx < strLstSize(keyList); keyIdx++)
|
||||||
|
{
|
||||||
|
String *key = strLstGet(keyList, keyIdx);
|
||||||
|
|
||||||
|
// Find the optionName in the main list
|
||||||
|
unsigned int optionIdx = 0;
|
||||||
|
|
||||||
|
while (optionList[optionIdx].name != NULL)
|
||||||
|
{
|
||||||
|
if (strcmp(strPtr(key), optionList[optionIdx].name) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
optionIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn if the option not found
|
||||||
|
if (optionList[optionIdx].name == NULL)
|
||||||
|
{
|
||||||
|
/// ??? Put warning here once there is a logging system
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Warn if negate option found in config
|
||||||
|
else if (optionList[optionIdx].val & PARSE_NEGATE_FLAG)
|
||||||
|
{
|
||||||
|
/// ??? Put warning here once there is a logging system
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
optionId = optionList[optionIdx].val & PARSE_OPTION_MASK;
|
||||||
|
ConfigDefineOption optionDefId = cfgOptionDefIdFromId(optionId);
|
||||||
|
|
||||||
|
/// Warn if this option should be command-line only
|
||||||
|
if (cfgDefOptionSection(optionDefId) == cfgDefSectionCommandLine)
|
||||||
|
{
|
||||||
|
/// ??? Put warning here once there is a logging system
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue if this option has already been found
|
||||||
|
if (parseOptionList[optionId].found)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Continue if the option is not valid for this command
|
||||||
|
if (!cfgDefOptionValid(commandDefId, optionDefId))
|
||||||
|
{
|
||||||
|
// Warn if it is in a command section
|
||||||
|
if (sectionIdx % 2 == 0)
|
||||||
|
{
|
||||||
|
// ??? Put warning here once there is a logging system (and remove continue and braces)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only get the option if it is valid for this section
|
||||||
|
if ((stanza != NULL && sectionIdx < 2) || cfgDefOptionSection(optionDefId) == cfgDefSectionGlobal)
|
||||||
|
{
|
||||||
|
const Variant *value = iniGetDefault(config, section, key, NULL);
|
||||||
|
|
||||||
|
if (varType(value) == varTypeString && strSize(varStr(value)) == 0)
|
||||||
|
THROW(OptionInvalidValueError, "section '%s', key '%s' must have a value", strPtr(section),
|
||||||
|
strPtr(key));
|
||||||
|
|
||||||
|
parseOptionList[optionId].found = true;
|
||||||
|
parseOptionList[optionId].source = cfgSourceConfig;
|
||||||
|
|
||||||
|
// Convert boolean to string
|
||||||
|
if (cfgDefOptionType(optionDefId) == cfgDefOptTypeBoolean)
|
||||||
|
{
|
||||||
|
if (strcasecmp(strPtr(varStr(value)), "n") == 0)
|
||||||
|
parseOptionList[optionId].negate = true;
|
||||||
|
else if (strcasecmp(strPtr(varStr(value)), "y") != 0)
|
||||||
|
THROW(OptionInvalidError, "boolean option '%s' must be 'y' or 'n'", strPtr(key));
|
||||||
|
}
|
||||||
|
// Else add the string value
|
||||||
|
else if (varType(value) == varTypeString)
|
||||||
|
{
|
||||||
|
parseOptionList[optionId].valueList = strLstNew();
|
||||||
|
strLstAdd(parseOptionList[optionId].valueList, varStr(value));
|
||||||
|
}
|
||||||
|
// Else add the string list
|
||||||
|
else
|
||||||
|
parseOptionList[optionId].valueList = strLstNewVarLst(varVarLst(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 3: validate option definitions and load into configuration
|
||||||
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool allResolved;
|
||||||
|
bool optionResolved[CFG_OPTION_TOTAL] = {false};
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Assume that all dependencies will be resolved in this loop. This probably won't be true the first few times, but
|
||||||
|
// eventually it will be or the do loop would never exit.
|
||||||
|
allResolved = true;
|
||||||
|
|
||||||
|
// Loop through all options
|
||||||
|
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
||||||
|
{
|
||||||
|
// Get the option data parsed from the command-line
|
||||||
|
ParseOption *parseOption = &parseOptionList[optionId];
|
||||||
|
|
||||||
|
// Get the option definition id -- will be used to look up option rules
|
||||||
|
ConfigDefineOption optionDefId = cfgOptionDefIdFromId(optionId);
|
||||||
|
ConfigDefineOptionType optionDefType = cfgDefOptionType(optionDefId);
|
||||||
|
|
||||||
|
// Skip this option if it has already been resolved
|
||||||
|
if (optionResolved[optionId])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Error if the option is not valid for this command
|
||||||
|
if (parseOption->found && !cfgDefOptionValid(commandDefId, optionDefId))
|
||||||
|
{
|
||||||
|
THROW(
|
||||||
|
OptionInvalidError, "option '%s' not valid for command '%s'", cfgOptionName(optionId),
|
||||||
|
cfgCommandName(cfgCommand()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the option valid for this command? If not, mark it as resolved since there is nothing more to do.
|
||||||
|
cfgOptionValidSet(optionId, cfgDefOptionValid(commandDefId, optionDefId));
|
||||||
|
|
||||||
|
if (!cfgOptionValid(optionId))
|
||||||
|
{
|
||||||
|
optionResolved[optionId] = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the value set for this option?
|
||||||
|
bool optionSet = parseOption->found && (optionDefType == cfgDefOptTypeBoolean || !parseOption->negate);
|
||||||
|
|
||||||
|
// Set negate flag
|
||||||
|
cfgOptionNegateSet(optionId, parseOption->negate);
|
||||||
|
|
||||||
|
// Check option dependencies
|
||||||
|
bool dependResolved = true;
|
||||||
|
|
||||||
|
if (cfgDefOptionDepend(commandDefId, optionDefId))
|
||||||
|
{
|
||||||
|
ConfigOption dependOptionId =
|
||||||
|
cfgOptionIdFromDefId(cfgDefOptionDependOption(commandDefId, optionDefId), cfgOptionIndex(optionId));
|
||||||
|
ConfigDefineOption dependOptionDefId = cfgOptionDefIdFromId(dependOptionId);
|
||||||
|
ConfigDefineOptionType dependOptionDefType = cfgDefOptionType(dependOptionDefId);
|
||||||
|
|
||||||
|
// Make sure the depend option has been resolved, otherwise skip this option for now
|
||||||
|
if (!optionResolved[dependOptionId])
|
||||||
|
{
|
||||||
|
allResolved = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the depend option value
|
||||||
|
const Variant *dependValue = cfgOption(dependOptionId);
|
||||||
|
|
||||||
|
if (dependValue != NULL)
|
||||||
|
{
|
||||||
|
if (dependOptionDefType == cfgDefOptTypeBoolean)
|
||||||
|
{
|
||||||
|
if (cfgOptionBool(dependOptionId))
|
||||||
|
dependValue = varNewStrZ("1");
|
||||||
|
else
|
||||||
|
dependValue = varNewStrZ("0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't resolve if the depend option value is null
|
||||||
|
if (dependValue == NULL)
|
||||||
|
{
|
||||||
|
dependResolved = false;
|
||||||
|
|
||||||
|
// if (optionSet)
|
||||||
|
if (optionSet && parseOption->source == cfgSourceParam)
|
||||||
|
{
|
||||||
|
THROW(
|
||||||
|
OptionInvalidError, "option '%s' not valid without option '%s'", cfgOptionName(optionId),
|
||||||
|
cfgOptionName(dependOptionId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If a depend list exists, make sure the value is in the list
|
||||||
|
else if (cfgDefOptionDependValueTotal(commandDefId, optionDefId) > 0)
|
||||||
|
{
|
||||||
|
dependResolved = cfgDefOptionDependValueValid(commandDefId, optionDefId, strPtr(varStr(dependValue)));
|
||||||
|
|
||||||
|
// If not depend not resolved and option value is set then error
|
||||||
|
if (!dependResolved && optionSet && parseOption->source == cfgSourceParam)
|
||||||
|
{
|
||||||
|
// Get the depend option name
|
||||||
|
String *dependOptionName = strNew(cfgOptionName(dependOptionId));
|
||||||
|
|
||||||
|
// Build the list of possible depend values
|
||||||
|
StringList *dependValueList = strLstNew();
|
||||||
|
|
||||||
|
for (int listIdx = 0; listIdx < cfgDefOptionDependValueTotal(commandDefId, optionDefId); listIdx++)
|
||||||
|
{
|
||||||
|
const char *dependValue = cfgDefOptionDependValue(commandDefId, optionDefId, listIdx);
|
||||||
|
|
||||||
|
// Build list based on depend option type
|
||||||
|
switch (dependOptionDefType)
|
||||||
|
{
|
||||||
|
// Boolean outputs depend option name as no-* when false
|
||||||
|
case cfgDefOptTypeBoolean:
|
||||||
|
{
|
||||||
|
if (strcmp(dependValue, "0") == 0)
|
||||||
|
dependOptionName = strNewFmt("no-%s", cfgOptionName(dependOptionId));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is output with quotes
|
||||||
|
case cfgDefOptTypeString:
|
||||||
|
{
|
||||||
|
strLstAdd(dependValueList, strNewFmt("'%s'", dependValue));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other types are output plain
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
strLstAddZ(dependValueList, dependValue); // {uncovered - no depends of other types}
|
||||||
|
break; // {+uncovered}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the error string
|
||||||
|
String *error = strNew("option '%s' not valid without option '%s'");
|
||||||
|
|
||||||
|
if (strLstSize(dependValueList) == 1)
|
||||||
|
strCat(error, " = %s");
|
||||||
|
else if (strLstSize(dependValueList) > 1)
|
||||||
|
strCat(error, " in (%s)");
|
||||||
|
|
||||||
|
// Throw the error
|
||||||
|
THROW(
|
||||||
|
OptionInvalidError, strPtr(error), cfgOptionName(optionId), strPtr(dependOptionName),
|
||||||
|
strPtr(strLstJoin(dependValueList, ", ")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the option defined?
|
||||||
|
if (optionSet && dependResolved)
|
||||||
|
{
|
||||||
|
if (optionDefType == cfgDefOptTypeBoolean)
|
||||||
|
{
|
||||||
|
cfgOptionSet(optionId, parseOption->source, varNewBool(!parseOption->negate));
|
||||||
|
}
|
||||||
|
else if (optionDefType == cfgDefOptTypeHash)
|
||||||
|
{
|
||||||
|
Variant *value = varNewKv();
|
||||||
|
KeyValue *keyValue = varKv(value);
|
||||||
|
|
||||||
|
for (unsigned int listIdx = 0; listIdx < strLstSize(parseOption->valueList); listIdx++)
|
||||||
|
{
|
||||||
|
const char *pair = strPtr(strLstGet(parseOption->valueList, listIdx));
|
||||||
|
const char *equal = strchr(pair, '=');
|
||||||
|
|
||||||
|
if (equal == NULL)
|
||||||
|
{
|
||||||
|
THROW(
|
||||||
|
OptionInvalidError, "key/value '%s' not valid for '%s' option",
|
||||||
|
strPtr(strLstGet(parseOption->valueList, listIdx)), cfgOptionName(optionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
kvPut(keyValue, varNewStr(strNewSzN(pair, equal - pair)), varNewStr(strNew(equal + 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgOptionSet(optionId, parseOption->source, value);
|
||||||
|
}
|
||||||
|
else if (optionDefType == cfgDefOptTypeList)
|
||||||
|
{
|
||||||
|
cfgOptionSet(optionId, parseOption->source, varNewVarLst(varLstNewStrLst(parseOption->valueList)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String *value = strLstGet(parseOption->valueList, 0);
|
||||||
|
|
||||||
|
// If the option has an allow list then check it
|
||||||
|
if (cfgDefOptionAllowList(commandDefId, optionDefId) &&
|
||||||
|
!cfgDefOptionAllowListValueValid(commandDefId, optionDefId, strPtr(value)))
|
||||||
|
{
|
||||||
|
THROW(
|
||||||
|
OptionInvalidValueError, "'%s' is not valid for '%s' option", strPtr(value),
|
||||||
|
cfgOptionName(optionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a numeric type check that the value is valid
|
||||||
|
if (optionDefType == cfgDefOptTypeInteger || optionDefType == cfgDefOptTypeFloat)
|
||||||
|
{
|
||||||
|
double valueDbl = 0;
|
||||||
|
|
||||||
|
// Check that the value can be converted
|
||||||
|
TRY_BEGIN()
|
||||||
|
{
|
||||||
|
if (optionDefType == cfgDefOptTypeInteger)
|
||||||
|
valueDbl = varIntForce(varNewStr(value));
|
||||||
|
else
|
||||||
|
valueDbl = varDblForce(varNewStr(value));
|
||||||
|
}
|
||||||
|
CATCH_ANY()
|
||||||
|
{
|
||||||
|
THROW(
|
||||||
|
OptionInvalidValueError, "'%s' is not valid for '%s' option", strPtr(value),
|
||||||
|
cfgOptionName(optionId));
|
||||||
|
}
|
||||||
|
TRY_END();
|
||||||
|
|
||||||
|
// Check value range
|
||||||
|
if (cfgDefOptionAllowRange(commandDefId, optionDefId) &&
|
||||||
|
(valueDbl < cfgDefOptionAllowRangeMin(commandDefId, optionDefId) ||
|
||||||
|
valueDbl > cfgDefOptionAllowRangeMax(commandDefId, optionDefId)))
|
||||||
|
{
|
||||||
|
THROW(
|
||||||
|
OptionInvalidValueError, "'%s' is not valid for '%s' option", strPtr(value),
|
||||||
|
cfgOptionName(optionId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgOptionSet(optionId, parseOption->source, varNewStr(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dependResolved && parseOption->negate)
|
||||||
|
cfgOptionSet(optionId, parseOption->source, NULL);
|
||||||
|
// Else try to set a default
|
||||||
|
else if (dependResolved)
|
||||||
|
{
|
||||||
|
// Get the default value for this option
|
||||||
|
const char *value = cfgDefOptionDefault(commandDefId, optionDefId);
|
||||||
|
|
||||||
|
if (value != NULL)
|
||||||
|
cfgOptionSet(optionId, cfgSourceDefault, varNewStrZ(value));
|
||||||
|
else if (cfgOptionIndex(optionId) == 0 && cfgDefOptionRequired(commandDefId, optionDefId) &&
|
||||||
|
!cfgCommandHelp())
|
||||||
|
{
|
||||||
|
const char *hint = "";
|
||||||
|
|
||||||
|
if (cfgDefOptionSection(optionDefId) == cfgDefSectionStanza)
|
||||||
|
hint = "\nHINT: does this stanza exist?";
|
||||||
|
|
||||||
|
THROW(
|
||||||
|
OptionRequiredError, "%s command requires option: %s%s", cfgCommandName(cfgCommand()),
|
||||||
|
cfgOptionName(optionId), hint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option is now resolved
|
||||||
|
optionResolved[optionId] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!allResolved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_TEMP_END();
|
||||||
}
|
}
|
||||||
|
@ -6,29 +6,6 @@ Parse Configuration
|
|||||||
|
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
|
||||||
Struct to hold options parsed from the command line (??? move back to parse.c once perl exec works on full config data)
|
|
||||||
***********************************************************************************************************************************/
|
|
||||||
typedef struct ParseOption
|
|
||||||
{
|
|
||||||
bool found:1; // Was the option found on the command line?
|
|
||||||
bool negate:1; // Was the option negated on the command line?
|
|
||||||
StringList *valueList; // List of values found
|
|
||||||
} ParseOption;
|
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
|
||||||
Struct to hold all parsed data (??? move back to parse.c once perl exec works on full config data)
|
|
||||||
***********************************************************************************************************************************/
|
|
||||||
typedef struct ParseData
|
|
||||||
{
|
|
||||||
ConfigCommand command; // Command found
|
|
||||||
StringList *perlOptionList; // List of perl options
|
|
||||||
StringList *commandArgList; // List of command arguments
|
|
||||||
ParseOption parseOptionList[CFG_OPTION_TOTAL]; // List of parsed options
|
|
||||||
} ParseData;
|
|
||||||
|
|
||||||
ParseData *configParseArg(int argListSize, const char *argList[]);
|
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Functions
|
Functions
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
|
@ -18,7 +18,7 @@ int main(int argListSize, const char *argList[])
|
|||||||
configParse(argListSize, argList);
|
configParse(argListSize, argList);
|
||||||
|
|
||||||
// Display version
|
// Display version
|
||||||
if (cfgCommand() == cfgCmdVersion)
|
if (!cfgCommandHelp() && cfgCommand() == cfgCmdVersion)
|
||||||
{
|
{
|
||||||
printf(PGBACKREST_NAME " " PGBACKREST_VERSION "\n");
|
printf(PGBACKREST_NAME " " PGBACKREST_VERSION "\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@ -26,11 +26,11 @@ int main(int argListSize, const char *argList[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute Perl for commands not implemented in C
|
// Execute Perl for commands not implemented in C
|
||||||
perlExec(perlCommand(argListSize, argList));
|
perlExec(perlCommand());
|
||||||
}
|
}
|
||||||
CATCH_ANY()
|
CATCH_ANY()
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR: [%03d]: %s\n", errorCode(), errorMessage());
|
fprintf(stderr, "ERROR [%03d]: %s\n", errorCode(), errorMessage());
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
exit(errorCode());
|
exit(errorCode());
|
||||||
}
|
}
|
||||||
|
105
src/perl/exec.c
105
src/perl/exec.c
@ -11,7 +11,7 @@ Execute Perl for Legacy Functionality
|
|||||||
#include "common/error.h"
|
#include "common/error.h"
|
||||||
#include "common/memContext.h"
|
#include "common/memContext.h"
|
||||||
#include "common/type.h"
|
#include "common/type.h"
|
||||||
#include "config/parse.h"
|
#include "config/config.h"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Constants used to build perl options
|
Constants used to build perl options
|
||||||
@ -27,10 +27,8 @@ Constants used to build perl options
|
|||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Build list of perl options to use for exec
|
Build list of perl options to use for exec
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
StringList *perlCommand(int argListSize, const char *argList[])
|
StringList *perlCommand()
|
||||||
{
|
{
|
||||||
ParseData *parseData = configParseArg(argListSize, argList);
|
|
||||||
|
|
||||||
// Begin arg list for perl exec
|
// Begin arg list for perl exec
|
||||||
StringList *perlArgList = strLstNew();
|
StringList *perlArgList = strLstNew();
|
||||||
strLstAdd(perlArgList, strNew(ENV_EXE));
|
strLstAdd(perlArgList, strNew(ENV_EXE));
|
||||||
@ -41,52 +39,107 @@ StringList *perlCommand(int argListSize, const char *argList[])
|
|||||||
|
|
||||||
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
||||||
{
|
{
|
||||||
ParseOption *option = &parseData->parseOptionList[optionId];
|
// Skip the option if it is not valid or not a command line option
|
||||||
|
if (!cfgOptionValid(optionId) || cfgOptionSource(optionId) != cfgSourceParam)
|
||||||
|
continue;
|
||||||
|
|
||||||
// If option was found
|
|
||||||
if (option->found)
|
|
||||||
{
|
|
||||||
// If option was negated
|
// If option was negated
|
||||||
if (option->negate)
|
if (cfgOptionNegate(optionId))
|
||||||
strCatFmt(mainCallParam, ", '--no-%s\'", cfgOptionName(optionId));
|
strCatFmt(mainCallParam, ", '--no-%s'", cfgOptionName(optionId));
|
||||||
// Else option with no arguments
|
// Else not negated
|
||||||
else if (option->valueList == NULL)
|
|
||||||
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
|
|
||||||
// Else options with arguments
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (unsigned int argIdx = 0; argIdx < strLstSize(option->valueList); argIdx++)
|
switch (cfgDefOptionType(cfgOptionDefIdFromId(optionId)))
|
||||||
|
{
|
||||||
|
case cfgDefOptTypeBoolean:
|
||||||
{
|
{
|
||||||
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
|
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
|
||||||
strCatFmt(mainCallParam, ", '%s'", strPtr(strLstGet(option->valueList, argIdx)));
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case cfgDefOptTypeFloat:
|
||||||
|
{
|
||||||
|
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
|
||||||
|
strCatFmt(mainCallParam, ", '%lg'", cfgOptionDbl(optionId));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case cfgDefOptTypeHash:
|
||||||
|
{
|
||||||
|
const KeyValue *valueKv = cfgOptionKv(optionId);
|
||||||
|
const VariantList *keyList = kvKeyList(valueKv);
|
||||||
|
|
||||||
|
for (unsigned int listIdx = 0; listIdx < varLstSize(keyList); listIdx++)
|
||||||
|
{
|
||||||
|
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
|
||||||
|
strCatFmt(
|
||||||
|
mainCallParam, ", '%s=%s'", strPtr(varStr(varLstGet(keyList, listIdx))),
|
||||||
|
strPtr(varStr(kvGet(valueKv, varLstGet(keyList, listIdx)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case cfgDefOptTypeInteger:
|
||||||
|
{
|
||||||
|
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
|
||||||
|
strCatFmt(mainCallParam, ", '%d'", cfgOptionInt(optionId));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case cfgDefOptTypeList:
|
||||||
|
{
|
||||||
|
StringList *valueList = strLstNewVarLst(cfgOptionLst(optionId));
|
||||||
|
|
||||||
|
for (unsigned int listIdx = 0; listIdx < strLstSize(valueList); listIdx++)
|
||||||
|
{
|
||||||
|
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
|
||||||
|
strCatFmt(mainCallParam, ", '%s'", strPtr(strLstGet(valueList, listIdx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case cfgDefOptTypeString:
|
||||||
|
{
|
||||||
|
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
|
||||||
|
strCatFmt(mainCallParam, ", '%s'", strPtr(cfgOptionStr(optionId)));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add help command if it was set
|
||||||
|
if (cfgCommandHelp())
|
||||||
|
strCatFmt(mainCallParam, ", '%s'", cfgCommandName(cfgCmdHelp));
|
||||||
|
|
||||||
// Add command to pass to main
|
// Add command to pass to main
|
||||||
strCatFmt(mainCallParam, ", '%s'", cfgCommandName(parseData->command));
|
if (cfgCommand() != cfgCmdNone && cfgCommand() != cfgCmdHelp)
|
||||||
|
strCatFmt(mainCallParam, ", '%s'", cfgCommandName(cfgCommand()));
|
||||||
|
|
||||||
// Add command arguments to pass to main
|
// Add command arguments to pass to main
|
||||||
if (parseData->commandArgList != NULL)
|
for (unsigned int paramIdx = 0; paramIdx < strLstSize(cfgCommandParam()); paramIdx++)
|
||||||
for (unsigned int argIdx = 0; argIdx < strLstSize(parseData->commandArgList); argIdx++)
|
strCatFmt(mainCallParam, ", '%s'", strPtr(strLstGet(cfgCommandParam(), paramIdx)));
|
||||||
strCatFmt(mainCallParam, ", '%s'", strPtr(strLstGet(parseData->commandArgList, argIdx)));
|
|
||||||
|
|
||||||
// Construct perl option list to add to bin
|
// Construct perl option list to add to bin
|
||||||
|
StringList *perlOptionList = strLstNewVarLst(cfgOptionLst(cfgOptPerlOption));
|
||||||
String *binPerlOption = strNew("");
|
String *binPerlOption = strNew("");
|
||||||
|
|
||||||
if (parseData->perlOptionList != NULL)
|
if (perlOptionList != NULL)
|
||||||
for (unsigned int argIdx = 0; argIdx < strLstSize(parseData->perlOptionList); argIdx++)
|
|
||||||
{
|
{
|
||||||
// Add to bin option list
|
for (unsigned int argIdx = 0; argIdx < strLstSize(perlOptionList); argIdx++)
|
||||||
strCatFmt(binPerlOption, " --" PARAM_PERL_OPTION "=\"%s\"", strPtr(strLstGet(parseData->perlOptionList, argIdx)));
|
{
|
||||||
|
// // Add to bin option list
|
||||||
|
// strCatFmt(binPerlOption, " --" PARAM_PERL_OPTION "=\"%s\"", strPtr(strLstGet(perlOptionList, argIdx)));
|
||||||
|
|
||||||
// Add to list that will be passed to exec
|
// Add to list that will be passed to exec
|
||||||
strLstAdd(perlArgList, strLstGet(parseData->perlOptionList, argIdx));
|
strLstAdd(perlArgList, strLstGet(perlOptionList, argIdx));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct Perl main call
|
// Construct Perl main call
|
||||||
String *mainCall = strNewFmt(PGBACKREST_MAIN "('%s%s'%s)", argList[0], strPtr(binPerlOption), strPtr(mainCallParam));
|
String *mainCall = strNewFmt(PGBACKREST_MAIN "('%s%s'%s)", strPtr(cfgExe()), strPtr(binPerlOption), strPtr(mainCallParam));
|
||||||
|
|
||||||
// End arg list for perl exec
|
// End arg list for perl exec
|
||||||
strLstAdd(perlArgList, strNew("-M" PGBACKREST_MODULE));
|
strLstAdd(perlArgList, strNew("-M" PGBACKREST_MODULE));
|
||||||
|
@ -9,7 +9,7 @@ Execute Perl for Legacy Functionality
|
|||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Functions
|
Functions
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
StringList *perlCommand(int argListSize, const char *argList[]);
|
StringList *perlCommand();
|
||||||
void perlExec(StringList *perlArgList);
|
void perlExec(StringList *perlArgList);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -440,7 +440,7 @@ full backup - invalid cmd line (db-master host)
|
|||||||
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --type=full --stanza=bogus backup
|
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --type=full --stanza=bogus backup
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
STDERR:
|
STDERR:
|
||||||
ERROR [037]: : backup command requires option: db1-path
|
ERROR [037]: backup command requires option: db1-path
|
||||||
HINT: does this stanza exist?
|
HINT: does this stanza exist?
|
||||||
|
|
||||||
stop all stanzas (db-master host)
|
stop all stanzas (db-master host)
|
||||||
|
@ -394,7 +394,7 @@ my $oTestDef =
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
&TESTDEF_NAME => 'parse',
|
&TESTDEF_NAME => 'parse',
|
||||||
&TESTDEF_TOTAL => 2,
|
&TESTDEF_TOTAL => 1,
|
||||||
&TESTDEF_C => true,
|
&TESTDEF_C => true,
|
||||||
|
|
||||||
&TESTDEF_COVERAGE =>
|
&TESTDEF_COVERAGE =>
|
||||||
|
@ -71,8 +71,86 @@ void testRun()
|
|||||||
// -----------------------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------------------
|
||||||
if (testBegin("configuration"))
|
if (testBegin("configuration"))
|
||||||
{
|
{
|
||||||
|
TEST_RESULT_VOID(cfgInit(), "config init");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
TEST_RESULT_INT(cfgCommand(), cfgCmdNone, "command begins as none");
|
TEST_RESULT_INT(cfgCommand(), cfgCmdNone, "command begins as none");
|
||||||
TEST_RESULT_VOID(cfgCommandSet(cfgCmdBackup), "command set to backup");
|
TEST_RESULT_VOID(cfgCommandSet(cfgCmdBackup), "command set to backup");
|
||||||
TEST_RESULT_INT(cfgCommand(), cfgCmdBackup, "command is backup");
|
TEST_RESULT_INT(cfgCommand(), cfgCmdBackup, "command is backup");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_RESULT_BOOL(cfgCommandHelp(), false, "command help defaults to false");
|
||||||
|
TEST_RESULT_VOID(cfgCommandHelpSet(true), "set command help");
|
||||||
|
TEST_RESULT_BOOL(cfgCommandHelp(), true, "command help is set");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_RESULT_INT(strLstSize(cfgCommandParam()), 0, "command param list defaults to empty");
|
||||||
|
TEST_RESULT_VOID(cfgCommandParamSet(strLstAddZ(strLstNew(), "param")), "set command param list");
|
||||||
|
TEST_RESULT_INT(strLstSize(cfgCommandParam()), 1, "command param list is set");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_RESULT_PTR(cfgExe(), NULL, "exe defaults to null");
|
||||||
|
TEST_RESULT_VOID(cfgExeSet(strNew("/path/to/exe")), "set exe");
|
||||||
|
TEST_RESULT_STR(strPtr(cfgExe()), "/path/to/exe", "exe is set");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_RESULT_BOOL(cfgOptionNegate(cfgOptConfig), false, "negate defaults to false");
|
||||||
|
TEST_RESULT_VOID(cfgOptionNegateSet(cfgOptConfig, true), "set negate");
|
||||||
|
TEST_RESULT_BOOL(cfgOptionNegate(cfgOptConfig), true, "negate is set");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_RESULT_BOOL(cfgOptionValid(cfgOptConfig), false, "valid defaults to false");
|
||||||
|
TEST_RESULT_VOID(cfgOptionValidSet(cfgOptConfig, true), "set valid");
|
||||||
|
TEST_RESULT_BOOL(cfgOptionValid(cfgOptConfig), true, "valid is set");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_RESULT_PTR(cfgOption(cfgOptOnline), NULL, "online is null");
|
||||||
|
TEST_RESULT_VOID(cfgOptionSet(cfgOptOnline, cfgSourceParam, varNewBool(false)), "set online");
|
||||||
|
TEST_RESULT_BOOL(cfgOptionBool(cfgOptOnline), false, "online is set");
|
||||||
|
TEST_RESULT_VOID(cfgOptionSet(cfgOptOnline, cfgSourceParam, varNewStrZ("1")), "set online");
|
||||||
|
TEST_RESULT_BOOL(cfgOptionBool(cfgOptOnline), true, "online is set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptOnline), cfgSourceParam, "online source is set");
|
||||||
|
TEST_ERROR(cfgOptionDbl(cfgOptOnline), AssertError, "option 'online' is not type 'double'");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(cfgOptionSet(cfgOptCompressLevel, cfgSourceParam, varNewInt(1)), "set compress-level");
|
||||||
|
TEST_RESULT_INT(cfgOptionInt(cfgOptCompressLevel), 1, "compress-level is set");
|
||||||
|
TEST_RESULT_VOID(cfgOptionSet(cfgOptCompressLevel, cfgSourceDefault, varNewStrZ("3")), "set compress-level");
|
||||||
|
TEST_RESULT_INT(cfgOptionInt(cfgOptCompressLevel), 3, "compress-level is set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptCompressLevel), cfgSourceDefault, "compress source is set");
|
||||||
|
TEST_ERROR(cfgOptionBool(cfgOptCompressLevel), AssertError, "option 'compress-level' is not type 'bool'");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(cfgOptionSet(cfgOptProtocolTimeout, cfgSourceParam, varNewDbl(1.1)), "set protocol-timeout");
|
||||||
|
TEST_RESULT_DOUBLE(cfgOptionDbl(cfgOptProtocolTimeout), 1.1, "protocol-timeout is set");
|
||||||
|
TEST_RESULT_VOID(cfgOptionSet(cfgOptProtocolTimeout, cfgSourceConfig, varNewStrZ("3.3")), "set protocol-timeout");
|
||||||
|
TEST_RESULT_DOUBLE(cfgOptionDbl(cfgOptProtocolTimeout), 3.3, "protocol-timeout is set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptProtocolTimeout), cfgSourceConfig, "protocol-timeout source is set");
|
||||||
|
TEST_ERROR(cfgOptionKv(cfgOptProtocolTimeout), AssertError, "option 'protocol-timeout' is not type 'KeyValue'");
|
||||||
|
|
||||||
|
TEST_ERROR(
|
||||||
|
cfgOptionSet(cfgOptRecoveryOption, cfgSourceParam, varNewDbl(1.1)), AssertError,
|
||||||
|
"option 'recovery-option' must be set with KeyValue variant");
|
||||||
|
TEST_RESULT_VOID(cfgOptionSet(cfgOptRecoveryOption, cfgSourceConfig, varNewKv()), "set recovery-option");
|
||||||
|
TEST_RESULT_INT(varLstSize(kvKeyList(cfgOptionKv(cfgOptRecoveryOption))), 0, "recovery-option is set");
|
||||||
|
TEST_ERROR(cfgOptionLst(cfgOptRecoveryOption), AssertError, "option 'recovery-option' is not type 'VariantList'");
|
||||||
|
|
||||||
|
TEST_RESULT_INT(varLstSize(cfgOptionLst(cfgOptDbInclude)), 0, "db-include defaults to empty");
|
||||||
|
TEST_ERROR(
|
||||||
|
cfgOptionSet(cfgOptDbInclude, cfgSourceParam, varNewDbl(1.1)), AssertError,
|
||||||
|
"option 'db-include' must be set with VariantList variant");
|
||||||
|
TEST_RESULT_VOID(cfgOptionSet(cfgOptDbInclude, cfgSourceConfig, varNewVarLstEmpty()), "set db-include");
|
||||||
|
TEST_RESULT_INT(varLstSize(cfgOptionLst(cfgOptDbInclude)), 0, "db-include is set");
|
||||||
|
TEST_ERROR(cfgOptionStr(cfgOptDbInclude), AssertError, "option 'db-include' is not type 'String'");
|
||||||
|
|
||||||
|
TEST_RESULT_PTR(cfgOptionStr(cfgOptStanza), NULL, "stanza defaults to null");
|
||||||
|
TEST_ERROR(
|
||||||
|
cfgOptionSet(cfgOptStanza, cfgSourceParam, varNewDbl(1.1)), AssertError,
|
||||||
|
"option 'stanza' must be set with String variant");
|
||||||
|
TEST_RESULT_VOID(cfgOptionSet(cfgOptStanza, cfgSourceConfig, varNewStrZ("db")), "set stanza");
|
||||||
|
TEST_RESULT_STR(strPtr(cfgOptionStr(cfgOptStanza)), "db", "stanza is set");
|
||||||
|
TEST_ERROR(cfgOptionInt(cfgOptStanza), AssertError, "option 'stanza' is not type 'int'");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_RESULT_VOID(cfgInit(), "config init resets value");
|
||||||
|
TEST_RESULT_INT(cfgCommand(), cfgCmdNone, "command begins as none");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Test Configuration Parse
|
Test Configuration Parse
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
|
|
||||||
#define TEST_BACKREST_EXE "pgbackrest"
|
#define TEST_BACKREST_EXE "pgbackrest"
|
||||||
|
|
||||||
#define TEST_COMMAND_ARCHIVE_GET "archive-get"
|
#define TEST_COMMAND_ARCHIVE_GET "archive-get"
|
||||||
@ -16,71 +15,37 @@ Test run
|
|||||||
void testRun()
|
void testRun()
|
||||||
{
|
{
|
||||||
// -----------------------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------------------
|
||||||
if (testBegin("configParseArg()"))
|
if (testBegin("configParse()"))
|
||||||
{
|
{
|
||||||
ParseData *parseData = NULL;
|
StringList *argList = NULL;
|
||||||
|
String *configFile = strNewFmt("%s/test.config", testPath());
|
||||||
StringList *argList = strLstNew();
|
|
||||||
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
|
||||||
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "no command, no args - set help command");
|
|
||||||
TEST_RESULT_INT(parseData->command, cfgCmdHelp, " command is " TEST_COMMAND_HELP);
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
|
||||||
strLstAdd(argList, strNew("--online"));
|
|
||||||
TEST_ERROR(configParseArg(strLstSize(argList), strLstPtr(argList)), CommandRequiredError, "no command found");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
|
||||||
strLstAdd(argList, strNew(TEST_COMMAND_VERSION));
|
|
||||||
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_VERSION " command");
|
|
||||||
TEST_RESULT_INT(parseData->command, cfgCmdVersion, " command is " TEST_COMMAND_VERSION);
|
|
||||||
TEST_RESULT_PTR(parseData->perlOptionList, NULL, " no perl options");
|
|
||||||
TEST_RESULT_PTR(parseData->commandArgList, NULL, " no command arguments");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
|
||||||
strLstAdd(argList, strNew("--perl-option=value"));
|
|
||||||
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "perl option");
|
|
||||||
TEST_RESULT_STR(strPtr(strLstJoin(parseData->perlOptionList, ",")), "value", "check perl option");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
|
||||||
strLstAdd(argList, strNewFmt("--%s", cfgOptionName(cfgOptDelta)));
|
|
||||||
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "delta option");
|
|
||||||
TEST_RESULT_BOOL(parseData->parseOptionList[cfgOptDelta].found, true, " option found");
|
|
||||||
TEST_RESULT_BOOL(parseData->parseOptionList[cfgOptDelta].negate, false, " option not negated");
|
|
||||||
TEST_RESULT_PTR(parseData->parseOptionList[cfgOptDelta].valueList, NULL, " no values");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
|
||||||
strLstAdd(argList, strNew("--" BOGUS_STR));
|
|
||||||
TEST_ERROR(configParseArg(strLstSize(argList), strLstPtr(argList)), OptionInvalidError, "invalid option '--BOGUS'");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
|
||||||
argList = strLstNew();
|
|
||||||
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
|
||||||
strLstAdd(argList, strNew("--no-archive-check"));
|
|
||||||
strLstAdd(argList, strNew(TEST_COMMAND_HELP));
|
|
||||||
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_HELP " command");
|
|
||||||
TEST_RESULT_BOOL(parseData->parseOptionList[cfgOptArchiveCheck].negate, true, " option negated");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
argList = strLstNew();
|
argList = strLstNew();
|
||||||
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
strLstAdd(argList, strNew(BOGUS_STR));
|
strLstAdd(argList, strNew(BOGUS_STR));
|
||||||
TEST_ERROR(configParseArg(strLstSize(argList), strLstPtr(argList)), CommandInvalidError, "invalid command 'BOGUS'");
|
TEST_ERROR(configParse(strLstSize(argList), strLstPtr(argList)), CommandInvalidError, "invalid command 'BOGUS'");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
argList = strLstNew();
|
argList = strLstNew();
|
||||||
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
strLstAdd(argList, strNew("--no-online"));
|
strLstAdd(argList, strNew("--" BOGUS_STR));
|
||||||
strLstAdd(argList, strNew("--no-online"));
|
TEST_ERROR(configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError, "invalid option '--BOGUS'");
|
||||||
TEST_ERROR(
|
|
||||||
configParseArg(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
|
||||||
"option 'online' is negated multiple times");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
argList = strLstNew();
|
argList = strLstNew();
|
||||||
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
strLstAdd(argList, strNew("--db-host"));
|
strLstAdd(argList, strNew("--db-host"));
|
||||||
TEST_ERROR(
|
TEST_ERROR(
|
||||||
configParseArg(strLstSize(argList), strLstPtr(argList)), OptionInvalidError, "option '--db-host' requires argument");
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError, "option '--db-host' requires argument");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--no-online"));
|
||||||
|
strLstAdd(argList, strNew("--no-online"));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError, "option 'online' is negated multiple times");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
argList = strLstNew();
|
argList = strLstNew();
|
||||||
@ -88,8 +53,7 @@ void testRun()
|
|||||||
strLstAdd(argList, strNew("--config=/etc/config"));
|
strLstAdd(argList, strNew("--config=/etc/config"));
|
||||||
strLstAdd(argList, strNew("--no-config"));
|
strLstAdd(argList, strNew("--no-config"));
|
||||||
TEST_ERROR(
|
TEST_ERROR(
|
||||||
configParseArg(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError, "option 'config' cannot be set and negated");
|
||||||
"option 'config' cannot be set and negated");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
argList = strLstNew();
|
argList = strLstNew();
|
||||||
@ -97,48 +61,362 @@ void testRun()
|
|||||||
strLstAdd(argList, strNew("--compress-level=3"));
|
strLstAdd(argList, strNew("--compress-level=3"));
|
||||||
strLstAdd(argList, strNew("--compress-level=3"));
|
strLstAdd(argList, strNew("--compress-level=3"));
|
||||||
TEST_ERROR(
|
TEST_ERROR(
|
||||||
configParseArg(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
||||||
"option 'compress-level' cannot have multiple arguments");
|
"option 'compress-level' cannot have multiple arguments");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
argList = strLstNew();
|
argList = strLstNew();
|
||||||
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--online"));
|
||||||
|
TEST_ERROR(configParse(strLstSize(argList), strLstPtr(argList)), CommandRequiredError, "no command found");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionRequiredError,
|
||||||
|
"backup command requires option: db1-path\nHINT: does this stanza exist?");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionRequiredError,
|
||||||
|
"backup command requires option: stanza");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--no-config"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--repo-s3-key=xxx"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
||||||
|
"option 'repo-s3-key' not valid without option 'repo-type' = 's3'");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--backup-user=xxx"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
||||||
|
"option 'backup-user' not valid without option 'backup-host'");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--force"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
||||||
|
"option 'force' not valid without option 'no-online'");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--test-delay=1"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
||||||
|
"option 'test-delay' not valid without option 'test'");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--recovery-option=a=b"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
||||||
|
"option 'recovery-option' not valid for command 'backup'");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--target-exclusive"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
||||||
|
"option 'target-exclusive' not valid without option 'type' in ('time', 'xid')");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--type=bogus"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidValueError,
|
||||||
|
"'bogus' is not valid for 'type' option");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--process-max=0"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidValueError,
|
||||||
|
"'0' is not valid for 'process-max' option");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--process-max=bogus"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidValueError,
|
||||||
|
"'bogus' is not valid for 'process-max' option");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--protocol-timeout=.01"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidValueError,
|
||||||
|
"'.01' is not valid for 'protocol-timeout' option");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--protocol-timeout=bogus"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidValueError,
|
||||||
|
"'bogus' is not valid for 'protocol-timeout' option");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNewFmt("--config=%s", strPtr(configFile)));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
|
|
||||||
|
storagePut(storageLocal(), configFile, bufNewStr(strNew(
|
||||||
|
"[global]\n"
|
||||||
|
"compress=bogus\n"
|
||||||
|
)));
|
||||||
|
|
||||||
|
TEST_ERROR(configParse(
|
||||||
|
strLstSize(argList), strLstPtr(argList)), OptionInvalidError, "boolean option 'compress' must be 'y' or 'n'");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNewFmt("--config=%s", strPtr(configFile)));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
|
|
||||||
|
storagePut(storageLocal(), configFile, bufNewStr(strNew(
|
||||||
|
"[global]\n"
|
||||||
|
"compress=\n"
|
||||||
|
)));
|
||||||
|
|
||||||
|
TEST_ERROR(configParse(
|
||||||
|
strLstSize(argList), strLstPtr(argList)), OptionInvalidValueError,
|
||||||
|
"section 'global', key 'compress' must have a value");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), "no command");
|
||||||
|
TEST_RESULT_BOOL(cfgCommandHelp(), true, " help is set");
|
||||||
|
TEST_RESULT_INT(cfgCommand(), cfgCmdNone, " command is none");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("help"));
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), "help command");
|
||||||
|
TEST_RESULT_BOOL(cfgCommandHelp(), true, " help is set");
|
||||||
|
TEST_RESULT_INT(cfgCommand(), cfgCmdHelp, " command is help");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("help"));
|
||||||
|
strLstAdd(argList, strNew("version"));
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), "help for version command");
|
||||||
|
TEST_RESULT_BOOL(cfgCommandHelp(), true, " help is set");
|
||||||
|
TEST_RESULT_INT(cfgCommand(), cfgCmdVersion, " command is version");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
strLstAdd(argList, strNew(TEST_COMMAND_ARCHIVE_GET));
|
strLstAdd(argList, strNew(TEST_COMMAND_ARCHIVE_GET));
|
||||||
strLstAdd(argList, strNew("000000010000000200000003"));
|
strLstAdd(argList, strNew("000000010000000200000003"));
|
||||||
strLstAdd(argList, strNew("/path/to/wal/RECOVERYWAL"));
|
strLstAdd(argList, strNew("/path/to/wal/RECOVERYWAL"));
|
||||||
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "command arguments");
|
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), "command arguments");
|
||||||
TEST_RESULT_STR(
|
TEST_RESULT_STR(
|
||||||
strPtr(strLstJoin(parseData->commandArgList, "|")), "000000010000000200000003|/path/to/wal/RECOVERYWAL",
|
strPtr(strLstJoin(cfgCommandParam(), "|")), "000000010000000200000003|/path/to/wal/RECOVERYWAL",
|
||||||
" check command arguments");
|
" check command arguments");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
argList = strLstNew();
|
argList = strLstNew();
|
||||||
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
strLstAdd(argList, strNew("--db-host=db1.test.org"));
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew("--backup-host=backup"));
|
||||||
|
strLstAdd(argList, strNew("--backup-user=pgbackrest"));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--no-online"));
|
||||||
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "single valid option");
|
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_BACKUP " command");
|
||||||
TEST_RESULT_STR(
|
TEST_RESULT_INT(cfgCommand(), cfgCmdBackup, " command is " TEST_COMMAND_BACKUP);
|
||||||
strPtr(strLstJoin(parseData->parseOptionList[cfgOptDbHost].valueList, "|")), "db1.test.org", " check db-host option");
|
|
||||||
|
TEST_RESULT_STR(strPtr(cfgExe()), TEST_BACKREST_EXE, " exe is set");
|
||||||
|
|
||||||
|
TEST_RESULT_STR(strPtr(cfgOptionStr(cfgOptStanza)), "db", " stanza is set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptStanza), cfgSourceParam, " stanza is source param");
|
||||||
|
TEST_RESULT_STR(strPtr(cfgOptionStr(cfgOptDbPath)), "/path/to/db", " db-path is set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptDbPath), cfgSourceParam, " db-path is source param");
|
||||||
|
TEST_RESULT_BOOL(cfgOptionBool(cfgOptOnline), false, " online is not set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptOnline), cfgSourceParam, " online is source default");
|
||||||
|
TEST_RESULT_BOOL(cfgOptionBool(cfgOptCompress), true, " compress is set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptCompress), cfgSourceDefault, " compress is source default");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
argList = strLstNew();
|
argList = strLstNew();
|
||||||
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
strLstAdd(argList, strNew("--link-map=ts1=/path/to/ts1"));
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
strLstAdd(argList, strNew("--link-map=ts2=/path/to/ts2"));
|
strLstAdd(argList, strNewFmt("--config=%s", strPtr(configFile)));
|
||||||
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
strLstAdd(argList, strNew("--no-online"));
|
||||||
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "multiple valid options");
|
strLstAdd(argList, strNew("--db1-host=db"));
|
||||||
TEST_RESULT_STR(
|
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
|
||||||
strPtr(strLstJoin(parseData->parseOptionList[cfgOptLinkMap].valueList, "|")), "ts1=/path/to/ts1|ts2=/path/to/ts2",
|
|
||||||
" check link-map options");
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------------------
|
storagePut(storageLocal(), configFile, bufNewStr(strNew(
|
||||||
if (testBegin("configParse()"))
|
"[global]\n"
|
||||||
{
|
"compress-level=3\n"
|
||||||
StringList *argList = strLstNew();
|
"\n"
|
||||||
|
"[global:backup]\n"
|
||||||
|
"hardlink=y\n"
|
||||||
|
"bogus=bogus\n"
|
||||||
|
"no-compress=y\n"
|
||||||
|
"archive-copy=y\n"
|
||||||
|
"online=y\n"
|
||||||
|
"\n"
|
||||||
|
"[db:backup]\n"
|
||||||
|
"compress=n\n"
|
||||||
|
"recovery-option=a=b\n"
|
||||||
|
"\n"
|
||||||
|
"[db]\n"
|
||||||
|
"db1-host=db\n"
|
||||||
|
"db1-path=/path/to/db\n"
|
||||||
|
"recovery-option=c=d\n"
|
||||||
|
)));
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_BACKUP " command");
|
||||||
|
|
||||||
|
TEST_RESULT_STR(strPtr(cfgOptionStr(cfgOptDbPath)), "/path/to/db", " db-path is set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptDbPath), cfgSourceConfig, " db-path is source config");
|
||||||
|
TEST_RESULT_BOOL(cfgOptionBool(cfgOptCompress), false, " compress not is set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptCompress), cfgSourceConfig, " compress is source config");
|
||||||
|
TEST_RESULT_PTR(cfgOption(cfgOptArchiveCheck), NULL, " archive-check is not set");
|
||||||
|
TEST_RESULT_PTR(cfgOption(cfgOptArchiveCopy), NULL, " archive-copy is not set");
|
||||||
|
TEST_RESULT_BOOL(cfgOptionBool(cfgOptHardlink), true, " hardlink is set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptHardlink), cfgSourceConfig, " hardlink is source config");
|
||||||
|
TEST_RESULT_INT(cfgOptionInt(cfgOptCompressLevel), 3, " compress-level is set");
|
||||||
|
TEST_RESULT_INT(cfgOptionSource(cfgOptCompressLevel), cfgSourceConfig, " compress-level is source config");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
strLstAdd(argList, strNew(TEST_COMMAND_HELP));
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_HELP " command");
|
strLstAdd(argList, strNew("--recovery-option=a"));
|
||||||
TEST_RESULT_INT(cfgCommand(), cfgCmdHelp, " command is " TEST_COMMAND_HELP);
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
||||||
|
"key/value 'a' not valid for 'recovery-option' option");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--recovery-option=a"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
TEST_ERROR(
|
||||||
|
configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
||||||
|
"key/value 'a' not valid for 'recovery-option' option");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--db-include=abc"));
|
||||||
|
strLstAdd(argList, strNew("--db-include=def"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_RESTORE " command");
|
||||||
|
|
||||||
|
const VariantList *includeList = NULL;
|
||||||
|
TEST_ASSIGN(includeList, cfgOptionLst(cfgOptDbInclude), "get db include options");
|
||||||
|
TEST_RESULT_STR(strPtr(varStr(varLstGet(includeList, 0))), "abc", "check db include option");
|
||||||
|
TEST_RESULT_STR(strPtr(varStr(varLstGet(includeList, 1))), "def", "check db include option");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||||
|
strLstAdd(argList, strNew("--recovery-option=a=b"));
|
||||||
|
strLstAdd(argList, strNew("--recovery-option=c=de=fg hi"));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_RESTORE " command");
|
||||||
|
|
||||||
|
const KeyValue *recoveryKv = NULL;
|
||||||
|
TEST_ASSIGN(recoveryKv, cfgOptionKv(cfgOptRecoveryOption), "get recovery options");
|
||||||
|
TEST_RESULT_STR(strPtr(varStr(kvGet(recoveryKv, varNewStr(strNew("a"))))), "b", "check recovery option");
|
||||||
|
TEST_RESULT_STR(strPtr(varStr(kvGet(recoveryKv, varNewStr(strNew("c"))))), "de=fg hi", "check recovery option");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
|
||||||
|
strLstAdd(argList, strNewFmt("--config=%s", strPtr(configFile)));
|
||||||
|
strLstAdd(argList, strNew("--stanza=db"));
|
||||||
|
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
|
||||||
|
|
||||||
|
storagePut(storageLocal(), configFile, bufNewStr(strNew(
|
||||||
|
"[global:restore]\n"
|
||||||
|
"recovery-option=f=g\n"
|
||||||
|
"recovery-option=hijk=l\n"
|
||||||
|
"\n"
|
||||||
|
"[db]\n"
|
||||||
|
"db1-path=/path/to/db\n"
|
||||||
|
)));
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_RESTORE " command");
|
||||||
|
|
||||||
|
TEST_ASSIGN(recoveryKv, cfgOptionKv(cfgOptRecoveryOption), "get recovery options");
|
||||||
|
TEST_RESULT_STR(strPtr(varStr(kvGet(recoveryKv, varNewStr(strNew("f"))))), "g", "check recovery option");
|
||||||
|
TEST_RESULT_STR(strPtr(varStr(kvGet(recoveryKv, varNewStr(strNew("hijk"))))), "l", "check recovery option");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Test Perl Exec
|
Test Perl Exec
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
|
#include "config/config.h"
|
||||||
|
|
||||||
#define TEST_ENV_EXE "/usr/bin/env"
|
#define TEST_ENV_EXE "/usr/bin/env"
|
||||||
#define TEST_PERL_EXE "perl"
|
#define TEST_PERL_EXE "perl"
|
||||||
@ -17,69 +18,80 @@ void testRun()
|
|||||||
if (testBegin("perlCommand()"))
|
if (testBegin("perlCommand()"))
|
||||||
{
|
{
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
const char *cmdLineParam[128];
|
cfgInit();
|
||||||
int cmdLineParamSize = 0;
|
cfgCommandSet(cfgCmdInfo);
|
||||||
|
cfgExeSet(strNew(TEST_BACKREST_EXE));
|
||||||
cmdLineParam[cmdLineParamSize++] = TEST_BACKREST_EXE;
|
|
||||||
cmdLineParam[cmdLineParamSize++] = "backup";
|
|
||||||
|
|
||||||
TEST_RESULT_STR(
|
TEST_RESULT_STR(
|
||||||
strPtr(strLstJoin(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
|
strPtr(strLstJoin(perlCommand(), "|")),
|
||||||
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', 'backup')|[NULL]", "simple command");
|
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', 'info')|[NULL]", "command with no options");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
cmdLineParam[cmdLineParamSize++] = "--compress";
|
cfgInit();
|
||||||
|
cfgCommandSet(cfgCmdBackup);
|
||||||
|
cfgExeSet(strNew(TEST_BACKREST_EXE));
|
||||||
|
|
||||||
|
cfgOptionValidSet(cfgOptCompress, true);
|
||||||
|
cfgOptionSet(cfgOptCompress, cfgSourceParam, varNewBool(true));
|
||||||
|
|
||||||
|
cfgOptionValidSet(cfgOptOnline, true);
|
||||||
|
cfgOptionNegateSet(cfgOptOnline, true);
|
||||||
|
cfgOptionSet(cfgOptOnline, cfgSourceParam, varNewBool(false));
|
||||||
|
|
||||||
|
cfgOptionValidSet(cfgOptProtocolTimeout, true);
|
||||||
|
cfgOptionSet(cfgOptProtocolTimeout, cfgSourceParam, varNewDbl(1.1));
|
||||||
|
|
||||||
|
cfgOptionValidSet(cfgOptCompressLevel, true);
|
||||||
|
cfgOptionSet(cfgOptCompressLevel, cfgSourceParam, varNewInt(3));
|
||||||
|
|
||||||
|
cfgOptionValidSet(cfgOptStanza, true);
|
||||||
|
cfgOptionSet(cfgOptStanza, cfgSourceParam, varNewStr(strNew("db")));
|
||||||
|
|
||||||
TEST_RESULT_STR(
|
TEST_RESULT_STR(
|
||||||
strPtr(strLstJoin(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
|
strPtr(strLstJoin(perlCommand(), "|")),
|
||||||
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', '--compress', 'backup')|[NULL]", "simple option");
|
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "'"
|
||||||
|
", '--compress', '--compress-level', '3', '--no-online', '--protocol-timeout', '1.1', '--stanza', 'db'"
|
||||||
|
", 'backup')|[NULL]", "simple options");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
cmdLineParam[cmdLineParamSize++] = "--db-host=db1";
|
cfgInit();
|
||||||
|
cfgCommandHelpSet(true);
|
||||||
|
cfgCommandSet(cfgCmdRestore);
|
||||||
|
cfgExeSet(strNew(TEST_BACKREST_EXE));
|
||||||
|
|
||||||
|
cfgOptionValidSet(cfgOptDbInclude, true);
|
||||||
|
StringList *includeList = strLstNew();
|
||||||
|
strLstAdd(includeList, strNew("db1"));
|
||||||
|
strLstAdd(includeList, strNew("db2"));
|
||||||
|
cfgOptionSet(cfgOptDbInclude, cfgSourceParam, varNewVarLst(varLstNewStrLst(includeList)));
|
||||||
|
|
||||||
|
cfgOptionValidSet(cfgOptRecoveryOption, true);
|
||||||
|
// !!! WHY DO WE STILL NEED TO CREATE THE VAR KV EMPTY?
|
||||||
|
Variant *recoveryVar = varNewKv();
|
||||||
|
KeyValue *recoveryKv = varKv(recoveryVar);
|
||||||
|
kvPut(recoveryKv, varNewStr(strNew("standby_mode")), varNewStr(strNew("on")));
|
||||||
|
kvPut(recoveryKv, varNewStr(strNew("primary_conn_info")), varNewStr(strNew("blah")));
|
||||||
|
cfgOptionSet(cfgOptRecoveryOption, cfgSourceParam, recoveryVar);
|
||||||
|
|
||||||
|
StringList *commandParamList = strLstNew();
|
||||||
|
strLstAdd(commandParamList, strNew("param1"));
|
||||||
|
strLstAdd(commandParamList, strNew("param2"));
|
||||||
|
cfgCommandParamSet(commandParamList);
|
||||||
|
|
||||||
|
cfgOptionValidSet(cfgOptPerlOption, true);
|
||||||
|
// !!! WHY DO WE STILL NEED TO CREATE THE VAR KV EMPTY?
|
||||||
|
StringList *perlList = strLstNew();
|
||||||
|
strLstAdd(perlList, strNew("-I."));
|
||||||
|
strLstAdd(perlList, strNew("-MDevel::Cover=-silent,1"));
|
||||||
|
cfgOptionSet(cfgOptPerlOption, cfgSourceParam, varNewVarLst(varLstNewStrLst(perlList)));
|
||||||
|
|
||||||
TEST_RESULT_STR(
|
TEST_RESULT_STR(
|
||||||
strPtr(strLstJoin(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
|
strPtr(strLstJoin(perlCommand(), "|")),
|
||||||
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', '--compress', '--db1-host', 'db1', 'backup')|[NULL]",
|
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|-MDevel::Cover=-silent,1|" TEST_PERL_MAIN "'"
|
||||||
"option with = before value");
|
", '--db-include', 'db1', '--db-include', 'db2'"
|
||||||
|
", '--perl-option', '-I.', '--perl-option', '-MDevel::Cover=-silent,1'"
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
", '--recovery-option', 'standby_mode=on', '--recovery-option', 'primary_conn_info=blah'"
|
||||||
cmdLineParam[cmdLineParamSize++] = "--db-user";
|
", 'help', 'restore', 'param1', 'param2')|[NULL]", "complex options");
|
||||||
cmdLineParam[cmdLineParamSize++] = "postgres";
|
|
||||||
|
|
||||||
TEST_RESULT_STR(
|
|
||||||
strPtr(strLstJoin(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
|
|
||||||
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN
|
|
||||||
"', '--compress', '--db1-host', 'db1', '--db1-user', 'postgres', 'backup')|[NULL]",
|
|
||||||
"option with space before value");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
|
||||||
cmdLineParam[cmdLineParamSize++] = "--perl-option=-I.";
|
|
||||||
|
|
||||||
TEST_RESULT_STR(
|
|
||||||
strPtr(strLstJoin(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
|
|
||||||
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|" TEST_PERL_MAIN
|
|
||||||
" --perl-option=\"-I.\"', '--compress', '--db1-host', 'db1', '--db1-user', 'postgres', 'backup')|[NULL]",
|
|
||||||
"perl option");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
|
||||||
cmdLineParam[cmdLineParamSize++] = "--no-online";
|
|
||||||
|
|
||||||
TEST_RESULT_STR(
|
|
||||||
strPtr(strLstJoin(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
|
|
||||||
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|" TEST_PERL_MAIN
|
|
||||||
" --perl-option=\"-I.\"', '--compress', '--db1-host', 'db1', '--db1-user', 'postgres', '--no-online',"
|
|
||||||
" 'backup')|[NULL]",
|
|
||||||
"perl option");
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
|
||||||
cmdLineParam[cmdLineParamSize++] = "cmdarg1";
|
|
||||||
|
|
||||||
TEST_RESULT_STR(
|
|
||||||
strPtr(strLstJoin(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
|
|
||||||
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|" TEST_PERL_MAIN
|
|
||||||
" --perl-option=\"-I.\"', '--compress', '--db1-host', 'db1', '--db1-user', 'postgres', '--no-online', 'backup',"
|
|
||||||
" 'cmdarg1')|[NULL]",
|
|
||||||
"perl option");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------------------
|
||||||
|
Reference in New Issue
Block a user