mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-02-07 13:42:41 +02:00
478 lines
14 KiB
Perl
478 lines
14 KiB
Perl
####################################################################################################################################
|
|
# DOC RENDER MODULE
|
|
####################################################################################################################################
|
|
package BackRestDoc::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 lib dirname($0) . '/../lib';
|
|
use BackRest::Common::Log;
|
|
use BackRest::Common::String;
|
|
|
|
####################################################################################################################################
|
|
# Operation constants
|
|
####################################################################################################################################
|
|
use constant OP_DOC_RENDER => 'DocRender';
|
|
|
|
use constant OP_DOC_RENDER_PROCESS => OP_DOC_RENDER . '->process';
|
|
use constant OP_DOC_RENDER_PROCESS_TAG => OP_DOC_RENDER . '->processTag';
|
|
use constant OP_DOC_RENDER_PROCESS_TEXT => OP_DOC_RENDER . '->processText';
|
|
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
|
|
####################################################################################################################################
|
|
my $oRenderTag =
|
|
{
|
|
'markdown' =>
|
|
{
|
|
'b' => ['**', '**'],
|
|
'i' => ['_', '_'],
|
|
'bi' => ['_**', '**_'],
|
|
'ul' => ["\n", ''],
|
|
'ol' => ["\n", ''],
|
|
'li' => ['- ', "\n"],
|
|
'id' => ['`', '`'],
|
|
'file' => ['`', '`'],
|
|
'path' => ['`', '`'],
|
|
'cmd' => ['`', '`'],
|
|
'param' => ['`', '`'],
|
|
'setting' => ['`', '`'],
|
|
'code' => ['`', '`'],
|
|
'code-block' => ['```', '```'],
|
|
'exe' => [undef, ''],
|
|
'backrest' => [undef, ''],
|
|
'postgres' => ['PostgreSQL', '']
|
|
},
|
|
|
|
'text' =>
|
|
{
|
|
'b' => ['', ''],
|
|
'i' => ['', ''],
|
|
'bi' => ['', ''],
|
|
'ul' => ["\n", ''],
|
|
'ol' => ["\n", ''],
|
|
'li' => ['* ', "\n"],
|
|
'id' => ['', ''],
|
|
'file' => ['', ''],
|
|
'path' => ['', ''],
|
|
'cmd' => ['', ''],
|
|
'param' => ['', ''],
|
|
'setting' => ['', ''],
|
|
'code' => ['', ''],
|
|
'code-block' => ['', ''],
|
|
'exe' => [undef, ''],
|
|
'backrest' => [undef, ''],
|
|
'postgres' => ['PostgreSQL', '']
|
|
},
|
|
|
|
'html' =>
|
|
{
|
|
'b' => ['<b>', '</b>']
|
|
}
|
|
};
|
|
|
|
####################################################################################################################################
|
|
# 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->{strType},
|
|
$self->{strProjectName},
|
|
$self->{strExeName}
|
|
) =
|
|
logDebugParam
|
|
(
|
|
OP_DOC_RENDER_NEW, \@_,
|
|
{name => 'strType'},
|
|
{name => 'strProjectName'},
|
|
{name => 'strExeName'}
|
|
);
|
|
|
|
$$oRenderTag{markdown}{backrest}[0] = $self->{strProjectName};
|
|
$$oRenderTag{markdown}{exe}[0] = $self->{strExeName};
|
|
$$oRenderTag{text}{backrest}[0] = $self->{strProjectName};
|
|
$$oRenderTag{text}{exe}[0] = $self->{strExeName};
|
|
|
|
# Return from function and log return values if any
|
|
return logDebugReturn
|
|
(
|
|
$strOperation,
|
|
{name => 'self', value => $self}
|
|
);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# process
|
|
#
|
|
# Render the document
|
|
####################################################################################################################################
|
|
sub process
|
|
{
|
|
my $self = shift;
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
my
|
|
(
|
|
$strOperation,
|
|
$oDoc,
|
|
$iDepth,
|
|
$bChildList,
|
|
) =
|
|
logDebugParam
|
|
(
|
|
OP_DOC_RENDER_PROCESS, \@_,
|
|
{name => 'oDoc', trace => true},
|
|
{name => 'iDepth', default => 1, trace => true},
|
|
{name => 'bChildList', default => true, trace => true}
|
|
);
|
|
|
|
my $strType = $self->{strType};
|
|
my $strProjectName = $self->{strProjectName};
|
|
|
|
my $strBuffer = "";
|
|
my $bList = $oDoc->nameGet() =~ /.*-bullet-list$/;
|
|
$bChildList = defined($bChildList) ? $bChildList : false;
|
|
my $iChildDepth = $iDepth;
|
|
|
|
my @stryMonth = ('January', 'February', 'March', 'April', 'May', 'June',
|
|
'July', 'August', 'September', 'October', 'November', 'December');
|
|
|
|
if ($strType eq 'markdown' || $strType eq 'text')
|
|
{
|
|
if (defined($oDoc->paramGet('id', false)))
|
|
{
|
|
my @stryToken = split('-', $oDoc->nameGet());
|
|
my $strTitle = @stryToken == 0 ? '[unknown]' : $stryToken[@stryToken - 1];
|
|
|
|
$strBuffer = ('#' x $iDepth) . ' `' . $oDoc->paramGet('id') . '` ' . $strTitle;
|
|
}
|
|
|
|
if (defined($oDoc->paramGet('title', false)))
|
|
{
|
|
$strBuffer = ('#' x $iDepth) . ' ';
|
|
|
|
if (defined($oDoc->paramGet('version', false)))
|
|
{
|
|
$strBuffer .= 'v' . $oDoc->paramGet('version') . ': ';
|
|
}
|
|
|
|
$strBuffer .= ($iDepth == 1 ? "${strProjectName} - " : '') . $oDoc->paramGet('title');
|
|
|
|
if (defined($oDoc->paramGet('date', false)))
|
|
{
|
|
my $strDate = $oDoc->paramGet('date');
|
|
|
|
if ($strDate !~ /^(XXXX-XX-XX)|([0-9]{4}-[0-9]{2}-[0-9]{2})$/)
|
|
{
|
|
confess "invalid date ${strDate}";
|
|
}
|
|
|
|
if ($strDate =~ /^X/)
|
|
{
|
|
$strBuffer .= "\n__No Release Date Set__";
|
|
}
|
|
else
|
|
{
|
|
$strBuffer .= "\n__Released " . $stryMonth[(substr($strDate, 5, 2) - 1)] . ' ' .
|
|
(substr($strDate, 8, 2) + 0) . ', ' . substr($strDate, 0, 4) . '__';
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($strBuffer ne "")
|
|
{
|
|
$iChildDepth++;
|
|
}
|
|
|
|
if (defined($oDoc->nodeGet('summary', false)))
|
|
{
|
|
if ($strBuffer ne "")
|
|
{
|
|
$strBuffer .= "\n\n";
|
|
}
|
|
|
|
if ($bChildList)
|
|
{
|
|
$strBuffer .= '* ';
|
|
}
|
|
|
|
$strBuffer .= $self->processText($oDoc->nodeGet('summary')->textGet());
|
|
}
|
|
|
|
if (defined($oDoc->textGet(false)))
|
|
{
|
|
if ($strBuffer ne "")
|
|
{
|
|
$strBuffer .= "\n\n";
|
|
}
|
|
|
|
if ($bChildList)
|
|
{
|
|
$strBuffer .= '* ';
|
|
}
|
|
|
|
$strBuffer .= $self->processText($oDoc->textGet());
|
|
}
|
|
|
|
if ($oDoc->nameGet() eq 'config-key' || $oDoc->nameGet() eq 'option')
|
|
{
|
|
my $strError = 'config section ?, key ' . $oDoc->paramGet('id') . 'requires';
|
|
|
|
my $bRequired = defined($oDoc->fieldGet('required', false)) && $oDoc->fieldGet('required');
|
|
my $strDefault = $oDoc->fieldGet('default', false);
|
|
my $strAllow = $oDoc->fieldGet('allow', false);
|
|
my $strOverride = $oDoc->fieldGet('override', false);
|
|
my $strExample = $oDoc->fieldGet('example', false);
|
|
|
|
# !!! Temporary hack to make docs generate correctly. This should be replace with a parameter so that it can be
|
|
# changed based on the build. Maybe check the exe name by default?
|
|
if ($oDoc->paramGet('id') eq 'config')
|
|
{
|
|
$strDefault = '/etc/pg_backrest.conf';
|
|
}
|
|
|
|
if (defined($strExample))
|
|
{
|
|
if (index($strExample, '=') == -1)
|
|
{
|
|
$strExample = "=${strExample}";
|
|
}
|
|
else
|
|
{
|
|
$strExample = " ${strExample}";
|
|
}
|
|
|
|
$strExample = $oDoc->paramGet('id') . $strExample;
|
|
|
|
if (defined($oDoc->fieldGet('cmd', false)) && $oDoc->fieldGet('cmd'))
|
|
{
|
|
$strExample = '--' . $strExample;
|
|
|
|
if (index($oDoc->fieldGet('example'), ' ') != -1)
|
|
{
|
|
$strExample = "\"${strExample}\"";
|
|
}
|
|
}
|
|
}
|
|
|
|
$strBuffer .= "\n```\n" .
|
|
($bRequired ? "required: " . ($bRequired ? 'y' : 'n') . "\n" : '') .
|
|
(defined($strDefault) ? "default: ${strDefault}\n" : '') .
|
|
(defined($strAllow) ? "allow: ${strAllow}\n" : '') .
|
|
(defined($strOverride) ? "override: ${strOverride}\n" : '') .
|
|
(defined($strExample) ? "example: ${strExample}\n" : '') .
|
|
"```";
|
|
}
|
|
|
|
if ($strBuffer ne "" && $iDepth != 1 && !$bList)
|
|
{
|
|
$strBuffer = "\n\n" . $strBuffer;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
confess "unknown type ${strType}";
|
|
}
|
|
|
|
my $bFirst = true;
|
|
|
|
foreach my $oChild ($oDoc->nodeList(undef, false))
|
|
{
|
|
if ($oChild->nameGet() ne 'summary')
|
|
{
|
|
if ($strType eq 'markdown' || $strType eq 'text')
|
|
{
|
|
}
|
|
else
|
|
{
|
|
confess "unknown type ${strType}";
|
|
}
|
|
|
|
$strBuffer .= $self->process($oChild, $iChildDepth, $bList);
|
|
}
|
|
}
|
|
|
|
if ($iDepth == 1)
|
|
{
|
|
if ($strType eq 'markdown' || $strType eq 'text')
|
|
{
|
|
$strBuffer .= "\n";
|
|
}
|
|
else
|
|
{
|
|
confess "unknown type ${strType}";
|
|
}
|
|
}
|
|
|
|
# Return from function and log return values if any
|
|
return logDebugReturn
|
|
(
|
|
$strOperation,
|
|
{name => 'strBuffer', value => $strBuffer, trace => true}
|
|
);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# processTag
|
|
####################################################################################################################################
|
|
sub processTag
|
|
{
|
|
my $self = shift;
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
my
|
|
(
|
|
$strOperation,
|
|
$oTag
|
|
) =
|
|
logDebugParam
|
|
(
|
|
OP_DOC_RENDER_PROCESS_TAG, \@_,
|
|
{name => 'oTag', trace => true}
|
|
);
|
|
|
|
my $strBuffer = "";
|
|
|
|
my $strType = $self->{strType};
|
|
my $strTag = $oTag->nameGet();
|
|
my $strStart = $$oRenderTag{$strType}{$strTag}[0];
|
|
my $strStop = $$oRenderTag{$strType}{$strTag}[1];
|
|
|
|
if (!defined($strStart) || !defined($strStop))
|
|
{
|
|
confess "invalid type ${strType} or tag ${strTag}";
|
|
}
|
|
|
|
$strBuffer .= $strStart;
|
|
|
|
if ($strTag eq 'li' || $strTag eq 'code-block')
|
|
{
|
|
$strBuffer .= $self->processText($oTag);
|
|
}
|
|
elsif (defined($oTag->valueGet()))
|
|
{
|
|
$strBuffer .= $oTag->valueGet();
|
|
}
|
|
else
|
|
{
|
|
foreach my $oSubTag ($oTag->nodeList(undef, false))
|
|
{
|
|
$strBuffer .= $self->processTag($oSubTag);
|
|
}
|
|
}
|
|
|
|
$strBuffer .= $strStop;
|
|
|
|
# Return from function and log return values if any
|
|
return logDebugReturn
|
|
(
|
|
$strOperation,
|
|
{name => 'strBuffer', value => $strBuffer, trace => true}
|
|
);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# processText
|
|
####################################################################################################################################
|
|
sub processText
|
|
{
|
|
my $self = shift;
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
my
|
|
(
|
|
$strOperation,
|
|
$oText
|
|
) =
|
|
logDebugParam
|
|
(
|
|
OP_DOC_RENDER_PROCESS_TEXT, \@_,
|
|
{name => 'oText', trace => true}
|
|
);
|
|
|
|
my $strType = $self->{strType};
|
|
my $strBuffer = '';
|
|
|
|
foreach my $oNode ($oText->nodeList(undef, false))
|
|
{
|
|
if (ref(\$oNode) eq "SCALAR")
|
|
{
|
|
$strBuffer .= $oNode;
|
|
}
|
|
else
|
|
{
|
|
$strBuffer .= $self->processTag($oNode);
|
|
}
|
|
}
|
|
|
|
# Return from function and log return values if any
|
|
return logDebugReturn
|
|
(
|
|
$strOperation,
|
|
{name => 'strBuffer', value => $strBuffer, trace => true}
|
|
);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# save
|
|
####################################################################################################################################
|
|
sub save
|
|
{
|
|
my $self = shift;
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
my
|
|
(
|
|
$strOperation,
|
|
$strFileName,
|
|
$strBuffer
|
|
) =
|
|
logDebugParam
|
|
(
|
|
OP_DOC_RENDER_SAVE, \@_,
|
|
{name => 'strFileName', trace => true},
|
|
{name => 'strBuffer', trace => true}
|
|
);
|
|
|
|
# Open the file
|
|
my $hFile;
|
|
open($hFile, '>', $strFileName)
|
|
or confess &log(ERROR, "unable to open ${strFileName}");
|
|
|
|
# Write the buffer
|
|
my $iBufferOut = syswrite($hFile, $strBuffer);
|
|
|
|
# Report any errors
|
|
if (!defined($iBufferOut) || $iBufferOut != length($strBuffer))
|
|
{
|
|
confess "unable to write '${strBuffer}'" . (defined($!) ? ': ' . $! : '');
|
|
}
|
|
|
|
# Close the file
|
|
close($hFile);
|
|
|
|
# Return from function and log return values if any
|
|
return logDebugReturn($strOperation);
|
|
}
|
|
|
|
1;
|