From 5fb1a98525c3bcb8ddb076b1e919e77812d4dfd6 Mon Sep 17 00:00:00 2001 From: pallasscat <64778984+pallasscat@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:22:21 +0300 Subject: [PATCH] Various fixes in tools/ to improve code generation (#199) * Fixed excessive newlines * Fixed unquoted variables; fixed directory issues caused by unzipping into current directory; updated schema version to latest; minor fixes * Switched to regex based cleanup; added double space cleanup; switched to int-based schema version selection; minor fixes --- tools/gen_script.sh | 13 ++++---- tools/generate_from_schema.py | 59 +++++++++++------------------------ tools/source.tmpl | 10 +++--- 3 files changed, 30 insertions(+), 52 deletions(-) diff --git a/tools/gen_script.sh b/tools/gen_script.sh index 4b16a6c5..f9edafeb 100755 --- a/tools/gen_script.sh +++ b/tools/gen_script.sh @@ -15,7 +15,7 @@ PYTHON="python3" # # Inspect the url for the schema you want - for example, the 2020.1 update # document is "DSP8010_2020.1.zip" on this page. The base name then is: -schemadoc="DSP8010_2020.4" +schemadoc="DSP8010_2022.2" # Check if filename provided on the command line if [[ "$#" -eq 1 ]]; then @@ -42,24 +42,23 @@ if [[ ! -d $schemadoc ]]; then if [[ ! -f "${schemadoc}.zip" ]]; then # Use curl instead of wget because it is more likely to be present echo "Fetching schema document $schemadoc" - curl -G -L "https://www.dmtf.org/sites/default/files/standards/documents/${schemadoc}.zip" > ${schemadoc}.zip + curl -G -L "https://www.dmtf.org/sites/default/files/standards/documents/${schemadoc}.zip" > "${schemadoc}.zip" fi echo "Extracting schema files..." - unzip "${schemadoc}.zip" + unzip -q "${schemadoc}.zip" -d "${schemadoc}" fi # Generate the object list. Not elegant, but it works well enough for now. # # SerialInterface and Switch still have some identifier issues to be worked out -# Collection files, Schedule, Protocol are "common" and included differently +# Collection files, Schedule, are "common" and included differently # redfish-schema, odata and all the versions of each object aren't needed # # General process is get a list of the json-schema objects from the zip, drop # things we don't need/want, and clip the column we want generating a file of # object names we can use later. -schema_paths=$(find "$schemadoc" -name *.json) -schema_objects=$(find "$schemadoc" -name *json | cut -d '/' -f 3 | cut -d . -f 1 | grep -v Collection | grep -v "redfish-" | grep -v odata | grep -v Protocol | sort | uniq) +schema_objects=$(find "${schemadoc}/json-schema" -name "*.json" | cut -d '/' -f 3 | cut -d '.' -f 1 | grep -Fiv -e 'collection' -e 'redfish-' -e 'odata' -e 'protocol' | sort | uniq ) # Now we're ready to generate the go source based on these files if [[ ! -d gofiles ]]; then @@ -69,7 +68,7 @@ fi # Loop through each one and generate the raw source file for object in $schema_objects; do echo "Processing object ${object}..." - $PYTHON generate_from_schema.py -l "${schemadoc}/json-schema" -t redfish $object -o "gofiles/${object}.go" + $PYTHON generate_from_schema.py -l "${schemadoc}/json-schema" -t redfish "${object}" -o "gofiles/${object}.go" done # Then clean them up diff --git a/tools/generate_from_schema.py b/tools/generate_from_schema.py index fb40bab1..275eea83 100755 --- a/tools/generate_from_schema.py +++ b/tools/generate_from_schema.py @@ -9,14 +9,15 @@ import logging import os import textwrap +import re import jinja2 import requests LOG = logging.getLogger(__name__) -REDFISH_SCHEMA_BASE = 'http://redfish.dmtf.org/schemas/v1/' -SWORDFISH_SCHEMA_BASE = 'http://redfish.dmtf.org/schemas/swordfish/v1/' +REDFISH_SCHEMA_BASE = 'https://redfish.dmtf.org/schemas/v1/' +SWORDFISH_SCHEMA_BASE = 'https://redfish.dmtf.org/schemas/swordfish/v1/' COMMON_NAME_CHANGES = { 'Oem': 'OEM', @@ -34,43 +35,13 @@ 'Identifier': 'Identifier shall be unique within the managed ecosystem.', } -# Needed for some invalid variable names -NUMBER_WORDS = { - '1': 'One', - '2': 'Two', - '3': 'Three', - '4': 'Four', - '5': 'Five', - '6': 'Six', - '7': 'Seven', - '8': 'Eight', - '9': 'Nine', -} - def _ident(name): """Gets an identifying name that has been cleaned up from the raw name.""" - outname = name - - # Convert dashes to underscores - outname = outname.replace('-', '_') - # Watch out for keyword switch - outname = outname.replace('switch', 'Switch') - # Collapse spaces - outname = outname.replace(' ', '') - # Replace special characters - outname = outname.replace(':', '_') - outname = outname.replace('/', '_div_') - outname = outname.replace('+', '_plus_') + return re.sub(r'[^a-zA-Z0-9]', r'', name) - if len(outname) == 1: - if outname[0].isdigit(): - outname = NUMBER_WORDS.get(outname, "N%s" % outname) - return outname - - -def _format_comment(name, description, cutpoint='used', add=' is'): +def _format_comment(name, description, cutpoint='shall', add=''): if name in COMMON_DESC: return '// %s' % COMMON_DESC[name] @@ -86,14 +57,14 @@ def _get_desc(obj): desc = obj.get('longDescription') if not desc: desc = obj.get('description', '') - return desc + return re.sub(r' ', r' ', desc) def _get_type(name, obj): result = 'string' tipe = obj.get('type') anyof = obj.get('anyOf') or obj.get('items', {}).get('anyOf') - if 'count' in name.lower(): + if name.endswith('Count'): result = 'int' elif name == 'Status': result = 'common.Status' @@ -101,6 +72,8 @@ def _get_type(name, obj): result = 'common.Identifier' elif name == 'Description': result = 'string' + elif name == 'UUID': + result = 'string' elif tipe == 'object': result = name elif isinstance(tipe, list): @@ -174,7 +147,7 @@ def _add_enum(params, name, enum): enum_info = { 'name': name, 'identname': _ident(name), - 'description': _format_comment(name, _get_desc(enum)), + 'description': _format_comment(_ident(name), _get_desc(enum), cutpoint='', add=' is'), 'members': []} for en in enum.get('enum', []): @@ -184,7 +157,7 @@ def _add_enum(params, name, enum): else: desc = enum.get('enumDescriptions', {}).get(en, '') member['description'] = _format_comment( - '%s%s' % (en, name), desc, cutpoint='shall', add='') + '%s%s' % (_ident(en), name), desc, cutpoint='shall', add='') enum_info['members'].append(member) params['enums'].append(enum_info) @@ -250,6 +223,7 @@ def main(): # Get the most recent versioned schema from the base version_url = '' + major, minor, errata = 0, 0, 0 for classdef in base_data.get('definitions', []): if classdef == args.object: refs = base_data['definitions'][classdef].get('anyOf', []) @@ -258,8 +232,13 @@ def main(): if 'idRef' in reflink: continue refurl = reflink.split('#')[0] - if refurl > version_url: - version_url = refurl + refver = re.search(r'v(\d+_\d+_\d+)', refurl) + if refver: + ver = refver.group(1).split('_') + mjr, mnr, ert = int(ver[0]), int(ver[1]), int(ver[2]) + if mjr > major or mnr > minor or ert > errata: + version_url = refurl + major, minor, errata = mjr, mnr, ert break if version_url: diff --git a/tools/source.tmpl b/tools/source.tmpl index 36eb21fd..c799c85d 100644 --- a/tools/source.tmpl +++ b/tools/source.tmpl @@ -17,20 +17,20 @@ import ( type {{ enum.name }} string const ( -{% for enum_member in enum.members %} +{%- for enum_member in enum.members %} {{ enum_member.description }} {{ enum_member.identname }}{{ enum.name }} {{ enum.name }} = "{{ enum_member.name }}" {%- endfor %} ) -{% endfor %} +{%- endfor %} {% for class in classes -%} {{ class.description }} type {{ class.name }} struct { -{% if class.isEntity %} +{%- if class.isEntity %} common.Entity -{% endif %} -{% for attr in class.attrs %} +{%- endif %} +{%- for attr in class.attrs %} {{ attr.description }} {{ attr.name }} {{ attr.type }} {%- endfor %}