From df6086bd24ce9d9322e5c048e5337719e9a43a0a Mon Sep 17 00:00:00 2001 From: David Steele Date: Thu, 2 Jun 2016 09:25:12 -0400 Subject: [PATCH] Added a man page to document generation. --- doc/doc.pl | 16 +- doc/lib/BackRestDoc/Common/DocConfig.pm | 212 ++++++++++++++++++++++++ doc/xml/index.xml | 1 + doc/xml/reference.xml | 10 +- doc/xml/release.xml | 9 + lib/pgBackRest/Config/ConfigHelpData.pm | 12 +- 6 files changed, 246 insertions(+), 14 deletions(-) diff --git a/doc/doc.pl b/doc/doc.pl index 746ba7606..e0f4be620 100755 --- a/doc/doc.pl +++ b/doc/doc.pl @@ -160,12 +160,13 @@ if (@stryOutput == 0) if ($oManifest->isBackRest()) { push(@stryOutput, 'help'); + push(@stryOutput, 'man'); } } for my $strOutput (@stryOutput) { - if (!(($strOutput eq 'help' || $strOutput eq 'markdown') && $oManifest->isBackRest())) + if (!(($strOutput eq 'help' || $strOutput eq 'man') && $oManifest->isBackRest())) { $oManifest->renderGet($strOutput); } @@ -185,14 +186,23 @@ for my $strOutput (@stryOutput) $oMarkdown->process(); } - elsif ($strOutput eq 'help' && $oManifest->isBackRest()) + elsif (($strOutput eq 'help' || $strOutput eq 'man') && $oManifest->isBackRest()) { # Generate the command-line help my $oRender = new BackRestDoc::Common::DocRender('text', $oManifest); my $oDocConfig = new BackRestDoc::Common::DocConfig( new BackRestDoc::Common::Doc("${strBasePath}/xml/reference.xml"), $oRender); - $oDocConfig->helpDataWrite($oManifest); + + if ($strOutput eq 'help') + { + $oDocConfig->helpDataWrite($oManifest); + } + else + { + filePathCreate("${strBasePath}/output/man", '0770', true, true); + fileStringWrite("${strBasePath}/output/man/" . lc(BACKREST_NAME) . '.1.txt', $oDocConfig->manGet($oManifest), false); + } } elsif ($strOutput eq 'html') { diff --git a/doc/lib/BackRestDoc/Common/DocConfig.pm b/doc/lib/BackRestDoc/Common/DocConfig.pm index 107366f9b..81d25d36c 100644 --- a/doc/lib/BackRestDoc/Common/DocConfig.pm +++ b/doc/lib/BackRestDoc/Common/DocConfig.pm @@ -17,6 +17,7 @@ use pgBackRest::Common::String; use pgBackRest::Config::Config; use pgBackRest::Config::ConfigHelp; use pgBackRest::FileCommon; +use pgBackRest::Version; #################################################################################################################################### # Help types @@ -479,6 +480,217 @@ sub helpDataWriteFormatText return $strText; } +#################################################################################################################################### +# 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" . + ' ' . BACKREST_NAME . ' - ' . $oManifest->variableReplace($oIndexDoc->paramGet('subtitle')) . "\n\n" . + "SYNOPSIS\n" . + ' ' . BACKREST_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')) + { + if ($iParaTotal >= 2) + { + last; + } + + $strManPage .= ($iParaTotal == 0 ? "\n" : "\n\n") . ' ' . + manGetFormatText($oManifest->variableReplace($self->{oDocRender}->processText($oPara->textGet())), 80, 2); + + $iParaTotal++; + } + + # Build command and config hashes + my $hOptionRule = optionRuleGet(); + my $hConfig = $self->{oConfigHash}; + my $hCommandList = {}; + my $iCommandMaxLen = 0; + my $hOptionList = {}; + my $iOptionMaxLen = 0; + + foreach my $strCommand (sort(keys(%{$$hConfig{&CONFIG_HELP_COMMAND}}))) + { + 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) + { + $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}}))) + { + 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} : CONFIG_SECTION_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}; + + # Contruct the default + my $strCommand = defined(${commandHashGet()}{$strSection}) ? $strSection : undef; + my $strDefault = optionDefault($strOption, $strCommand); + + if (defined($strDefault)) + { + if ($$hOptionRule{$strOption}{&OPTION_RULE_TYPE} eq &OPTION_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" . + ' ' . OPTION_DEFAULT_CONFIG . "\n" . + ' ' . OPTION_DEFAULT_REPO_PATH . "\n" . + ' ' . OPTION_DEFAULT_LOG_PATH . "\n" . + ' ' . OPTION_DEFAULT_SPOOL_PATH . "\n" . + ' ' . OPTION_DEFAULT_LOCK_PATH . "\n" . + "\n" . + "EXAMPLES\n" . + "\n" . + " * Create a backup of the PostgreSQL `main` cluster:\n" . + "\n" . + ' $ ' . BACKREST_EXE . ' --' . OPTION_STANZA . "=main backup\n" . + "\n" . + ' The `main` cluster should be configured in `' . OPTION_DEFAULT_CONFIG . "`\n" . + "\n" . + " * Show all available backups:\n" . + "\n" . + ' $ ' . BACKREST_EXE . ' ' . CMD_INFO . "\n" . + "\n" . + " * Show all available backups for a specific cluster:\n" . + "\n" . + ' $ ' . BACKREST_EXE . ' --' . OPTION_STANZA . '=main ' . CMD_INFO . "\n" . + "\n" . + " * Show backup specific options:\n" . + "\n" . + ' $ ' . BACKREST_EXE . ' ' . CMD_HELP . ' ' . CMD_BACKUP . "\n" . + "\n" . + "SEE ALSO\n" . + "\n" . + ' /usr/share/doc/' . BACKREST_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; +} + #################################################################################################################################### # helpConfigDocGet # diff --git a/doc/xml/index.xml b/doc/xml/index.xml index 7da1f6280..cc538e999 100644 --- a/doc/xml/index.xml +++ b/doc/xml/index.xml @@ -28,6 +28,7 @@
Introduction +

aims to be a simple, reliable backup and restore system that can seamlessly scale up to the largest databases and workloads.

Instead of relying on traditional backup tools like tar and rsync, implements all backup features internally and uses a custom protocol for communicating with remote systems. Removing reliance on tar and rsync allows for better solutions to database-specific backup challenges. The custom remote protocol allows for more flexibility and limits the types of connections that are required to perform a backup which increases security.

diff --git a/doc/xml/reference.xml b/doc/xml/reference.xml index 1ca11afa4..4731d1763 100644 --- a/doc/xml/reference.xml +++ b/doc/xml/reference.xml @@ -474,9 +474,9 @@ Cluster data directory. - This should be the same as the data_directory setting in postgresql.conf. Even though this value can be read from postgresql.conf or the database cluster it is prudent to set it in case those resources are not available during a restore or cold backup scenario. + This should be the same as the data_directory setting in postgresql.conf. Even though this value can be read from postgresql.conf or the database cluster it is prudent to set it in case those resources are not available during a restore or offline backup scenario. - The db-path option is tested against the value reported by on every hot backup so it should always be current. + The db-path option is tested against the value reported by on every online backup so it should always be current. /data/db @@ -557,18 +557,18 @@