1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-12 10:04:14 +02:00

Move Perl option JSON generation to a new module.

Linking exec.c into LibC will not be an option once the perl exec loads the Perl interpreter.
This commit is contained in:
David Steele 2018-02-14 09:49:01 -05:00
parent 68a83ea2dc
commit fda62dfc48
9 changed files with 274 additions and 212 deletions

View File

@ -46,7 +46,7 @@ These includes are from the src directory. There is no Perl-specific code in th
#include "config/config.h"
#include "config/define.h"
#include "config/load.h"
#include "perl/exec.h"
#include "perl/config.h"
#include "postgres/pageChecksum.h"
/***********************************************************************************************************************************

View File

@ -96,7 +96,7 @@ my @stryCFile =
'config/define.c',
'config/load.c',
'config/parse.c',
'perl/exec.c',
'perl/config.c',
'postgres/pageChecksum.c',
'storage/helper.c',
'storage/storage.c',

View File

@ -25,6 +25,7 @@ pgbackrest: \
config/define.o \
config/load.o \
config/parse.o \
perl/config.o \
perl/exec.o \
storage/helper.o \
storage/storage.o \
@ -52,6 +53,7 @@ pgbackrest: \
config/define.o \
config/load.o \
config/parse.o \
perl/config.o \
perl/exec.o \
storage/helper.o \
storage/storage.o \

132
src/perl/config.c Normal file
View File

@ -0,0 +1,132 @@
/***********************************************************************************************************************************
Perl Configuration
***********************************************************************************************************************************/
#include "common/memContext.h"
#include "config/config.h"
/***********************************************************************************************************************************
Build JSON output from options
***********************************************************************************************************************************/
String *
perlOptionJson()
{
String *result = strNew("{");
MEM_CONTEXT_TEMP_BEGIN()
{
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
{
// Skip the option if it is not valid
if (!cfgOptionValid(optionId))
continue;
// Output option
if (strSize(result) != 1)
strCat(result, ",");
strCatFmt(result, "\"%s\":{", cfgOptionName(optionId));
// Output source unless it is default
if (cfgOptionSource(optionId) != cfgSourceDefault)
{
strCat(result, "\"source\":\"");
if (cfgOptionSource(optionId) == cfgSourceParam)
strCat(result, "param");
else
strCat(result, "config");
strCat(result, "\"");
// Add a comma if another define will be added
if (cfgOption(optionId) != NULL)
strCat(result, ",");
}
// If option was negated
if (cfgOptionNegate(optionId))
strCatFmt(result, "\"negate\":%s", strPtr(varStrForce(varNewBool(true))));
else
{
// If option is reset then add flag
if (cfgOptionReset(optionId))
strCatFmt(result, "\"reset\":%s", strPtr(varStrForce(varNewBool(true))));
// If has a value
if (cfgOption(optionId) != NULL)
{
// If option is reset, then add a comma separator before setting the value
if (cfgOptionReset(optionId))
strCat(result, ",");
strCat(result, "\"value\":");
switch (cfgDefOptionType(cfgOptionDefIdFromId(optionId)))
{
case cfgDefOptTypeBoolean:
case cfgDefOptTypeFloat:
case cfgDefOptTypeInteger:
{
strCat(result, strPtr(varStrForce(cfgOption(optionId))));
break;
}
case cfgDefOptTypeString:
{
strCatFmt(result, "\"%s\"", strPtr(cfgOptionStr(optionId)));
break;
}
case cfgDefOptTypeHash:
{
const KeyValue *valueKv = cfgOptionKv(optionId);
const VariantList *keyList = kvKeyList(valueKv);
strCat(result, "{");
for (unsigned int listIdx = 0; listIdx < varLstSize(keyList); listIdx++)
{
if (listIdx != 0)
strCat(result, ",");
strCatFmt(
result, "\"%s\":\"%s\"", strPtr(varStr(varLstGet(keyList, listIdx))),
strPtr(varStr(kvGet(valueKv, varLstGet(keyList, listIdx)))));
}
strCat(result, "}");
break;
}
case cfgDefOptTypeList:
{
StringList *valueList = strLstNewVarLst(cfgOptionLst(optionId));
strCat(result, "{");
for (unsigned int listIdx = 0; listIdx < strLstSize(valueList); listIdx++)
{
if (listIdx != 0)
strCat(result, ",");
strCatFmt(result, "\"%s\":true", strPtr(strLstGet(valueList, listIdx)));
}
strCat(result, "}");
break;
}
}
}
}
strCat(result, "}");
}
strCat(result, "}");
}
MEM_CONTEXT_TEMP_END();
return result;
}

14
src/perl/config.h Normal file
View File

@ -0,0 +1,14 @@
/***********************************************************************************************************************************
Perl Configuration
***********************************************************************************************************************************/
#ifndef PERL_CONFIG_H
#define PERL_CONFIG_H
#include "common/type.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
String *perlOptionJson();
#endif

View File

@ -12,6 +12,7 @@ Execute Perl for Legacy Functionality
#include "common/memContext.h"
#include "common/type.h"
#include "config/config.h"
#include "perl/config.h"
/***********************************************************************************************************************************
Constants used to build perl options
@ -24,133 +25,6 @@ Constants used to build perl options
#define PGBACKREST_MODULE PGBACKREST_NAME "::Main"
#define PGBACKREST_MAIN PGBACKREST_MODULE "::main"
/***********************************************************************************************************************************
Build JSON output from options
***********************************************************************************************************************************/
String *
perlOptionJson()
{
String *result = strNew("{");
MEM_CONTEXT_TEMP_BEGIN()
{
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
{
// Skip the option if it is not valid
if (!cfgOptionValid(optionId))
continue;
// Output option
if (strSize(result) != 1)
strCat(result, ",");
strCatFmt(result, "\"%s\":{", cfgOptionName(optionId));
// Output source unless it is default
if (cfgOptionSource(optionId) != cfgSourceDefault)
{
strCat(result, "\"source\":\"");
if (cfgOptionSource(optionId) == cfgSourceParam)
strCat(result, "param");
else
strCat(result, "config");
strCat(result, "\"");
// Add a comma if another define will be added
if (cfgOption(optionId) != NULL)
strCat(result, ",");
}
// If option was negated
if (cfgOptionNegate(optionId))
strCatFmt(result, "\"negate\":%s", strPtr(varStrForce(varNewBool(true))));
else
{
// If option is reset then add indicator
if (cfgOptionReset(optionId))
strCatFmt(result, "\"reset\":%s", strPtr(varStrForce(varNewBool(true))));
// Else not negated and has a value
if (cfgOption(optionId) != NULL)
{
// If option is reset, then add a comma separator before setting the value
if (cfgOptionReset(optionId))
strCat(result, ",");
strCat(result, "\"value\":");
switch (cfgDefOptionType(cfgOptionDefIdFromId(optionId)))
{
case cfgDefOptTypeBoolean:
case cfgDefOptTypeFloat:
case cfgDefOptTypeInteger:
{
strCat(result, strPtr(varStrForce(cfgOption(optionId))));
break;
}
case cfgDefOptTypeString:
{
strCatFmt(result, "\"%s\"", strPtr(cfgOptionStr(optionId)));
break;
}
case cfgDefOptTypeHash:
{
const KeyValue *valueKv = cfgOptionKv(optionId);
const VariantList *keyList = kvKeyList(valueKv);
strCat(result, "{");
for (unsigned int listIdx = 0; listIdx < varLstSize(keyList); listIdx++)
{
if (listIdx != 0)
strCat(result, ",");
strCatFmt(
result, "\"%s\":\"%s\"", strPtr(varStr(varLstGet(keyList, listIdx))),
strPtr(varStr(kvGet(valueKv, varLstGet(keyList, listIdx)))));
}
strCat(result, "}");
break;
}
case cfgDefOptTypeList:
{
StringList *valueList = strLstNewVarLst(cfgOptionLst(optionId));
strCat(result, "{");
for (unsigned int listIdx = 0; listIdx < strLstSize(valueList); listIdx++)
{
if (listIdx != 0)
strCat(result, ",");
strCatFmt(result, "\"%s\":true", strPtr(strLstGet(valueList, listIdx)));
}
strCat(result, "}");
break;
}
}
}
}
strCat(result, "}");
}
strCat(result, "}");
}
MEM_CONTEXT_TEMP_END();
return result;
}
/***********************************************************************************************************************************
Build list of perl options to use for exec
***********************************************************************************************************************************/

View File

@ -388,6 +388,17 @@ my $oTestDef =
&TESTDEF_TEST =>
[
{
&TESTDEF_NAME => 'config',
&TESTDEF_TOTAL => 1,
&TESTDEF_C => true,
&TESTDEF_COVERAGE =>
{
'perl/config' => TESTDEF_COVERAGE_FULL,
},
},
{
&TESTDEF_NAME => 'exec',
&TESTDEF_TOTAL => 2,

View File

@ -0,0 +1,98 @@
/***********************************************************************************************************************************
Test Perl Exec
***********************************************************************************************************************************/
#include "config/config.h"
/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
void
testRun()
{
// -----------------------------------------------------------------------------------------------------------------------------
if (testBegin("perlMain()"))
{
cfgInit();
TEST_RESULT_STR(strPtr(perlOptionJson()), "{}", "no options");
// -------------------------------------------------------------------------------------------------------------------------
cfgInit();
cfgOptionValidSet(cfgOptCompress, true);
cfgOptionSet(cfgOptCompress, cfgSourceParam, varNewBool(true));
cfgOptionValidSet(cfgOptOnline, true);
cfgOptionNegateSet(cfgOptOnline, true);
cfgOptionSet(cfgOptOnline, cfgSourceParam, varNewBool(false));
cfgOptionValidSet(cfgOptPgHost, true);
cfgOptionResetSet(cfgOptPgHost, true);
cfgOptionValidSet(cfgOptBackupStandby, true);
cfgOptionResetSet(cfgOptBackupStandby, true);
cfgOptionSet(cfgOptBackupStandby, cfgSourceDefault, varNewBool(false));
cfgOptionValidSet(cfgOptProtocolTimeout, true);
cfgOptionSet(cfgOptProtocolTimeout, cfgSourceParam, varNewDbl(1.1));
cfgOptionValidSet(cfgOptArchiveQueueMax, true);
cfgOptionSet(cfgOptArchiveQueueMax, cfgSourceParam, varNewInt64(999999999999));
cfgOptionValidSet(cfgOptCompressLevel, true);
cfgOptionSet(cfgOptCompressLevel, cfgSourceConfig, varNewInt(3));
cfgOptionValidSet(cfgOptStanza, true);
cfgOptionSet(cfgOptStanza, cfgSourceDefault, varNewStr(strNew("db")));
TEST_RESULT_STR(
strPtr(perlOptionJson()),
"{"
"\"archive-queue-max\":{\"source\":\"param\",\"value\":999999999999},"
"\"backup-standby\":{\"reset\":true,\"value\":false},"
"\"compress\":{\"source\":\"param\",\"value\":true},"
"\"compress-level\":{\"source\":\"config\",\"value\":3},"
"\"online\":{\"source\":\"param\",\"negate\":true},"
"\"pg1-host\":{\"reset\":true},"
"\"protocol-timeout\":{\"source\":\"param\",\"value\":1.1},"
"\"stanza\":{\"value\":\"db\"}"
"}",
"simple options");
// -------------------------------------------------------------------------------------------------------------------------
cfgInit();
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);
StringList *perlList = strLstNew();
strLstAdd(perlList, strNew("-I."));
strLstAdd(perlList, strNew("-MDevel::Cover=-silent,1"));
cfgOptionSet(cfgOptPerlOption, cfgSourceParam, varNewVarLst(varLstNewStrLst(perlList)));
TEST_RESULT_STR(
strPtr(perlOptionJson()),
"{"
"\"db-include\":{\"source\":\"param\",\"value\":{\"db1\":true,\"db2\":true}},"
"\"perl-option\":{\"source\":\"param\",\"value\":{\"-I.\":true,\"-MDevel::Cover=-silent,1\":true}},"
"\"recovery-option\":{\"source\":\"param\",\"value\":{\"standby_mode\":\"on\",\"primary_conn_info\":\"blah\"}}"
"}",
"complex options");
}
}

View File

@ -2,12 +2,7 @@
Test Perl Exec
***********************************************************************************************************************************/
#include "config/config.h"
#define TEST_ENV_EXE "/usr/bin/env"
#define TEST_PERL_EXE "perl"
#define TEST_BACKREST_EXE "/path/to/pgbackrest"
#define TEST_PERL_MAIN \
"-MpgBackRest::Main|-e|pgBackRest::Main::main('" TEST_BACKREST_EXE ""
#include "config/load.h"
/***********************************************************************************************************************************
Test Run
@ -16,92 +11,27 @@ void
testRun()
{
// -----------------------------------------------------------------------------------------------------------------------------
if (testBegin("perlCommand()"))
if (testBegin("perlMain()"))
{
// -------------------------------------------------------------------------------------------------------------------------
cfgInit();
cfgCommandSet(cfgCmdInfo);
cfgExeSet(strNew(TEST_BACKREST_EXE));
cfgExeSet(strNew("/path/to/pgbackrest"));
cfgOptionSet(cfgOptPerlBin, cfgSourceParam, varNewStrZ("/usr/bin/perl"));
TEST_RESULT_STR(
strPtr(strLstJoin(perlCommand(), "|")),
"/usr/bin/perl|" TEST_PERL_MAIN "','info','{}')|[NULL]", "custom command with no options");
cfgOptionSet(cfgOptPerlBin, cfgSourceParam, NULL);
TEST_RESULT_STR(
strPtr(strLstJoin(perlCommand(), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "','info','{}')|[NULL]", "command with no options");
"/usr/bin/perl|-MpgBackRest::Main|-e|pgBackRest::Main::main('/path/to/pgbackrest','info','{}')|[NULL]",
"custom command with no options");
// -------------------------------------------------------------------------------------------------------------------------
cfgInit();
cfgCommandSet(cfgCmdBackup);
cfgExeSet(strNew(TEST_BACKREST_EXE));
cfgOptionSet(cfgOptPerlBin, cfgSourceParam, NULL);
cfgOptionValidSet(cfgOptCompress, true);
cfgOptionSet(cfgOptCompress, cfgSourceParam, varNewBool(true));
cfgOptionValidSet(cfgOptOnline, true);
cfgOptionNegateSet(cfgOptOnline, true);
cfgOptionSet(cfgOptOnline, cfgSourceParam, varNewBool(false));
cfgOptionValidSet(cfgOptPgHost, true);
cfgOptionResetSet(cfgOptPgHost, true);
cfgOptionValidSet(cfgOptBackupStandby, true);
cfgOptionResetSet(cfgOptBackupStandby, true);
cfgOptionSet(cfgOptBackupStandby, cfgSourceDefault, varNewBool(false));
cfgOptionValidSet(cfgOptProtocolTimeout, true);
cfgOptionSet(cfgOptProtocolTimeout, cfgSourceParam, varNewDbl(1.1));
cfgOptionValidSet(cfgOptArchiveQueueMax, true);
cfgOptionSet(cfgOptArchiveQueueMax, cfgSourceParam, varNewInt64(999999999999));
cfgOptionValidSet(cfgOptCompressLevel, true);
cfgOptionSet(cfgOptCompressLevel, cfgSourceConfig, varNewInt(3));
cfgOptionValidSet(cfgOptStanza, true);
cfgOptionSet(cfgOptStanza, cfgSourceDefault, varNewStr(strNew("db")));
TEST_RESULT_STR(
strPtr(strLstJoin(perlCommand(), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "','backup','{"
"\"archive-queue-max\":{\"source\":\"param\",\"value\":999999999999},"
"\"backup-standby\":{\"reset\":true,\"value\":false},"
"\"compress\":{\"source\":\"param\",\"value\":true},"
"\"compress-level\":{\"source\":\"config\",\"value\":3},"
"\"online\":{\"source\":\"param\",\"negate\":true},"
"\"pg1-host\":{\"reset\":true},"
"\"protocol-timeout\":{\"source\":\"param\",\"value\":1.1},"
"\"stanza\":{\"value\":\"db\"}"
"}')|[NULL]",
"simple options");
// -------------------------------------------------------------------------------------------------------------------------
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"));
strLstAdd(commandParamList, strNew("A"));
strLstAdd(commandParamList, strNew("B"));
cfgCommandParamSet(commandParamList);
cfgOptionValidSet(cfgOptPerlOption, true);
@ -112,11 +42,12 @@ testRun()
TEST_RESULT_STR(
strPtr(strLstJoin(perlCommand(), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|-MDevel::Cover=-silent,1|" TEST_PERL_MAIN "','restore','{"
"\"db-include\":{\"source\":\"param\",\"value\":{\"db1\":true,\"db2\":true}},"
"\"perl-option\":{\"source\":\"param\",\"value\":{\"-I.\":true,\"-MDevel::Cover=-silent,1\":true}},"
"\"recovery-option\":{\"source\":\"param\",\"value\":{\"standby_mode\":\"on\",\"primary_conn_info\":\"blah\"}}"
"}','param1','param2')|[NULL]", "complex options");
"/usr/bin/env|perl|-I.|-MDevel::Cover=-silent,1|-MpgBackRest::Main|-e|pgBackRest::Main::main("
"'/path/to/pgbackrest','info','{"
"\"compress\":{\"source\":\"param\",\"value\":true},"
"\"perl-option\":{\"source\":\"param\",\"value\":{\"-I.\":true,\"-MDevel::Cover=-silent,1\":true}}"
"}','A','B')|[NULL]",
"command with one option and params");
}
// -----------------------------------------------------------------------------------------------------------------------------