From 3fd2e411d4a68470bc18987a004c688662c11068 Mon Sep 17 00:00:00 2001 From: zhuguanyu Date: Mon, 14 Aug 2023 15:03:42 +0800 Subject: YANG Comparator for YANG model automation Issue-ID: MODELING-680 Change-Id: I555b4870d1fd5ca97136772f868482721af982d2 Signed-off-by: zhuguanyu --- .../yangkit/comparator/WhenMustComparator.java | 34 ++ .../yangkit/comparator/YangComparator.java | 594 +++++++++++++++++++++ .../yangkit/comparator/YangComparatorRegister.java | 136 +++++ .../yangkit/comparator/YangCompareResult.java | 65 +++ .../comparator/YangCompareResultSerializer.java | 69 +++ .../comparator/YangCompareResultXmlSerializer.java | 259 +++++++++ .../comparator/YangStatementComparator.java | 31 ++ .../comparator/YangStatementCompareResult.java | 119 +++++ .../yangkit/comparator/YangTreeCompareResult.java | 209 ++++++++ .../comparator/YangTreeMetaCompareResult.java | 124 +++++ .../comparator/app/YangComparatorPlugin.java | 157 ++++++ .../comparator/app/YangComparatorRunner.java | 218 ++++++++ yang-comparator/src/main/resources/plugins.json | 34 ++ yang-comparator/src/main/resources/rules.xml | 563 +++++++++++++++++++ 14 files changed, 2612 insertions(+) create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/WhenMustComparator.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangComparator.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangComparatorRegister.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResult.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResultSerializer.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResultXmlSerializer.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangStatementComparator.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangStatementCompareResult.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangTreeCompareResult.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangTreeMetaCompareResult.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/app/YangComparatorPlugin.java create mode 100644 yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/app/YangComparatorRunner.java create mode 100644 yang-comparator/src/main/resources/plugins.json create mode 100644 yang-comparator/src/main/resources/rules.xml (limited to 'yang-comparator/src/main') diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/WhenMustComparator.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/WhenMustComparator.java new file mode 100644 index 0000000..cc6992a --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/WhenMustComparator.java @@ -0,0 +1,34 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator; + +import org.yangcentral.yangkit.model.api.stmt.YangStatement; + +public class WhenMustComparator extends CommonYangStatementComparator { + @Override + protected CompatibilityInfo defaultCompatibility(YangStatement left, YangStatement right, + CompatibilityRule.ChangeInfo changeInfo) { + if (changeInfo == CompatibilityRule.ChangeInfo.ADDED) { + return new CompatibilityInfo(CompatibilityRule.Compatibility.NBC, + "add a new when/must, it's non-backward-compatible."); + } else if (changeInfo == CompatibilityRule.ChangeInfo.CHANGED) { + return new CompatibilityInfo(CompatibilityRule.Compatibility.UNKNOWN, + "change a when/must, the compatibility is unknown."); + } + return super.defaultCompatibility(left, right, changeInfo); + } +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangComparator.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangComparator.java new file mode 100644 index 0000000..0650879 --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangComparator.java @@ -0,0 +1,594 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.dom4j.Attribute; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; +import org.yangcentral.yangkit.base.YangElement; +import org.yangcentral.yangkit.common.api.Namespace; +import org.yangcentral.yangkit.model.api.schema.YangSchemaContext; +import org.yangcentral.yangkit.model.api.stmt.Augment; +import org.yangcentral.yangkit.model.api.stmt.MainModule; +import org.yangcentral.yangkit.model.api.stmt.Module; +import org.yangcentral.yangkit.model.api.stmt.SchemaNode; +import org.yangcentral.yangkit.model.api.stmt.SchemaNodeContainer; +import org.yangcentral.yangkit.model.api.stmt.Status; +import org.yangcentral.yangkit.model.api.stmt.StatusStmt; +import org.yangcentral.yangkit.model.api.stmt.SubModule; +import org.yangcentral.yangkit.model.api.stmt.VirtualSchemaNode; +import org.yangcentral.yangkit.model.api.stmt.YangBuiltinStatement; +import org.yangcentral.yangkit.model.api.stmt.YangStatement; +import org.yangcentral.yangkit.model.api.stmt.YangUnknown; + + +public class YangComparator { + private final YangSchemaContext leftContext; + private final YangSchemaContext rightContext; + private CompatibilityRules compatibilityRules; + + /** + * constructor. + * + * @param leftContext left schema context (older) + * @param rightContext right schema context (newer) + */ + public YangComparator(YangSchemaContext leftContext, YangSchemaContext rightContext) { + this.leftContext = leftContext; + this.rightContext = rightContext; + } + + /** + * get compatibility rules. + * + * @return rules + */ + public CompatibilityRules getCompatibilityRules() { + return compatibilityRules; + } + + /** + * set compatibility rules. + * + * @param compatibilityRules rules + */ + public void setCompatibilityRules(CompatibilityRules compatibilityRules) { + this.compatibilityRules = compatibilityRules; + } + + /** + * get module tree nodes from module. + * + * @param module module + * @return list of tree nodes + */ + public static List getModuleTreeNodes(MainModule module) { + List effectiveSchemaNodeChildren = new ArrayList<>(); + effectiveSchemaNodeChildren.addAll(getEffectiveSchemaNodeChildren(module)); + for (Augment augment : module.getAugments()) { + effectiveSchemaNodeChildren.addAll(getEffectiveSchemaNodeChildren(augment)); + } + return effectiveSchemaNodeChildren; + } + + /** + * get effective schema node children. + * + * @param schemaNodeContainer schema node container. + * @return list of children + */ + public static List getEffectiveSchemaNodeChildren(SchemaNodeContainer schemaNodeContainer) { + List effectiveSchemaNodeChildren = new ArrayList<>(); + for (SchemaNode schemaNode : schemaNodeContainer.getSchemaNodeChildren()) { + if (schemaNode instanceof VirtualSchemaNode) { + VirtualSchemaNode virtualSchemaNode = (VirtualSchemaNode) schemaNode; + effectiveSchemaNodeChildren.addAll(getEffectiveSchemaNodeChildren(virtualSchemaNode)); + } else { + if (schemaNodeContainer instanceof YangStatement) { + YangStatement parent = (YangStatement) schemaNodeContainer; + Namespace parentNs = parent.getContext().getNamespace(); + Namespace childNs = schemaNode.getContext().getNamespace(); + if (parentNs != null && childNs != null && parentNs.getUri().equals(childNs.getUri())) { + effectiveSchemaNodeChildren.add(schemaNode); + } + } else { + effectiveSchemaNodeChildren.add(schemaNode); + } + } + + + } + return effectiveSchemaNodeChildren; + } + + /** + * compare the left and right statement. + * + * @param left left statement + * @param right right statement + * @return compare result. + */ + public List compareStatement(YangStatement left, YangStatement right) { + return compareStatement(left, right, false); + } + + /** + * compare the left and right statements + * + * @param leftElements list of left statements + * @param rightElements list of right statements + * @param exceptSchemaNode whether except schema node + * @return list of compare results. + */ + public List compareStatement(List leftElements, + List rightElements, + boolean exceptSchemaNode) { + List compareResults = new ArrayList<>(); + List foundStatements = new ArrayList<>(); + + if (leftElements.size() > 0) { + for (YangElement subElement : leftElements) { + if (!(subElement instanceof YangStatement)) { + continue; + } + YangStatement leftSubStatement = (YangStatement) subElement; + if (exceptSchemaNode) { + if (leftSubStatement instanceof SchemaNode) { + continue; + } + } + + List rightSubStatements = new ArrayList<>(); + for (YangElement rightElement : rightElements) { + if (!(rightElement instanceof YangStatement)) { + continue; + } + if (leftSubStatement.getYangKeyword().equals(((YangStatement) rightElement).getYangKeyword())) { + rightSubStatements.add((YangStatement) rightElement); + } + } + if (rightSubStatements.size() == 0) { + //no right statement, so change type is delete + YangStatementCompareResult yangStatementCompareResult = + new YangStatementCompareResult(ChangeType.DELETE, leftSubStatement, null); + compareResults.add(yangStatementCompareResult); + continue; + } + YangStatement matchedRightSubStatement = + CommonYangStatementComparator.searchStatement(leftSubStatement, rightSubStatements, + foundStatements); + if (null == matchedRightSubStatement) { + YangStatementCompareResult yangStatementCompareResult = + new YangStatementCompareResult(ChangeType.DELETE, leftSubStatement, null); + compareResults.add(yangStatementCompareResult); + } else { + foundStatements.add(matchedRightSubStatement); + compareResults.addAll( + compareStatement(leftSubStatement, matchedRightSubStatement, exceptSchemaNode)); + } + } + } + if (rightElements.size() > 0) { + for (YangElement subElement : rightElements) { + if (!(subElement instanceof YangStatement)) { + continue; + } + if (exceptSchemaNode) { + if (subElement instanceof SchemaNode) { + continue; + } + } + YangStatement rightSubElement = (YangStatement) subElement; + if (CommonYangStatementComparator.contains(foundStatements, rightSubElement)) { + continue; + } + YangStatementCompareResult yangStatementCompareResult = new YangStatementCompareResult(ChangeType.ADD, + null, rightSubElement); + compareResults.add(yangStatementCompareResult); + } + } + return compareResults; + } + + /** + * compare left and right statement. + * + * @param left left statement + * @param right right statement + * @param exceptSchemaNode whether except schema node + * @return list of compare result. + */ + public List compareStatement(YangStatement left, YangStatement right, boolean exceptSchemaNode) { + List compareResults = new ArrayList<>(); + if (left == null && right == null) { + return compareResults; + } + if (left == null && right != null) { + YangStatementCompareResult compareResult = new YangStatementCompareResult(ChangeType.ADD, left, right); + compareResults.add(compareResult); + return compareResults; + } + if (left != null && right == null) { + YangStatementCompareResult compareResult = new YangStatementCompareResult(ChangeType.DELETE, left, right); + compareResults.add(compareResult); + return compareResults; + } + + if (!CommonYangStatementComparator.yangStatementIsEqual(left, right)) { + YangStatementCompareResult yangStatementCompareResult = new YangStatementCompareResult(ChangeType.MODIFY, + left, right); + compareResults.add(yangStatementCompareResult); + } + compareResults.addAll(compareStatement(left.getSubElements(), right.getSubElements(), exceptSchemaNode)); + return compareResults; + } + + /** + * compare statements of left and right schema context. + * + * @return list of compare results + */ + public List compareStatement() { + List compareResults = new ArrayList<>(); + List foundModules = new ArrayList<>(); + List modules = leftContext.getModules(); + for (Module module : modules) { + List rightModules = rightContext.getModule(module.getArgStr()); + if (rightModules == null || rightModules.size() == 0) { + //not find + YangStatementCompareResult yangStatementCompareResult = + new YangStatementCompareResult(ChangeType.DELETE, + module, null); + compareResults.add(yangStatementCompareResult); + } else { + Module rightModule = rightModules.get(0); + foundModules.add(rightModule); + compareResults.addAll(compareStatement(module, rightModule)); + } + } + for (Module rightModule : rightContext.getModules()) { + if (rightModule instanceof SubModule) { + continue; + } + if (CommonYangStatementComparator.contains(foundModules, rightModule)) { + continue; + } + YangStatementCompareResult yangStatementCompareResult = + new YangStatementCompareResult(ChangeType.ADD, null, rightModule); + compareResults.add(yangStatementCompareResult); + } + return compareResults; + } + + /** + * resort the compare results. + * + * @param results original results + * @return sorted results + */ + public Map> resortYangCompareResult(List results) { + Map> map = new HashMap<>(); + for (YangCompareResult yangCompareResult : results) { + String module = yangCompareResult.getModule().getArgStr(); + List mapResults = map.get(module); + if (null == mapResults) { + mapResults = new ArrayList<>(); + map.put(module, mapResults); + } + mapResults.add(yangCompareResult); + + } + return map; + } + + private String outputCompareResult(List compareResults) { + Map> resortedResults = resortYangCompareResult(compareResults); + StringBuffer sb = new StringBuffer(); + Iterator>> it = resortedResults.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry> entry = it.next(); + sb.append("module:").append(entry.getKey()).append("\n"); + sb.append("\t").append("added:\n"); + List value = entry.getValue(); + for (YangCompareResult result : value) { + if (result.getChangeType() != ChangeType.ADD) { + continue; + } + sb.append(result.getChangeDescription("\t\t")).append("\n"); + } + sb.append("\t").append("deleted:\n"); + for (YangCompareResult result : value) { + if (result.getChangeType() != ChangeType.DELETE) { + continue; + } + sb.append(result.getChangeDescription("\t\t")).append("\n"); + } + sb.append("\t").append("changed:\n"); + for (YangCompareResult result : value) { + if (result.getChangeType() != ChangeType.MODIFY) { + continue; + } + sb.append(result.getChangeDescription("\t\t")).append("\n"); + } + } + return sb.toString(); + } + + /** + * output the xml format results. + * + * @param compareResults original results + * @param compareType compare type + * @return xml format results + */ + public Document outputXmlCompareResult(List compareResults, CompareType compareType) { + return outputXmlCompareResult(compareResults, true, compareType); + } + + /** + * output the xml format results. + * + * @param compareResults original results + * @param needCompatible whether need compatibility result. + * @param compareType compare type + * @return xml format results + */ + public Document outputXmlCompareResult(List compareResults, boolean needCompatible, + CompareType compareType) { + Map> resortedResults = resortYangCompareResult(compareResults); + Element root = DocumentHelper.createElement("modules"); + Document document = DocumentHelper.createDocument(root); + Iterator>> it = resortedResults.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry> entry = it.next(); + List value = entry.getValue(); + if (value.size() == 0) { + continue; + } + Element moduleElement = DocumentHelper.createElement("module"); + root.add(moduleElement); + Attribute name = DocumentHelper.createAttribute(moduleElement, "name", entry.getKey()); + moduleElement.add(name); + if (compareType == CompareType.COMPATIBLE_CHECK || compareType == CompareType.STMT) { + Element addedStmts = DocumentHelper.createElement("added-statements"); + moduleElement.add(addedStmts); + Element deletedStmts = DocumentHelper.createElement("deleted-statements"); + moduleElement.add(deletedStmts); + Element changedStmts = DocumentHelper.createElement("changed-statements"); + moduleElement.add(changedStmts); + for (YangCompareResult result : value) { + if (!(result instanceof YangStatementCompareResult)) { + continue; + } + if (result.getChangeType() != ChangeType.ADD) { + continue; + } + addedStmts.add((Element) YangCompareResultSerializer.getXmlSerializer(result) + .serialize(false, false, false, needCompatible)); + } + for (YangCompareResult result : value) { + if (!(result instanceof YangStatementCompareResult)) { + continue; + } + if (result.getChangeType() != ChangeType.DELETE) { + continue; + } + deletedStmts.add((Element) YangCompareResultSerializer.getXmlSerializer(result) + .serialize(false, false, false, needCompatible)); + } + for (YangCompareResult result : value) { + if (!(result instanceof YangStatementCompareResult)) { + continue; + } + if (result.getChangeType() != ChangeType.MODIFY) { + continue; + } + changedStmts.add((Element) YangCompareResultSerializer.getXmlSerializer(result) + .serialize(false, false, false, needCompatible)); + } + } + + if (compareType == CompareType.COMPATIBLE_CHECK || compareType == CompareType.TREE) { + Element addedPaths = DocumentHelper.createElement("added-paths"); + moduleElement.add(addedPaths); + Element deletedPaths = DocumentHelper.createElement("deleted-paths"); + moduleElement.add(deletedPaths); + Element changedPaths = DocumentHelper.createElement("changed-paths"); + moduleElement.add(changedPaths); + + for (YangCompareResult result : value) { + if (!(result instanceof YangTreeCompareResult)) { + continue; + } + if (result.getChangeType() != ChangeType.ADD) { + continue; + } + addedPaths.add((Element) YangCompareResultSerializer.getXmlSerializer(result) + .serialize(false, false, false, needCompatible)); + } + for (YangCompareResult result : value) { + if (!(result instanceof YangTreeCompareResult)) { + continue; + } + if (result.getChangeType() != ChangeType.DELETE) { + continue; + } + deletedPaths.add((Element) YangCompareResultSerializer.getXmlSerializer(result) + .serialize(false, false, false, needCompatible)); + } + for (YangCompareResult result : value) { + if (!(result instanceof YangTreeCompareResult)) { + continue; + } + if (result.getChangeType() != ChangeType.MODIFY) { + continue; + } + changedPaths.add((Element) YangCompareResultSerializer.getXmlSerializer(result) + .serialize(false, false, true, needCompatible)); + } + Element obsoleted = DocumentHelper.createElement("obsoleted-paths"); + moduleElement.add(obsoleted); + for (YangCompareResult result : value) { + if (!(result instanceof YangTreeCompareResult)) { + continue; + } + if (result.getChangeType() != ChangeType.MODIFY) { + continue; + } + YangTreeCompareResult yangTreeCompareResult = (YangTreeCompareResult) result; + if (yangTreeCompareResult.getMetaCompareResults().size() == 0) { + continue; + } + YangTreeMetaCompareResult find = null; + for (YangCompareResult metaCompareResult : yangTreeCompareResult.getMetaCompareResults()) { + YangStatementCompareResult yangStatementCompareResult = + (YangStatementCompareResult) metaCompareResult; + if (yangStatementCompareResult.getRight() instanceof StatusStmt) { + StatusStmt right = (StatusStmt) yangStatementCompareResult.getRight(); + if (right.getStatus() == Status.OBSOLETE) { + obsoleted.add( + (Element) YangCompareResultSerializer.getXmlSerializer(result) + .serialize(false, false, false, false)); + } + } + } + + } + Element deprecated = DocumentHelper.createElement("deprecated-paths"); + moduleElement.add(deprecated); + for (YangCompareResult result : value) { + if (!(result instanceof YangTreeCompareResult)) { + continue; + } + if (result.getChangeType() != ChangeType.MODIFY) { + continue; + } + YangTreeCompareResult yangTreeCompareResult = (YangTreeCompareResult) result; + if (yangTreeCompareResult.getMetaCompareResults().size() == 0) { + continue; + } + YangTreeMetaCompareResult find = null; + for (YangCompareResult metaCompareResult : yangTreeCompareResult.getMetaCompareResults()) { + YangStatementCompareResult yangStatementCompareResult = + (YangStatementCompareResult) metaCompareResult; + if (yangStatementCompareResult.getRight() instanceof StatusStmt) { + StatusStmt right = (StatusStmt) yangStatementCompareResult.getRight(); + if (right.getStatus() == Status.DEPRECATED) { + obsoleted.add( + (Element) YangCompareResultSerializer.getXmlSerializer(result) + .serialize(false, false, false, false)); + } + } + } + + } + } + } + return document; + } + + /** + * output statement to string. + * + * @param statement yang statement + * @return string + */ + public static String outputStatement(YangStatement statement) { + StringBuffer sb = new StringBuffer(); + if (statement instanceof YangBuiltinStatement) { + sb.append(statement.getYangKeyword().getLocalName()); + } else { + YangUnknown unknown = (YangUnknown) statement; + sb.append(unknown.getKeyword()); + } + if (statement.getArgStr() != null) { + sb.append(" ").append(statement.getArgStr()); + } + return sb.toString(); + } + + /** + * compare statements according to compare type and rule. + * + * @param compareType compare type + * @param rule rule file path + * @return list of results + * @throws DocumentException document exception + */ + public List compare(CompareType compareType, String rule) throws DocumentException { + if (rule != null) { + SAXReader reader = new SAXReader(); + Document document = reader.read(new File(rule)); + CompatibilityRules.getInstance().deserialize(document); + } + List compareResults = new ArrayList<>(); + if (compareType == CompareType.STMT) { + compareResults = compareStatement(); + + } else if (compareType == CompareType.TREE) { + List matched = new ArrayList<>(); + for (Module leftModule : leftContext.getModules()) { + if (!(leftModule instanceof MainModule)) { + continue; + } + List leftSchemaNodes = getModuleTreeNodes((MainModule) leftModule); + Module matchedModule = null; + for (Module rightModule : rightContext.getModules()) { + if (rightModule.getArgStr().equals(leftModule.getArgStr())) { + matched.add(rightModule); + matchedModule = rightModule; + break; + } + } + List rightSchemaNodes = new ArrayList<>(); + if (null != matchedModule) { + rightSchemaNodes.addAll(getModuleTreeNodes((MainModule) matchedModule)); + } + compareResults.addAll(CommonYangStatementComparator.compareStatements(leftSchemaNodes, rightSchemaNodes, + CommonYangStatementComparator.OPTION_ONLY_SCHEMA)); + } + for (Module rightModule : rightContext.getModules()) { + if (matched.contains(rightModule)) { + continue; + } + if (!(rightModule instanceof MainModule)) { + continue; + } + compareResults.addAll( + CommonYangStatementComparator.compareStatements(new ArrayList<>(), getModuleTreeNodes( + (MainModule) rightModule), CommonYangStatementComparator.OPTION_ONLY_SCHEMA)); + } + } else if (compareType == CompareType.COMPATIBLE_CHECK) { + compareResults = CommonYangStatementComparator.compareStatements( + leftContext.getModules(), rightContext.getModules(), CommonYangStatementComparator.OPTION_ALL + ); + } + return compareResults; + } + + +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangComparatorRegister.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangComparatorRegister.java new file mode 100644 index 0000000..db54d35 --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangComparatorRegister.java @@ -0,0 +1,136 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.yangcentral.yangkit.base.YangBuiltinKeyword; + + +public class YangComparatorRegister { + private static final YangComparatorRegister ourInstance = new YangComparatorRegister(); + private final Map policyMap = new ConcurrentHashMap<>(); + + /** + * get register instance. + * + * @return instance + */ + public static YangComparatorRegister getInstance() { + return ourInstance; + } + + private YangComparatorRegister() { + inlineRegister(); + } + + /** + * register comparator. + * + * @param yangKeyword keyword + * @param comparator comparator + */ + public void registerComparator(String yangKeyword, YangStatementComparator comparator) { + policyMap.put(yangKeyword, comparator); + } + + /** + * get comparator by yang keyword. + * + * @param yangKeyword yang keyword + * @return comparator + */ + public YangStatementComparator getComparator(String yangKeyword) { + if (yangKeyword == null) { + return new CommonYangStatementComparator(); + } + YangStatementComparator comparator = policyMap.get(yangKeyword); + if (comparator == null) { + return new CommonYangStatementComparator(); + } + return comparator; + } + + private void inlineRegister() { + //config + registerComparator(YangBuiltinKeyword.CONFIG.getKeyword(), new ConfigComparator()); + //enum,bit + registerComparator(YangBuiltinKeyword.ENUM.getKeyword(), new EnumBitComparator()); + registerComparator(YangBuiltinKeyword.BIT.getKeyword(), new EnumBitComparator()); + //module + registerComparator(YangBuiltinKeyword.MODULE.getKeyword(), new ModuleComparator()); + registerComparator(YangBuiltinKeyword.SUBMODULE.getKeyword(), new ModuleComparator()); + //namespace + registerComparator(YangBuiltinKeyword.NAMESPACE.getKeyword(), new NamespaceComparator()); + //schema node + registerComparator(YangBuiltinKeyword.CONTAINER.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.LIST.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.CHOICE.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.CASE.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.RPC.getKeyword(), new OperationComparator()); + registerComparator(YangBuiltinKeyword.ACTION.getKeyword(), new OperationComparator()); + registerComparator(YangBuiltinKeyword.INPUT.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.OUTPUT.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.NOTIFICATION.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.LEAFLIST.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.LEAF.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.ANYDATA.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.ANYXML.getKeyword(), new SchemaNodeComparator()); + registerComparator(YangBuiltinKeyword.AUGMENT.getKeyword(), new AugmentComparator()); + //type + registerComparator(YangBuiltinKeyword.TYPE.getKeyword(), new TypeStatementComparator()); + //value + registerComparator(YangBuiltinKeyword.VALUE.getKeyword(), new ValuePositionComparator()); + //position + registerComparator(YangBuiltinKeyword.POSITION.getKeyword(), new ValuePositionComparator()); + //range + registerComparator(YangBuiltinKeyword.RANGE.getKeyword(), new RangeLengthComparator()); + //length + registerComparator(YangBuiltinKeyword.LENGTH.getKeyword(), new RangeLengthComparator()); + //pattern + registerComparator(YangBuiltinKeyword.PATTERN.getKeyword(), new PatternComparator()); + //default + registerComparator(YangBuiltinKeyword.DEFAULT.getKeyword(), new DefaultComparator()); + //units + registerComparator(YangBuiltinKeyword.UNITS.getKeyword(), new UnitsComparator()); + //description + registerComparator(YangBuiltinKeyword.DESCRIPTION.getKeyword(), new DescriptionComparator()); + //reference + registerComparator(YangBuiltinKeyword.REFERENCE.getKeyword(), new ReferenceComparator()); + //when/must + registerComparator(YangBuiltinKeyword.WHEN.getKeyword(), new WhenMustComparator()); + registerComparator(YangBuiltinKeyword.MUST.getKeyword(), new WhenMustComparator()); + //mandatory + registerComparator(YangBuiltinKeyword.MANDATORY.getKeyword(), new MandatoryComparator()); + //max-elements + registerComparator(YangBuiltinKeyword.MAXELEMENTS.getKeyword(), new MaxElementsComparator()); + //min-elements + registerComparator(YangBuiltinKeyword.MINELEMENTS.getKeyword(), new MinElementsComparator()); + //base + registerComparator(YangBuiltinKeyword.BASE.getKeyword(), new BaseComparator()); + //typedef,extension,feature,identity + registerComparator(YangBuiltinKeyword.TYPEDEF.getKeyword(), new IdentifierComparator()); + registerComparator(YangBuiltinKeyword.EXTENSION.getKeyword(), new IdentifierComparator()); + registerComparator(YangBuiltinKeyword.FEATURE.getKeyword(), new IdentifierComparator()); + registerComparator(YangBuiltinKeyword.IDENTITY.getKeyword(), new IdentifierComparator()); + //if-feature + registerComparator(YangBuiltinKeyword.IFFEATURE.getKeyword(), new IfFeatureComparator()); + //unique + registerComparator(YangBuiltinKeyword.UNIQUE.getKeyword(), new UniqueComparator()); + + } +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResult.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResult.java new file mode 100644 index 0000000..24cafff --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResult.java @@ -0,0 +1,65 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator; + +import org.yangcentral.yangkit.model.api.stmt.Module; + + +public interface YangCompareResult { + /** + * get change type. + * @return change type. + */ + ChangeType getChangeType(); + + /** + * get left. + * @return left + */ + T getLeft(); + + /** + * get right. + * @return right + */ + T getRight(); + + /** + * get change description. + * @param indent indent + * @return string + */ + String getChangeDescription(String indent); + + /** + * get module. + * @return module + */ + Module getModule(); + + /** + * get compatibility info. + * @return compatibility info. + */ + CompatibilityInfo getCompatibilityInfo(); + + /** + * set compatibility info. + * @param compatibilityInfo compatibility info + */ + void setCompatibilityInfo(CompatibilityInfo compatibilityInfo); +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResultSerializer.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResultSerializer.java new file mode 100644 index 0000000..d96acdc --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResultSerializer.java @@ -0,0 +1,69 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator; + + +public abstract class YangCompareResultSerializer { + private final YangCompareResult yangCompareResult; + + /** + * constructor. + * + * @param yangCompareResult result + */ + public YangCompareResultSerializer(YangCompareResult yangCompareResult) { + this.yangCompareResult = yangCompareResult; + } + + /** + * serialize result. + * + * @return the result of T format. + */ + public abstract T serialize(); + + /** + * serialize result. + * + * @param needChangeType whether need change type + * @param needMetaPath whether need meta path + * @param needMeta whether need meta + * @param needCompatibility whether need compatibility. + * @return the result of T format. + */ + public abstract T serialize(boolean needChangeType, boolean needMetaPath, boolean needMeta, + boolean needCompatibility); + + /** + * get compare result. + * + * @return result. + */ + public YangCompareResult getYangCompareResult() { + return yangCompareResult; + } + + /** + * get xml serializer. + * + * @param yangCompareResult result + * @return xml serializer + */ + public static YangCompareResultSerializer getXmlSerializer(YangCompareResult yangCompareResult) { + return new YangCompareResultXmlSerializer(yangCompareResult); + } +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResultXmlSerializer.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResultXmlSerializer.java new file mode 100644 index 0000000..59ac35a --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangCompareResultXmlSerializer.java @@ -0,0 +1,259 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator; + +import org.dom4j.Attribute; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; + + +public class YangCompareResultXmlSerializer extends YangCompareResultSerializer { + /** + * constructor. + * + * @param yangCompareResult result + */ + public YangCompareResultXmlSerializer(YangCompareResult yangCompareResult) { + super(yangCompareResult); + } + + private void serializeYangStatementCompareResult(YangStatementCompareResult yangStatementCompareResult, + Element element, + boolean needType, boolean needCompatibility) { + //change type + if (needType) { + Element changeType = DocumentHelper.createElement("type"); + changeType.setText(yangStatementCompareResult.getChangeType().getName()); + element.add(changeType); + } + + StringBuffer sb = new StringBuffer(); + sb.append("module:").append(yangStatementCompareResult.getModule().getArgStr()).append(" "); + switch (yangStatementCompareResult.getChangeType()) { + case ADD: { + //statement + Attribute name = DocumentHelper.createAttribute(element, "text", + YangComparator.outputStatement(yangStatementCompareResult.getRight())); + element.add(name); + //position + Element position = DocumentHelper.createElement("position"); + element.add(position); + position.setText(sb.append(yangStatementCompareResult.getRight() + .getElementPosition().getLocation().getLocation()).toString()); + + + break; + } + case DELETE: { + //statement + Attribute name = DocumentHelper.createAttribute(element, "text", + YangComparator.outputStatement(yangStatementCompareResult.getLeft())); + element.add(name); + //position + Element position = DocumentHelper.createElement("position"); + element.add(position); + position.setText(sb.append(yangStatementCompareResult.getLeft() + .getElementPosition().getLocation().getLocation()).toString()); + break; + } + case MODIFY: { + Attribute name = DocumentHelper.createAttribute(element, "text", + YangComparator.outputStatement(yangStatementCompareResult.getRight())); + element.add(name); + //position + Element toPosition = DocumentHelper.createElement("position"); + element.add(toPosition); + toPosition.setText(sb.toString() + + yangStatementCompareResult.getRight().getElementPosition().getLocation().getLocation()); + + Element from = DocumentHelper.createElement("previous"); + //statement + Element fromStatement = DocumentHelper.createElement("statement"); + from.add(fromStatement); + Attribute fromName = DocumentHelper.createAttribute(fromStatement, "text", + YangComparator.outputStatement(yangStatementCompareResult.getLeft())); + fromStatement.add(fromName); + //position + Element fromPosition = DocumentHelper.createElement("position"); + from.add(fromPosition); + fromPosition.setText(sb.toString() + + yangStatementCompareResult.getLeft().getElementPosition().getLocation().getLocation()); + element.add(from); + break; + } + default: { + break; + } + } + //compatible + if (needCompatibility) { + Element compatibility = DocumentHelper.createElement("compatibility"); + element.add(compatibility); + Attribute type = DocumentHelper.createAttribute(compatibility, "type", + yangStatementCompareResult.getCompatibilityInfo().getCompatibility().getName()); + compatibility.add(type); + if (yangStatementCompareResult.getCompatibilityInfo().getDescription() != null) { + Element description = DocumentHelper.createElement("description"); + compatibility.add(description); + description.setText(yangStatementCompareResult.getCompatibilityInfo().getDescription()); + } + } + } + + private void serializeYangTreeCompareResult(YangTreeCompareResult yangTreeCompareResult, Element element, + boolean needType, boolean needMeta, + boolean needCompatibility) { + + //change type + if (needType) { + Element changeType = DocumentHelper.createElement("type"); + changeType.setText(yangTreeCompareResult.getChangeType().getName()); + element.add(changeType); + } + + //schema-path + if (yangTreeCompareResult.getSchemaPath() != null) { + Attribute link = + DocumentHelper.createAttribute(element, "link", yangTreeCompareResult.getSchemaPath().toString()); + element.add(link); + } else { + System.out.println(yangTreeCompareResult.getChangeDescription(" ")); + } + + //position + Element position = DocumentHelper.createElement("position"); + StringBuffer sb = new StringBuffer(); + sb.append("module:").append(yangTreeCompareResult.getModule().getArgStr()).append(" "); + switch (yangTreeCompareResult.getChangeType()) { + case ADD: + case MODIFY: { + if (yangTreeCompareResult.getRight().getElementPosition() == null) { + break; + } + sb.append(yangTreeCompareResult.getRight().getElementPosition().getLocation().getLocation()); + position.setText(sb.toString()); + break; + } + case DELETE: { + sb.append(yangTreeCompareResult.getLeft().getElementPosition().getLocation().getLocation()); + position.setText(sb.toString()); + break; + } + default: { + break; + } + } + element.add(position); + if (needCompatibility) { + //compatible + Element compatibility = DocumentHelper.createElement("compatibility"); + element.add(compatibility); + Attribute type = DocumentHelper.createAttribute(compatibility, "type", + yangTreeCompareResult.getCompatibilityInfo().getCompatibility().getName()); + compatibility.add(type); + if (yangTreeCompareResult.getCompatibilityInfo().getDescription() != null) { + Element description = DocumentHelper.createElement("description"); + compatibility.add(description); + description.setText(yangTreeCompareResult.getCompatibilityInfo().getDescription()); + } + } + + //meta difference + if (needMeta) { + if (yangTreeCompareResult.getMetaCompareResults().size() > 0) { + Element metaDiff = DocumentHelper.createElement("metas"); + for (YangCompareResult yangCompareResult : yangTreeCompareResult.getMetaCompareResults()) { + metaDiff.add(new YangCompareResultXmlSerializer(yangCompareResult).serialize(true, false, true, + needCompatibility)); + } + element.add(metaDiff); + } + } + } + + private void serializeYangTreeMetaCompareResult(YangTreeMetaCompareResult yangTreeMetaCompareResult, + Element element, + boolean needType, boolean needPath) { + //change type + if (needType) { + Element changeType = DocumentHelper.createElement("type"); + changeType.setText(yangTreeMetaCompareResult.getChangeType().getName()); + element.add(changeType); + } + if (needPath) { + Attribute link = DocumentHelper.createAttribute(element, "link", + yangTreeMetaCompareResult.getTarget().getSchemaPath().toString()); + element.add(link); + } + //meta + Attribute name = DocumentHelper.createAttribute(element, "name", yangTreeMetaCompareResult.getMeta()); + element.add(name); + switch (yangTreeMetaCompareResult.getChangeType()) { + case ADD: { + Element value = DocumentHelper.createElement("value"); + value.setText(yangTreeMetaCompareResult.getRight()); + element.add(value); + break; + } + case DELETE: { + Element value = DocumentHelper.createElement("value"); + value.setText(yangTreeMetaCompareResult.getLeft()); + element.add(value); + break; + } + case MODIFY: { + Element from = DocumentHelper.createElement("from"); + from.setText(yangTreeMetaCompareResult.getLeft()); + element.add(from); + Element to = DocumentHelper.createElement("to"); + to.setText(yangTreeMetaCompareResult.getRight()); + element.add(to); + break; + } + default: { + break; + } + } + } + + @Override + public Element serialize() { + return serialize(true, false, true, true); + } + + @Override + public Element serialize(boolean needChangeType, boolean needMetaPath, boolean needMeta, + boolean needCompatibility) { + YangCompareResult yangCompareResult = getYangCompareResult(); + Element element = null; + if (yangCompareResult instanceof YangStatementCompareResult) { + YangStatementCompareResult yangStatementCompareResult = (YangStatementCompareResult) yangCompareResult; + element = DocumentHelper.createElement("statement"); + serializeYangStatementCompareResult(yangStatementCompareResult, element, needChangeType, needCompatibility); + } else if (yangCompareResult instanceof YangTreeCompareResult) { + YangTreeCompareResult yangTreeCompareResult = (YangTreeCompareResult) yangCompareResult; + element = DocumentHelper.createElement("path"); + serializeYangTreeCompareResult(yangTreeCompareResult, element, needChangeType, needMeta, needCompatibility); + } else if (yangCompareResult instanceof YangTreeMetaCompareResult) { + YangTreeMetaCompareResult yangTreeMetaCompareResult = (YangTreeMetaCompareResult) yangCompareResult; + element = DocumentHelper.createElement("meta"); + serializeYangTreeMetaCompareResult(yangTreeMetaCompareResult, element, needChangeType, needMetaPath); + } + return element; + } + +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangStatementComparator.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangStatementComparator.java new file mode 100644 index 0000000..62bfc9b --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangStatementComparator.java @@ -0,0 +1,31 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator; + +import java.util.List; +import org.yangcentral.yangkit.model.api.stmt.YangStatement; + + +public interface YangStatementComparator { + /** + * compare statements. + * @param left left statement. + * @param right right statement. + * @return result. + */ + List compare(T left, T right); +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangStatementCompareResult.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangStatementCompareResult.java new file mode 100644 index 0000000..9d8847c --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangStatementCompareResult.java @@ -0,0 +1,119 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator; + +import org.yangcentral.yangkit.model.api.stmt.Module; +import org.yangcentral.yangkit.model.api.stmt.YangStatement; + + +public class YangStatementCompareResult implements YangCompareResult { + private final ChangeType changeType; + private final YangStatement left; + private final YangStatement right; + private CompatibilityInfo compatibilityInfo; + + /** + * constructor. + * + * @param changeType change type + * @param left left statement + * @param right right statement + */ + public YangStatementCompareResult(ChangeType changeType, YangStatement left, YangStatement right) { + this.changeType = changeType; + this.left = left; + this.right = right; + } + + @Override + public ChangeType getChangeType() { + return changeType; + } + + @Override + public YangStatement getLeft() { + return left; + } + + @Override + public YangStatement getRight() { + return right; + } + + + @Override + public String getChangeDescription(String indent) { + StringBuffer sb = new StringBuffer(); + if (null != indent) { + sb.append(indent); + } + + switch (changeType) { + case ADD: { + sb.append(YangComparator.outputStatement(right)); + sb.append("\t@").append("module:").append(right.getContext().getCurModule().getArgStr()).append(" ") + .append(right.getElementPosition().getLocation().getLocation()); + break; + } + case MODIFY: { + sb.append("FROM "); + sb.append(YangComparator.outputStatement(left)); + sb.append(" TO "); + sb.append(YangComparator.outputStatement(right)); + sb.append("\t@").append("module:").append(right.getContext().getCurModule().getArgStr()).append(" ") + .append(right.getElementPosition().getLocation().getLocation()); + break; + } + case DELETE: { + sb.append(YangComparator.outputStatement(left)); + sb.append("\t@").append("module:").append(left.getContext().getCurModule().getArgStr()).append(" ") + .append(left.getElementPosition().getLocation().getLocation()); + break; + } + default: { + break; + } + } + return sb.toString(); + } + + @Override + public Module getModule() { + switch (changeType) { + case ADD: + case MODIFY: { + return right.getContext().getCurModule(); + } + case DELETE: { + return left.getContext().getCurModule(); + } + default: { + return null; + } + } + } + + @Override + public CompatibilityInfo getCompatibilityInfo() { + return compatibilityInfo; + } + + @Override + public void setCompatibilityInfo(CompatibilityInfo compatibility) { + this.compatibilityInfo = compatibility; + } +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangTreeCompareResult.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangTreeCompareResult.java new file mode 100644 index 0000000..b3c2792 --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangTreeCompareResult.java @@ -0,0 +1,209 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator; + +import java.util.ArrayList; +import java.util.List; + +import org.yangcentral.yangkit.model.api.schema.SchemaPath; +import org.yangcentral.yangkit.model.api.stmt.Module; +import org.yangcentral.yangkit.model.api.stmt.SchemaNode; + + +public class YangTreeCompareResult implements YangCompareResult { + private final SchemaPath.Absolute schemaPath; + private final ChangeType changeType; + private SchemaNode left; + private SchemaNode right; + private String changeDescription; + private List metaCompareResults = new ArrayList<>(); + private CompatibilityInfo compatibilityInfo; + + /** + * constructor. + * + * @param schemaPath schema path + * @param changeType change type + */ + public YangTreeCompareResult(SchemaPath.Absolute schemaPath, ChangeType changeType) { + this.schemaPath = schemaPath; + this.changeType = changeType; + } + + /** + * get meta compare results. + * + * @return list of compare results + */ + public List getMetaCompareResults() { + return metaCompareResults; + } + + /** + * set meta compare results. + * + * @param metaCompareResults list of meta compare results + */ + public void setMetaCompareResults(List metaCompareResults) { + this.metaCompareResults = metaCompareResults; + } + + /** + * add meta compare result. + * + * @param metaResult result + */ + public void addMetaCompareResult(YangCompareResult metaResult) { + metaCompareResults.add(metaResult); + return; + } + + @Override + public SchemaNode getLeft() { + return left; + } + + /** + * set left schema node. + * + * @param left left schema node. + */ + public void setLeft(SchemaNode left) { + this.left = left; + } + + @Override + public SchemaNode getRight() { + return right; + } + + /** + * set right schema node. + * + * @param right right schema node + */ + public void setRight(SchemaNode right) { + this.right = right; + } + + /** + * get schema path. + * + * @return schema path + */ + public SchemaPath.Absolute getSchemaPath() { + return schemaPath; + } + + @Override + public ChangeType getChangeType() { + return changeType; + } + + /** + * set change description. + * + * @param changeDescription description. + */ + public void setChangeDescription(String changeDescription) { + this.changeDescription = changeDescription; + } + + @Override + public String getChangeDescription(String indent) { + StringBuffer sb = new StringBuffer(); + if (indent != null) { + sb.append(indent); + } + if (changeDescription != null) { + sb.append("\t").append(changeDescription); + return sb.toString(); + } + if (null != schemaPath) { + sb.append(schemaPath.toString()); + } + sb.append("\t@").append("module:"); + switch (changeType) { + case ADD: + case MODIFY: { + sb.append(right.getContext().getCurModule().getArgStr()).append(" ") + .append(right.getElementPosition().getLocation().getLocation()); + break; + } + case DELETE: { + sb.append(left.getContext().getCurModule().getArgStr()).append(" ") + .append(left.getElementPosition().getLocation().getLocation()); + break; + } + default: { + break; + } + } + + if (metaCompareResults.size() > 0) { + for (YangCompareResult compareResult : metaCompareResults) { + sb.append("\n").append(indent).append("\t"); + switch (compareResult.getChangeType()) { + case ADD: { + sb.append("added:"); + break; + } + case DELETE: { + sb.append("deleted:"); + break; + } + case MODIFY: { + sb.append("changed:"); + break; + } + default: { + break; + } + } + sb.append(" "); + sb.append(compareResult.getChangeDescription(null)); + } + } + return sb.toString(); + } + + @Override + public Module getModule() { + switch (changeType) { + case ADD: + case MODIFY: { + return right.getContext().getCurModule(); + } + case DELETE: { + return left.getContext().getCurModule(); + } + default: { + return null; + } + } + } + + @Override + public CompatibilityInfo getCompatibilityInfo() { + return compatibilityInfo; + } + + @Override + public void setCompatibilityInfo(CompatibilityInfo compatibility) { + this.compatibilityInfo = compatibility; + } +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangTreeMetaCompareResult.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangTreeMetaCompareResult.java new file mode 100644 index 0000000..3a160d0 --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/YangTreeMetaCompareResult.java @@ -0,0 +1,124 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator; + +import org.yangcentral.yangkit.model.api.stmt.Module; +import org.yangcentral.yangkit.model.api.stmt.SchemaNode; + + +public class YangTreeMetaCompareResult implements YangCompareResult { + private final SchemaNode target; + private final String meta; + private final String left; + private final String right; + private final ChangeType changeType; + private CompatibilityInfo compatibilityInfo; + + /** + * constructor. + * + * @param target target schema node + * @param meta meta + * @param changeType change type + * @param left left + * @param right right + */ + public YangTreeMetaCompareResult(SchemaNode target, String meta, ChangeType changeType, String left, + String right) { + this.target = target; + this.left = left; + this.right = right; + this.changeType = changeType; + this.meta = meta; + } + + @Override + public ChangeType getChangeType() { + return changeType; + } + + @Override + public String getLeft() { + return left; + } + + @Override + public String getRight() { + return right; + } + + /** + * get meta. + * + * @return meta + */ + public String getMeta() { + return meta; + } + + /** + * get target. + * + * @return target + */ + public SchemaNode getTarget() { + return target; + } + + @Override + public String getChangeDescription(String indent) { + StringBuffer sb = new StringBuffer(); + if (indent != null) { + sb.append(indent); + } + sb.append(changeType.getName()).append(":").append(meta).append(" "); + switch (changeType) { + case ADD: { + sb.append(right); + break; + } + case DELETE: { + sb.append(left); + break; + } + case MODIFY: { + sb.append("FROM:").append(left).append(" TO:") + .append(right); + break; + } + default: { + break; + } + } + return sb.toString(); + } + + @Override + public Module getModule() { + return getTarget().getContext().getCurModule(); + } + + @Override + public CompatibilityInfo getCompatibilityInfo() { + return compatibilityInfo; + } + + @Override + public void setCompatibilityInfo(CompatibilityInfo compatibility) { + this.compatibilityInfo = compatibility; + } +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/app/YangComparatorPlugin.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/app/YangComparatorPlugin.java new file mode 100644 index 0000000..8b513cc --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/app/YangComparatorPlugin.java @@ -0,0 +1,157 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator.app; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.onap.modeling.yangkit.comparator.CompareType; +import org.onap.modeling.yangkit.comparator.YangComparator; +import org.onap.modeling.yangkit.comparator.YangCompareResult; +import org.yangcentral.yangkit.common.api.validate.ValidatorResult; + +import org.yangcentral.yangkit.compiler.Settings; +import org.yangcentral.yangkit.compiler.YangCompiler; +import org.yangcentral.yangkit.compiler.YangCompilerException; +import org.yangcentral.yangkit.model.api.schema.YangSchemaContext; +import org.yangcentral.yangkit.plugin.YangCompilerPlugin; +import org.yangcentral.yangkit.plugin.YangCompilerPluginParameter; +import org.yangcentral.yangkit.utils.file.FileUtil; +import org.yangcentral.yangkit.utils.xml.XmlWriter; + + +/** + * yang comparator plugin. + */ +public class YangComparatorPlugin implements YangCompilerPlugin { + @Override + public YangCompilerPluginParameter getParameter(Properties properties, String name, String value) + throws YangCompilerException { + if (!name.equals("old-yang") && !name.equals("settings") + && !name.equals("compare-type") && !name.equals("rule") + && !name.equals("result")) { + throw new YangCompilerException("unrecognized parameter:" + name); + } + YangCompilerPluginParameter yangCompilerPluginParameter = new YangCompilerPluginParameter() { + @Override + public String getName() { + return name; + } + + @Override + public Object getValue() throws YangCompilerException { + if (name.equals("old-yang") || name.equals("settings") + || name.equals("rule") || name.equals("result")) { + Iterator> it = properties.entrySet().iterator(); + String formatStr = value; + while (it.hasNext()) { + Map.Entry entry = it.next(); + formatStr = formatStr.replaceAll("\\{" + entry.getKey() + "\\}", (String) entry.getValue()); + } + return formatStr; + } + + if (name.equals("compare-type")) { + if (value.equals("stmt")) { + return CompareType.STMT; + } else if (value.equals("tree")) { + return CompareType.TREE; + } else if (value.equals("compatible-check")) { + return CompareType.COMPATIBLE_CHECK; + } + throw new YangCompilerException("unrecognized value:" + value); + } + return null; + } + + }; + return yangCompilerPluginParameter; + } + + @Override + public void run(YangSchemaContext yangSchemaContext, YangCompiler yangCompiler, + List list) throws YangCompilerException { + CompareType compareType = null; + String oldYangPath = null; + String rulePath = null; + String resultPath = null; + for (YangCompilerPluginParameter parameter : list) { + //System.out.println("para name="+parameter.getName() + " para value="+parameter.getValue()); + if (parameter.getName().equals("old-yang")) { + oldYangPath = (String) parameter.getValue(); + yangCompiler.setYang(new File(oldYangPath)); + } else if (parameter.getName().equals("settings")) { + String settingsPath = (String) parameter.getValue(); + try { + yangCompiler.setSettings(Settings.parse(FileUtil.readFile2String(settingsPath))); + } catch (IOException e) { + throw new RuntimeException(e); + } + } else if (parameter.getName().equals("compare-type")) { + compareType = (CompareType) parameter.getValue(); + } else if (parameter.getName().equals("rule")) { + rulePath = (String) parameter.getValue(); + } else if (parameter.getName().equals("result")) { + resultPath = (String) parameter.getValue(); + } + + } + if (oldYangPath == null) { + throw new YangCompilerException("missing mandatory parameter:old-yang"); + } + if (compareType == null) { + throw new YangCompilerException("missing mandatory parameter:compare-type"); + } + if (resultPath == null) { + throw new YangCompilerException("missing mandatory parameter:result"); + } + YangSchemaContext oldSchemaContext = yangCompiler.buildSchemaContext(); + ValidatorResult oldResult = oldSchemaContext.validate(); + if (!oldResult.isOk()) { + throw new YangCompilerException("fail to validate the schema context of " + + oldYangPath + + ".\n" + + oldResult); + } + //System.out.println(oldSchemaContext.getValidateResult()); + YangComparator yangComparator = new YangComparator(oldSchemaContext, yangSchemaContext); + try { + List results = yangComparator.compare(compareType, rulePath); + boolean needCompatible = false; + if (compareType == CompareType.COMPATIBLE_CHECK) { + needCompatible = true; + } + Document document = yangComparator.outputXmlCompareResult(results, needCompatible, compareType); + //System.out.println(XmlWriter.transDom4jDoc2String(document)); + XmlWriter.writeDom4jDoc(document, resultPath); + } catch (DocumentException e) { + throw new RuntimeException(e); + } catch (RuntimeException e) { + for (StackTraceElement traceElement : e.getStackTrace()) { + System.out.println(traceElement); + } + + } + + } +} diff --git a/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/app/YangComparatorRunner.java b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/app/YangComparatorRunner.java new file mode 100644 index 0000000..1e76a75 --- /dev/null +++ b/yang-comparator/src/main/java/org/onap/modeling/yangkit/comparator/app/YangComparatorRunner.java @@ -0,0 +1,218 @@ +/* +Copyright 2023 Huawei Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.onap.modeling.yangkit.comparator.app; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.dom4j.DocumentException; +import org.onap.modeling.yangkit.comparator.CompareType; +import org.onap.modeling.yangkit.comparator.YangComparator; +import org.onap.modeling.yangkit.comparator.YangCompareResult; +import org.yangcentral.yangkit.common.api.validate.ValidatorResult; + +import org.yangcentral.yangkit.model.api.schema.YangSchemaContext; +import org.yangcentral.yangkit.parser.YangParserException; +import org.yangcentral.yangkit.parser.YangYinParser; +import org.yangcentral.yangkit.utils.xml.XmlWriter; + + +/** + * yang comparator runner. + */ +public class YangComparatorRunner { + /** + * main method. + * usage: -left --y {yang file or dir]} [--dep {dependency file or dir}] [--cap {capabilities.xml}] + * -right --y {yang file or dir]} [--dep {dependency file or dir}] [--cap {capabilities.xml}] + * -o {output.xml} + * {-tree | -stmt | -compatible-check [--rule rule.xml ]} + * + * @param args arguments + * @throws DocumentException document exception + * @throws IOException io exception + * @throws YangParserException yang parser exception + */ + + public static void main(String[] args) throws DocumentException, IOException, YangParserException { + int leftBeginPos = -1; + int rightBeginPos = -1; + int outBegin = -1; + int typeBegin = -1; + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.equalsIgnoreCase("-left")) { + leftBeginPos = i; + } else if (arg.equalsIgnoreCase("-right")) { + rightBeginPos = i; + } else if (arg.equalsIgnoreCase("-o")) { + outBegin = i; + } else if (arg.equalsIgnoreCase("-tree") + || arg.equalsIgnoreCase("-stmt") + || arg.equalsIgnoreCase("-compatible-check")) { + typeBegin = i; + } + } + if (leftBeginPos != 0) { + System.out.println("no left argument or left argument is not the 1st argument."); + System.out.println( + "usage: -left --y {yang file or dir]} [--dep {dependency file or dir}]" + + " [--cap {capabilities.xml}]\n" + + " -right --y {yang file or dir]} [--dep {dependency file or dir}]" + + " [--cap {capabilities.xml}]\n" + + " -o {output.xml}\n" + + " {-tree | -stmt [--filter filter.xml] | -compatible-check [--rule rule.xml]" + + " [--filter filter.xml]}"); + return; + } + if (rightBeginPos == -1) { + System.out.println("no right argument."); + System.out.println( + "usage: -left --y {yang file or dir]} [--dep {dependency file or dir}] [--cap {capabilities.xml}]\n" + + " -right --y {yang file or dir]} [--dep {dependency file or dir}] " + + "[--cap {capabilities.xml}]\n" + + " -o {output.xml}\n" + + " {-tree | -stmt [--filter filter.xml] | -compatible-check [--rule rule.xml]" + + " [--filter filter.xml]}"); + return; + } + if (outBegin == -1) { + System.out.println("no output argument."); + System.out.println( + "usage: -left --y {yang file or dir]} [--dep {dependency file or dir}] [--cap {capabilities.xml}]\n" + + " -right --y {yang file or dir]} [--dep {dependency file or dir}] " + + "[--cap {capabilities.xml}]\n" + + " -o {output.xml}\n" + + " {-tree | -stmt [--filter filter.xml] | -compatible-check [--rule rule.xml]" + + " [--filter filter.xml]}"); + return; + } + if (typeBegin == -1) { + System.out.println("no compare type argument, it should be '-tree' or '-stmt' or '-compatible-check' "); + System.out.println( + "usage: -left --y {yang file or dir]} [--dep {dependency file or dir}] [--cap {capabilities.xml}]\n" + + " -right --y {yang file or dir]} [--dep {dependency file or dir}] " + + "[--cap {capabilities.xml}]\n" + + " -o {output.xml}\n" + + " {-tree | -stmt [--filter filter.xml] | -compatible-check [--rule rule.xml] " + + "[--filter filter.xml]}"); + return; + } + String leftYangDir = null; + String leftDepDir = null; + String leftCap = null; + for (int i = leftBeginPos; i < rightBeginPos; i++) { + String arg = args[i]; + if (arg.equalsIgnoreCase("--y")) { + leftYangDir = args[i + 1]; + } else if (arg.equalsIgnoreCase("--dep")) { + leftDepDir = args[i + 1]; + } else if (arg.equalsIgnoreCase("--cap")) { + leftCap = args[i + 1]; + } + } + if (leftYangDir == null) { + System.out.println("left yang file should be specified using --y argument."); + System.out.println( + "usage: -left --y {yang file or dir]} [--dep {dependency file or dir}] [--cap {capabilities.xml}]\n" + + " -right --y {yang file or dir]} [--dep {dependency file or dir}] " + + "[--cap {capabilities.xml}]\n" + + " -o {output.xml}\n" + + " {-tree | -stmt [--filter filter.xml] | -compatible-check [--rule rule.xml]" + + " [--filter filter.xml]}"); + return; + } + String rightYangDir = null; + String rightDepDir = null; + String rightCap = null; + for (int i = rightBeginPos; i < outBegin; i++) { + String arg = args[i]; + if (arg.equalsIgnoreCase("--y")) { + rightYangDir = args[i + 1]; + } else if (arg.equalsIgnoreCase("--dep")) { + rightDepDir = args[i + 1]; + } else if (arg.equalsIgnoreCase("--cap")) { + rightCap = args[i + 1]; + } + } + if (rightYangDir == null) { + System.out.println("right yang file should be specified using --y argument."); + System.out.println( + "usage: -left --y {yang file or dir]} [--dep {dependency file or dir}] [--cap {capabilities.xml}]\n" + + " -right --y {yang file or dir]} [--dep {dependency file or dir}] " + + "[--cap {capabilities.xml}]\n" + + " -o {output.xml}\n" + + " {-tree | -stmt [--filter filter.xml] | -compatible-check [--rule rule.xml]" + + " [--filter filter.xml]}"); + return; + } + String output = args[outBegin + 1]; + File outputFile = new File(output); + if (!outputFile.exists()) { + if (outputFile.getParentFile() != null && !outputFile.getParentFile().exists()) { + outputFile.getParentFile().mkdirs(); + } + outputFile.createNewFile(); + } + String compareTypeStr = args[typeBegin]; + String rule = null; + String filter = null; + if (compareTypeStr.equalsIgnoreCase("-compatible-check") + || compareTypeStr.equalsIgnoreCase("-tree")) { + for (int i = typeBegin; i < args.length; i++) { + String arg = args[i]; + if (arg.equalsIgnoreCase("--rule")) { + rule = args[i + 1]; + } else if (arg.equalsIgnoreCase("--filter")) { + filter = args[i + 1]; + } + } + } + YangSchemaContext leftSchemaContext = YangYinParser.parse(leftYangDir, leftDepDir, leftCap); + ValidatorResult leftValidatorResult = leftSchemaContext.validate(); + if (!leftValidatorResult.isOk()) { + System.out.println("The yang files in directory:" + leftYangDir + " have something wrong."); + System.out.println(leftValidatorResult); + } + + YangSchemaContext rightSchemaContext = YangYinParser.parse(rightYangDir, rightDepDir, rightCap); + ValidatorResult rightValidatorResult = rightSchemaContext.validate(); + if (!rightValidatorResult.isOk()) { + System.out.println("The yang files in directory:" + rightYangDir + " have something wrong."); + System.out.println(rightValidatorResult); + } + + YangComparator comparator = new YangComparator(leftSchemaContext, rightSchemaContext); + CompareType compareType = null; + if (compareTypeStr.equalsIgnoreCase("-stmt")) { + compareType = CompareType.STMT; + } else if (compareTypeStr.equalsIgnoreCase("-tree")) { + compareType = CompareType.TREE; + } else if (compareTypeStr.equalsIgnoreCase("-compatible-check")) { + compareType = CompareType.COMPATIBLE_CHECK; + } + + List compareResults = comparator.compare(compareType, rule); + boolean needCompatible = false; + if (compareType == CompareType.COMPATIBLE_CHECK) { + needCompatible = true; + } + XmlWriter.writeDom4jDoc(comparator.outputXmlCompareResult(compareResults, needCompatible, compareType), output); + } + +} diff --git a/yang-comparator/src/main/resources/plugins.json b/yang-comparator/src/main/resources/plugins.json new file mode 100644 index 0000000..4534d4d --- /dev/null +++ b/yang-comparator/src/main/resources/plugins.json @@ -0,0 +1,34 @@ +{ + "plugins": { + "plugin": [ + { + "name": "yang_comparator", + "class-path": "yang-comparator-1.0-SNAPSHOT.jar", + "class": "com.huawei.yang.comparator.app.YangComparatorPlugin", + "description": "a plugin for comparing two yang schema.", + "parameter": [ + { + "name": "old-yang", + "description": "mandatory,the old version yang directory." + }, + { + "name": "settings", + "description": "optional,the settings file path." + }, + { + "name": "compare-type", + "description": "mandatory, specify compare-type, one of stmt,tree,or compatible-check" + }, + { + "name": "rule", + "description": "optional, specify the path of compatible-rule file." + }, + { + "name": "result", + "description": "mandatory, specify the compare result file path, the result file is a xml format." + } + ] + } + ] + } +} \ No newline at end of file diff --git a/yang-comparator/src/main/resources/rules.xml b/yang-comparator/src/main/resources/rules.xml new file mode 100644 index 0000000..15a6520 --- /dev/null +++ b/yang-comparator/src/main/resources/rules.xml @@ -0,0 +1,563 @@ + + + + schema-node-rule1 + + container + list + choice + case + rpc + action + input + output + notification + leaf + leaf-list + anyxml + anydata + + added + backward-compatible + add an optional schema node, it's backward-compatible change. + + + schema-node-rule2 + + container + list + choice + case + rpc + action + input + output + notification + leaf + leaf-list + anyxml + anydata + + deleted + non-backward-compatible + delete a schema node, it's non-backward-compatible change. + + + schema-node-rule3 + + container + list + choice + case + rpc + action + input + output + notification + leaf + leaf-list + anyxml + anydata + + mandatory-added + non-backward-compatible + add a mandatory true schema node, it's non-backward-compatible change. + + + typedef-rule1 + + typedef + + added + backward-compatible + add a typedef, it's backward-compatible + + + typedef-rule2 + + typedef + + deleted + non-backward-compatible + delete a typedef, it's backward-compatible + + + type-changed-rule1 + + type + + integer-type-changed + backward-compatible + type changed from one integer to other integer, it's backward-compatible + + + type-changed-rule2 + + type + + changed + integer-type-changed + non-backward-compatible + type changed, it's non-backward-compatible + + + scope-expanded-rule1 + + range + length + fraction-digits + min-elements + max-elements + mandatory + config + + expand + backward-compatible + the scope is expanded, it's backward-compatible + + + scope-reduced-rule1 + + range + length + fraction-digits + min-elements + max-elements + mandatory + config + + reduce + non-backward-compatible + the scope is reduced, it's non-backward-compatible + + + enumeration-bits-rule1 + + enum + bit + + added + backward-compatible + add a enum/bit, it's backward-compatible + + + enumeration-bits-rule2 + + enum + bit + + deleted + non-backward-compatible + delete a enum/bit, it's non-backward-compatible + + + enumeration-bits-rule3 + + enum + bit + + changed + non-backward-compatible + change a enum/bit,for example, the value of this enum is changed, it's non-backward-compatible + + + default-rule + + default + + any + non-backward-compatible + any change of default will be treated as non-backward-compatible change + + + pattern-rule1 + + pattern + + added + non-backward-compatible + add a new pattern ,it's a non-backward-compatible change + + + pattern-rule2 + + pattern + + deleted + backward-compatible + delete a pattern ,it's a backward-compatible change + + + pattern-rule3 + + pattern + + changed + unknown + pattern is changed ,it's a unknown change + + + modifier-rule1 + + modifier + + any + non-backward-compatible + any change of modifier will be treated as a non-backward-compatible change + + + key-rule + + key + + any + non-backward-compatible + any change of key will be treated as a non-backward-compatible change + + + mandatory-rule1 + + mandatory + + reduce + non-backward-compatible + from mandatory false to mandatory true, it's non-backward-compatible change + + + mandatory-rule2 + + mandatory + + expand + backward-compatible + from mandatory true to mandatory false, it's backward-compatible change + + + unique-rule1 + + unique + + added + non-backward-compatible + add a new unique, it's a non-backward-compatible change + + + unique-rule2 + + unique + + deleted + backward-compatible + delete a unique, it's a backward-compatible change + + + unique-rule3 + + unique + + reduce + non-backward-compatible + unique attrs are added, it's a non-backward-compatible change + + + unique-rule4 + + unique + + expand + backward-compatible + unique attrs are deleted, it's a non-backward-compatible change + + + config-rule1 + + config + + expand + backward-compatible + config from false to true, it's a backward-compatible change. + + + config-rule2 + + config + + reduce + non-backward-compatible + config from true to false, it's a non-backward-compatible change. + + + support-filter-rule1 + + huawei-extension:support-filter + + expand + backward-compatible + support-filter from false to true, it's backward-compatible change. + + + support-filter-rule2 + + huawei-extension:support-filter + + reduce + non-backward-compatible + support-filter from true to false, it's non-backward-compatible change. + + + path-rule1 + + path + + expand + backward-compatible + the node-set which the path points to is expanded, it's backward-compatible change. + + + path-rule2 + + path + + reduce + non-backward-compatible + the node-set which the path points to is reduced, it's non-backward-compatible change. + + + path-rule3 + + path + + changed + non-backward-compatible + the node-set which the path points to is changed (e.g. from one data node to another data node), + it's non-backward-compatible change. + + + require-instance-rule1 + + require-instance + + expand + backward-compatible + require-instance from true to false, it's backward-compatible change. + + + require-instance-rule2 + + require-instance + + reduce + non-backward-compatible + require-instance from false to true, it's non-backward-compatible change. + + + units-rule1 + + units + + added + backward-compatible + add a units, it's backward-compatible change. + + + units-rule2 + + units + + deleted + non-backward-compatible + delete units, it's non-backward-compatible change. + + + units-rule3 + + units + + changed + non-backward-compatible + change units, it's non-backward-compatible change. + + + when-must-rule1 + + when + must + + added + non-backward-compatible + add a when or must, it's non-backward-compatible change. + + + when-must-rule2 + + when + must + + deleted + backward-compatible + delete a when or must, it's non-backward-compatible change. + + + when-must-rule3 + + when + must + + changed + unknown + when or must is changed, it's unknown change. + + + if-feature-rule1 + + if-feature + + added + non-backward-compatible + add a if-feature,it's non-backward-compatible change. + + + if-feature-rule2 + + if-feature + + deleted + backward-compatible + delete a if-feature,it's backward-compatible change. + + + if-feature-rule3 + + if-feature + + changed + non-backward-compatible + a if-feature changed,it's non-backward-compatible change. + + + belongs-to-rule + + belongs-to + + any + non-backward-compatible + any change for belongs-to is non-backward-compatible. + + + prefix-rule + + prefix + + changed + non-backward-compatible + any change for prefix is non-backward-compatible. + + + yang-version-rule + + yang-version + + changed + non-backward-compatible + any change for yang-version is non-backward-compatible + + + namespace-rule + + namespace + + changed + non-backward-compatible + any change for namespace is non-backward-compatible. + + + identity-rule1 + + identity + + added + backward-compatible + add a new identity, it's a backward-compatible change. + + + identity-rule2 + + identity + + deleted + non-backward-compatible + delete a new identity, it's a non-backward-compatible change. + + + base-rule1 + + base + + added + backward-compatible + add a new base, it's a backward-compatible change. + + + base-rule2 + + base + + deleted + non-backward-compatible + delete a base, it's a non-backward-compatible change. + + + extension-rule1 + + extension + + added + backward-compatible + add a new extension, it's a backward-compatible change. + + + extension-rule2 + + extension + + deleted + non-backward-compatible + delete a new extension, it's a non-backward-compatible change. + + + argument-rule + + argument + + any + non-backward-compatible + any chang for argument is a non-backward-compatible change. + + + yin-element-rule + + yin-element + + change + non-backward-compatible + any chang for yin-element is a non-backward-compatible change. + + + revision-date-rule + + revision-date + + change + non-backward-compatible + any chang for revision-date is a non-backward-compatible change. + + + ordered-by-rule + + ordered-by + + change + non-backward-compatible + any chang for ordered-by is a non-backward-compatible change. + + \ No newline at end of file -- cgit