config_tools: pretty-print JSON schema violations

The default error messages provided by the ajv validation library read like
this:

    * must have required property MEMORY.STACK_SIZE

    * must match pattern "<a regular expression>"

Such messages may look confusing as users are not supposed to understand
the internal naming of the config items or the regular expressions used to
validate strings.

This patch enables the XML schema to include 'acrn:errormsg' annotations
which is a dictionary from error types to customized error messages. This
mechanism is used to show more user-friendly messages upon common errors
such as missing or invalid data in required config item.

Tracked-On: #6691
Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
Junjie Mao 2022-05-25 16:02:54 +08:00 committed by acrnsi-robot
parent 8042806676
commit e42d323459
4 changed files with 40 additions and 15 deletions

View File

@ -151,6 +151,17 @@ class XS2JS:
if '@acrn:widget-options' in annotation:
js_ele['ui:options'] = eval(f"{{{annotation['@acrn:widget-options']}}}")
def convert_errormsg_config(self, annotation, js_ele):
if '@acrn:errormsg' in annotation:
opts = eval(f"{{{annotation['@acrn:errormsg']}}}")
# An items of an error schema requires an "err:" prefix.
keys = list(opts.keys())
for key in keys:
opts[f"err:{key}"] = opts.pop(key)
js_ele.update(opts)
def xst2jst(self, type_name) -> str:
"""convert xml schema type name to json schema type name"""
if type_name in self.xst2jst_mapping:
@ -195,9 +206,10 @@ class XS2JS:
enum_names.append(enum_name)
js_st["enumNames"] = enum_names
# widget and its options
# widget configs and error messages
if 'xs:annotation' in obj:
self.convert_widget_config(obj['xs:annotation'], js_st)
self.convert_errormsg_config(obj['xs:annotation'], js_st)
js_st.update(self.xsa2jsa(restriction))
return js_st
@ -298,7 +310,7 @@ class XS2JS:
if '@maxOccurs' in element:
# ui:options seen at this moment are copied from the annotation of the type.
possible_keys = ['type', '$ref', 'oneOf', 'ui:options']
possible_keys = ['type', '$ref', 'oneOf', 'ui:options', 'err:required', 'err:pattern']
convert_to_items_success = False
js_ele['items'] = {}
for possible_key in possible_keys:
@ -353,6 +365,9 @@ class XS2JS:
# widget and its options
self.convert_widget_config(element['xs:annotation'], js_ele)
# Error messages
self.convert_errormsg_config(element['xs:annotation'], js_ele)
properties[name] = js_ele
# build result

View File

@ -71,12 +71,14 @@
<xs:complexType name="EPCSection">
<xs:sequence>
<xs:element name="base" type="HexFormat" default="0">
<xs:annotation acrn:title="EPC section base" acrn:applicable-vms="pre-launched">
<xs:annotation acrn:title="EPC section base" acrn:applicable-vms="pre-launched"
acrn:errormsg="'required': 'EPC section base is required.'">
<xs:documentation>Specify the enclave page cache (EPC) section base for Intel Software Guard Extensions (SGX). Must be page aligned.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="size" type="HexFormat" default="0">
<xs:annotation acrn:title="EPC section size (bytes)" acrn:applicable-vms="pre-launched">
<xs:annotation acrn:title="EPC section size (bytes)" acrn:applicable-vms="pre-launched"
acrn:errormsg="'required': 'EPC section size is required.'">
<xs:documentation>Specify the enclave page cache (EPC) section size in bytes for Intel Software Guard Extensions (SGX). Must be page aligned.</xs:documentation>
</xs:annotation>
</xs:element>
@ -86,12 +88,14 @@
<xs:complexType name="HPARegionType">
<xs:sequence>
<xs:element name="start_hpa" type="HexFormat">
<xs:annotation acrn:title="Start physical address">
<xs:annotation acrn:title="Start physical address"
acrn:errormsg="'required': 'Physical memory base address is required.'">
<xs:documentation>Specify the starting address for non-contiguous allocation.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="size_hpa" type="xs:integer">
<xs:annotation acrn:title="Size (MB)">
<xs:annotation acrn:title="Size (MB)"
acrn:errormsg="'required': 'Physical memory size is required.'">
<xs:documentation>Specify the physical memory size for non-contiguous allocation in megabytes.
The size is a subset of the VM's total memory size specified on the Basic tab.</xs:documentation>
</xs:annotation>
@ -278,7 +282,8 @@ The size is a subset of the VM's total memory size specified on the Basic tab.</
<xs:sequence>
<xs:element name="usb_dev" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation acrn:title="USB device assignment"
acrn:options="//usb_device/@description" acrn:options-sorted-by="lambda s: s">
acrn:options="//usb_device/@description" acrn:options-sorted-by="lambda s: s"
acrn:errormsg="'required': 'USB device required. If no USB device is available, click the X at the top right corner of this entry to remove.'">
<xs:documentation>Select the USB physical bus and port number that will be emulated by the ACRN Device Model for this VM. USB 3.0, 2.0, and 1.0 are supported.</xs:documentation>
</xs:annotation>
</xs:element>

View File

@ -124,7 +124,8 @@
<xs:complexType name="MemoryOptionsType">
<xs:all>
<xs:element name="STACK_SIZE" type="HexFormat" default="0x2000">
<xs:annotation acrn:title="CPU memory stack size (bytes)" acrn:views="advanced">
<xs:annotation acrn:title="CPU memory stack size (bytes)" acrn:views="advanced"
acrn:errormsg="'required': 'Stack size is required.'">
<xs:documentation>Specify the size of the memory stack in bytes for each physical CPU. For example, if you specify 8 kilobytes, each CPU will get its own 8-kilobyte stack.</xs:documentation>
</xs:annotation>
</xs:element>
@ -299,9 +300,10 @@ Refer to :ref:`vuart_config` for detailed vUART settings.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="name" type="VMNameType">
<xs:annotation acrn:title="VM name" acrn:views="basic">
<xs:documentation>Specify the name used to identify this VM. The VM name will be shown in the hypervisor console vm_list command.</xs:documentation>
</xs:annotation>
<xs:annotation acrn:title="VM name" acrn:views="basic"
acrn:errormsg="'required': 'VM name is required.'">
<xs:documentation>Specify the name used to identify this VM. The VM name will be shown in the hypervisor console vm_list command.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="vm_type" type="VMType" minOccurs="0">
<xs:annotation acrn:title="VM type" acrn:views="basic">
@ -484,8 +486,9 @@ mouse, and tablet. It sends Linux input layer events over virtio.</xs:documenta
<xs:documentation>The virtio-blk device presents a block device to the VM. Each virtio-blk device appears as a disk inside the VM.</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:annotation acrn:widget-options="'placeholder': '/home/user/path/to/disk.image'" />
<xs:restriction base="xs:string" />
<xs:annotation acrn:widget-options="'placeholder': '/home/user/path/to/disk.image'"
acrn:errormsg="'required': 'Path to a disk image required.'"/>
<xs:restriction base="xs:string" />
</xs:simpleType>
</xs:element>
</xs:all>

View File

@ -14,7 +14,8 @@
</xs:simpleType>
<xs:simpleType name="HexFormat">
<xs:annotation acrn:widget-options="'placeholder': 'A hexadecimal number with a leading 0x, e.g. 0x1000.'">
<xs:annotation acrn:widget-options="'placeholder': 'A hexadecimal number with a leading 0x, e.g. 0x1000.'"
acrn:errormsg="'pattern': 'Must be a hexadecimal integer (case-insensitive).'">
<xs:documentation>An Integer value in hexadecimal format (with a leading ``0x``).</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
@ -167,7 +168,8 @@ Read more about the available scheduling options in :ref:`cpu_sharing`.</xs:docu
</xs:simpleType>
<xs:simpleType name="VMNameType">
<xs:annotation acrn:widget-options="'placeholder': 'A string with at most 15 non-space characters, e.g. Linux-VM-1.'">
<xs:annotation acrn:widget-options="'placeholder': 'A string with at most 15 non-space characters, e.g. Linux-VM-1.'"
acrn:errormsg="'pattern': 'Must NOT be longer than 15 characters or contain characters other than letters, digits, \'_\' and \'-\'.'">
<xs:documentation>A string of up to 15 letters, digits, ``_``, or ``-``.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">