You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-08-01 06:46:52 +03:00
Migrate man page generation to C.
This commit is contained in:
22
doc/doc.pl
22
doc/doc.pl
@ -291,13 +291,11 @@ eval
|
||||
# Render output
|
||||
for my $strOutput (@stryOutput)
|
||||
{
|
||||
if (!($strOutput eq 'man' && $oManifest->isBackRest()))
|
||||
{
|
||||
$oManifest->renderGet($strOutput);
|
||||
}
|
||||
|
||||
&log(INFO, "render ${strOutput} output");
|
||||
|
||||
# Man output has already been generated in C so do not remove it
|
||||
next if ($strOutput eq 'man');
|
||||
|
||||
# Clean contents of out directory
|
||||
if (!$bOutPreserve)
|
||||
{
|
||||
@ -316,6 +314,8 @@ eval
|
||||
}
|
||||
}
|
||||
|
||||
$oManifest->renderGet($strOutput);
|
||||
|
||||
if ($strOutput eq 'markdown')
|
||||
{
|
||||
my $oMarkdown =
|
||||
@ -329,18 +329,6 @@ eval
|
||||
|
||||
$oMarkdown->process();
|
||||
}
|
||||
elsif ($strOutput eq 'man' && $oManifest->isBackRest())
|
||||
{
|
||||
# Generate the command-line help
|
||||
my $oRender = new pgBackRestDoc::Common::DocRender('text', $oManifest, !$bNoExe);
|
||||
my $oDocConfig =
|
||||
new pgBackRestDoc::Common::DocConfig(
|
||||
new pgBackRestDoc::Common::Doc("${strBasePath}/../src/build/help/help.xml"), $oRender);
|
||||
|
||||
$oStorageDoc->pathCreate(
|
||||
"${strBasePath}/output/man", {strMode => '0770', bIgnoreExists => true, bCreateParent => true});
|
||||
$oStorageDoc->put("${strBasePath}/output/man/" . lc(PROJECT_NAME) . '.1.txt', $oDocConfig->manGet($oManifest));
|
||||
}
|
||||
elsif ($strOutput eq 'html')
|
||||
{
|
||||
my $oHtmlSite =
|
||||
|
@ -298,223 +298,4 @@ sub process
|
||||
logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# manGet
|
||||
#
|
||||
# Generate the man page.
|
||||
####################################################################################################################################
|
||||
sub manGet
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oManifest
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->manGet', \@_,
|
||||
{name => 'oManifest'}
|
||||
);
|
||||
|
||||
# Get index.xml to pull various text from
|
||||
my $oIndexDoc = ${$oManifest->sourceGet('index')}{doc};
|
||||
|
||||
# Write the header
|
||||
my $strManPage =
|
||||
"NAME\n" .
|
||||
' ' . PROJECT_NAME . ' - ' . $oManifest->variableReplace($oIndexDoc->paramGet('subtitle')) . "\n\n" .
|
||||
"SYNOPSIS\n" .
|
||||
' ' . PROJECT_EXE . ' [options] [command]';
|
||||
|
||||
# Output the description (first two paragraphs of index.xml introduction)
|
||||
my $iParaTotal = 0;
|
||||
|
||||
$strManPage .= "\n\n" .
|
||||
"DESCRIPTION";
|
||||
|
||||
foreach my $oPara ($oIndexDoc->nodeGetById('section', 'introduction')->nodeList('p'))
|
||||
{
|
||||
$strManPage .= ($iParaTotal == 0 ? "\n" : "\n\n") . ' ' .
|
||||
manGetFormatText($oManifest->variableReplace($self->{oDocRender}->processText($oPara->textGet())), 80, 2);
|
||||
|
||||
last;
|
||||
}
|
||||
|
||||
# Build command and config hashes
|
||||
my $hConfigDefine = cfgDefine();
|
||||
my $hConfig = $self->{oConfigHash};
|
||||
my $hCommandList = {};
|
||||
my $iCommandMaxLen = 0;
|
||||
my $hOptionList = {};
|
||||
my $iOptionMaxLen = 0;
|
||||
|
||||
foreach my $strCommand (sort(keys(%{$$hConfig{&CONFIG_HELP_COMMAND}})))
|
||||
{
|
||||
# Skip internal commands
|
||||
next if $hConfig->{&CONFIG_HELP_COMMAND}{$strCommand}{&CONFIG_HELP_INTERNAL};
|
||||
|
||||
my $hCommand = $$hConfig{&CONFIG_HELP_COMMAND}{$strCommand};
|
||||
$iCommandMaxLen = length($strCommand) > $iCommandMaxLen ? length($strCommand) : $iCommandMaxLen;
|
||||
|
||||
$$hCommandList{$strCommand}{summary} = $$hCommand{&CONFIG_HELP_SUMMARY};
|
||||
|
||||
if (defined($$hCommand{&CONFIG_HELP_OPTION}))
|
||||
{
|
||||
foreach my $strOption (sort(keys(%{$$hCommand{&CONFIG_HELP_OPTION}})))
|
||||
{
|
||||
my $hOption = $$hCommand{&CONFIG_HELP_OPTION}{$strOption};
|
||||
|
||||
if ($$hOption{&CONFIG_HELP_SOURCE} eq CONFIG_HELP_SOURCE_COMMAND)
|
||||
{
|
||||
# Skip internal options
|
||||
next if $hOption->{&CONFIG_HELP_INTERNAL};
|
||||
|
||||
$iOptionMaxLen = length($strOption) > $iOptionMaxLen ? length($strOption) : $iOptionMaxLen;
|
||||
|
||||
$$hOptionList{$strCommand}{$strOption}{&CONFIG_HELP_SUMMARY} = $$hOption{&CONFIG_HELP_SUMMARY};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $strOption (sort(keys(%{$$hConfig{&CONFIG_HELP_OPTION}})))
|
||||
{
|
||||
# Skip internal options
|
||||
next if $hConfig->{&CONFIG_HELP_OPTION}{$strOption}{&CONFIG_HELP_INTERNAL};
|
||||
|
||||
my $hOption = $$hConfig{&CONFIG_HELP_OPTION}{$strOption};
|
||||
$iOptionMaxLen = length($strOption) > $iOptionMaxLen ? length($strOption) : $iOptionMaxLen;
|
||||
my $strSection = defined($$hOption{&CONFIG_HELP_SECTION}) ? $$hOption{&CONFIG_HELP_SECTION} : CFGDEF_GENERAL;
|
||||
|
||||
$$hOptionList{$strSection}{$strOption}{&CONFIG_HELP_SUMMARY} = $$hOption{&CONFIG_HELP_SUMMARY};
|
||||
}
|
||||
|
||||
# Output Commands
|
||||
$strManPage .= "\n\n" .
|
||||
'COMMANDS';
|
||||
|
||||
foreach my $strCommand (sort(keys(%{$hCommandList})))
|
||||
{
|
||||
# Construct the summary
|
||||
my $strSummary = $oManifest->variableReplace($self->{oDocRender}->processText($$hCommandList{$strCommand}{summary}));
|
||||
# $strSummary = lcfirst(substr($strSummary, 0, length($strSummary) - 1));
|
||||
|
||||
# Output the summary
|
||||
$strManPage .=
|
||||
"\n " . "${strCommand}" . (' ' x ($iCommandMaxLen - length($strCommand))) . ' ' .
|
||||
manGetFormatText($strSummary, 80, $iCommandMaxLen + 4);
|
||||
}
|
||||
|
||||
# Output options
|
||||
my $bFirst = true;
|
||||
$strManPage .= "\n\n" .
|
||||
'OPTIONS';
|
||||
|
||||
foreach my $strSection (sort(keys(%{$hOptionList})))
|
||||
{
|
||||
$strManPage .= ($bFirst ?'' : "\n") . "\n " . ucfirst($strSection) . ' Options:';
|
||||
|
||||
foreach my $strOption (sort(keys(%{$$hOptionList{$strSection}})))
|
||||
{
|
||||
my $hOption = $$hOptionList{$strSection}{$strOption};
|
||||
|
||||
# Construct the default
|
||||
my $strCommand = grep(/$strSection/i, cfgDefineCommandList()) ? $strSection : undef;
|
||||
my $strDefault = docConfigOptionDefault($strOption, $strCommand);
|
||||
|
||||
if (defined($strDefault))
|
||||
{
|
||||
if ($strOption eq CFGOPT_REPO_HOST_CMD || $strOption eq CFGOPT_PG_HOST_CMD)
|
||||
{
|
||||
$strDefault = PROJECT_EXE;
|
||||
}
|
||||
elsif ($$hConfigDefine{$strOption}{&CFGDEF_TYPE} eq &CFGDEF_TYPE_BOOLEAN)
|
||||
{
|
||||
$strDefault = $strDefault ? 'y' : 'n';
|
||||
}
|
||||
}
|
||||
#
|
||||
# use Data::Dumper; confess Dumper($$hOption{&CONFIG_HELP_SUMMARY});
|
||||
|
||||
# Construct the summary
|
||||
my $strSummary = $oManifest->variableReplace($self->{oDocRender}->processText($$hOption{&CONFIG_HELP_SUMMARY}));
|
||||
|
||||
$strSummary = $strSummary . (defined($strDefault) ? " [default=${strDefault}]" : '');
|
||||
|
||||
# Output the summary
|
||||
$strManPage .=
|
||||
"\n " . "--${strOption}" . (' ' x ($iOptionMaxLen - length($strOption))) . ' ' .
|
||||
manGetFormatText($strSummary, 80, $iOptionMaxLen + 8);
|
||||
}
|
||||
|
||||
$bFirst = false;
|
||||
}
|
||||
|
||||
# Write files, examples, and references
|
||||
$strManPage .= "\n\n" .
|
||||
"FILES\n" .
|
||||
"\n" .
|
||||
' ' . docConfigOptionDefault(CFGOPT_CONFIG) . "\n" .
|
||||
' ' . docConfigOptionDefault(CFGOPT_REPO_PATH) . "\n" .
|
||||
' ' . docConfigOptionDefault(CFGOPT_LOG_PATH) . "\n" .
|
||||
' ' . docConfigOptionDefault(CFGOPT_SPOOL_PATH) . "\n" .
|
||||
' ' . docConfigOptionDefault(CFGOPT_LOCK_PATH) . "\n" .
|
||||
"\n" .
|
||||
"EXAMPLES\n" .
|
||||
"\n" .
|
||||
" * Create a backup of the PostgreSQL `main` cluster:\n" .
|
||||
"\n" .
|
||||
' $ ' . PROJECT_EXE . ' --' . CFGOPT_STANZA . "=main backup\n" .
|
||||
"\n" .
|
||||
' The `main` cluster should be configured in `' . docConfigOptionDefault(CFGOPT_CONFIG) . "`\n" .
|
||||
"\n" .
|
||||
" * Show all available backups:\n" .
|
||||
"\n" .
|
||||
' $ ' . PROJECT_EXE . ' ' . CFGCMD_INFO . "\n" .
|
||||
"\n" .
|
||||
" * Show all available backups for a specific cluster:\n" .
|
||||
"\n" .
|
||||
' $ ' . PROJECT_EXE . ' --' . CFGOPT_STANZA . '=main ' . CFGCMD_INFO . "\n" .
|
||||
"\n" .
|
||||
" * Show backup specific options:\n" .
|
||||
"\n" .
|
||||
' $ ' . PROJECT_EXE . ' ' . CFGCMD_HELP . ' ' . CFGCMD_BACKUP . "\n" .
|
||||
"\n" .
|
||||
"SEE ALSO\n" .
|
||||
"\n" .
|
||||
' /usr/share/doc/' . PROJECT_EXE . "-doc/html/index.html\n" .
|
||||
' ' . $oManifest->variableReplace('{[backrest-url-base]}') . "\n";
|
||||
|
||||
return $strManPage;
|
||||
}
|
||||
|
||||
# Helper function for manGet() used to format text by indenting and splitting
|
||||
sub manGetFormatText
|
||||
{
|
||||
my $strLine = shift;
|
||||
my $iLength = shift;
|
||||
my $iIndentRest = shift;
|
||||
|
||||
my $strPart;
|
||||
my $strResult;
|
||||
my $bFirst = true;
|
||||
|
||||
do
|
||||
{
|
||||
my $iIndent = $bFirst ? 0 : $iIndentRest;
|
||||
|
||||
($strPart, $strLine) = stringSplit($strLine, ' ', $iLength - $iIndentRest);
|
||||
|
||||
$strResult .= ($bFirst ? '' : "\n") . (' ' x $iIndent) . trim($strPart);
|
||||
|
||||
$bFirst = false;
|
||||
}
|
||||
while (defined($strLine));
|
||||
|
||||
return $strResult;
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -3,6 +3,7 @@ Build Command
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include "command/build/man.h"
|
||||
#include "command/build/reference.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
@ -22,6 +23,8 @@ cmdBuild(const String *const pathRepo)
|
||||
Storage *const storageRepo = storagePosixNewP(pathRepo, .write = true);
|
||||
const BldCfg bldCfg = bldCfgParse(storageRepo);
|
||||
const BldHlp bldHlp = bldHlpParse(storageRepo, bldCfg, true);
|
||||
XmlNode *const xml = xmlDocumentRoot(
|
||||
xmlDocumentNewBuf(storageGetP(storageNewReadP(storageRepo, STRDEF("doc/xml/index.xml")))));
|
||||
|
||||
storagePutP(
|
||||
storageNewWriteP(storageRepo, STRDEF("doc/output/xml/command.xml")),
|
||||
@ -29,6 +32,9 @@ cmdBuild(const String *const pathRepo)
|
||||
storagePutP(
|
||||
storageNewWriteP(storageRepo, STRDEF("doc/output/xml/configuration.xml")),
|
||||
xmlDocumentBuf(referenceConfigurationRender(&bldCfg, &bldHlp)));
|
||||
storagePutP(
|
||||
storageNewWriteP(storageRepo, STRDEF("doc/output/man/" PROJECT_BIN ".1.txt")),
|
||||
BUFSTR(referenceManRender(xml, &bldCfg, &bldHlp)));
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
|
299
doc/src/command/build/man.c
Normal file
299
doc/src/command/build/man.c
Normal file
@ -0,0 +1,299 @@
|
||||
/***********************************************************************************************************************************
|
||||
Build Manual Page Reference
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include "build/common/string.h"
|
||||
#include "build/help/render.h"
|
||||
#include "command/build/man.h"
|
||||
#include "command/help/help.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "version.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Define the console width - use a fixed width of 80 since this should be safe on virtually all consoles
|
||||
***********************************************************************************************************************************/
|
||||
#define CONSOLE_WIDTH 80
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Basic variable replacement. This only handles a few cases but will error in case of unknown variables.
|
||||
***********************************************************************************************************************************/
|
||||
String *
|
||||
referenceManReplace(String *const string)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_LOG_PARAM(STRING, string);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
String *const result = strCat(strNew(), string);
|
||||
|
||||
strReplace(result, STRDEF("{[postgres]}"), STRDEF("PostgreSQL"));
|
||||
strReplace(result, STRDEF("{[project]}"), STRDEF("pgBackRest"));
|
||||
|
||||
if (strstr(strZ(result), "{[") != NULL)
|
||||
THROW_FMT(AssertError, "unreplaced variable(s) in: %s", strZ(string));
|
||||
|
||||
FUNCTION_TEST_RETURN(STRING, result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
typedef struct ReferenceManSectionData
|
||||
{
|
||||
const String *name; // Section name
|
||||
List *optList; // Option list
|
||||
} ReferenceManSectionData;
|
||||
|
||||
// Helper to calculate max width
|
||||
static size_t
|
||||
referenceManMaxWidth(const size_t widthMax, const String *const string)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_LOG_PARAM(SIZE, widthMax);
|
||||
FUNCTION_LOG_PARAM(STRING, string);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
if (strSize(string) > widthMax)
|
||||
FUNCTION_TEST_RETURN(SIZE, strSize(string));
|
||||
|
||||
FUNCTION_TEST_RETURN(SIZE, widthMax);
|
||||
}
|
||||
|
||||
String *
|
||||
referenceManRender(const XmlNode *const indexRoot, const BldCfg *const bldCfg, const BldHlp *const bldHlp)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(XML_NODE, indexRoot);
|
||||
FUNCTION_LOG_PARAM_P(VOID, bldCfg);
|
||||
FUNCTION_LOG_PARAM_P(VOID, bldHlp);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
String *const result = strNew();
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Output header
|
||||
const String *const subtitle = referenceManReplace(xmlNodeAttribute(indexRoot, STRDEF("subtitle")));
|
||||
const String *const description = helpRenderText(
|
||||
referenceManReplace(xmlNodeContent(xmlNodeChild(indexRoot, STRDEF("description"), true))), false, false, 2, true,
|
||||
CONSOLE_WIDTH);
|
||||
|
||||
strCatFmt(
|
||||
result,
|
||||
"NAME\n"
|
||||
" " PROJECT_NAME " - %s\n\n"
|
||||
"SYNOPSIS\n"
|
||||
" " PROJECT_BIN " [options] [command]\n\n"
|
||||
"DESCRIPTION\n"
|
||||
"%s\n",
|
||||
strZ(subtitle), strZ(description));
|
||||
|
||||
// Output commands
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
// Determine max command width
|
||||
size_t commandWidthMax = 0;
|
||||
|
||||
for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldHlp->cmdList); cmdIdx++)
|
||||
{
|
||||
const BldHlpCommand *const cmdHlp = lstGet(bldHlp->cmdList, cmdIdx);
|
||||
const BldCfgCommand *const cmdCfg = lstFind(bldCfg->cmdList, &cmdHlp->name);
|
||||
ASSERT(cmdCfg != NULL);
|
||||
|
||||
// Skip internal commands
|
||||
if (cmdCfg->internal)
|
||||
continue;
|
||||
|
||||
// Update max command width
|
||||
commandWidthMax = referenceManMaxWidth(commandWidthMax, cmdHlp->name);
|
||||
}
|
||||
|
||||
// Output commands
|
||||
strCatZ(result, "\nCOMMANDS\n");
|
||||
|
||||
for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldHlp->cmdList); cmdIdx++)
|
||||
{
|
||||
const BldHlpCommand *const cmdHlp = lstGet(bldHlp->cmdList, cmdIdx);
|
||||
const BldCfgCommand *const cmdCfg = lstFind(bldCfg->cmdList, &cmdHlp->name);
|
||||
ASSERT(cmdCfg != NULL);
|
||||
|
||||
// Skip internal commands
|
||||
if (cmdCfg->internal)
|
||||
continue;
|
||||
|
||||
strCatFmt(
|
||||
result, " %s %*s%s\n", strZ(cmdHlp->name),
|
||||
(int)(commandWidthMax - strSize(cmdHlp->name)), "",
|
||||
strZ(helpRenderText(bldHlpRenderXml(cmdHlp->summary), false, false, commandWidthMax + 4, false, CONSOLE_WIDTH)));
|
||||
}
|
||||
|
||||
// Output options
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
// Determine max option width and build list of sections/options
|
||||
List *const sectionList = lstNewP(sizeof(ReferenceManSectionData), .comparator = lstComparatorStr);
|
||||
size_t optionWidthMax = 0;
|
||||
|
||||
for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldHlp->cmdList); cmdIdx++)
|
||||
{
|
||||
const BldHlpCommand *const cmdHlp = lstGet(bldHlp->cmdList, cmdIdx);
|
||||
const BldCfgCommand *const cmdCfg = lstFind(bldCfg->cmdList, &cmdHlp->name);
|
||||
ASSERT(cmdCfg != NULL);
|
||||
|
||||
// Skip internal commands
|
||||
if (cmdCfg->internal)
|
||||
continue;
|
||||
|
||||
if (cmdHlp->optList != NULL)
|
||||
{
|
||||
// Get section name
|
||||
const String *const sectionName = strFirstUpper(strDup(cmdHlp->name));
|
||||
|
||||
for (unsigned int optIdx = 0; optIdx < lstSize(cmdHlp->optList); optIdx++)
|
||||
{
|
||||
const BldHlpOption *const optHlp = lstGet(cmdHlp->optList, optIdx);
|
||||
const BldCfgOption *const optCfg = lstFind(bldCfg->optList, &optHlp->name);
|
||||
ASSERT(optCfg != NULL);
|
||||
|
||||
// Skip internal options
|
||||
const BldCfgOptionCommand *const optCmdCfg = lstFind(optCfg->cmdList, &cmdHlp->name);
|
||||
ASSERT(optCmdCfg != NULL);
|
||||
|
||||
if (optCmdCfg->internal)
|
||||
continue;
|
||||
|
||||
// Update max option width
|
||||
optionWidthMax = referenceManMaxWidth(optionWidthMax, optHlp->name);
|
||||
|
||||
// Add/get section
|
||||
ReferenceManSectionData *section = lstFind(sectionList, §ionName);
|
||||
|
||||
if (section == NULL)
|
||||
{
|
||||
MEM_CONTEXT_OBJ_BEGIN(sectionList)
|
||||
{
|
||||
const ReferenceManSectionData sectionNew =
|
||||
{
|
||||
.name = strDup(sectionName),
|
||||
.optList = lstNewP(sizeof(BldHlpOption), .comparator = lstComparatorStr),
|
||||
};
|
||||
|
||||
section = lstAdd(sectionList, §ionNew);
|
||||
}
|
||||
MEM_CONTEXT_OBJ_END();
|
||||
}
|
||||
|
||||
// Add option
|
||||
lstAdd(section->optList, optHlp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int optIdx = 0; optIdx < lstSize(bldHlp->optList); optIdx++)
|
||||
{
|
||||
const BldHlpOption *const optHlp = lstGet(bldHlp->optList, optIdx);
|
||||
const BldCfgOption *const optCfg = lstFind(bldCfg->optList, &optHlp->name);
|
||||
ASSERT(optCfg != NULL);
|
||||
|
||||
// Skip if option is internal
|
||||
if (optCfg->internal)
|
||||
continue;
|
||||
|
||||
// Update max option width
|
||||
optionWidthMax = referenceManMaxWidth(optionWidthMax, optHlp->name);
|
||||
|
||||
// Get section name
|
||||
const String *const sectionName = optHlp->section == NULL ? STRDEF("General") : strFirstUpper(strDup(optHlp->section));
|
||||
|
||||
// Add/get section
|
||||
ReferenceManSectionData *section = lstFind(sectionList, §ionName);
|
||||
|
||||
if (section == NULL)
|
||||
{
|
||||
MEM_CONTEXT_OBJ_BEGIN(sectionList)
|
||||
{
|
||||
const ReferenceManSectionData sectionNew =
|
||||
{
|
||||
.name = strDup(sectionName),
|
||||
.optList = lstNewP(sizeof(BldHlpOption), .comparator = lstComparatorStr),
|
||||
};
|
||||
|
||||
section = lstAdd(sectionList, §ionNew);
|
||||
}
|
||||
MEM_CONTEXT_OBJ_END();
|
||||
}
|
||||
|
||||
// Add option
|
||||
lstAdd(section->optList, optHlp);
|
||||
lstSort(section->optList, sortOrderAsc);
|
||||
}
|
||||
|
||||
lstSort(sectionList, sortOrderAsc);
|
||||
|
||||
// Output options
|
||||
strCatZ(result, "\nOPTIONS\n");
|
||||
|
||||
for (unsigned int sectionIdx = 0; sectionIdx < lstSize(sectionList); sectionIdx++)
|
||||
{
|
||||
const ReferenceManSectionData *const section = lstGet(sectionList, sectionIdx);
|
||||
|
||||
if (sectionIdx != 0)
|
||||
strCatZ(result, "\n");
|
||||
|
||||
strCatFmt(result, " %s Options:\n", strZ(section->name));
|
||||
|
||||
for (unsigned int optIdx = 0; optIdx < lstSize(section->optList); optIdx++)
|
||||
{
|
||||
const BldHlpOption *const optHlp = lstGet(section->optList, optIdx);
|
||||
|
||||
strCatFmt(
|
||||
result, " --%s %*s%s\n", strZ(optHlp->name),
|
||||
(int)(optionWidthMax - strSize(optHlp->name)), "",
|
||||
strZ(helpRenderText(bldHlpRenderXml(optHlp->summary), false, false, optionWidthMax + 8, false, CONSOLE_WIDTH)));
|
||||
}
|
||||
}
|
||||
|
||||
// Output files
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
strCatZ(
|
||||
result,
|
||||
"\nFILES\n"
|
||||
" " CFGOPTDEF_CONFIG_PATH "/" PROJECT_CONFIG_FILE "\n"
|
||||
" /var/lib/pgbackrest\n"
|
||||
" /var/log/pgbackrest\n"
|
||||
" /var/spool/pgbackrest\n"
|
||||
" /tmp/pgbackrest\n");
|
||||
|
||||
// Output examples
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
strCatZ(
|
||||
result,
|
||||
"\nEXAMPLES\n"
|
||||
" * Create a backup of the PostgreSQL `main` cluster:\n"
|
||||
"\n"
|
||||
" $ pgbackrest --stanza=main backup\n"
|
||||
"\n"
|
||||
" The `main` cluster should be configured in `" CFGOPTDEF_CONFIG_PATH "/" PROJECT_CONFIG_FILE "`\n"
|
||||
"\n"
|
||||
" * Show all available backups:\n"
|
||||
"\n"
|
||||
" $ pgbackrest info\n"
|
||||
"\n"
|
||||
" * Show all available backups for a specific cluster:\n"
|
||||
"\n"
|
||||
" $ pgbackrest --stanza=main info\n"
|
||||
"\n"
|
||||
" * Show backup specific options:\n"
|
||||
"\n"
|
||||
" $ pgbackrest help backup\n");
|
||||
|
||||
// Output see also
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
strCatZ(
|
||||
result,
|
||||
"\nSEE ALSO\n"
|
||||
" /usr/share/doc/pgbackrest-doc/html/index.html\n"
|
||||
" http://www.pgbackrest.org\n");
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
FUNCTION_LOG_RETURN(STRING, result);
|
||||
}
|
17
doc/src/command/build/man.h
Normal file
17
doc/src/command/build/man.h
Normal file
@ -0,0 +1,17 @@
|
||||
/***********************************************************************************************************************************
|
||||
Build Manual Page Reference
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef DOC_COMMAND_BUILD_MAN_H
|
||||
#define DOC_COMMAND_BUILD_MAN_H
|
||||
|
||||
#include "build/config/parse.h"
|
||||
#include "build/help/parse.h"
|
||||
#include "common/type/xml.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Build manual page reference
|
||||
String *referenceManRender(const XmlNode *indexRoot, const BldCfg *bldCfg, const BldHlp *bldHlp);
|
||||
|
||||
#endif
|
@ -32,10 +32,12 @@ src_doc = [
|
||||
'../../src/build/common/yaml.c',
|
||||
'../../src/build/config/parse.c',
|
||||
'../../src/build/help/parse.c',
|
||||
'../../src/build/help/render.c',
|
||||
'../../src/command/command.c',
|
||||
'../../src/command/exit.c',
|
||||
'../../src/command/help/help.c',
|
||||
'../../src/common/compress/bz2/common.c',
|
||||
'../../src/common/compress/bz2/compress.c',
|
||||
'../../src/common/compress/bz2/decompress.c',
|
||||
'../../src/common/ini.c',
|
||||
'../../src/common/io/fd.c',
|
||||
@ -47,6 +49,7 @@ src_doc = [
|
||||
'../../src/config/config.c',
|
||||
'../../src/config/parse.c',
|
||||
'command/build/build.c',
|
||||
'command/build/man.c',
|
||||
'command/build/reference.c',
|
||||
'config/load.c',
|
||||
'main.c',
|
||||
|
@ -117,7 +117,7 @@ bldHlpRenderXmlNode(const xmlNodePtr xml)
|
||||
return result;
|
||||
}
|
||||
|
||||
static String *
|
||||
String *
|
||||
bldHlpRenderXml(const XmlNode *const xml)
|
||||
{
|
||||
return strTrim(bldHlpRenderXmlNode(*(const xmlNodePtr *)xml));
|
||||
|
@ -13,4 +13,7 @@ Functions
|
||||
// Render help
|
||||
void bldHlpRender(const Storage *const storageRepo, const BldCfg bldCfg, const BldHlp bldHlp);
|
||||
|
||||
// Render xml as text
|
||||
String *bldHlpRenderXml(const XmlNode *xml);
|
||||
|
||||
#endif
|
||||
|
@ -93,10 +93,8 @@ helpRenderSplitSize(const String *string, const char *delimiter, size_t size)
|
||||
FUNCTION_TEST_RETURN(STRING_LIST, this);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Helper function for helpRender() to make output look good on a console
|
||||
***********************************************************************************************************************************/
|
||||
static String *
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN String *
|
||||
helpRenderText(
|
||||
const String *const text, const bool internal, const bool beta, const size_t indent, const bool indentFirst,
|
||||
const size_t length)
|
||||
|
@ -12,4 +12,7 @@ Functions
|
||||
// Render help and output to stdout
|
||||
FN_EXTERN void cmdHelp(const Buffer *const helpData);
|
||||
|
||||
// Render help text
|
||||
FN_EXTERN String *helpRenderText(const String *text, bool internal, bool beta, size_t indent, bool indentFirst, size_t length);
|
||||
|
||||
#endif
|
||||
|
@ -992,6 +992,7 @@ unit:
|
||||
|
||||
coverage:
|
||||
- doc/command/build/build
|
||||
- doc/command/build/man
|
||||
- doc/command/build/reference
|
||||
|
||||
# **********************************************************************************************************************************
|
||||
|
@ -19,6 +19,11 @@ testRun(void)
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("cmdBuild()"))
|
||||
{
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("referenceManReplace()");
|
||||
|
||||
TEST_ERROR(referenceManReplace(strNewZ("TEST {[")), AssertError, "unreplaced variable(s) in: TEST {[");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("referenceCommandSection()");
|
||||
|
||||
@ -35,6 +40,14 @@ testRun(void)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("parse and render");
|
||||
|
||||
HRN_STORAGE_PUT_Z(
|
||||
storageTest, "doc/xml/index.xml",
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<!DOCTYPE doc SYSTEM \"doc.dtd\">\n"
|
||||
"<doc title=\"{[project]}\" subtitle=\"Reliable {[postgres]} Backup & Restore\" toc=\"n\">\n"
|
||||
"<description>{[project]} is a reliable backup and restore solution for {[postgres]}...</description>\n"
|
||||
"</doc>\n");
|
||||
|
||||
HRN_STORAGE_PUT_Z(
|
||||
storageTest, "src/build/config/config.yaml",
|
||||
"command:\n"
|
||||
@ -95,6 +108,13 @@ testRun(void)
|
||||
" deprecate:\n"
|
||||
" frc: {}\n"
|
||||
"\n"
|
||||
" internal-opt:\n"
|
||||
" type: boolean\n"
|
||||
" internal: true\n"
|
||||
" default: true\n"
|
||||
" command:\n"
|
||||
" backup: {}\n"
|
||||
"\n"
|
||||
" stanza:\n"
|
||||
" type: string\n"
|
||||
" default: demo\n"
|
||||
@ -176,6 +196,13 @@ testRun(void)
|
||||
" <example>y</example>"
|
||||
" </option>\n"
|
||||
"\n"
|
||||
" <option id=\"internal-opt\" name=\"Internal Opt\">\n"
|
||||
" <summary>Internal option command backup summary.</summary>\n"
|
||||
" <text><p>internal option command backup description.</p></text>\n"
|
||||
" <example>n</example>"
|
||||
" <example>y</example>"
|
||||
" </option>\n"
|
||||
"\n"
|
||||
" <option id=\"repo-compress-level\" name=\"Repo Compress Level Backup\">\n"
|
||||
" <summary>Repo compress level option command backup summary.</summary>\n"
|
||||
" <text><p>Repo compress level option command backup description.</p></text>\n"
|
||||
@ -326,6 +353,68 @@ testRun(void)
|
||||
"</section>"
|
||||
// {uncrustify_on}
|
||||
"</doc>\n");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("pgbackrest.1.txt");
|
||||
|
||||
TEST_STORAGE_GET(
|
||||
storageTest,
|
||||
"doc/output/man/pgbackrest.1.txt",
|
||||
"NAME\n"
|
||||
" pgBackRest - Reliable PostgreSQL Backup & Restore\n"
|
||||
"\n"
|
||||
"SYNOPSIS\n"
|
||||
" pgbackrest [options] [command]\n"
|
||||
"\n"
|
||||
"DESCRIPTION\n"
|
||||
" pgBackRest is a reliable backup and restore solution for PostgreSQL...\n"
|
||||
"\n"
|
||||
"COMMANDS\n"
|
||||
" backup backup command summary.\n"
|
||||
" check Check command summary.\n"
|
||||
"\n"
|
||||
"OPTIONS\n"
|
||||
" Backup Options:\n"
|
||||
" --force Force option command backup summary.\n"
|
||||
" --repo-compress-level Repo compress level option command backup summary.\n"
|
||||
"\n"
|
||||
" General Options:\n"
|
||||
" --buffer-size Buffer size option summary.\n"
|
||||
" --config config option summary.\n"
|
||||
" --secure Secure option summary.\n"
|
||||
"\n"
|
||||
" Stanza Options:\n"
|
||||
" --stanza Stanza option summary.\n"
|
||||
"\n"
|
||||
"FILES\n"
|
||||
" /etc/pgbackrest/pgbackrest.conf\n"
|
||||
" /var/lib/pgbackrest\n"
|
||||
" /var/log/pgbackrest\n"
|
||||
" /var/spool/pgbackrest\n"
|
||||
" /tmp/pgbackrest\n"
|
||||
"\n"
|
||||
"EXAMPLES\n"
|
||||
" * Create a backup of the PostgreSQL `main` cluster:\n"
|
||||
"\n"
|
||||
" $ pgbackrest --stanza=main backup\n"
|
||||
"\n"
|
||||
" The `main` cluster should be configured in `/etc/pgbackrest/pgbackrest.conf`\n"
|
||||
"\n"
|
||||
" * Show all available backups:\n"
|
||||
"\n"
|
||||
" $ pgbackrest info\n"
|
||||
"\n"
|
||||
" * Show all available backups for a specific cluster:\n"
|
||||
"\n"
|
||||
" $ pgbackrest --stanza=main info\n"
|
||||
"\n"
|
||||
" * Show backup specific options:\n"
|
||||
"\n"
|
||||
" $ pgbackrest help backup\n"
|
||||
"\n"
|
||||
"SEE ALSO\n"
|
||||
" /usr/share/doc/pgbackrest-doc/html/index.html\n"
|
||||
" http://www.pgbackrest.org\n");
|
||||
}
|
||||
|
||||
FUNCTION_HARNESS_RETURN_VOID();
|
||||
|
Reference in New Issue
Block a user