diff --git a/mc_openapi/__main__.py b/mc_openapi/__main__.py index f6aae0ce68e12eaaf3ade3c372f62a1fa000e238..e78350cb086387238235e481e662852a8a2d0250 100644 --- a/mc_openapi/__main__.py +++ b/mc_openapi/__main__.py @@ -134,9 +134,7 @@ else: print("Failed to parse the DOMLR.", file=sys.stderr) exit(-1) - if (doml_ver == DOMLVersion.V2_2 - or doml_ver == DOMLVersion.V2_2_1 - or doml_ver == DOMLVersion.V2_3): + if DOMLVersion.has_DOMLR_support(doml_ver): model = get_pyecore_model(doml_xmi, doml_ver) func_reqs = model.functionalRequirements.items for req in func_reqs: diff --git a/mc_openapi/doml_mc/intermediate_model/metamodel.py b/mc_openapi/doml_mc/intermediate_model/metamodel.py index bb4fb87194c7298d9a7abe503225e45137902d5a..a3874b17ec3e3ef53f65f0fc8e1229293e496bc4 100644 --- a/mc_openapi/doml_mc/intermediate_model/metamodel.py +++ b/mc_openapi/doml_mc/intermediate_model/metamodel.py @@ -21,10 +21,13 @@ class DOMLVersion(Enum): """Retrieve DOML version from string. Try to be less pedantic about versions e.g.: 2.0 becomes V2_0""" - doml_ver = v.replace(".", "_") + doml_ver = v.replace(".", "_").replace("v", "V") if doml_ver[0] != "V": doml_ver = "V" + doml_ver return DOMLVersion[doml_ver] + + def has_DOMLR_support(v: "DOMLVersion"): + return v != DOMLVersion.V2_0 and v != DOMLVersion.V2_1 Multiplicity = tuple[Literal["0", "1"], Literal["1", "*"]] diff --git a/mc_openapi/doml_mc/xmi_parser/doml_model.py b/mc_openapi/doml_mc/xmi_parser/doml_model.py index cc77024f974931bd687c3f01a4fe65f76a9ad832..9359ddacce9ec300c533d58e18383971953d4830 100644 --- a/mc_openapi/doml_mc/xmi_parser/doml_model.py +++ b/mc_openapi/doml_mc/xmi_parser/doml_model.py @@ -82,11 +82,28 @@ def parse_doml_model(raw_model: bytes, doml_version: Optional[DOMLVersion]) -> T try: dv = doml_versions.pop(0) doml_version = dv - return parse_xmi_model(raw_model, dv), dv + parsed_xmi_model = parse_xmi_model(raw_model, dv) + # Try to extract the user-specified version from the DOML + try: + model_version = parsed_xmi_model.version + if model_version: + try: + dv = DOMLVersion.get(model_version) + return parse_xmi_model(raw_model, dv), dv + except: + MSG_ERR_INVALID_DOML_VERSION = f"DOML requires version \"{model_version}\", but could not parse it with that version. Is the version valid?" + logging.error(MSG_ERR_INVALID_DOML_VERSION) + raise RuntimeError(MSG_ERR_INVALID_DOML_VERSION) + except: + pass + # DOML version is not specified, proceed as usual + return parsed_xmi_model, dv except Exception as e: logging.info(f"Couldn't parse with DOML {dv.value}. Trying another version...") if len(doml_versions) == 0: - raise e + MSG_ERR_NO_DOML_VERSIONS = "No other compatible DOML versions found!" + logging.error(MSG_ERR_NO_DOML_VERSIONS) + raise RuntimeError(MSG_ERR_NO_DOML_VERSIONS) else: return get_model(raw_model, doml_version) @@ -95,7 +112,7 @@ def parse_doml_model(raw_model: bytes, doml_version: Optional[DOMLVersion]) -> T try: model = parse_xmi_model(raw_model, doml_version) except: - raise Exception("Parsing of DOML failed. Perhaps you are using the wrong DOML version or IDE?") + raise RuntimeError("Parsing of DOML failed. Perhaps you are using the wrong DOML version or IDE?") logging.info(f"Model '{model.name}' parsed as DOML {doml_version.value}") diff --git a/mc_openapi/handlers.py b/mc_openapi/handlers.py index 0190955bd204a9f4ea29423502199fede859f746..7808d5925affc673a41ddf40e8070745a0d7c5fb 100644 --- a/mc_openapi/handlers.py +++ b/mc_openapi/handlers.py @@ -37,9 +37,7 @@ def post(body, version=None): user_req_str_consts = [] # Add support for Requirements in DOML - if (dmc.doml_version == DOMLVersion.V2_2 - or dmc.doml_version == DOMLVersion.V2_2_1 - or dmc.doml_version == DOMLVersion.V2_3): + if DOMLVersion.has_DOMLR_support(dmc.doml_version): domlr_parser = Parser(DOMLRTransformer) model = get_pyecore_model(doml_xmi, dmc.doml_version) func_reqs = model.functionalRequirements.items diff --git a/tests/doml/v2.2/nginx_func_req.doml b/tests/doml/v2.2/nginx_func_req.doml index f810a6be84417f7a40da07b084b08c4e5f50db8a..3595366211af53d66fead9a293e9a38c69622bbb 100644 --- a/tests/doml/v2.2/nginx_func_req.doml +++ b/tests/doml/v2.2/nginx_func_req.doml @@ -1,4 +1,5 @@ doml nginx_func_req +version "v2.2" application app { @@ -121,29 +122,29 @@ optimization opt { } functional_requirements { - req_ext ``` - > "example requirement to test" - # Expr to parse - not ( - vm is class infrastructure.VirtualMachine - and - vm is not class infrastructure.Storage - or - vm is not class infrastructure.Storage - implies - vm is class infrastructure.Storage - ) - iff - not exists iface, apple ( - forall orange ( - vm has association infrastructure.ComputingNode->ifaces iface - or - vm has association infrastructure.ComputingNode->ifaces iface - ) - and - vm has attribute infrastructure.ComputingNode->os Os1 - ) - --- - "Virtual Machine {vm} has no iface" - ```; -} +req_ext ``` + +# + "VM must have iface and iface is connected to network" +# forall vm ( +# vm is class abstract.VirtualMachine +# implies +# ( +# vm has abstract.ComputingNode.ifaces iface +# and +# iface has abstract.NetworkInterface.belongsTo net +# ) +# ) +# error: "TEST ERROR" + +- "VM must have iface and iface is connected to network" + vm is class abstract.VirtualMachine + and + not exists iface, net ( + vm has abstract.ComputingNode.ifaces iface + and + iface has abstract.NetworkInterface.belongsTo net + + ) + error: "TEST ERROR" + + ```;} diff --git a/tests/doml/v2.2/nginx_func_req.domlx b/tests/doml/v2.2/nginx_func_req.domlx index 5de0b46c4eec6bf1f1f466f72579750e22cfc2d9..aff808cd870eb85a17785aceb7aa0052c58a2cf2 100644 --- a/tests/doml/v2.2/nginx_func_req.domlx +++ b/tests/doml/v2.2/nginx_func_req.domlx @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="ASCII"?> -<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_func_req" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> +<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_func_req" version="v2.2" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0"> <application name="app"> <components xsi:type="app:SoftwareComponent" name="nginx"> <annotations xsi:type="commons:SProperty" key="source_code" value="/usr/share/nginx/html/index.html"/> @@ -55,5 +55,5 @@ <configurations name="conf"> <deployments component="//@application/@components.0" node="//@infrastructure/@groups.0/@machineDefinition"/> </configurations> - <functionalRequirements name="req_ext" description="```

 + "VM must have iface and iface is connected to network"
 	forall vm (
 		vm is class abstract.VirtualMachine
 	implies
 (
 	vm has abstract.ComputingNode.ifaces iface
 	and
 	iface has abstract.NetworkInterface.belongsTo net
 )
 )
 error: "TEST ERROR"
 
 ```"/> + <functionalRequirements name="req_ext" description="```

# + "VM must have iface and iface is connected to network"
# 	forall vm (
# 		vm is class abstract.VirtualMachine
# 	implies
# (
# 	vm has abstract.ComputingNode.ifaces iface
# 	and
# 	iface has abstract.NetworkInterface.belongsTo net
# )
# )
# error: "TEST ERROR"

- "VM must have iface and iface is connected to network"
	vm is class abstract.VirtualMachine
	and
	not exists iface, net (
 	vm has abstract.ComputingNode.ifaces iface
 	and
 	iface has abstract.NetworkInterface.belongsTo net
 
 )
 error: "TEST ERROR"
 
 ```"/> </commons:DOMLModel>