1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-12 10:04:14 +02:00

Migrate error code generation to C.

Parse src/build/error.yaml and write to src/config/error.auto.h and src/config/error.auto.c.
This commit is contained in:
David Steele 2021-08-02 18:32:11 -04:00
parent aaa9136820
commit 74c0c44fc8
14 changed files with 448 additions and 202 deletions

View File

@ -1,136 +0,0 @@
####################################################################################################################################
# Auto-Generate Error Mappings
####################################################################################################################################
package pgBackRestBuild::Error::Build;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use Exporter qw(import);
our @EXPORT = qw();
use pgBackRestDoc::Common::Log;
use pgBackRestBuild::Build::Common;
use pgBackRestBuild::Error::Data;
####################################################################################################################################
# Constants
####################################################################################################################################
use constant BLDLCL_FILE_DEFINE => 'error';
use constant BLDLCL_DATA_ERROR => '01-dataError';
use constant BLDLCL_DATA_ERROR_ARRAY => '01-dataErrorArray';
####################################################################################################################################
# Definitions for constants and data to build
####################################################################################################################################
my $strSummary = 'Error Type Definition';
my $rhBuild =
{
&BLD_FILE =>
{
&BLDLCL_FILE_DEFINE =>
{
&BLD_SUMMARY => $strSummary,
&BLD_DECLARE =>
{
&BLDLCL_DATA_ERROR =>
{
&BLD_SUMMARY => 'Error type declarations',
},
},
&BLD_DATA =>
{
&BLDLCL_DATA_ERROR =>
{
&BLD_SUMMARY => 'Error type definitions',
},
&BLDLCL_DATA_ERROR_ARRAY =>
{
&BLD_SUMMARY => 'Error type array',
},
},
},
},
};
####################################################################################################################################
# Build configuration constants and data
####################################################################################################################################
sub buildError
{
# Build error list
#-------------------------------------------------------------------------------------------------------------------------------
my $rhErrorDefine = errorDefine();
# Order by id for the list that is id ordered
my $rhErrorId = {};
foreach my $strType (sort(keys(%{$rhErrorDefine})))
{
my $iCode = $rhErrorDefine->{$strType};
if (defined($rhErrorId->{$iCode}))
{
confess &log(ERROR, "error code ${iCode} is by '" . $rhErrorId->{$iCode} . "' and '${strType}'");
}
$rhErrorId->{$iCode} = $strType;
}
# Output errors
my $strBuildSource;
foreach my $iCode (sort({sprintf("%03d", $a) cmp sprintf("%03d", $b)} keys(%{$rhErrorId})))
{
my $strType = $rhErrorId->{$iCode};
$strBuildSource .=
"ERROR_DECLARE(" . bldEnum("", $strType, true) . "Error);\n";
}
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DECLARE}{&BLDLCL_DATA_ERROR}{&BLD_SOURCE} = $strBuildSource;
# Output error definition data
$strBuildSource = undef;
foreach my $iCode (sort({sprintf("%03d", $a) cmp sprintf("%03d", $b)} keys(%{$rhErrorId})))
{
my $strType = $rhErrorId->{$iCode};
$strBuildSource .=
"ERROR_DEFINE(" . (' ' x (3 - length($iCode))) . "${iCode}, " . bldEnum("", $strType, true) . "Error, RuntimeError);\n";
}
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_ERROR}{&BLD_SOURCE} = $strBuildSource;
# Output error array
$strBuildSource =
"static const ErrorType *errorTypeList[] =\n" .
"{\n";
foreach my $iCode (sort({sprintf("%03d", $a) cmp sprintf("%03d", $b)} keys(%{$rhErrorId})))
{
$strBuildSource .=
" &" . bldEnum("", $rhErrorId->{$iCode}, true) . "Error,\n";
}
$strBuildSource .=
" NULL,\n" .
"};";
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_ERROR_ARRAY}{&BLD_SOURCE} = $strBuildSource;
return $rhBuild;
}
push @EXPORT, qw(buildError);
1;

View File

@ -1,52 +0,0 @@
####################################################################################################################################
# Error Definition Data
####################################################################################################################################
package pgBackRestBuild::Error::Data;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use Exporter qw(import);
our @EXPORT = qw();
use Storable qw(dclone);
####################################################################################################################################
# Error min and max values
####################################################################################################################################
use constant ERRDEF_MIN => 25;
push @EXPORT, qw(ERRDEF_MIN);
use constant ERRDEF_MAX => 125;
push @EXPORT, qw(ERRDEF_MAX);
####################################################################################################################################
# Error definition data
####################################################################################################################################
my $rhErrorDefine;
####################################################################################################################################
# Load error definition from YAML
####################################################################################################################################
sub errorDefineLoad
{
my $strErrorYaml = shift;
require YAML::XS;
YAML::XS->import(qw(Load));
$rhErrorDefine = Load($strErrorYaml);
}
push @EXPORT, qw(errorDefineLoad);
####################################################################################################################################
# Get error definition
####################################################################################################################################
sub errorDefine
{
return dclone($rhErrorDefine);
}
push @EXPORT, qw(errorDefine);
1;

View File

@ -221,6 +221,22 @@ build-config: $(OBJS_BUILD_CONFIG) build/config/config.yaml config/config.auto.h
$(CC) -o build-config $(OBJS_BUILD_CONFIG) $(LDFLAGS) $(LIBS) $(LIBS_BUILD)
./build-config $(VPATH)
####################################################################################################################################
# Compile and link error generator
####################################################################################################################################
SRCS_BUILD_ERROR = \
build/common/render.c \
build/common/yaml.c \
build/error/main.c \
build/error/parse.c \
build/error/render.c
OBJS_BUILD_ERROR = $(patsubst %.c,$(BUILDDIR)/%.o,$(SRCS_BUILD) $(SRCS_BUILD_ERROR))
build-error: $(OBJS_BUILD_ERROR) build/error/error.yaml
$(CC) -o build-error $(OBJS_BUILD_ERROR) $(LDFLAGS) $(LIBS) $(LIBS_BUILD)
./build-error $(VPATH)
####################################################################################################################################
# Installation. DESTDIR can be used to modify the install location.
####################################################################################################################################

42
src/build/error/main.c Normal file
View File

@ -0,0 +1,42 @@
/***********************************************************************************************************************************
Auto-Generate Errors
***********************************************************************************************************************************/
#include <unistd.h>
#include "common/log.h"
#include "storage/posix/storage.h"
#include "build/error/parse.h"
#include "build/error/render.h"
int
main(int argListSize, const char *argList[])
{
// Check parameters
CHECK(argListSize <= 2);
// Initialize logging
logInit(logLevelWarn, logLevelError, logLevelOff, false, 0, 1, false);
// If the path was specified
const String *pathRepo;
if (argListSize >= 2)
{
pathRepo = strPath(STR(argList[1]));
}
// Else use current working directory
else
{
char currentWorkDir[1024];
THROW_ON_SYS_ERROR(getcwd(currentWorkDir, sizeof(currentWorkDir)) == NULL, FormatError, "unable to get cwd");
pathRepo = strPath(STR(currentWorkDir));
}
// Render error
const Storage *const storageRepo = storagePosixNewP(pathRepo, .write = true);
bldErrRender(storageRepo, bldErrParse(storageRepo));
return 0;
}

95
src/build/error/parse.c Normal file
View File

@ -0,0 +1,95 @@
/***********************************************************************************************************************************
Parse Error Yaml
***********************************************************************************************************************************/
#include "build.auto.h"
#include <yaml.h>
#include "common/log.h"
#include "common/macro.h"
#include "common/type/convert.h"
#include "storage/posix/storage.h"
#include "build/common/yaml.h"
#include "build/error/parse.h"
/***********************************************************************************************************************************
Error min/max codes
***********************************************************************************************************************************/
#define ERROR_CODE_MIN 25
#define ERROR_CODE_MAX 125
/***********************************************************************************************************************************
Parse error list
***********************************************************************************************************************************/
typedef struct BldErrErrorRaw
{
const String *const name; // See BldErrError for comments
unsigned int code;
} BldErrErrorRaw;
static List *
bldErrParseErrorList(Yaml *const yaml)
{
List *const result = lstNewP(sizeof(BldErrError), .comparator = lstComparatorStr);
MEM_CONTEXT_TEMP_BEGIN()
{
yamlEventNextCheck(yaml, yamlEventTypeMapBegin);
YamlEvent err = yamlEventNext(yaml);
do
{
yamlEventCheck(err, yamlEventTypeScalar);
BldErrErrorRaw errRaw =
{
.name = err.value,
};
// Parse error code and check that it is valid
YamlEvent errVal = yamlEventNextCheck(yaml, yamlEventTypeScalar);
errRaw.code = cvtZToUInt(strZ(errVal.value));
if (errRaw.code < ERROR_CODE_MIN || errRaw.code > ERROR_CODE_MAX)
{
THROW_FMT(
FormatError, "error '%s' code must be >= " STRINGIFY(ERROR_CODE_MIN) " and <= " STRINGIFY(ERROR_CODE_MAX),
strZ(errRaw.name));
}
// Add to list
MEM_CONTEXT_BEGIN(lstMemContext(result))
{
lstAdd(
result,
&(BldErrError)
{
.name = strDup(errRaw.name),
.code = errRaw.code,
});
}
MEM_CONTEXT_END();
err = yamlEventNext(yaml);
}
while (err.type != yamlEventTypeMapEnd);
}
MEM_CONTEXT_TEMP_END();
return result;
}
/**********************************************************************************************************************************/
BldErr
bldErrParse(const Storage *const storageRepo)
{
// Initialize yaml
Yaml *const yaml = yamlNew(storageGetP(storageNewReadP(storageRepo, STRDEF("src/build/error/error.yaml"))));
// Parse error
const List *const errList = bldErrParseErrorList(yaml);
return (BldErr){.errList = errList};
}

29
src/build/error/parse.h Normal file
View File

@ -0,0 +1,29 @@
/***********************************************************************************************************************************
Parse Error Yaml
***********************************************************************************************************************************/
#ifndef BUILD_ERROR_PARSE_H
#define BUILD_ERROR_PARSE_H
#include "common/type/string.h"
/***********************************************************************************************************************************
Types
***********************************************************************************************************************************/
typedef struct BldErrError
{
const String *const name; // Name
const unsigned int code; // Code
} BldErrError;
typedef struct BldErr
{
const List *const errList; // Command list
} BldErr;
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
// Parse error.yaml
BldErr bldErrParse(const Storage *const storageRepo);
#endif

138
src/build/error/render.c Normal file
View File

@ -0,0 +1,138 @@
/***********************************************************************************************************************************
Render Error Data
***********************************************************************************************************************************/
#include "build.auto.h"
#include <ctype.h>
#include "common/log.h"
#include "storage/posix/storage.h"
#include "build/common/render.h"
#include "build/error/render.h"
/***********************************************************************************************************************************
Build error name from a string
***********************************************************************************************************************************/
static String *
bldErrName(const String *const value)
{
String *const result = strNew();
const char *const valuePtr = strZ(value);
bool upper = true;
for (unsigned int valueIdx = 0; valueIdx < strSize(value); valueIdx++)
{
strCatChr(result, upper ? (char)toupper(valuePtr[valueIdx]) : valuePtr[valueIdx]);
upper = false;
if (valuePtr[valueIdx + 1] == '-')
{
upper = true;
valueIdx++;
}
}
strCatZ(result, "Error");
return result;
}
/***********************************************************************************************************************************
Render error.auto.h
***********************************************************************************************************************************/
#define ERROR_MODULE "error"
#define ERROR_AUTO_COMMENT "Error Type Definition"
static void
bldErrRenderErrorAutoH(const Storage *const storageRepo, const BldErr bldErr)
{
String *error = strNewFmt(
"%s"
"#ifndef COMMON_ERROR_AUTO_H\n"
"#define COMMON_ERROR_AUTO_H\n",
strZ(bldHeader(ERROR_MODULE, ERROR_AUTO_COMMENT)));
// Error declarations
// -----------------------------------------------------------------------------------------------------------------------------
strCatZ(
error,
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Error type declarations\n"
COMMENT_BLOCK_END "\n");
for (unsigned int errIdx = 0; errIdx < lstSize(bldErr.errList); errIdx++)
{
const BldErrError *const err = lstGet(bldErr.errList, errIdx);
strCatFmt(error, "ERROR_DECLARE(%s);\n", strZ(bldErrName(err->name)));
}
// End and save
strCatZ(
error,
"\n"
"#endif\n");
bldPut(storageRepo, "src/common/error.auto.h", BUFSTR(error));
}
/***********************************************************************************************************************************
Render error.auto.c
***********************************************************************************************************************************/
static void
bldErrRenderErrorAutoC(const Storage *const storageRepo, const BldErr bldErr)
{
String *error = bldHeader(ERROR_MODULE, ERROR_AUTO_COMMENT);
// Error type definitions
// -----------------------------------------------------------------------------------------------------------------------------
strCatZ(
error,
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Error type definitions\n"
COMMENT_BLOCK_END "\n");
for (unsigned int errIdx = 0; errIdx < lstSize(bldErr.errList); errIdx++)
{
const BldErrError *const err = lstGet(bldErr.errList, errIdx);
strCatFmt(error, "ERROR_DEFINE(%3u, %s, RuntimeError);\n", err->code, strZ(bldErrName(err->name)));
}
// Error type array
// -----------------------------------------------------------------------------------------------------------------------------
strCatZ(
error,
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Error type array\n"
COMMENT_BLOCK_END "\n"
"static const ErrorType *errorTypeList[] =\n"
"{\n");
for (unsigned int errIdx = 0; errIdx < lstSize(bldErr.errList); errIdx++)
{
const BldErrError *const err = lstGet(bldErr.errList, errIdx);
strCatFmt(error, " &%s,\n", strZ(bldErrName(err->name)));
}
strCatZ(
error,
" NULL,\n"
"};\n");
bldPut(storageRepo, "src/common/error.auto.c", BUFSTR(error));
}
/**********************************************************************************************************************************/
void
bldErrRender(const Storage *const storageRepo, const BldErr bldErr)
{
bldErrRenderErrorAutoH(storageRepo, bldErr);
bldErrRenderErrorAutoC(storageRepo, bldErr);
}

15
src/build/error/render.h Normal file
View File

@ -0,0 +1,15 @@
/***********************************************************************************************************************************
Render Error Data
***********************************************************************************************************************************/
#ifndef BUILD_ERROR_RENDER_H
#define BUILD_ERROR_RENDER_H
#include "build/error/parse.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
// Render auto-generated error files
void bldErrRender(const Storage *const storageRepo, const BldErr bldErr);
#endif

View File

@ -1,7 +1,7 @@
/***********************************************************************************************************************************
Error Type Definition
Automatically generated by Build.pm -- do not modify directly.
Automatically generated by 'make build-error' -- do not modify directly.
***********************************************************************************************************************************/
/***********************************************************************************************************************************

View File

@ -1,7 +1,7 @@
/***********************************************************************************************************************************
Error Type Definition
Automatically generated by Build.pm -- do not modify directly.
Automatically generated by 'make build-error' -- do not modify directly.
***********************************************************************************************************************************/
#ifndef COMMON_ERROR_AUTO_H
#define COMMON_ERROR_AUTO_H

View File

@ -623,6 +623,14 @@ unit:
- build/config/parse
- build/config/render
# ----------------------------------------------------------------------------------------------------------------------------
- name: error
total: 1
coverage:
- build/error/parse
- build/error/render
# ********************************************************************************************************************************
- name: info

View File

@ -0,0 +1,101 @@
/***********************************************************************************************************************************
Test Build Error
***********************************************************************************************************************************/
#include "common/harnessStorage.h"
/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
void
testRun(void)
{
FUNCTION_HARNESS_VOID();
// Create default storage object for testing
Storage *storageTest = storagePosixNewP(TEST_PATH_STR, .write = true);
// *****************************************************************************************************************************
if (testBegin("bldErrParse() and bldErrRender()"))
{
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("parse errors");
HRN_STORAGE_PUT_Z(
storageTest, "src/build/error/error.yaml",
"assert: 24\n");
TEST_ERROR(bldErrParse(storageTest), FormatError, "error 'assert' code must be >= 25 and <= 125");
HRN_STORAGE_PUT_Z(
storageTest, "src/build/error/error.yaml",
"assert: 126\n");
TEST_ERROR(bldErrParse(storageTest), FormatError, "error 'assert' code must be >= 25 and <= 125");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("parse and render error");
HRN_STORAGE_PUT_Z(
storageTest, "src/build/error/error.yaml",
"assert: 25\n"
"option-invalid: 31\n"
"runtime: 122\n");
TEST_RESULT_VOID(bldErrRender(storageTest, bldErrParse(storageTest)), "parse and render");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("check error.auto.h");
TEST_STORAGE_GET(
storageTest,
"src/common/error.auto.h",
COMMENT_BLOCK_BEGIN "\n"
"Error Type Definition\n"
"\n"
"Automatically generated by 'make build-error' -- do not modify directly.\n"
COMMENT_BLOCK_END "\n"
"#ifndef COMMON_ERROR_AUTO_H\n"
"#define COMMON_ERROR_AUTO_H\n"
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Error type declarations\n"
COMMENT_BLOCK_END "\n"
"ERROR_DECLARE(AssertError);\n"
"ERROR_DECLARE(OptionInvalidError);\n"
"ERROR_DECLARE(RuntimeError);\n"
"\n"
"#endif\n");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("check error.auto.c");
TEST_STORAGE_GET(
storageTest,
"src/common/error.auto.c",
COMMENT_BLOCK_BEGIN "\n"
"Error Type Definition\n"
"\n"
"Automatically generated by 'make build-error' -- do not modify directly.\n"
COMMENT_BLOCK_END "\n"
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Error type definitions\n"
COMMENT_BLOCK_END "\n"
"ERROR_DEFINE( 25, AssertError, RuntimeError);\n"
"ERROR_DEFINE( 31, OptionInvalidError, RuntimeError);\n"
"ERROR_DEFINE(122, RuntimeError, RuntimeError);\n"
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Error type array\n"
COMMENT_BLOCK_END "\n"
"static const ErrorType *errorTypeList[] =\n"
"{\n"
" &AssertError,\n"
" &OptionInvalidError,\n"
" &RuntimeError,\n"
" NULL,\n"
"};\n");
}
FUNCTION_HARNESS_RETURN_VOID();
}

View File

@ -37,8 +37,6 @@ use pgBackRestDoc::ProjectInfo;
use pgBackRestBuild::Build;
use pgBackRestBuild::Build::Common;
use pgBackRestBuild::Config::BuildHelp;
use pgBackRestBuild::Error::Build;
use pgBackRestBuild::Error::Data;
use pgBackRestTest::Common::BuildTest;
use pgBackRestTest::Common::CodeCountTest;
@ -538,8 +536,6 @@ eval
# Auto-generate C files
#-----------------------------------------------------------------------------------------------------------------------
errorDefineLoad(${$oStorageBackRest->get("build/error.yaml")});
my $rhBuild =
{
'configHelp' =>
@ -547,12 +543,6 @@ eval
&BLD_DATA => buildConfigHelp(),
&BLD_PATH => 'command/help',
},
'error' =>
{
&BLD_DATA => buildError(),
&BLD_PATH => 'common',
},
};
my @stryBuilt = buildAll("${strBackRestBase}/src", $rhBuild);
@ -568,8 +558,8 @@ eval
&log(INFO, " autogenerated C code: " . (@stryBuilt ? join(', ', @stryBuilt) : 'no changes'));
# Build configuration
executeTest("make -C ${strBuildPath} build-config");
# Build code
executeTest("make -C ${strBuildPath} build-config build-error");
if ($bGenOnly)
{