<commit_before>####################################################################################################################################
# DOC EXECUTE MODULE
####################################################################################################################################
package pgBackRestDoc::Common::DocExecute;
use parent 'pgBackRestDoc::Common::DocRender';

use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';

use Cwd qw(abs_path);
use Exporter qw(import);
    our @EXPORT = qw();
use File::Basename qw(dirname);
use Storable qw(dclone);

use pgBackRestBuild::Config::Data;

use pgBackRestTest::Common::ExecuteTest;
use pgBackRestTest::Common::HostTest;
use pgBackRestTest::Common::HostGroupTest;

use pgBackRestDoc::Common::DocManifest;
use pgBackRestDoc::Common::Exception;
use pgBackRestDoc::Common::Ini;
use pgBackRestDoc::Common::Log;
use pgBackRestDoc::Common::String;
use pgBackRestDoc::ProjectInfo;

####################################################################################################################################
# User that's building the docs
####################################################################################################################################
use constant DOC_USER                                              => getpwuid($UID) eq 'root' ? 'ubuntu' : getpwuid($UID) . '';

####################################################################################################################################
# Generate indexed defines
####################################################################################################################################
my $rhConfigDefineIndex = cfgDefine();

foreach my $strKey (sort(keys(%{$rhConfigDefineIndex})))
{
    # Build options for all possible db configurations
    if (defined($rhConfigDefineIndex->{$strKey}{&CFGDEF_PREFIX}) &&
        $rhConfigDefineIndex->{$strKey}{&CFGDEF_PREFIX} eq CFGDEF_PREFIX_PG)
    {
        my $strPrefix = $rhConfigDefineIndex->{$strKey}{&CFGDEF_PREFIX};

        for (my $iIndex = 1; $iIndex <= CFGDEF_INDEX_PG; $iIndex++)
        {
            my $strKeyNew = "${strPrefix}${iIndex}" . substr($strKey, length($strPrefix));

            $rhConfigDefineIndex->{$strKeyNew} = dclone($rhConfigDefineIndex->{$strKey});

            $rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_INDEX_TOTAL} = CFGDEF_INDEX_PG;
            $rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_INDEX} = $iIndex - 1;

            # Options indexed > 1 are never required
            if ($iIndex != 1)
            {
                $rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_REQUIRED} = false;
            }

            if (defined($rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_DEPEND}) &&
                defined($rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION}))
            {
                $rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION} =
                    "${strPrefix}${iIndex}" .
                    substr(
                        $rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION},
                        length($strPrefix));
            }
        }

        delete($rhConfigDefineIndex->{$strKey});
    }
    else
    {
        $rhConfigDefineIndex->{$strKey}{&CFGDEF_INDEX} = 0;
    }
}

####################################################################################################################################
# CONSTRUCTOR
####################################################################################################################################
sub new
{
    my $class = shift;       # Class name

    # Assign function parameters, defaults, and log debug info
    my
    (
        $strOperation,
        $strType,
        $oManifest,
        $strRenderOutKey,
        $bExe
    ) =
        logDebugParam
        (
            __PACKAGE__ . '->new', \@_,
            {name => 'strType'},
            {name => 'oManifest'},
            {name => 'strRenderOutKey'},
            {name => 'bExe'}
        );

    # Create the class hash
    my $self = $class->SUPER::new($strType, $oManifest, $bExe, $strRenderOutKey);
    bless $self, $class;

    if (defined($self->{oSource}{hyCache}))
    {
        $self->{bCache} = true;
        $self->{iCacheIdx} = 0;
    }
    else
    {
        $self->{bCache} = false;
    }

    $self->{bExe} = $bExe;

    $self->{iCmdLineLen} = $self->{oDoc}->paramGet('cmd-line-len', false, 80);

    # Return from function and log return values if any
    return logDebugReturn
    (
        $strOperation,
        {name => 'self', value => $self}
    );
}

####################################################################################################################################
# executeKey
#
# Get a unique key for the execution step to determine if the cache is valid.
####################################################################################################################################
sub executeKey
{
    my $self = shift;

    # Assign function parameters, defaults, and log debug info
    my
    (
        $strOperation,
        $strHostName,
        $oCommand,
    ) =
        logDebugParam
        (
            __PACKAGE__ . '->executeKey', \@_,
            {name => 'strHostName', trace => true},
            {name => 'oCommand', trace => true},
        );

    # Add user to command
    my $bUserForce = $oCommand->paramTest('user-force', 'y') ? true : false;
    my $strCommand = $self->{oManifest}->variableReplace(trim($oCommand->fieldGet('exe-cmd')));
    my $strUser = $self->{oManifest}->variableReplace($oCommand->paramGet('user', false, DOC_USER));
    $strCommand = ($strUser eq DOC_USER || $bUserForce ? '' : ('sudo ' . ($strUser eq 'root' ? '' : "-u $strUser "))) . $strCommand;

    # Format and split command
    $strCommand =~ s/[ ]*\n[ ]*/ \\\n    /smg;
    $strCommand =~ s/ \\\@ \\//smg;
    my @stryCommand = split("\n", $strCommand);

    my $hCacheKey =
    {
        host => $strHostName,
        cmd => \@stryCommand,
        output => JSON::PP::false,
    };

    $$hCacheKey{'run-as-user'} = $bUserForce ? $strUser : undef;

    if (defined($oCommand->fieldGet('exe-cmd-extra', false)))
    {
        $$hCacheKey{'cmd-extra'} = $oCommand->fieldGet('exe-cmd-extra');
    }

    if (defined($oCommand->paramGet('err-expect', false)))
    {
        $$hCacheKey{'err-expect'} = $oCommand->paramGet('err-expect');
    }

    if ($oCommand->paramTest('output', 'y') || $oCommand->paramTest('show', 'y') || $oCommand->paramTest('variable-key'))
    {
        $$hCacheKey{'output'} = JSON::PP::true;<commit_msg>Do variable replacements for cmd-extra in documentation.<commit_after>####################################################################################################################################
# DOC EXECUTE MODULE
####################################################################################################################################
package pgBackRestDoc::Common::DocExecute;
use parent 'pgBackRestDoc::Common::DocRender';

use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';

use Cwd qw(abs_path);
use Exporter qw(import);
    our @EXPORT = qw();
use File::Basename qw(dirname);
use Storable qw(dclone);

use pgBackRestBuild::Config::Data;

use pgBackRestTest::Common::ExecuteTest;
use pgBackRestTest::Common::HostTest;
use pgBackRestTest::Common::HostGroupTest;

use pgBackRestDoc::Common::DocManifest;
use pgBackRestDoc::Common::Exception;
use pgBackRestDoc::Common::Ini;
use pgBackRestDoc::Common::Log;
use pgBackRestDoc::Common::String;
use pgBackRestDoc::ProjectInfo;

####################################################################################################################################
# User that's building the docs
####################################################################################################################################
use constant DOC_USER                                              => getpwuid($UID) eq 'root' ? 'ubuntu' : getpwuid($UID) . '';

####################################################################################################################################
# Generate indexed defines
####################################################################################################################################
my $rhConfigDefineIndex = cfgDefine();

foreach my $strKey (sort(keys(%{$rhConfigDefineIndex})))
{
    # Build options for all possible db configurations
    if (defined($rhConfigDefineIndex->{$strKey}{&CFGDEF_PREFIX}) &&
        $rhConfigDefineIndex->{$strKey}{&CFGDEF_PREFIX} eq CFGDEF_PREFIX_PG)
    {
        my $strPrefix = $rhConfigDefineIndex->{$strKey}{&CFGDEF_PREFIX};

        for (my $iIndex = 1; $iIndex <= CFGDEF_INDEX_PG; $iIndex++)
        {
            my $strKeyNew = "${strPrefix}${iIndex}" . substr($strKey, length($strPrefix));

            $rhConfigDefineIndex->{$strKeyNew} = dclone($rhConfigDefineIndex->{$strKey});

            $rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_INDEX_TOTAL} = CFGDEF_INDEX_PG;
            $rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_INDEX} = $iIndex - 1;

            # Options indexed > 1 are never required
            if ($iIndex != 1)
            {
                $rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_REQUIRED} = false;
            }

            if (defined($rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_DEPEND}) &&
                defined($rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION}))
            {
                $rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION} =
                    "${strPrefix}${iIndex}" .
                    substr(
                        $rhConfigDefineIndex->{$strKeyNew}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION},
                        length($strPrefix));
            }
        }

        delete($rhConfigDefineIndex->{$strKey});
    }
    else
    {
        $rhConfigDefineIndex->{$strKey}{&CFGDEF_INDEX} = 0;
    }
}

####################################################################################################################################
# CONSTRUCTOR
####################################################################################################################################
sub new
{
    my $class = shift;       # Class name

    # Assign function parameters, defaults, and log debug info
    my
    (
        $strOperation,
        $strType,
        $oManifest,
        $strRenderOutKey,
        $bExe
    ) =
        logDebugParam
        (
            __PACKAGE__ . '->new', \@_,
            {name => 'strType'},
            {name => 'oManifest'},
            {name => 'strRenderOutKey'},
            {name => 'bExe'}
        );

    # Create the class hash
    my $self = $class->SUPER::new($strType, $oManifest, $bExe, $strRenderOutKey);
    bless $self, $class;

    if (defined($self->{oSource}{hyCache}))
    {
        $self->{bCache} = true;
        $self->{iCacheIdx} = 0;
    }
    else
    {
        $self->{bCache} = false;
    }

    $self->{bExe} = $bExe;

    $self->{iCmdLineLen} = $self->{oDoc}->paramGet('cmd-line-len', false, 80);

    # Return from function and log return values if any
    return logDebugReturn
    (
        $strOperation,
        {name => 'self', value => $self}
    );
}

####################################################################################################################################
# executeKey
#
# Get a unique key for the execution step to determine if the cache is valid.
####################################################################################################################################
sub executeKey
{
    my $self = shift;

    # Assign function parameters, defaults, and log debug info
    my
    (
        $strOperation,
        $strHostName,
        $oCommand,
    ) =
        logDebugParam
        (
            __PACKAGE__ . '->executeKey', \@_,
            {name => 'strHostName', trace => true},
            {name => 'oCommand', trace => true},
        );

    # Add user to command
    my $bUserForce = $oCommand->paramTest('user-force', 'y') ? true : false;
    my $strCommand = $self->{oManifest}->variableReplace(trim($oCommand->fieldGet('exe-cmd')));
    my $strUser = $self->{oManifest}->variableReplace($oCommand->paramGet('user', false, DOC_USER));
    $strCommand = ($strUser eq DOC_USER || $bUserForce ? '' : ('sudo ' . ($strUser eq 'root' ? '' : "-u $strUser "))) . $strCommand;

    # Format and split command
    $strCommand =~ s/[ ]*\n[ ]*/ \\\n    /smg;
    $strCommand =~ s/ \\\@ \\//smg;
    my @stryCommand = split("\n", $strCommand);

    my $hCacheKey =
    {
        host => $strHostName,
        cmd => \@stryCommand,
        output => JSON::PP::false,
    };

    $$hCacheKey{'run-as-user'} = $bUserForce ? $strUser : undef;

    if (defined($oCommand->fieldGet('exe-cmd-extra', false)))
    {
        $$hCacheKey{'cmd-extra'} = $self->{oManifest}->variableReplace($oCommand->fieldGet('exe-cmd-extra'));
    }

    if (defined($oCommand->paramGet('err-expect', false)))
    {
        $$hCacheKey{'err-expect'} = $oCommand->paramGet('err-expect');
    }

    if ($oCommand->paramTest('output', 'y') || $oCommand->paramTest('show', 'y') || $oCommand->paramTest('variable-key'))
    {
        $$hCacheKey{'output'} = JSON::PP::true;
{'fraction_non_alphanumeric': 0.32425816023738874, 'fraction_numerical': 0.0011869436201780415, 'mean_word_length': 3.537529451363177, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 115, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2638649', 'n_tokens_mistral': 3775, 'n_tokens_neox': 3572, 'n_words': 671}