Imported Upstream version 4.0.5
This commit is contained in:
257
makeapi
257
makeapi
@@ -23,16 +23,11 @@
|
||||
# Test the API against a known-good API to ensure that changes aren't made
|
||||
# lightly.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import importlib
|
||||
import itertools
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import inspect
|
||||
import operator
|
||||
|
||||
from ipalib import api
|
||||
from ipalib.parameters import Param
|
||||
from ipalib.output import Output
|
||||
@@ -47,44 +42,21 @@ API_NO_FILE = 4
|
||||
API_DOC_ERROR = 8
|
||||
|
||||
# attributes removed from Param.__kw dictionary
|
||||
PARAM_IGNORED_KW_ATTRIBUTES = (
|
||||
'attribute',
|
||||
'cli_metavar',
|
||||
'default_from',
|
||||
'doc',
|
||||
'exclude',
|
||||
'exponential',
|
||||
'flags',
|
||||
'hint',
|
||||
'include',
|
||||
'label',
|
||||
'length',
|
||||
'maxlength',
|
||||
'maxvalue',
|
||||
'minlength',
|
||||
'minvalue',
|
||||
'noextrawhitespace',
|
||||
'normalizer',
|
||||
'numberclass',
|
||||
'only_absolute',
|
||||
'only_relative',
|
||||
'pattern',
|
||||
'pattern_errmsg',
|
||||
'precision',
|
||||
'primary_key',
|
||||
'require_service',
|
||||
'query',
|
||||
'sortorder',
|
||||
)
|
||||
PARAM_IGNORED_KW_ATTRIBUTES = ('label',
|
||||
'doc',
|
||||
'normalizer',
|
||||
'default_from',
|
||||
'hint',
|
||||
'flags',
|
||||
'sortorder',
|
||||
'pattern_errmsg',)
|
||||
|
||||
# attributes removed from Output object
|
||||
OUTPUT_IGNORED_ATTRIBUTES = (
|
||||
'doc',
|
||||
'flags',
|
||||
)
|
||||
OUTPUT_IGNORED_ATTRIBUTES = ('doc',
|
||||
'flags',)
|
||||
|
||||
def parse_options():
|
||||
from optparse import OptionParser # pylint: disable=deprecated-module
|
||||
from optparse import OptionParser
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option("--validate", dest="validate", action="store_true",
|
||||
@@ -154,7 +126,7 @@ def validate_doc():
|
||||
rval = 0
|
||||
|
||||
# Used to track if we've processed a module already
|
||||
topics = {}
|
||||
modules = {}
|
||||
|
||||
# Initialize error counters
|
||||
n_missing_cmd_doc = 0
|
||||
@@ -171,75 +143,58 @@ def validate_doc():
|
||||
continue
|
||||
|
||||
# Have we processed this module yet?
|
||||
topic = cmd.topic
|
||||
while topic is not None:
|
||||
if not topics.setdefault(topic, 0):
|
||||
# First time seeing this module, validate the module contents
|
||||
doc = None
|
||||
next_topic = None
|
||||
if not modules.setdefault(cmd.module, 0):
|
||||
# First time seeing this module, validate the module contents
|
||||
mod = sys.modules[cmd.module]
|
||||
|
||||
for package in api.packages:
|
||||
module = '%s.%s' % (package.__name__, topic)
|
||||
try:
|
||||
mod = sys.modules[module]
|
||||
except KeyError:
|
||||
try:
|
||||
mod = importlib.import_module(module)
|
||||
except ImportError:
|
||||
continue
|
||||
|
||||
if mod.__doc__ is not None:
|
||||
doc = mod.__doc__
|
||||
|
||||
# See if there is a module topic, if so validate it
|
||||
try:
|
||||
next_topic = mod.topic
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# Does the module have documentation?
|
||||
if doc is None:
|
||||
src_file = inspect.getsourcefile(mod)
|
||||
n_missing_mod_doc += 1
|
||||
print("%s: module \"%s\" has no doc" %
|
||||
(src_file, module))
|
||||
# Yes the module has doc, but is it internationalized?
|
||||
elif not is_i18n(doc):
|
||||
# See if there is a module topic, if so validate it
|
||||
topic = getattr(mod, 'topic', None)
|
||||
if topic is not None:
|
||||
if not is_i18n(topic[1]):
|
||||
src_file = inspect.getsourcefile(cmd_class)
|
||||
n_missing_mod_i18n += 1
|
||||
print("%s: module \"%s\" doc is not internationalized" %
|
||||
(src_file, module))
|
||||
else:
|
||||
next_topic = None
|
||||
print "%s: topic in module \"%s\" is not internationalized" % \
|
||||
(src_file, cmd.module)
|
||||
|
||||
# Increment the count of how many commands in this module
|
||||
topics[topic] = topics[topic] + 1
|
||||
# Does the module have documentation?
|
||||
if mod.__doc__ is None:
|
||||
src_file = inspect.getsourcefile(mod)
|
||||
n_missing_mod_doc += 1
|
||||
print "%s: module \"%s\" has no doc" % \
|
||||
(src_file, cmd.module)
|
||||
# Yes the module has doc, but is it internationalized?
|
||||
elif not is_i18n(mod.__doc__):
|
||||
src_file = inspect.getsourcefile(cmd_class)
|
||||
n_missing_mod_i18n += 1
|
||||
print "%s: module \"%s\" doc is not internationalized" % \
|
||||
(src_file, cmd.module)
|
||||
|
||||
topic = next_topic
|
||||
# Increment the count of how many commands in this module
|
||||
modules[cmd.module] = modules[cmd.module] + 1
|
||||
|
||||
# Does the command have documentation?
|
||||
if cmd.doc is None:
|
||||
if cmd.__doc__ is None:
|
||||
src_file = inspect.getsourcefile(cmd_class)
|
||||
line_num = inspect.getsourcelines(cmd_class)[1]
|
||||
n_missing_cmd_doc += 1
|
||||
print("%s:%d command \"%s\" has no doc" % (src_file, line_num, cmd.name))
|
||||
print "%s:%d command \"%s\" has no doc" % (src_file, line_num, cmd.name)
|
||||
# Yes the command has doc, but is it internationalized?
|
||||
elif not is_i18n(cmd.doc):
|
||||
elif not is_i18n(cmd.__doc__):
|
||||
src_file = inspect.getsourcefile(cmd_class)
|
||||
line_num = inspect.getsourcelines(cmd_class)[1]
|
||||
n_missing_cmd_i18n += 1
|
||||
print("%s:%d command \"%s\" doc is not internationalized" % (src_file, line_num, cmd.name))
|
||||
print "%s:%d command \"%s\" doc is not internationalized" % (src_file, line_num, cmd.name)
|
||||
|
||||
# If any errors, emit summary information and adjust return value
|
||||
if n_missing_cmd_doc > 0 or n_missing_cmd_i18n > 0:
|
||||
rval = API_DOC_ERROR
|
||||
print("%d commands without doc, %d commands whose doc is not i18n" % \
|
||||
(n_missing_cmd_doc, n_missing_cmd_i18n))
|
||||
print "%d commands without doc, %d commands whose doc is not i18n" % \
|
||||
(n_missing_cmd_doc, n_missing_cmd_i18n)
|
||||
|
||||
if n_missing_mod_doc > 0 or n_missing_mod_i18n > 0:
|
||||
rval = API_DOC_ERROR
|
||||
print("%d modules without doc, %d modules whose doc is not i18n" % \
|
||||
(n_missing_mod_doc, n_missing_mod_i18n))
|
||||
print "%d modules without doc, %d modules whose doc is not i18n" % \
|
||||
(n_missing_mod_doc, n_missing_mod_i18n)
|
||||
|
||||
return rval
|
||||
|
||||
@@ -249,7 +204,7 @@ def make_api():
|
||||
"""
|
||||
fd = open(API_FILE, 'w')
|
||||
for cmd in api.Command():
|
||||
fd.write('command: %s\n' % cmd.full_name)
|
||||
fd.write('command: %s\n' % cmd.name)
|
||||
fd.write('args: %d,%d,%d\n' % (len(cmd.args), len(cmd.options), len(cmd.output)))
|
||||
for a in cmd.args():
|
||||
fd.write('arg: %s\n' % param_repr(a))
|
||||
@@ -257,16 +212,8 @@ def make_api():
|
||||
fd.write('option: %s\n' % param_repr(o))
|
||||
for o in sorted(cmd.output(), key=operator.attrgetter('name')):
|
||||
fd.write('output: %s\n' % param_repr(o))
|
||||
for plugin in sorted(itertools.chain(api.Command(), api.Object()),
|
||||
key=operator.attrgetter('full_name')):
|
||||
try:
|
||||
default_plugin = api.Command[plugin.name]
|
||||
except KeyError:
|
||||
default_plugin = api.Object[plugin.name]
|
||||
if plugin is default_plugin:
|
||||
fd.write('default: %s\n' % plugin.full_name)
|
||||
for name, version in sorted(
|
||||
capabilities.items(), key=operator.itemgetter(1, 0)):
|
||||
capabilities.items(), key=lambda (k, v): (v, k)):
|
||||
fd.write('capability: %s %s\n' % (name, version))
|
||||
fd.close()
|
||||
|
||||
@@ -282,7 +229,7 @@ def find_name(line):
|
||||
if m:
|
||||
name = m.group(1)
|
||||
else:
|
||||
print("Couldn't find name in: %s" % line)
|
||||
print "Couldn't find name in: %s" % line
|
||||
name = ''
|
||||
return name
|
||||
|
||||
@@ -292,33 +239,33 @@ def _finalize_command_validation(cmd, found_args, expected_args,
|
||||
passed = True
|
||||
# Check the args of the previous command.
|
||||
if len(found_args) != expected_args:
|
||||
print('Argument count in %s of %d doesn\'t match expected: %d' % (
|
||||
cmd.name, len(found_args), expected_args))
|
||||
print 'Argument count in %s of %d doesn\'t match expected: %d' % (
|
||||
cmd.name, len(found_args), expected_args)
|
||||
passed = False
|
||||
if len(found_options) != expected_options:
|
||||
print('Options count in %s of %d doesn\'t match expected: %d' % (
|
||||
cmd.name, len(found_options), expected_options))
|
||||
print 'Options count in %s of %d doesn\'t match expected: %d' % (
|
||||
cmd.name, len(found_options), expected_options)
|
||||
passed = False
|
||||
if len(found_output) != expected_output:
|
||||
print('Output count in %s of %d doesn\'t match expected: %d' % (
|
||||
cmd.name, len(found_output), expected_output))
|
||||
print 'Output count in %s of %d doesn\'t match expected: %d' % (
|
||||
cmd.name, len(found_output), expected_output)
|
||||
passed = False
|
||||
|
||||
# Check if there is not a new arg/opt/output in previous command
|
||||
for a in cmd.args():
|
||||
if a.param_spec not in found_args:
|
||||
print('Argument %s of command %s in ipalib, not in API file:\n%s' % (
|
||||
a.param_spec, cmd.name, param_repr(a)))
|
||||
print 'Argument %s of command %s in ipalib, not in API file:\n%s' % (
|
||||
a.param_spec, cmd.name, param_repr(a))
|
||||
passed = False
|
||||
for o in cmd.options():
|
||||
if o.param_spec not in found_options:
|
||||
print('Option %s of command %s in ipalib, not in API file:\n%s' % (
|
||||
o.param_spec, cmd.name, param_repr(o)))
|
||||
print 'Option %s of command %s in ipalib, not in API file:\n%s' % (
|
||||
o.param_spec, cmd.name, param_repr(o))
|
||||
passed = False
|
||||
for o in cmd.output():
|
||||
if o.name not in found_output:
|
||||
print('Output %s of command %s in ipalib, not in API file:\n%s' % (
|
||||
o.name, cmd.name, param_repr(o)))
|
||||
print 'Output %s of command %s in ipalib, not in API file:\n%s' % (
|
||||
o.name, cmd.name, param_repr(o))
|
||||
passed = False
|
||||
|
||||
return passed
|
||||
@@ -346,7 +293,6 @@ def validate_api():
|
||||
# First run through the file and compare it to the API
|
||||
existing_cmds = []
|
||||
existing_capabilities = set()
|
||||
existing_defaults = set()
|
||||
cmd = None
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
@@ -359,7 +305,7 @@ def validate_api():
|
||||
|
||||
(arg, name) = line.split(': ', 1)
|
||||
if name not in api.Command:
|
||||
print("Command %s in API file, not in ipalib" % name)
|
||||
print "Command %s in API file, not in ipalib" % name
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
cmd = None
|
||||
else:
|
||||
@@ -384,14 +330,14 @@ def validate_api():
|
||||
else:
|
||||
if a.name == arg:
|
||||
found = True
|
||||
print('Arg in %s doesn\'t match.\nGot %s\nExpected %s' % (
|
||||
name, param_repr(a), line))
|
||||
print 'Arg in %s doesn\'t match.\nGot %s\nExpected %s' % (
|
||||
name, param_repr(a), line)
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
if found:
|
||||
found_args.append(arg)
|
||||
else:
|
||||
arg = find_name(line)
|
||||
print("Argument '%s' in command '%s' in API file not found" % (arg, name))
|
||||
print "Argument '%s' in command '%s' in API file not found" % (arg, name)
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
if line.startswith('option:') and cmd:
|
||||
line = line.replace('option: ', '')
|
||||
@@ -403,13 +349,13 @@ def validate_api():
|
||||
else:
|
||||
if o.name == option:
|
||||
found = True
|
||||
print('Option in %s doesn\'t match. Got %s Expected %s' % (name, o, line))
|
||||
print 'Option in %s doesn\'t match. Got %s Expected %s' % (name, o, line)
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
if found:
|
||||
found_options.append(option)
|
||||
else:
|
||||
option = find_name(line)
|
||||
print("Option '%s' in command '%s' in API file not found" % (option, name))
|
||||
print "Option '%s' in command '%s' in API file not found" % (option, name)
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
if line.startswith('output:') and cmd:
|
||||
line = line.replace('output: ', '')
|
||||
@@ -421,54 +367,27 @@ def validate_api():
|
||||
else:
|
||||
if o.name == output:
|
||||
found = True
|
||||
print('Output in %s doesn\'t match. Got %s Expected %s' % (name, o, line))
|
||||
print 'Output in %s doesn\'t match. Got %s Expected %s' % (name, o, line)
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
if found:
|
||||
found_output.append(output)
|
||||
else:
|
||||
output = find_name(line)
|
||||
print("Option '%s' in command '%s' in API file not found" % (output, name))
|
||||
print "Option '%s' in command '%s' in API file not found" % (output, name)
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
if line.startswith('default:'):
|
||||
default = line.replace('default: ', '')
|
||||
existing_defaults.add(default)
|
||||
default_name = None
|
||||
for namespace in (api.Command, api.Object):
|
||||
try:
|
||||
default_name = namespace[default].name
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
break
|
||||
else:
|
||||
print("Plugin %s in API file, not in ipalib" % default)
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
if default_name is not None:
|
||||
try:
|
||||
expected_default = namespace[default_name].full_name
|
||||
except KeyError:
|
||||
print("Default version of plugin %s in API file not "
|
||||
"found" % default_name)
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
else:
|
||||
if default != expected_default:
|
||||
print("Default version of plugin %s in API file "
|
||||
"doesn't match. Got %s, expected %s." %
|
||||
(default_name, default, expected_default))
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
if line.startswith('capability:'):
|
||||
cap, version = line.replace('capability: ', '').split(' ', 1)
|
||||
existing_capabilities.add(cap)
|
||||
try:
|
||||
expected_version = str(capabilities[cap])
|
||||
except KeyError:
|
||||
print("Capability '%s' in API file not found" % cap)
|
||||
print "Capability '%s' in API file not found" % cap
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
else:
|
||||
if version != expected_version:
|
||||
print((
|
||||
print (
|
||||
"Capability '%s' in API file doesn't match. Got %s, "
|
||||
"expected %s.") % (cap, version, expected_version))
|
||||
"expected %s.") % (cap, version, expected_version)
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
|
||||
if cmd:
|
||||
@@ -479,40 +398,30 @@ def validate_api():
|
||||
|
||||
# Now look for new commands not in the current API
|
||||
for cmd in api.Command():
|
||||
if cmd.full_name not in existing_cmds:
|
||||
print("Command %s in ipalib, not in API" % cmd.full_name)
|
||||
if cmd.name not in existing_cmds:
|
||||
print "Command %s in ipalib, not in API" % cmd.name
|
||||
rval |= API_NEW_COMMAND
|
||||
|
||||
for namespace in (api.Command, api.Object):
|
||||
for plugin in namespace():
|
||||
if plugin.name in namespace and namespace[plugin.name] is cmd:
|
||||
if plugin.full_name not in existing_defaults:
|
||||
print("Default version of command %s in ipalib, not in "
|
||||
"API" % plugin.name)
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
|
||||
for cap in capabilities:
|
||||
if cap not in existing_capabilities:
|
||||
print("Capability %s in ipalib, not in API" % cap)
|
||||
print "Capability %s in ipalib, not in API" % cap
|
||||
rval |= API_FILE_DIFFERENCE
|
||||
|
||||
return rval
|
||||
|
||||
def main():
|
||||
rval = 0
|
||||
options, _args = parse_options()
|
||||
options, args = parse_options()
|
||||
|
||||
cfg = dict(
|
||||
in_server=True,
|
||||
in_tree=True,
|
||||
context='cli',
|
||||
in_server=False,
|
||||
debug=False,
|
||||
verbose=0,
|
||||
validate_api=True,
|
||||
enable_ra=True,
|
||||
mode='developer',
|
||||
plugins_on_demand=False,
|
||||
realm="EXAMPLE.COM",
|
||||
domain="example.com",
|
||||
)
|
||||
|
||||
api.bootstrap(**cfg)
|
||||
@@ -523,25 +432,25 @@ def main():
|
||||
|
||||
if options.validate:
|
||||
if not os.path.exists(API_FILE):
|
||||
print('No %s to validate' % API_FILE)
|
||||
print 'No %s to validate' % API_FILE
|
||||
rval |= API_NO_FILE
|
||||
else:
|
||||
rval |= validate_api()
|
||||
else:
|
||||
print("Writing API to API.txt")
|
||||
print "Writing API to API.txt"
|
||||
rval |= make_api()
|
||||
|
||||
if rval & API_FILE_DIFFERENCE:
|
||||
print('')
|
||||
print('There are one or more changes to the API.\nEither undo the API changes or update API.txt and increment the major version in VERSION.')
|
||||
print ''
|
||||
print 'There are one or more changes to the API.\nEither undo the API changes or update API.txt and increment the major version in VERSION.'
|
||||
|
||||
if rval & API_NEW_COMMAND:
|
||||
print('')
|
||||
print('There are one or more new commands defined.\nUpdate API.txt and increment the minor version in VERSION.')
|
||||
print ''
|
||||
print 'There are one or more new commands defined.\nUpdate API.txt and increment the minor version in VERSION.'
|
||||
|
||||
if rval & API_DOC_ERROR:
|
||||
print('')
|
||||
print('There are one or more documentation problems.\nYou must fix these before preceeding')
|
||||
print ''
|
||||
print 'There are one or more documentation problems.\nYou must fix these before preceeding'
|
||||
|
||||
return rval
|
||||
|
||||
|
||||
Reference in New Issue
Block a user