SERVER 10160 generate symbolic JS constants for ErrorCodes
Signed-off-by: Adam Midvidy <amidvidy@gmail.com>
This commit is contained in:
committed by
Adam Midvidy
parent
d34f1fe4e5
commit
ea25f4c281
@@ -19,7 +19,7 @@
|
||||
|
||||
// from command interface
|
||||
assert.commandFailedWithCode(t.runCommand("distinct", {"key": {a: 1}}),
|
||||
14); // ErrorCodes::TypeMismatch
|
||||
ErrorCodes.TypeMismatch);
|
||||
|
||||
|
||||
//second argument should be a document or error
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
// from command interface
|
||||
assert.commandFailedWithCode(t.runCommand("distinct", {"key": "a", "query": "a"}),
|
||||
14); // ErrorCodes::TypeMismatch
|
||||
ErrorCodes.TypeMismatch);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Import("env")
|
||||
generateErrorCodes = env.Command(
|
||||
target=['error_codes.h', 'error_codes.cpp'],
|
||||
source=['generate_error_codes.py', 'error_codes.err'],
|
||||
action='$PYTHON $SOURCES $TARGETS')
|
||||
action=['$PYTHON ${SOURCES[0]} cpp ${SOURCES[1]} --cpp-header=${TARGETS[0]} --cpp-source=${TARGETS[1]}'])
|
||||
env.Alias('generated-sources', generateErrorCodes)
|
||||
|
||||
env.CppUnitTest('base_test',
|
||||
|
||||
@@ -36,19 +36,29 @@ error_code("symbol2", code2)
|
||||
error_class("class1", ["symbol1", "symbol2, ..."])
|
||||
|
||||
Usage:
|
||||
python generate_error_codes.py <path to error_codes.err> <header file path> <source file path>
|
||||
python generate_error_codes.py <cpp|js> <path to error_codes.err> [options]
|
||||
"""
|
||||
|
||||
usage_msg = "usage: %prog <cpp|js> /path/to/error_codes.err [options]"
|
||||
|
||||
from optparse import OptionParser
|
||||
import sys
|
||||
|
||||
def main(argv):
|
||||
if len(argv) != 4:
|
||||
usage("Wrong number of arguments.")
|
||||
|
||||
error_codes, error_classes = parse_error_definitions_from_file(argv[1])
|
||||
generator = argv[1]
|
||||
error_codes, error_classes = parse_error_definitions_from_file(argv[2])
|
||||
check_for_conflicts(error_codes, error_classes)
|
||||
generate_header(argv[2], error_codes, error_classes)
|
||||
generate_source(argv[3], error_codes, error_classes)
|
||||
if (generator == 'cpp'):
|
||||
if (len(argv) != 5):
|
||||
usage('Wrong number of arguments')
|
||||
cpp_gen = cpp_generator(error_codes, error_classes)
|
||||
cpp_gen.generate()
|
||||
elif (generator == 'js'):
|
||||
if (len(argv) != 4):
|
||||
usage('Wrong number of arguments')
|
||||
js_gen = js_generator(error_codes, error_classes)
|
||||
js_gen.generate()
|
||||
else:
|
||||
usage('Must specify which generator(s) to use.')
|
||||
|
||||
def die(message=None):
|
||||
sys.stderr.write(message or "Fatal error\n")
|
||||
@@ -120,37 +130,147 @@ def has_missing_error_codes(error_codes, error_classes):
|
||||
failed = True
|
||||
return failed
|
||||
|
||||
def generate_header(filename, error_codes, error_classes):
|
||||
class base_generator(object):
|
||||
def __init__(self, error_codes, error_classes):
|
||||
self.error_codes = error_codes
|
||||
self.error_classes = error_classes
|
||||
|
||||
enum_declarations = ',\n '.join('%s = %s' % ec for ec in error_codes)
|
||||
predicate_declarations = ';\n '.join(
|
||||
'static bool is%s(Error err)' % ec[0] for ec in error_classes)
|
||||
def parseOptions(self, options, usage_msg):
|
||||
parser = OptionParser(usage=usage_msg)
|
||||
for (f,d,n,m,h) in options:
|
||||
parser.add_option(f,dest=d,nargs=n,metavar=m,help=h)
|
||||
(options, args) = parser.parse_args()
|
||||
return options
|
||||
|
||||
open(filename, 'wb').write(header_template % dict(
|
||||
error_code_enum_declarations=enum_declarations,
|
||||
error_code_class_predicate_declarations=predicate_declarations))
|
||||
|
||||
def generate_source(filename, error_codes, error_classes):
|
||||
symbol_to_string_cases = ';\n '.join(
|
||||
'case %s: return "%s"' % (ec[0], ec[0]) for ec in error_codes)
|
||||
string_to_symbol_cases = ';\n '.join(
|
||||
'if (name == "%s") return %s' % (ec[0], ec[0])
|
||||
for ec in error_codes)
|
||||
int_to_symbol_cases = ';\n '.join(
|
||||
'case %s: return %s' % (ec[0], ec[0]) for ec in error_codes)
|
||||
predicate_definitions = '\n '.join(
|
||||
generate_error_class_predicate_definition(*ec) for ec in error_classes)
|
||||
open(filename, 'wb').write(source_template % dict(
|
||||
symbol_to_string_cases=symbol_to_string_cases,
|
||||
string_to_symbol_cases=string_to_symbol_cases,
|
||||
int_to_symbol_cases=int_to_symbol_cases,
|
||||
error_code_class_predicate_definitions=predicate_definitions))
|
||||
class js_generator(base_generator):
|
||||
def __init__(self, error_codes, error_classes):
|
||||
super(js_generator, self).__init__(error_codes, error_classes)
|
||||
options = [('--js-source','js_source',1,'DEST_JS_SOURCE','specify dest JS source file to save to')]
|
||||
options = self.parseOptions(options, usage_msg)
|
||||
if (options.js_source):
|
||||
self.js_source = options.js_source
|
||||
else:
|
||||
usage('Must specify JS source files')
|
||||
|
||||
def generate_error_class_predicate_definition(class_name, code_names):
|
||||
cases = '\n '.join('case %s:' % c for c in code_names)
|
||||
return error_class_predicate_template % dict(class_name=class_name, cases=cases)
|
||||
def generate(self):
|
||||
self.generate_source()
|
||||
|
||||
header_template = '''// AUTO-GENERATED FILE DO NOT EDIT
|
||||
def generate_source(self):
|
||||
string_to_int_cases = ',\n '.join(
|
||||
'%s: %s' % (ec[0], ec[1]) for ec in self.error_codes)
|
||||
int_to_string_cases = ',\n '.join(
|
||||
'%s: \'%s\'' % (ec[1], ec[0]) for ec in self.error_codes)
|
||||
predicate_definitions = '\n\n'.join(
|
||||
self.generate_error_class_predicate_definition(*ec) for ec in self.error_classes)
|
||||
open(self.js_source, 'wb').write(self.source_template % dict(
|
||||
string_to_int_cases=string_to_int_cases,
|
||||
int_to_string_cases=int_to_string_cases
|
||||
))
|
||||
|
||||
def generate_error_class_predicate_definition(self, class_name, code_names):
|
||||
cases = '\n '.join('case \'%s\':' % c for c in code_names)
|
||||
return self.error_class_predicate_template % dict(class_name=class_name, cases=cases)
|
||||
|
||||
source_template = '''// AUTO-GENERATED FILE DO NOT EDIT
|
||||
// See src/mongo/base/generate_error_codes.py
|
||||
/* Copyright 2015 MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the GNU Affero General Public License in all respects
|
||||
* for all of the code used other than as permitted herein. If you modify
|
||||
* file(s) with this exception, you may extend this exception to your
|
||||
* version of the file(s), but you are not obligated to do so. If you do not
|
||||
* wish to do so, delete this exception statement from your version. If you
|
||||
* delete this exception statement from all source files in the program,
|
||||
* then also delete it in the license file.
|
||||
*/
|
||||
|
||||
var ErrorCodes = {
|
||||
%(string_to_int_cases)s
|
||||
};
|
||||
|
||||
var ErrorCodeStrings = {
|
||||
%(int_to_string_cases)s
|
||||
};
|
||||
'''
|
||||
|
||||
error_class_predicate_template = '''function is%(class_name)s(err) {
|
||||
if (typeof err === 'string') {
|
||||
error = err;
|
||||
} else if (typeof err === 'number') {
|
||||
error = ErrorCodeStrings[err];
|
||||
}
|
||||
switch (error) {
|
||||
%(cases)s
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
class cpp_generator(base_generator):
|
||||
def __init__(self, error_codes, error_classes):
|
||||
super(cpp_generator, self).__init__(error_codes, error_classes)
|
||||
options = [('--cpp-header','cpp_header',1,'DEST_CPP_HEADER','specify dest CPP header file to save to'), ('--cpp-source','cpp_source',1,'DEST_CPP_SOURCE','specify dest CPP source file to save to')]
|
||||
options = self.parseOptions(options, usage_msg)
|
||||
if (options.cpp_header and options.cpp_source):
|
||||
self.cpp_header = options.cpp_header
|
||||
self.cpp_source = options.cpp_source
|
||||
else:
|
||||
usage('Must specify CPP header and source files')
|
||||
|
||||
def generate(self):
|
||||
self.generate_header()
|
||||
self.generate_source()
|
||||
|
||||
def generate_header(self):
|
||||
|
||||
enum_declarations = ',\n '.join('%s = %s' % ec for ec in self.error_codes)
|
||||
predicate_declarations = ';\n '.join(
|
||||
'static bool is%s(Error err)' % ec[0] for ec in self.error_classes)
|
||||
|
||||
open(self.cpp_header, 'wb').write(self.header_template % dict(
|
||||
error_code_enum_declarations=enum_declarations,
|
||||
error_code_class_predicate_declarations=predicate_declarations))
|
||||
|
||||
def generate_source(self):
|
||||
symbol_to_string_cases = ';\n '.join(
|
||||
'case %s: return "%s"' % (ec[0], ec[0]) for ec in self.error_codes)
|
||||
string_to_symbol_cases = ';\n '.join(
|
||||
'if (name == "%s") return %s' % (ec[0], ec[0])
|
||||
for ec in self.error_codes)
|
||||
int_to_symbol_cases = ';\n '.join(
|
||||
'case %s: return %s' % (ec[0], ec[0]) for ec in self.error_codes)
|
||||
predicate_definitions = '\n '.join(
|
||||
self.generate_error_class_predicate_definition(*ec) for ec in self.error_classes)
|
||||
open(self.cpp_source, 'wb').write(self.source_template % dict(
|
||||
symbol_to_string_cases=symbol_to_string_cases,
|
||||
string_to_symbol_cases=string_to_symbol_cases,
|
||||
int_to_symbol_cases=int_to_symbol_cases,
|
||||
error_code_class_predicate_definitions=predicate_definitions))
|
||||
|
||||
def generate_error_class_predicate_definition(self, class_name, code_names):
|
||||
cases = '\n '.join('case %s:' % c for c in code_names)
|
||||
return self.error_class_predicate_template % dict(class_name=class_name, cases=cases)
|
||||
|
||||
header_template = '''// AUTO-GENERATED FILE DO NOT EDIT
|
||||
// See src/mongo/base/generate_error_codes.py
|
||||
/* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
@@ -178,52 +298,41 @@ header_template = '''// AUTO-GENERATED FILE DO NOT EDIT
|
||||
* delete this exception statement from all source files in the program,
|
||||
* then also delete it in the license file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "mongo/base/string_data.h"
|
||||
|
||||
namespace mongo {
|
||||
|
||||
/**
|
||||
* This is a generated class containing a table of error codes and their corresponding error
|
||||
* strings. The class is derived from the definitions in src/mongo/base/error_codes.err file.
|
||||
*
|
||||
* Do not update this file directly. Update src/mongo/base/error_codes.err instead.
|
||||
*/
|
||||
|
||||
class ErrorCodes {
|
||||
public:
|
||||
enum Error {
|
||||
%(error_code_enum_declarations)s,
|
||||
MaxError
|
||||
};
|
||||
|
||||
static std::string errorString(Error err);
|
||||
|
||||
/**
|
||||
* Parses an Error from its "name". Returns UnknownError if "name" is unrecognized.
|
||||
*
|
||||
* NOTE: Also returns UnknownError for the string "UnknownError".
|
||||
*/
|
||||
static Error fromString(StringData name);
|
||||
|
||||
/**
|
||||
* Casts an integer "code" to an Error. Unrecognized codes are preserved, meaning
|
||||
* that the result of a call to fromInt() may not be one of the values in the
|
||||
* Error enumeration.
|
||||
*/
|
||||
static Error fromInt(int code);
|
||||
|
||||
%(error_code_class_predicate_declarations)s;
|
||||
};
|
||||
|
||||
} // namespace mongo
|
||||
'''
|
||||
|
||||
source_template = '''// AUTO-GENERATED FILE DO NOT EDIT
|
||||
source_template = '''// AUTO-GENERATED FILE DO NOT EDIT
|
||||
// See src/mongo/base/generate_error_codes.py
|
||||
/* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
@@ -251,39 +360,30 @@ source_template = '''// AUTO-GENERATED FILE DO NOT EDIT
|
||||
* delete this exception statement from all source files in the program,
|
||||
* then also delete it in the license file.
|
||||
*/
|
||||
|
||||
#include "mongo/base/error_codes.h"
|
||||
|
||||
|
||||
#include "mongo/util/mongoutils/str.h"
|
||||
|
||||
namespace mongo {
|
||||
|
||||
std::string ErrorCodes::errorString(Error err) {
|
||||
switch (err) {
|
||||
%(symbol_to_string_cases)s;
|
||||
default: return mongoutils::str::stream() << "Location" << err;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCodes::Error ErrorCodes::fromString(StringData name) {
|
||||
%(string_to_symbol_cases)s;
|
||||
return UnknownError;
|
||||
}
|
||||
|
||||
ErrorCodes::Error ErrorCodes::fromInt(int code) {
|
||||
return static_cast<Error>(code);
|
||||
}
|
||||
|
||||
%(error_code_class_predicate_definitions)s
|
||||
|
||||
namespace {
|
||||
static_assert(sizeof(ErrorCodes::Error) == sizeof(int), "sizeof(ErrorCodes::Error) == sizeof(int)");
|
||||
} // namespace
|
||||
} // namespace mongo
|
||||
'''
|
||||
|
||||
error_class_predicate_template = '''bool ErrorCodes::is%(class_name)s(Error err) {
|
||||
error_class_predicate_template = '''bool ErrorCodes::is%(class_name)s(Error err) {
|
||||
switch (err) {
|
||||
%(cases)s
|
||||
return true;
|
||||
@@ -292,5 +392,7 @@ error_class_predicate_template = '''bool ErrorCodes::is%(class_name)s(Error err)
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
||||
|
||||
@@ -286,6 +286,7 @@ extern const JSFile utils;
|
||||
extern const JSFile utils_sh;
|
||||
extern const JSFile utils_auth;
|
||||
extern const JSFile bulk_api;
|
||||
extern const JSFile error_codes;
|
||||
}
|
||||
|
||||
void Scope::execCoreFiles() {
|
||||
@@ -297,6 +298,7 @@ void Scope::execCoreFiles() {
|
||||
execSetup(JSFiles::mr);
|
||||
execSetup(JSFiles::query);
|
||||
execSetup(JSFiles::bulk_api);
|
||||
execSetup(JSFiles::error_codes);
|
||||
execSetup(JSFiles::collection);
|
||||
execSetup(JSFiles::crud_api);
|
||||
execSetup(JSFiles::explain_query);
|
||||
|
||||
@@ -2,8 +2,14 @@
|
||||
|
||||
Import("env")
|
||||
|
||||
generateJSErrorCodes = env.Command(
|
||||
target=['error_codes.js'],
|
||||
source=['$BUILD_DIR/mongo/base/generate_error_codes.py', '$BUILD_DIR/mongo/base/error_codes.err'],
|
||||
action=['$PYTHON ${SOURCES[0]} js ${SOURCES[1]} --js-source=${TARGETS[0]}'])
|
||||
env.Alias('generated-sources', generateJSErrorCodes)
|
||||
|
||||
# Files added here need to be added in scripting/engine.cpp and buildscripts/vcxproj.header as well.
|
||||
env.JSHeader(
|
||||
js_header = env.JSHeader(
|
||||
target="mongo.cpp",
|
||||
source=[
|
||||
"assert.js",
|
||||
@@ -13,6 +19,7 @@ env.JSHeader(
|
||||
"db.js",
|
||||
"explain_query.js",
|
||||
"explainable.js",
|
||||
"error_codes.js",
|
||||
"mongo.js",
|
||||
"mr.js",
|
||||
"query.js",
|
||||
@@ -21,8 +28,9 @@ env.JSHeader(
|
||||
"utils.js",
|
||||
"utils_sh.js",
|
||||
"utils_auth.js",
|
||||
],
|
||||
]
|
||||
)
|
||||
env.Depends(js_header, env.Alias('generated-sources'))
|
||||
|
||||
# Files added here need to be added in shell/shell_utils.cpp and buildscripts/vcxproj.header as
|
||||
# well.
|
||||
|
||||
Reference in New Issue
Block a user