1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-11-29 22:28:02 +02:00

Added documentation in the user guide for delta restores, expiration, dedicated backup hosts, starting and stopping pgBackRest, and replication.

This commit is contained in:
David Steele
2015-11-22 16:44:01 -05:00
parent 8ddfdcdd3b
commit fa05715dec
33 changed files with 10520 additions and 1263 deletions

View File

@@ -15,6 +15,7 @@ use Scalar::Util qw(blessed);
use lib dirname($0) . '/../lib';
use BackRest::Common::Log;
use BackRest::Common::String;
use BackRest::FileCommon;
####################################################################################################################################
# Operation constants
@@ -27,8 +28,10 @@ use constant OP_DOC_NEW => OP_DOC .
use constant OP_DOC_NODE_BLESS => OP_DOC . '->nodeBless';
use constant OP_DOC_NODE_GET => OP_DOC . '->nodeGet';
use constant OP_DOC_NODE_LIST => OP_DOC . '->nodeList';
use constant OP_DOC_NODE_REMOVE => OP_DOC . '->nodeRemove';
use constant OP_DOC_PARAM_GET => OP_DOC . '->paramGet';
use constant OP_DOC_PARAM_SET => OP_DOC . '->paramSet';
use constant OP_DOC_PARAM_TEST => OP_DOC . '->paramSet';
use constant OP_DOC_PARSE => OP_DOC . '->parse';
use constant OP_DOC_VALUE_GET => OP_DOC . '->valueGet';
use constant OP_DOC_VALUE_SET => OP_DOC . '->valueSet';
@@ -49,44 +52,60 @@ sub new
# Assign function parameters, defaults, and log debug info
(
my $strOperation,
$self->{strFileName}
$self->{strFileName},
my $bCached
) =
logDebugParam
(
OP_DOC_NEW, \@_,
{name => 'strFileName', required => false}
{name => 'strFileName', required => false},
{name => 'bCached', default => false}
);
# Load the doc from a file if one has been defined
if (defined($self->{strFileName}))
{
my $oParser = XML::Checker::Parser->new(ErrorContext => 2, Style => 'Tree');
$oParser->set_sgml_search_path(dirname($self->{strFileName}) . '/dtd');
my $oTree;
eval
if ($bCached)
{
local $XML::Checker::FAIL = sub
{
my $iCode = shift;
$self->oDoc = XMLin(fileStringRead($self->{strFileName}));
}
else
{
my $oParser = XML::Checker::Parser->new(ErrorContext => 2, Style => 'Tree');
die XML::Checker::error_string($iCode, @_);
if (-e dirname($0) . '/dtd')
{
$oParser->set_sgml_search_path(dirname($0) . '/dtd')
}
else
{
$oParser->set_sgml_search_path(dirname($0) . '/xml/dtd');
}
my $oTree;
eval
{
local $XML::Checker::FAIL = sub
{
my $iCode = shift;
die XML::Checker::error_string($iCode, @_);
};
$oTree = $oParser->parsefile($self->{strFileName});
};
$oTree = $oParser->parsefile($self->{strFileName});
};
# Report any error that stopped parsing
if ($@)
{
$@ =~ s/at \/.*?$//s; # remove module line number
die "malformed xml in '$self->{strFileName}':\n" . trim($@);
}
# Report any error that stopped parsing
if ($@)
{
$@ =~ s/at \/.*?$//s; # remove module line number
die "malformed xml in '$self->{strFileName}':\n" . trim($@);
# Parse and build the doc
$self->{oDoc} = $self->build($self->parse(${$oTree}[0], ${$oTree}[1]));
}
# Parse and build the doc
$self->{oDoc} = $self->build($self->parse(${$oTree}[0], ${$oTree}[1]));
}
# Else create a blank doc
else
@@ -129,8 +148,8 @@ sub parse
my %oOut;
my $iIndex = 0;
my $bText = $strName eq 'text' || $strName eq 'li' || $strName eq 'code-block' || $strName eq 'p' || $strName eq 'title' ||
$strName eq 'summary';
my $bText = $strName eq 'text' || $strName eq 'li' || $strName eq 'p' || $strName eq 'title' ||
$strName eq 'summary' || $strName eq 'table-cell' || $strName eq 'table-column';
# Store the node name
$oOut{name} = $strName;
@@ -244,7 +263,8 @@ sub build
}
}
if ($$oDoc{name} eq 'p' || $$oDoc{name} eq 'title' || $$oDoc{name} eq 'summary')
if ($$oDoc{name} eq 'p' || $$oDoc{name} eq 'title' || $$oDoc{name} eq 'summary' ||
$$oDoc{name} eq 'table-cell' || $$oDoc{name} eq 'table-column')
{
$$oOut{field}{text} = $oDoc;
}
@@ -255,7 +275,7 @@ sub build
my $oSub = $$oDoc{children}[$iIndex];
my $strName = $$oSub{name};
if ($strName eq 'text' || $strName eq 'code-block')
if ($strName eq 'text')
{
$$oOut{field}{text} = $oSub;
}
@@ -351,6 +371,18 @@ sub nodeGet
return $self->nodeGetById(shift, undef, shift);
}
####################################################################################################################################
# nodeTest
#
# Test that a node exists
####################################################################################################################################
sub nodeTest
{
my $self = shift;
return defined($self->nodeGetById(shift, undef, false));
}
####################################################################################################################################
# nodeAdd
#
@@ -470,6 +502,55 @@ sub nodeList
);
}
####################################################################################################################################
# nodeRemove
#
# Remove a child node.
####################################################################################################################################
sub nodeRemove
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oChildRemove
) =
logDebugParam
(
OP_DOC_NODE_REMOVE, \@_,
{name => 'oChildRemove', required => false, trace => true}
);
my $bRemove = false;
my $oDoc = $self->{oDoc};
# Error if there are no children
if (!defined($$oDoc{children}))
{
confess &log(ERROR, "node has no children");
}
for (my $iIndex = 0; $iIndex < @{$$oDoc{children}}; $iIndex++)
{
if ($$oDoc{children}[$iIndex] == $oChildRemove->{oDoc})
{
splice(@{$$oDoc{children}}, $iIndex, 1);
$bRemove = true;
last;
}
}
if (!$bRemove)
{
confess &log(ERROR, "child was not found in node");
}
# Return from function and log return values if any
return logDebugReturn($strOperation);
}
####################################################################################################################################
# nameGet
####################################################################################################################################
@@ -539,6 +620,7 @@ sub paramGet
$strOperation,
$strName,
$bRequired,
$strDefault,
$strType
) =
logDebugParam
@@ -546,14 +628,20 @@ sub paramGet
OP_DOC_PARAM_GET, \@_,
{name => 'strName', trace => true},
{name => 'bRequired', default => true, trace => true},
{name => 'strDefault', required => false, trace => true},
{name => 'strType', default => 'param', trace => true}
);
my $strValue = ${$self->{oDoc}}{$strType}{$strName};
if (!defined($strValue) && $bRequired)
if (!defined($strValue))
{
confess "${strType} '${strName}' in required in node '$self->{strName}'";
if ($bRequired)
{
confess "${strType} '${strName}' in required in node '$self->{strName}'";
}
$strValue = $strDefault;
}
# Return from function and log return values if any
@@ -564,6 +652,51 @@ sub paramGet
);
}
####################################################################################################################################
# paramTest
#
# Test that a parameter exists or has a certain value.
####################################################################################################################################
sub paramTest
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strName,
$strExpectedValue,
$strType
) =
logDebugParam
(
OP_DOC_PARAM_TEST, \@_,
{name => 'strName', trace => true},
{name => 'strExpectedValue', required => false, trace => true},
{name => 'strType', default => 'param', trace => true}
);
my $bResult = true;
my $strValue = $self->paramGet($strName, false, undef, $strType);
if (!defined($strValue))
{
$bResult = false;
}
elsif (defined($strExpectedValue) && $strValue ne $strExpectedValue)
{
$bResult = false;
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'bResult', value => $bResult, trace => true}
);
}
####################################################################################################################################
# paramSet
#
@@ -585,7 +718,7 @@ sub paramSet
(
OP_DOC_PARAM_SET, \@_,
{name => 'strName', trace => true},
{name => 'strValue', trace => true},
{name => 'strValue', required => false, trace => true},
{name => 'strType', default => 'param', trace => true}
);
@@ -604,7 +737,19 @@ sub fieldGet
{
my $self = shift;
return $self->paramGet(shift, shift, 'field');
return $self->paramGet(shift, shift, shift, 'field');
}
####################################################################################################################################
# fieldTest
#
# Test if a field exists.
####################################################################################################################################
sub fieldTest
{
my $self = shift;
return $self->paramTest(shift, shift, 'field');
}
####################################################################################################################################
@@ -616,7 +761,7 @@ sub textGet
{
my $self = shift;
return $self->nodeBless($self->paramGet('text', shift, 'field'));
return $self->nodeBless($self->paramGet('text', shift, shift, 'field'));
}
####################################################################################################################################

View File

@@ -235,18 +235,28 @@ sub helpDataWrite
my $self = shift;
# Assign function parameters, defaults, and log debug info
my $strOperation = logDebugParam(OP_DOC_CONFIG_HELP_DATA_WRITE);
my
(
$strOperation,
$oManifest
) =
logDebugParam
(
OP_DOC_CONFIG_HELP_DATA_WRITE, \@_,
{name => 'oManifest'}
);
# Internal function used to format text by quoting it and splitting lines so it looks good in the module.
sub formatText
{
my $oManifest = shift;
my $oDocRender = shift;
my $oText = shift;
my $iIndent = shift;
my $iLength = shift;
# Split the string into lines for processing
my @stryText = split("\n", trim($oDocRender->processText($oText)));
my @stryText = split("\n", trim($oManifest->variableReplace($oDocRender->processText($oText))));
my $strText;
my $iIndex = 0;
@@ -321,9 +331,9 @@ sub helpDataWrite
(defined($$oOptionHash{&CONFIG_HELP_SECTION}) ? ' ' . &CONFIG_HELP_SECTION .
' => \'' . $$oOptionHash{&CONFIG_HELP_SECTION} . "',\n" : '') .
' ' . &CONFIG_HELP_SUMMARY . " =>\n" .
formatText($self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_SUMMARY}, 16, 112) . ",\n" .
formatText($oManifest, $self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_SUMMARY}, 16, 112) . ",\n" .
' ' . &CONFIG_HELP_DESCRIPTION . " =>\n" .
formatText($self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_DESCRIPTION}, 16, 112) . "\n" .
formatText($oManifest, $self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_DESCRIPTION}, 16, 112) . "\n" .
" }";
}
@@ -346,9 +356,9 @@ sub helpDataWrite
" '${strCommand}' =>\n" .
" {\n" .
' ' . &CONFIG_HELP_SUMMARY . " =>\n" .
formatText($self->{oDocRender}, $$oCommandHash{&CONFIG_HELP_SUMMARY}, 16, 112) . ",\n" .
formatText($oManifest, $self->{oDocRender}, $$oCommandHash{&CONFIG_HELP_SUMMARY}, 16, 112) . ",\n" .
' ' . &CONFIG_HELP_DESCRIPTION . " =>\n" .
formatText($self->{oDocRender}, $$oCommandHash{&CONFIG_HELP_DESCRIPTION}, 16, 112) . ",\n" .
formatText($oManifest, $self->{oDocRender}, $$oCommandHash{&CONFIG_HELP_DESCRIPTION}, 16, 112) . ",\n" .
"\n";
# Iterate options
@@ -385,9 +395,9 @@ sub helpDataWrite
" '${strOption}' =>\n" .
" {\n" .
' ' . &CONFIG_HELP_SUMMARY . " =>\n" .
formatText($self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_SUMMARY}, 24, 104) . ",\n" .
formatText($oManifest, $self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_SUMMARY}, 24, 104) . ",\n" .
' ' . &CONFIG_HELP_DESCRIPTION . " =>\n" .
formatText($self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_DESCRIPTION}, 24, 104) . "\n" .
formatText($oManifest, $self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_DESCRIPTION}, 24, 104) . "\n" .
" }";
$bExtraLinefeed = true;
@@ -612,7 +622,6 @@ sub helpCommandDocGet
return $oOption, $strSection;
}
# Working variables
my $oConfigHash = $self->{oConfigHash};
my $oOperationDoc = $self->{oDoc}->nodeGet('operation');

View File

@@ -0,0 +1,621 @@
####################################################################################################################################
# DOC EXECUTE MODULE
####################################################################################################################################
package BackRestDoc::Common::DocExecute;
use parent 'BackRestDoc::Common::DocRender';
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use Exporter qw(import);
our @EXPORT = qw();
use File::Basename qw(dirname);
use Storable qw(dclone);
use lib dirname($0) . '/../lib';
use BackRest::Common::Ini;
use BackRest::Common::Log;
use BackRest::Common::String;
use BackRest::FileCommon;
use lib dirname($0) . '/../test/lib';
use BackRestTest::Common::ExecuteTest;
use BackRestTest::Common::HostTest;
use BackRestDoc::Common::DocManifest;
####################################################################################################################################
# Operation constants
####################################################################################################################################
use constant OP_DOC_EXECUTE => 'DocExecute';
use constant OP_DOC_EXECUTE_BACKREST_CONFIG => OP_DOC_EXECUTE . '->backrestConfig';
use constant OP_DOC_EXECUTE_EXECUTE => OP_DOC_EXECUTE . '->execute';
use constant OP_DOC_EXECUTE_NEW => OP_DOC_EXECUTE . '->new';
use constant OP_DOC_EXECUTE_POSTGRES_CONFIG => OP_DOC_EXECUTE . '->postresConfig';
use constant OP_DOC_EXECUTE_SECTION_CHILD_PROCESS => OP_DOC_EXECUTE . '->sectionChildProcess';
####################################################################################################################################
# CONSTRUCTOR
####################################################################################################################################
sub new
{
my $class = shift; # Class name
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strType,
$oManifest,
$strRenderOutKey,
$bExe
) =
logDebugParam
(
OP_DOC_EXECUTE_NEW, \@_,
{name => 'strType'},
{name => 'oManifest'},
{name => 'strRenderOutKey'},
{name => 'bExe'}
);
# Create the class hash
my $self = $class->SUPER::new($strType, $oManifest, $strRenderOutKey);
bless $self, $class;
$self->{bExe} = $bExe;
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'self', value => $self}
);
}
####################################################################################################################################
# execute
####################################################################################################################################
sub execute
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oSection,
$strHostName,
$oCommand,
$iIndent
) =
logDebugParam
(
OP_DOC_EXECUTE_EXECUTE, \@_,
{name => 'oSection'},
{name => 'strHostName'},
{name => 'oCommand'},
{name => 'iIndent', default => 1}
);
# Working variables
my $strCommand;
my $strOutput;
if ($oCommand->fieldTest('actual-command'))
{
$strCommand = $oCommand->fieldGet('actual-command');
$strOutput = $oCommand->fieldGet('actual-output', false);
}
else
{
# Command variables
$strCommand = trim($oCommand->fieldGet('exe-cmd'));
my $strUser = $oCommand->paramGet('user', false, 'postgres');
my $bExeOutput = $oCommand->paramTest('output', 'y');
my $strVariableKey = $oCommand->paramGet('variable-key', false);
my $iExeExpectedError = $oCommand->paramGet('err-expect', false);
$strCommand = $self->{oManifest}->variableReplace(
(defined($strUser) && $strUser eq 'vagrant' ? '' :
('sudo ' . ($strUser eq 'root' ? '' : "-u ${strUser} "))) . $strCommand);
# Add continuation chars and proper spacing
$strCommand =~ s/[ ]*\n[ ]*/ \\\n /smg;
if (!$oCommand->paramTest('show', 'n') && $self->{bExe} && $self->isRequired($oSection))
{
# Make sure that no lines are greater than 80 chars
foreach my $strLine (split("\n", $strCommand))
{
if (length(trim($strLine)) > 80)
{
confess &log(ERROR, "command has a line > 80 characters:\n${strCommand}");
}
}
}
&log(DEBUG, (' ' x $iIndent) . "execute: $strCommand");
if (!$oCommand->paramTest('skip', 'y'))
{
if ($self->{bExe} && $self->isRequired($oSection))
{
# Check that the host is valid
my $oHost = $self->{host}{$strHostName};
if (!defined($oHost))
{
confess &log(ERROR, "cannot execute on host ${strHostName} because the host does not exist");
}
my $oExec = $oHost->execute($strCommand,
{iExpectedExitStatus => $iExeExpectedError,
bSuppressError => $oCommand->paramTest('err-suppress', 'y'),
iRetrySeconds => $oCommand->paramGet('retry', false)});
$oExec->begin();
$oExec->end();
if ($bExeOutput && defined($oExec->{strOutLog}) && $oExec->{strOutLog} ne '')
{
$strOutput = $oExec->{strOutLog};
# Trim off extra linefeeds before and after
$strOutput =~ s/^\n+|\n$//g;
if ($strCommand =~ / pg\_backrest /)
{
$strOutput =~ s/^ //smg;
$strOutput =~ s/^[0-9]{4}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9]\.[0-9]{3} T[0-9]{2} //smg;
}
}
if (defined($iExeExpectedError))
{
$strOutput .= trim($oExec->{strErrorLog});
}
# Output is assigned to a var
if (defined($strVariableKey))
{
$self->{oManifest}->variableSet($strVariableKey, trim($oExec->{strOutLog}));
}
elsif (!$oCommand->paramTest('filter', 'n') && $bExeOutput && defined($strOutput))
{
my $strHighLight = $self->{oManifest}->variableReplace($oCommand->fieldGet('exe-highlight', false));
if (!defined($strHighLight))
{
confess &log(ERROR, 'filter requires highlight definition: ' . $strCommand);
}
my $iFilterContext = $oCommand->paramGet('filter-context', false, 2);
my @stryOutput = split("\n", $strOutput);
undef($strOutput);
# my $iFiltered = 0;
my $iLastOutput = -1;
for (my $iIndex = 0; $iIndex < @stryOutput; $iIndex++)
{
if ($stryOutput[$iIndex] =~ /$strHighLight/)
{
# Determine the first line to output
my $iFilterFirst = $iIndex - $iFilterContext;
# Don't go past the beginning
$iFilterFirst = $iFilterFirst < 0 ? 0 : $iFilterFirst;
# Don't repeat lines that have already been output
$iFilterFirst = $iFilterFirst <= $iLastOutput ? $iLastOutput + 1 : $iFilterFirst;
# Determine the last line to output
my $iFilterLast = $iIndex + $iFilterContext;
# Don't got past the end
$iFilterLast = $iFilterLast >= @stryOutput ? @stryOutput -1 : $iFilterLast;
# Mark filtered lines if any
if ($iFilterFirst > $iLastOutput + 1)
{
my $iFiltered = $iFilterFirst - ($iLastOutput + 1);
if ($iFiltered > 1)
{
$strOutput .= (defined($strOutput) ? "\n" : '') .
" [filtered ${iFiltered} lines of output]";
}
else
{
$iFilterFirst -= 1;
}
}
# Output the lines
for (my $iOutputIndex = $iFilterFirst; $iOutputIndex <= $iFilterLast; $iOutputIndex++)
{
$strOutput .= (defined($strOutput) ? "\n" : '') . $stryOutput[$iOutputIndex];
}
$iLastOutput = $iFilterLast;
}
}
if (@stryOutput - 1 > $iLastOutput + 1)
{
my $iFiltered = (@stryOutput - 1) - ($iLastOutput + 1);
if ($iFiltered > 1)
{
$strOutput .= (defined($strOutput) ? "\n" : '') .
" [filtered ${iFiltered} lines of output]";
}
else
{
$strOutput .= (defined($strOutput) ? "\n" : '') . $stryOutput[@stryOutput - 1];
}
}
}
}
elsif ($bExeOutput)
{
$strOutput = 'Output suppressed for testing';
}
}
if (defined($strVariableKey) && !defined($self->{oManifest}->variableGet($strVariableKey)))
{
$self->{oManifest}->variableSet($strVariableKey, '[Test Variable]');
}
$oCommand->fieldSet('actual-command', $strCommand);
$oCommand->fieldSet('actual-output', $strOutput);
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'strCommand', value => $strCommand, trace => true},
{name => 'strOutput', value => $strOutput, trace => true}
);
}
####################################################################################################################################
# backrestConfig
####################################################################################################################################
sub backrestConfig
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oSection,
$oConfig,
$iDepth
) =
logDebugParam
(
OP_DOC_EXECUTE_BACKREST_CONFIG, \@_,
{name => 'oSection'},
{name => 'oConfig'},
{name => 'iDepth'}
);
# Working variables
my $strFile;
my $strConfig;
if ($oConfig->fieldTest('actual-file'))
{
$strFile = $oConfig->fieldGet('actual-file');
$strConfig = $oConfig->fieldGet('actual-config');
}
else
{
# Get filename
$strFile = $self->{oManifest}->variableReplace($oConfig->paramGet('file'));
&log(DEBUG, (' ' x $iDepth) . 'process backrest config: ' . $strFile);
if ($self->{bExe} && $self->isRequired($oSection))
{
# Check that the host is valid
my $strHostName = $self->{oManifest}->variableReplace($oConfig->paramGet('host'));
my $oHost = $self->{host}{$strHostName};
if (!defined($oHost))
{
confess &log(ERROR, "cannot configure backrest on host ${strHostName} because the host does not exist");
}
# Reset all options
if ($oConfig->paramTest('reset', 'y'))
{
delete(${$self->{config}}{$strHostName}{$strFile})
}
foreach my $oOption ($oConfig->nodeList('backrest-config-option'))
{
my $strSection = $oOption->paramGet('section');
my $strKey = $oOption->paramGet('key');
my $strValue;
if (!$oOption->paramTest('remove', 'y'))
{
$strValue = $self->{oManifest}->variableReplace(trim($oOption->valueGet(false)));
}
if (!defined($strValue))
{
delete(${$self->{config}}{$strHostName}{$strFile}{$strSection}{$strKey});
if (keys(${$self->{config}}{$strHostName}{$strFile}{$strSection}) == 0)
{
delete(${$self->{config}}{$strHostName}{$strFile}{$strSection});
}
&log(DEBUG, (' ' x ($iDepth + 1)) . "reset ${strSection}->${strKey}");
}
else
{
${$self->{config}}{$strHostName}{$strFile}{$strSection}{$strKey} = $strValue;
&log(DEBUG, (' ' x ($iDepth + 1)) . "set ${strSection}->${strKey} = ${strValue}");
}
}
my $strLocalFile = "/home/vagrant/data/db-master/etc/pg_backrest.conf";
# Save the ini file
iniSave($strLocalFile, $self->{config}{$strHostName}{$strFile}, true);
$strConfig = fileStringRead($strLocalFile);
$oHost->copyTo($strLocalFile, $strFile, $oConfig->paramGet('owner', false, 'postgres:postgres'), '640');
}
else
{
$strConfig = 'Config suppressed for testing';
}
$oConfig->fieldSet('actual-file', $strFile);
$oConfig->fieldSet('actual-config', $strConfig);
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'strFile', value => $strFile, trace => true},
{name => 'strConfig', value => $strConfig, trace => true},
{name => 'bShow', value => $oConfig->paramTest('show', 'n') ? false : true, trace => true}
);
}
####################################################################################################################################
# postgresConfig
####################################################################################################################################
sub postgresConfig
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oSection,
$oConfig,
$iDepth
) =
logDebugParam
(
OP_DOC_EXECUTE_POSTGRES_CONFIG, \@_,
{name => 'oSection'},
{name => 'oConfig'},
{name => 'iDepth'}
);
# Working variables
my $strFile;
my $strConfig;
if ($oConfig->fieldTest('actual-file'))
{
$strFile = $oConfig->fieldGet('actual-file');
$strConfig = $oConfig->fieldGet('actual-config');
}
else
{
# Get filename
$strFile = $self->{oManifest}->variableReplace($oConfig->paramGet('file'));
if ($self->{bExe} && $self->isRequired($oSection))
{
# Check that the host is valid
my $strHostName = $self->{oManifest}->variableReplace($oConfig->paramGet('host'));
my $oHost = $self->{host}{$strHostName};
if (!defined($oHost))
{
confess &log(ERROR, "cannot configure postgres on host ${strHostName} because the host does not exist");
}
my $strLocalFile = '/home/vagrant/data/db-master/etc/postgresql.conf';
$oHost->copyFrom($strFile, $strLocalFile);
if (!defined(${$self->{'pg-config'}}{$strHostName}{$strFile}{base}) && $self->{bExe})
{
${$self->{'pg-config'}}{$strHostName}{$strFile}{base} = fileStringRead($strLocalFile);
}
my $oConfigHash = $self->{'pg-config'}{$strHostName}{$strFile};
my $oConfigHashNew;
if (!defined($$oConfigHash{old}))
{
$oConfigHashNew = {};
$$oConfigHash{old} = {}
}
else
{
$oConfigHashNew = dclone($$oConfigHash{old});
}
&log(DEBUG, (' ' x $iDepth) . 'process postgres config: ' . $strFile);
foreach my $oOption ($oConfig->nodeList('postgres-config-option'))
{
my $strKey = $oOption->paramGet('key');
my $strValue = $self->{oManifest}->variableReplace(trim($oOption->valueGet()));
if ($strValue eq '')
{
delete($$oConfigHashNew{$strKey});
&log(DEBUG, (' ' x ($iDepth + 1)) . "reset ${strKey}");
}
else
{
$$oConfigHashNew{$strKey} = $strValue;
&log(DEBUG, (' ' x ($iDepth + 1)) . "set ${strKey} = ${strValue}");
}
}
# Generate config text
foreach my $strKey (sort(keys(%$oConfigHashNew)))
{
if (defined($strConfig))
{
$strConfig .= "\n";
}
$strConfig .= "${strKey} = $$oConfigHashNew{$strKey}";
}
# Save the conf file
if ($self->{bExe})
{
fileStringWrite($strLocalFile, $$oConfigHash{base} .
(defined($strConfig) ? "\n# pgBackRest Configuration\n${strConfig}\n" : ''));
$oHost->copyTo($strLocalFile, $strFile, 'postgres:postgres', '640');
}
$$oConfigHash{old} = $oConfigHashNew;
}
else
{
$strConfig = 'Config suppressed for testing';
}
$oConfig->fieldSet('actual-file', $strFile);
$oConfig->fieldSet('actual-config', $strConfig);
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'strFile', value => $strFile, trace => true},
{name => 'strConfig', value => $strConfig, trace => true},
{name => 'bShow', value => $oConfig->paramTest('show', 'n') ? false : true, trace => true}
);
}
####################################################################################################################################
# sectionChildProcesss
####################################################################################################################################
sub sectionChildProcess
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oSection,
$oChild,
$iDepth
) =
logDebugParam
(
OP_DOC_EXECUTE_SECTION_CHILD_PROCESS, \@_,
{name => 'oSection'},
{name => 'oChild'},
{name => 'iDepth'}
);
&log(DEBUG, (' ' x ($iDepth + 1)) . 'process child: ' . $oChild->nameGet());
# Execute a command
if ($oChild->nameGet() eq 'host-add')
{
if ($self->{bExe} && $self->isRequired($oSection) && !$oChild->paramTest('created', true))
{
my $strName = $self->{oManifest}->variableReplace($oChild->paramGet('name'));
my $strUser = $self->{oManifest}->variableReplace($oChild->paramGet('user'));
my $strImage = $self->{oManifest}->variableReplace($oChild->paramGet('image'));
my $strOS = $self->{oManifest}->variableReplace($oChild->paramGet('os', false));
my $strMount = $self->{oManifest}->variableReplace($oChild->paramGet('mount', false));
if (defined($self->{host}{$strName}))
{
confess &log(ERROR, 'cannot add host ${strName} because the host already exists');
}
my $oHost = new BackRestTest::Common::HostTest($strName, $strImage, $strUser, $strOS, $strMount);
$self->{host}{$strName} = $oHost;
$self->{oManifest}->variableSet("host-${strName}-ip", $oHost->{strIP});
# Execute cleanup commands
foreach my $oExecute ($oChild->nodeList('execute'))
{
$self->execute($oSection, $strName, $oExecute, $iDepth + 1);
}
$oHost->executeSimple("sh -c 'echo \"\" >> /etc/hosts\'");
$oHost->executeSimple("sh -c 'echo \"# Test Hosts\" >> /etc/hosts'");
# Add all other host IPs to this host
foreach my $strOtherHostName (sort(keys($self->{host})))
{
if ($strOtherHostName ne $strName)
{
my $oOtherHost = $self->{host}{$strOtherHostName};
$oHost->executeSimple("sh -c 'echo \"$oOtherHost->{strIP} ${strOtherHostName}\" >> /etc/hosts'");
}
}
# Add this host IP to all other hosts
foreach my $strOtherHostName (sort(keys($self->{host})))
{
if ($strOtherHostName ne $strName)
{
my $oOtherHost = $self->{host}{$strOtherHostName};
$oOtherHost->executeSimple("sh -c 'echo \"$oHost->{strIP} ${strName}\" >> /etc/hosts'");
}
}
$oChild->paramSet('created', true);
}
}
# Skip children that have already been processed and error on others
elsif ($oChild->nameGet() ne 'title')
{
confess &log(ASSERT, 'unable to process child type ' . $oChild->nameGet());
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation
);
}
1;

View File

@@ -0,0 +1,536 @@
####################################################################################################################################
# DOC MANIFEST MODULE
####################################################################################################################################
package BackRestDoc::Common::DocManifest;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use Cwd qw(abs_path);
use Exporter qw(import);
our @EXPORT = qw();
use File::Basename qw(dirname);
use Scalar::Util qw(blessed);
use lib dirname($0) . '/../lib';
use BackRest::Common::Log;
use BackRest::Common::String;
use BackRest::FileCommon;
####################################################################################################################################
# Operation constants
####################################################################################################################################
use constant OP_DOC_MANIFEST => 'DocManifest';
use constant OP_DOC_MANIFEST_NEW => OP_DOC_MANIFEST . '->new';
use constant OP_DOC_MANIFEST_RENDER_GET => OP_DOC_MANIFEST . '->renderGet';
use constant OP_DOC_MANIFEST_RENDER_LIST => OP_DOC_MANIFEST . '->renderList';
use constant OP_DOC_MANIFEST_RENDER_OUT_GET => OP_DOC_MANIFEST . '->renderOutGet';
use constant OP_DOC_MANIFEST_RENDER_OUT_LIST => OP_DOC_MANIFEST . '->renderOutList';
use constant OP_DOC_MANIFEST_SOURCE_GET => OP_DOC_MANIFEST . '->sourceGet';
use constant OP_DOC_MANIFEST_VARIABLE_LIST_PARSE => OP_DOC_MANIFEST . '->variableListParse';
####################################################################################################################################
# File constants
####################################################################################################################################
use constant FILE_MANIFEST => 'manifest.xml';
####################################################################################################################################
# Render constants
####################################################################################################################################
use constant RENDER => 'render';
use constant RENDER_FILE => 'file';
use constant RENDER_TYPE => 'type';
use constant RENDER_TYPE_HTML => 'html';
push @EXPORT, qw(RENDER_TYPE_HTML);
use constant RENDER_TYPE_PDF => 'pdf';
push @EXPORT, qw(RENDER_TYPE_PDF);
####################################################################################################################################
# CONSTRUCTOR
####################################################################################################################################
sub new
{
my $class = shift; # Class name
# Create the class hash
my $self = {};
bless $self, $class;
# Assign function parameters, defaults, and log debug info
(
my $strOperation,
$self->{stryKeyword},
$self->{stryRequire},
my $oVariableOverride,
$self->{strDocPath}
) =
logDebugParam
(
OP_DOC_MANIFEST_NEW, \@_,
{name => 'stryKeyword'},
{name => 'stryRequire'},
{name => 'oVariableOverride', required => false},
{name => 'strDocPath', required => false},
);
# Set the base path if it was not passed in
if (!defined($self->{strDocPath}))
{
$self->{strDocPath} = abs_path(dirname($0));
}
# Load the manifest
$self->{oManifestXml} = new BackRestDoc::Common::Doc("$self->{strDocPath}/manifest.xml");
# Iterate the sources
$self->{oManifest} = {};
foreach my $oSource ($self->{oManifestXml}->nodeGet('source-list')->nodeList('source'))
{
my $oSourceHash = {};
my $strKey = $oSource->paramGet('key');
logDebugMisc
(
$strOperation, 'load source',
{name => 'strKey', value => $strKey}
);
$$oSourceHash{doc} = new BackRestDoc::Common::Doc("$self->{strDocPath}/xml/${strKey}.xml");
# Read variables from source
$self->variableListParse($$oSourceHash{doc}->nodeGet('variable-list', false), $oVariableOverride);
${$self->{oManifest}}{source}{$strKey} = $oSourceHash;
}
# Iterate the renderers
foreach my $oRender ($self->{oManifestXml}->nodeGet('render-list')->nodeList('render'))
{
my $oRenderHash = {};
my $strType = $oRender->paramGet(RENDER_TYPE);
# Only one instance of each render type can be defined
if (defined(${$self->{oManifest}}{&RENDER}{$strType}))
{
confess &log(ERROR, "render ${strType} has already been defined");
}
# Get the file param
$${oRenderHash}{file} = $oRender->paramGet(RENDER_FILE, false);
logDebugMisc
(
$strOperation, ' load render',
{name => 'strType', value => $strType},
{name => 'strFile', value => $${oRenderHash}{file}}
);
# Error if file is set and render type is not pdf
if (defined($${oRenderHash}{file}) && $strType ne RENDER_TYPE_PDF)
{
confess &log(ERROR, 'only the pdf render type can have file set')
}
# Iterate the render sources
foreach my $oRenderOut ($oRender->nodeList('render-source'))
{
my $oRenderOutHash = {};
my $strKey = $oRenderOut->paramGet('key');
my $strSource = $oRenderOut->paramGet('source', false, $strKey);
$$oRenderOutHash{source} = $strSource;
# Get the filename if this is a pdf
$$oRenderOutHash{menu} = $oRenderOut->paramGet('menu', false);
if (defined($$oRenderOutHash{menu}) && $strType ne RENDER_TYPE_HTML)
{
confess &log(ERROR, 'only the html render type can have menu set')
}
logDebugMisc
(
$strOperation, ' load render source',
{name => 'strKey', value => $strKey},
{name => 'strSource', value => $strSource},
{name => 'strMenu', value => $${oRenderOutHash}{menu}}
);
$${oRenderHash}{out}{$strKey} = $oRenderOutHash;
}
${$self->{oManifest}}{render}{$strType} = $oRenderHash;
}
# Read variables from manifest
$self->variableListParse($self->{oManifestXml}->nodeGet('variable-list', false), $oVariableOverride);
# use Data::Dumper; confess Dumper($self->{oVariable});
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'self', value => $self}
);
}
####################################################################################################################################
# isBackRest
#
# Until all the backrest specific code can be abstracted, this function will identify when BackRest docs are being built.
####################################################################################################################################
sub isBackRest
{
my $self = shift;
return($self->variableTest('project-exe', 'pg_backrest'));
}
####################################################################################################################################
# keywordMatch
#
# See if all the keywords were on the command line.
####################################################################################################################################
sub keywordMatch
{
my $self = shift;
my $strKeywordRequired = shift;
if (defined($strKeywordRequired))
{
for my $strKeyword (split(',', $strKeywordRequired))
{
$strKeyword = trim($strKeyword);
if (!grep(/^$strKeyword$/, @{$self->{stryKeyword}}))
{
return false;
}
}
}
return true;
}
####################################################################################################################################
# variableListParse
#
# Parse a variable list and store variables.
####################################################################################################################################
sub variableListParse
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oVariableList,
$oVariableOverride
) =
logDebugParam
(
OP_DOC_MANIFEST_VARIABLE_LIST_PARSE, \@_,
{name => '$oVariableList', required => false},
{name => '$oVariableOverride', required => false}
);
if (defined($oVariableList))
{
foreach my $oVariable ($oVariableList->nodeList('variable'))
{
if ($self->keywordMatch($oVariable->paramGet('keyword', false)))
{
my $strKey = $oVariable->paramGet('key');
my $strValue = $oVariable->valueGet();
if ($oVariable->paramTest('eval', 'y'))
{
$strValue = eval $strValue;
if ($@)
{
confess &log(ERROR, "unable to evaluate ${strKey}: $@\n" . $oVariable->valueGet());
}
}
$self->variableSet($strKey, defined($$oVariableOverride{$strKey}) ? $$oVariableOverride{$strKey} : $strValue);
logDebugMisc
(
$strOperation, ' load variable',
{name => 'strKey', value => $strKey},
{name => 'strValue', value => $strValue}
);
}
}
}
# Return from function and log return values if any
return logDebugReturn($strOperation);
}
####################################################################################################################################
# variableReplace
#
# Replace variables in the string.
####################################################################################################################################
sub variableReplace
{
my $self = shift;
my $strBuffer = shift;
my $strType = shift;
if (!defined($strBuffer))
{
return undef;
}
foreach my $strName (sort(keys(%{$self->{oVariable}})))
{
my $strValue = $self->{oVariable}{$strName};
$strBuffer =~ s/\{\[$strName\]\}/$strValue/g;
}
if (defined($strType) && $strType eq 'latex')
{
$strBuffer =~ s/\\\_/\_/g;
$strBuffer =~ s/\_/\\\_/g;
$strBuffer =~ s/\\\#/\#/g;
$strBuffer =~ s/\#/\\\#/g;
}
return $strBuffer;
}
####################################################################################################################################
# variableSet
#
# Set a variable to be replaced later.
####################################################################################################################################
sub variableSet
{
my $self = shift;
my $strKey = shift;
my $strValue = shift;
my $bForce = shift;
if (defined(${$self->{oVariable}}{$strKey}) && (!defined($bForce) || !$bForce))
{
confess &log(ERROR, "${strKey} variable is already defined");
}
${$self->{oVariable}}{$strKey} = $self->variableReplace($strValue);
}
####################################################################################################################################
# variableGet
#
# Get the current value of a variable.
####################################################################################################################################
sub variableGet
{
my $self = shift;
my $strKey = shift;
return ${$self->{oVariable}}{$strKey};
}
####################################################################################################################################
# variableTest
#
# Test that a variable is defined or has an expected value.
####################################################################################################################################
sub variableTest
{
my $self = shift;
my $strKey = shift;
my $strExpectedValue = shift;
# Get the variable
my $strValue = ${$self->{oVariable}}{$strKey};
# Return false if it is not defined
if (!defined($strValue))
{
return false;
}
# Return false if it does not equal the expected value
if (defined($strExpectedValue) && $strValue ne $strExpectedValue)
{
return false;
}
return true;
}
####################################################################################################################################
# sourceGet
####################################################################################################################################
sub sourceGet
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strSource
) =
logDebugParam
(
OP_DOC_MANIFEST_SOURCE_GET, \@_,
{name => 'strSource', trace => true}
);
if (!defined(${$self->{oManifest}}{source}{$strSource}))
{
confess &log(ERROR, "source ${strSource} does not exist");
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'oSource', value => ${$self->{oManifest}}{source}{$strSource}}
);
}
####################################################################################################################################
# renderList
####################################################################################################################################
sub renderList
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my ($strOperation) = logDebugParam(OP_DOC_MANIFEST_RENDER_LIST);
# Check that the render output exists
my @stryRender;
if (defined(${$self->{oManifest}}{render}))
{
@stryRender = sort(keys(${$self->{oManifest}}{render}));
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'stryRender', value => \@stryRender}
);
}
####################################################################################################################################
# renderGet
####################################################################################################################################
sub renderGet
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strType
) =
logDebugParam
(
OP_DOC_MANIFEST_RENDER_GET, \@_,
{name => 'strType', trace => true}
);
# Check that the render exists
if (!defined(${$self->{oManifest}}{render}{$strType}))
{
confess &log(ERROR, "render type ${strType} does not exist");
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'oRenderOut', value => ${$self->{oManifest}}{render}{$strType}}
);
}
####################################################################################################################################
# renderOutList
####################################################################################################################################
sub renderOutList
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strType
) =
logDebugParam
(
OP_DOC_MANIFEST_RENDER_OUT_LIST, \@_,
{name => 'strType'}
);
# Check that the render output exists
my @stryRenderOut;
if (defined(${$self->{oManifest}}{render}{$strType}))
{
@stryRenderOut = sort(keys(${$self->{oManifest}}{render}{$strType}{out}));
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'stryRenderOut', value => \@stryRenderOut}
);
}
####################################################################################################################################
# renderOutGet
####################################################################################################################################
sub renderOutGet
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strType,
$strKey
) =
logDebugParam
(
OP_DOC_MANIFEST_RENDER_OUT_GET, \@_,
{name => 'strType', trace => true},
{name => 'strKey', trace => true}
);
# use Data::Dumper; print Dumper(${$self->{oManifest}}{render});
if (!defined(${$self->{oManifest}}{render}{$strType}{out}{$strKey}))
{
confess &log(ERROR, "render out ${strKey} does not exist");
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'oRenderOut', value => ${$self->{oManifest}}{render}{$strType}{out}{$strKey}}
);
}
1;

View File

@@ -15,6 +15,8 @@ use lib dirname($0) . '/../lib';
use BackRest::Common::Log;
use BackRest::Common::String;
use BackRestDoc::Common::DocManifest;
####################################################################################################################################
# Operation constants
####################################################################################################################################
@@ -26,8 +28,6 @@ use constant OP_DOC_RENDER_PROCESS_TEXT => OP_DOC_RE
use constant OP_DOC_RENDER_NEW => OP_DOC_RENDER . '->new';
use constant OP_DOC_RENDER_SAVE => OP_DOC_RENDER . '->save';
# use HTML::HTML5::Builder qw[:standard JQUERY];
####################################################################################################################################
# Render tags for various output types
####################################################################################################################################
@@ -35,9 +35,10 @@ my $oRenderTag =
{
'markdown' =>
{
'quote' => ['"', '"'],
'b' => ['**', '**'],
'i' => ['_', '_'],
'bi' => ['_**', '**_'],
# 'bi' => ['_**', '**_'],
'ul' => ["\n", "\n"],
'ol' => ["\n", "\n"],
'li' => ['- ', "\n"],
@@ -48,17 +49,18 @@ my $oRenderTag =
'param' => ['`', '`'],
'setting' => ['`', '`'],
'code' => ['`', '`'],
'code-block' => ['```', '```'],
'exe' => [undef, ''],
# 'code-block' => ['```', '```'],
# 'exe' => [undef, ''],
'backrest' => [undef, ''],
'postgres' => ['PostgreSQL', '']
},
'text' =>
{
'quote' => ['"', '"'],
'b' => ['', ''],
'i' => ['', ''],
'bi' => ['', ''],
# 'bi' => ['', ''],
'ul' => ["\n", "\n"],
'ol' => ["\n", "\n"],
'li' => ['* ', "\n"],
@@ -76,15 +78,47 @@ my $oRenderTag =
'postgres' => ['PostgreSQL', '']
},
'latex' =>
{
'quote' => ['``', '"'],
'b' => ['\textbf{', '}'],
'i' => ['\textit{', '}'],
# 'bi' => ['', ''],
# 'ul' => ["\n", "\n"],
# 'ol' => ["\n", "\n"],
# 'li' => ['* ', "\n"],
'id' => ['\textnormal{\texttt{', '}}'],
'host' => ['\textnormal{\textbf{', '}}'],
'file' => ['\textnormal{\texttt{', '}}'],
'path' => ['\textnormal{\texttt{', '}}'],
'cmd' => ['\textnormal{\texttt{', "}}"],
'user' => ['\textnormal{\texttt{', '}}'],
'br-option' => ['', ''],
# 'param' => ['\texttt{', '}'],
# 'setting' => ['\texttt{', '}'],
'br-option' => ['\textnormal{\texttt{', '}}'],
'br-setting' => ['\textnormal{\texttt{', '}}'],
'pg-option' => ['\textnormal{\texttt{', '}}'],
'pg-setting' => ['\textnormal{\texttt{', '}}'],
'code' => ['\textnormal{\texttt{', '}}'],
# 'code' => ['\texttt{', '}'],
# 'code-block' => ['', ''],
# 'exe' => [undef, ''],
'backrest' => [undef, ''],
'postgres' => ['PostgreSQL', '']
},
'html' =>
{
'quote' => ['<q>', '</q>'],
'b' => ['<b>', '</b>'],
'i' => ['<i>', '</i>'],
'bi' => ['<i><b>', '</b></i>'],
# 'bi' => ['<i><b>', '</b></i>'],
'ul' => ['<ul>', '</ul>'],
'ol' => ['<ol>', '</ol>'],
'li' => ['<li>', '</li>'],
'id' => ['<span class="id">', '</span>'],
'host' => ['<span class="host">', '</span>'],
'file' => ['<span class="file">', '</span>'],
'path' => ['<span class="path">', '</span>'],
'cmd' => ['<span class="cmd">', '</span>'],
@@ -93,9 +127,9 @@ my $oRenderTag =
'br-setting' => ['<span class="br-setting">', '</span>'],
'pg-option' => ['<span class="pg-option">', '</span>'],
'pg-setting' => ['<span class="pg-setting">', '</span>'],
'code' => ['<id>', '</id>'],
'code' => ['<span class="id">', '</span>'],
'code-block' => ['<code-block>', '</code-block>'],
'exe' => ['<id>', '</id>'],
'exe' => [undef, ''],
'setting' => ['<span class="br-setting">', '</span>'], # !!! This will need to be fixed
'backrest' => [undef, ''],
'postgres' => ['<span class="postgres">PostgreSQL</span>', '']
@@ -117,22 +151,76 @@ sub new
(
my $strOperation,
$self->{strType},
$self->{strProjectName},
$self->{strExeName}
$self->{oManifest},
$self->{strRenderOutKey},
) =
logDebugParam
(
OP_DOC_RENDER_NEW, \@_,
{name => 'strType'},
{name => 'strProjectName'},
{name => 'strExeName'}
{name => 'oManifest'},
{name => 'strRenderOutKey', required => false}
);
$$oRenderTag{markdown}{backrest}[0] = $self->{strProjectName};
$$oRenderTag{markdown}{exe}[0] = $self->{strExeName};
$$oRenderTag{text}{backrest}[0] = $self->{strProjectName};
$$oRenderTag{text}{exe}[0] = $self->{strExeName};
$$oRenderTag{html}{backrest}[0] = "<span class=\"backrest\">$self->{strProjectName}</span>";
# Initialize project tags
$$oRenderTag{markdown}{backrest}[0] = "{[project]}";
$$oRenderTag{markdown}{exe}[0] = "{[project-exe]}";
$$oRenderTag{text}{backrest}[0] = "{[project]}";
$$oRenderTag{text}{exe}[0] = "{[project-exe]}";
$$oRenderTag{latex}{backrest}[0] = "{[project]}";
$$oRenderTag{latex}{exe}[0] = "\\textnormal\{\\texttt\{[project-exe]}}\}\}";
$$oRenderTag{html}{backrest}[0] = "<span class=\"backrest\">{[project]}</span>";
$$oRenderTag{html}{exe}[0] = "<span class=\"file\">{[project-exe]}</span>";
if (defined($self->{strRenderOutKey}))
{
# Copy page data to self
my $oRenderOut = $self->{oManifest}->renderOutGet($self->{strType} eq 'latex' ? 'pdf' : $self->{strType}, $self->{strRenderOutKey});
# Get the reference if this is the backrest project
if ($self->{oManifest}->isBackRest())
{
$self->{oReference} = new BackRestDoc::Common::DocConfig(${$self->{oManifest}->sourceGet('reference')}{doc}, $self);
}
if (defined($$oRenderOut{source}) && $$oRenderOut{source} eq 'reference')
{
if ($self->{strRenderOutKey} eq 'configuration')
{
$self->{oDoc} = $self->{oReference}->helpConfigDocGet();
}
elsif ($self->{strRenderOutKey} eq 'command')
{
$self->{oDoc} = $self->{oReference}->helpCommandDocGet();
}
else
{
confess &log(ERROR, "cannot render $self->{strRenderOutKey} from source $$oRenderOut{source}");
}
}
else
{
$self->{oDoc} = ${$self->{oManifest}->sourceGet($self->{strRenderOutKey})}{doc};
}
}
if (defined($self->{strRenderOutKey}))
{
# Build the doc
$self->build($self->{oDoc});
# Get required sections
foreach my $strPath (@{$self->{oManifest}->{stryRequire}})
{
if (defined(${$self->{oSection}}{$strPath}))
{
$self->required($strPath);
}
}
}
# Return from function and log return values if any
return logDebugReturn
@@ -142,6 +230,183 @@ sub new
);
}
####################################################################################################################################
# variableReplace
#
# Replace variables in the string.
####################################################################################################################################
sub variableReplace
{
my $self = shift;
return $self->{oManifest}->variableReplace(shift, $self->{strType});
}
####################################################################################################################################
# variableSet
#
# Set a variable to be replaced later.
####################################################################################################################################
sub variableSet
{
my $self = shift;
return $self->{oManifest}->variableSet(shift, shift);
}
####################################################################################################################################
# variableGet
#
# Get the current value of a variable.
####################################################################################################################################
sub variableGet
{
my $self = shift;
return $self->{oManifest}->variableGet(shift);
}
####################################################################################################################################
# build
#
# Build the section map and perform keyword matching.
####################################################################################################################################
sub build
{
my $self = shift;
my $oNode = shift;
my $oParent = shift;
my $strPath = shift;
# &log(INFO, " node " . $oNode->nameGet());
my $strName = $oNode->nameGet();
if (defined($oParent))
{
if (!$self->{oManifest}->keywordMatch($oNode->paramGet('keyword', false)))
{
my $strDescription;
if (defined($oNode->nodeGet('title', false)))
{
$strDescription = $self->processText($oNode->nodeGet('title')->textGet());
}
&log(DEBUG, " filtered ${strName}" . (defined($strDescription) ? ": ${strDescription}" : ''));
$oParent->nodeRemove($oNode);
}
}
else
{
&log(DEBUG, ' build document');
$self->{oSection} = {};
}
if ($strName eq 'section')
{
if (defined($strPath))
{
$oNode->paramSet('path-parent', $strPath);
}
$strPath .= '/' . $oNode->paramGet('id');
&log(DEBUG, " path ${strPath}");
${$self->{oSection}}{$strPath} = $oNode;
$oNode->paramSet('path', $strPath);
}
# Iterate all nodes
foreach my $oChild ($oNode->nodeList(undef, false))
{
$self->build($oChild, $oNode, $strPath);
}
}
####################################################################################################################################
# required
#
# Build a list of required sections
####################################################################################################################################
sub required
{
my $self = shift;
my $strPath = shift;
my $bDepend = shift;
# If node is not found that means the path is invalid
my $oNode = ${$self->{oSection}}{$strPath};
if (!defined($oNode))
{
confess &log(ERROR, "invalid path ${strPath}");
}
# Only add sections that are listed dependencies
if (!defined($bDepend) || $bDepend)
{
# Match section and all child sections
foreach my $strChildPath (sort(keys($self->{oSection})))
{
if ($strChildPath =~ /^$strPath$/ || $strChildPath =~ /^$strPath\/.*$/)
{
&log(INFO, " require section: ${strChildPath}");
${$self->{oSectionRequired}}{$strChildPath} = true;
}
}
}
# Get the path of the current section's parent
my $strParentPath = $oNode->paramGet('path-parent', false);
if ($oNode->paramTest('depend'))
{
foreach my $strDepend (split(',', $oNode->paramGet('depend')))
{
if ($strDepend !~ /^\//)
{
if (!defined($strParentPath))
{
$strDepend = "/${strDepend}";
}
else
{
$strDepend = "${strParentPath}/${strDepend}";
}
}
$self->required($strDepend, true);
}
}
elsif (defined($strParentPath))
{
$self->required($strParentPath, false);
}
}
####################################################################################################################################
# isRequired
#
# Is it required to execute the section statements?
####################################################################################################################################
sub isRequired
{
my $self = shift;
my $oSection = shift;
if (!defined($self->{oSectionRequired}))
{
return true;
}
my $strPath = $oSection->paramGet('path');
defined(${$self->{oSectionRequired}}{$strPath}) ? true : false;
}
####################################################################################################################################
# process
#
@@ -168,7 +433,6 @@ sub process
);
my $strType = $self->{strType};
my $strProjectName = $self->{strProjectName};
my $strBuffer = "";
my $bList = $oDoc->nameGet() =~ /.*-bullet-list$/;
@@ -211,7 +475,7 @@ sub process
$strBuffer .= 'v' . $oDoc->paramGet('version') . ': ';
}
$strBuffer .= ($iDepth == 1 ? "${strProjectName}<br/>" : '') . $strTitle;
$strBuffer .= ($iDepth == 1 ? "{[project]}<br/>" : '') . $strTitle;
if (defined($oDoc->paramGet('date', false)))
{
@@ -369,6 +633,10 @@ sub processTag
$strBuffer = '<a href="' . $strUrl . '">' . $oTag->valueGet() . '</a>';
}
elsif ($strType eq 'latex')
{
$strBuffer = $oTag->valueGet();
}
else
{
confess "tag link not valid for type ${strType}";
@@ -439,6 +707,11 @@ sub processText
{
if (ref(\$oNode) eq "SCALAR")
{
if ($oNode =~ /\"/)
{
confess &log(ERROR, "unable to process quotes in string (use <quote> instead):\n${oNode}");
}
$strBuffer .= $oNode;
}
else
@@ -462,6 +735,17 @@ sub processText
$strBuffer =~ s/^ //smg;
# }
if ($strType eq 'latex')
{
$strBuffer =~ s/\&mdash\;/---/g;
$strBuffer =~ s/\&lt\;/\</g;
$strBuffer =~ s/\<\=/\$\\leq\$/g;
$strBuffer =~ s/\>\=/\$\\geq\$/g;
# $strBuffer =~ s/\_/\\_/g;
}
$strBuffer = $self->variableReplace($strBuffer);
# Return from function and log return values if any
return logDebugReturn
(