diff options
Diffstat (limited to 'yang-comparator')
15 files changed, 2858 insertions, 0 deletions
diff --git a/yang-comparator/pom.xml b/yang-comparator/pom.xml new file mode 100644 index 0000000..094b6ea --- /dev/null +++ b/yang-comparator/pom.xml @@ -0,0 +1,246 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onap.modeling.yangkit</groupId> + <artifactId>yangkit-parent</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> + + <groupId>org.onap.modeling.yangkit</groupId> + <artifactId>yang-comparator</artifactId> + <version>1.0.0-SNAPSHOT</version> + + <properties> + <maven.compiler.source>8</maven.compiler.source> + <maven.compiler.target>8</maven.compiler.target> + </properties> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <version>3.1.1</version> + <executions> + <execution> + <id>copy-dependencies</id> + <phase>compile</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + <configuration> + <outputDirectory> + ${project.build.directory}/libs + </outputDirectory> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>3.1.0</version> + <configuration> + <archive> + <manifest> + <addClasspath>true</addClasspath> + <mainClass>org.onap.modeling.yangkit.comparator.app.YangComparatorRunner</mainClass> + <classpathPrefix>libs/</classpathPrefix> + </manifest> + </archive> + </configuration> + </plugin> + </plugins> + + </build> + + <dependencies> + <dependency> + <groupId>io.github.yang-central.yangkit</groupId> + <artifactId>yangkit-parser</artifactId> + <version>1.3.5</version> + </dependency> + <dependency> + <groupId>io.github.yang-central.yangkit</groupId> + <artifactId>yang-compiler</artifactId> + <version>1.3.1</version> + </dependency> + <dependency> + <groupId>org.dom4j</groupId> + <artifactId>dom4j</artifactId> + <version>2.1.4</version> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.10.1</version> + </dependency> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi</artifactId> + <version>5.2.2</version> + </dependency> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi-ooxml</artifactId> + <version>5.2.2</version> + </dependency> + <dependency> + <groupId>jaxen</groupId> + <artifactId>jaxen</artifactId> + <version>2.0.0</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.12.0</version> + </dependency> + <dependency> + <groupId>org.antlr</groupId> + <artifactId>antlr4-runtime</artifactId> + <version>4.9.3</version> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <version>5.9.0</version> + </dependency> + <dependency> + <groupId>com.github.spotbugs</groupId> + <artifactId>spotbugs-annotations</artifactId> + <version>4.7.3</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>2.0.5</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <version>2.0.5</version> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>31.1-jre</version> + </dependency> + <dependency> + <groupId>com.github.albfernandez</groupId> + <artifactId>juniversalchardet</artifactId> + <version>2.4.0</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.13.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <version>3.0.2</version> + </dependency> + <dependency> + <groupId>org.eclipse.jdt</groupId> + <artifactId>org.eclipse.jdt.annotation</artifactId> + <version>2.2.600</version> + </dependency> + </dependencies> + <name>yang comparator</name> + <description>yang comparator is a tool which can compare two versions of yang releases. It can help users to identify the differences of the two versions. </description> + + <licenses> + <license> + <name>The Apache Software License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + </license> + </licenses> + + <profiles> + <profile> + <id>release</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-release-plugin</artifactId> + <version>2.5.3</version> + <configuration> + <autoVersionSubmodules>true</autoVersionSubmodules> + <useReleaseProfile>false</useReleaseProfile> + <releaseProfiles>release</releaseProfiles> + <goals>deploy</goals> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <version>2.2.1</version> + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar-no-fork</goal> + </goals> + </execution> + </executions> + </plugin> +<!-- + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>3.4.0</version> + <configuration> + <source>8</source> + <detectJavaApiLink>false</detectJavaApiLink> + <locale>en_US</locale> + <charset>UTF-8</charset> + <encoding>UTF-8</encoding> + <docencoding>UTF-8</docencoding> + + <doclet>ch.raffael.doclets.pegdown.PegdownDoclet</doclet> + <docletArtifact> + <groupId>ch.raffael.pegdown-doclet</groupId> + <artifactId>pegdown-doclet</artifactId> + <version>1.1</version> + </docletArtifact> + <useStandardDocletOptions>true</useStandardDocletOptions> + </configuration> + <executions> + <execution> + <id>attach-javadocs</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-gpg-plugin</artifactId> + <version>1.5</version> + <executions> + <execution> + <id>sign-artifacts</id> + <phase>verify</phase> + <goals> + <goal>sign</goal> + </goals> + </execution> + </executions> + </plugin> +--> + </plugins> + </build> + + </profile> + + </profiles> +</project> 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<SchemaNode> getModuleTreeNodes(MainModule module) { + List<SchemaNode> 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<SchemaNode> getEffectiveSchemaNodeChildren(SchemaNodeContainer schemaNodeContainer) { + List<SchemaNode> 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<YangCompareResult> 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<YangCompareResult> compareStatement(List<? extends YangElement> leftElements, + List<? extends YangElement> rightElements, + boolean exceptSchemaNode) { + List<YangCompareResult> compareResults = new ArrayList<>(); + List<YangStatement> 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<YangStatement> 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<YangCompareResult> compareStatement(YangStatement left, YangStatement right, boolean exceptSchemaNode) { + List<YangCompareResult> 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<YangCompareResult> compareStatement() { + List<YangCompareResult> compareResults = new ArrayList<>(); + List<Module> foundModules = new ArrayList<>(); + List<Module> modules = leftContext.getModules(); + for (Module module : modules) { + List<Module> 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<String, List<YangCompareResult>> resortYangCompareResult(List<YangCompareResult> results) { + Map<String, List<YangCompareResult>> map = new HashMap<>(); + for (YangCompareResult yangCompareResult : results) { + String module = yangCompareResult.getModule().getArgStr(); + List<YangCompareResult> mapResults = map.get(module); + if (null == mapResults) { + mapResults = new ArrayList<>(); + map.put(module, mapResults); + } + mapResults.add(yangCompareResult); + + } + return map; + } + + private String outputCompareResult(List<YangCompareResult> compareResults) { + Map<String, List<YangCompareResult>> resortedResults = resortYangCompareResult(compareResults); + StringBuffer sb = new StringBuffer(); + Iterator<Map.Entry<String, List<YangCompareResult>>> it = resortedResults.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, List<YangCompareResult>> entry = it.next(); + sb.append("module:").append(entry.getKey()).append("\n"); + sb.append("\t").append("added:\n"); + List<YangCompareResult> 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<YangCompareResult> 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<YangCompareResult> compareResults, boolean needCompatible, + CompareType compareType) { + Map<String, List<YangCompareResult>> resortedResults = resortYangCompareResult(compareResults); + Element root = DocumentHelper.createElement("modules"); + Document document = DocumentHelper.createDocument(root); + Iterator<Map.Entry<String, List<YangCompareResult>>> it = resortedResults.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, List<YangCompareResult>> entry = it.next(); + List<YangCompareResult> 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<YangCompareResult> 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<YangCompareResult> compareResults = new ArrayList<>(); + if (compareType == CompareType.STMT) { + compareResults = compareStatement(); + + } else if (compareType == CompareType.TREE) { + List<Module> matched = new ArrayList<>(); + for (Module leftModule : leftContext.getModules()) { + if (!(leftModule instanceof MainModule)) { + continue; + } + List<SchemaNode> 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<SchemaNode> 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<String, YangStatementComparator> 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<T> { + /** + * 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<T> { + 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<Element> { + /** + * 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<T extends YangStatement> { + /** + * compare statements. + * @param left left statement. + * @param right right statement. + * @return result. + */ + List<YangCompareResult> 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<YangStatement> { + 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<SchemaNode> { + private final SchemaPath.Absolute schemaPath; + private final ChangeType changeType; + private SchemaNode left; + private SchemaNode right; + private String changeDescription; + private List<YangCompareResult> 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<YangCompareResult> getMetaCompareResults() { + return metaCompareResults; + } + + /** + * set meta compare results. + * + * @param metaCompareResults list of meta compare results + */ + public void setMetaCompareResults(List<YangCompareResult> 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<String> { + 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<Map.Entry<Object, Object>> it = properties.entrySet().iterator(); + String formatStr = value; + while (it.hasNext()) { + Map.Entry<Object, Object> 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<YangCompilerPluginParameter> 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<YangCompareResult> 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<YangCompareResult> 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 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<rules> + <rule> + <rule-id>schema-node-rule1</rule-id> + <statements> + <statement>container</statement> + <statement>list</statement> + <statement>choice</statement> + <statement>case</statement> + <statement>rpc</statement> + <statement>action</statement> + <statement>input</statement> + <statement>output</statement> + <statement>notification</statement> + <statement>leaf</statement> + <statement>leaf-list</statement> + <statement>anyxml</statement> + <statement>anydata</statement> + </statements> + <condition>added</condition> + <compatible>backward-compatible</compatible> + <description>add an optional schema node, it's backward-compatible change.</description> + </rule> + <rule> + <rule-id>schema-node-rule2</rule-id> + <statements> + <statement>container</statement> + <statement>list</statement> + <statement>choice</statement> + <statement>case</statement> + <statement>rpc</statement> + <statement>action</statement> + <statement>input</statement> + <statement>output</statement> + <statement>notification</statement> + <statement>leaf</statement> + <statement>leaf-list</statement> + <statement>anyxml</statement> + <statement>anydata</statement> + </statements> + <condition>deleted</condition> + <compatible>non-backward-compatible</compatible> + <description>delete a schema node, it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>schema-node-rule3</rule-id> + <statements> + <statement>container</statement> + <statement>list</statement> + <statement>choice</statement> + <statement>case</statement> + <statement>rpc</statement> + <statement>action</statement> + <statement>input</statement> + <statement>output</statement> + <statement>notification</statement> + <statement>leaf</statement> + <statement>leaf-list</statement> + <statement>anyxml</statement> + <statement>anydata</statement> + </statements> + <condition>mandatory-added</condition> + <compatible>non-backward-compatible</compatible> + <description>add a mandatory true schema node, it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>typedef-rule1</rule-id> + <statements> + <statement>typedef</statement> + </statements> + <condition>added</condition> + <compatible>backward-compatible</compatible> + <description>add a typedef, it's backward-compatible</description> + </rule> + <rule> + <rule-id>typedef-rule2</rule-id> + <statements> + <statement>typedef</statement> + </statements> + <condition>deleted</condition> + <compatible>non-backward-compatible</compatible> + <description>delete a typedef, it's backward-compatible</description> + </rule> + <rule> + <rule-id>type-changed-rule1</rule-id> + <statements> + <statement>type</statement> + </statements> + <condition>integer-type-changed</condition> + <compatible>backward-compatible</compatible> + <description>type changed from one integer to other integer, it's backward-compatible</description> + </rule> + <rule> + <rule-id>type-changed-rule2</rule-id> + <statements> + <statement>type</statement> + </statements> + <condition>changed</condition> + <except-condition>integer-type-changed</except-condition> + <compatible>non-backward-compatible</compatible> + <description>type changed, it's non-backward-compatible</description> + </rule> + <rule> + <rule-id>scope-expanded-rule1</rule-id> + <statements> + <statement>range</statement> + <statement>length</statement> + <statement>fraction-digits</statement><!-- new value is smaller --> + <statement>min-elements</statement><!-- new value is smaller --> + <statement>max-elements</statement><!-- new value is greater --> + <statement>mandatory</statement><!-- from true to false --> + <statement>config</statement><!-- from false to true--> + </statements> + <condition>expand</condition> + <compatible>backward-compatible</compatible> + <description> the scope is expanded, it's backward-compatible</description> + </rule> + <rule> + <rule-id>scope-reduced-rule1</rule-id> + <statements> + <statement>range</statement> + <statement>length</statement> + <statement>fraction-digits</statement><!-- new value is greater --> + <statement>min-elements</statement><!-- new value is greater --> + <statement>max-elements</statement><!-- new value is smaller --> + <statement>mandatory</statement><!-- from false to true --> + <statement>config</statement><!-- from true to false--> + </statements> + <condition>reduce</condition> + <compatible>non-backward-compatible</compatible> + <description> the scope is reduced, it's non-backward-compatible</description> + </rule> + <rule> + <rule-id>enumeration-bits-rule1</rule-id> + <statements> + <statement>enum</statement> + <statement>bit</statement> + </statements> + <condition>added</condition> + <compatible>backward-compatible</compatible> + <description>add a enum/bit, it's backward-compatible</description> + </rule> + <rule> + <rule-id>enumeration-bits-rule2</rule-id> + <statements> + <statement>enum</statement> + <statement>bit</statement> + </statements> + <condition>deleted</condition> + <compatible>non-backward-compatible</compatible> + <description>delete a enum/bit, it's non-backward-compatible</description> + </rule> + <rule> + <rule-id>enumeration-bits-rule3</rule-id> + <statements> + <statement>enum</statement> + <statement>bit</statement> + </statements> + <condition>changed</condition> + <compatible>non-backward-compatible</compatible> + <description>change a enum/bit,for example, the value of this enum is changed, it's non-backward-compatible</description> + </rule> + <rule> + <rule-id>default-rule</rule-id> + <statements> + <statement>default</statement> + </statements> + <condition>any</condition> + <compatible>non-backward-compatible</compatible> + <description>any change of default will be treated as non-backward-compatible change</description> + </rule> + <rule> + <rule-id>pattern-rule1</rule-id> + <statements> + <statement>pattern</statement> + </statements> + <condition>added</condition> + <compatible>non-backward-compatible</compatible> + <description>add a new pattern ,it's a non-backward-compatible change</description> + </rule> + <rule> + <rule-id>pattern-rule2</rule-id> + <statements> + <statement>pattern</statement> + </statements> + <condition>deleted</condition> + <compatible>backward-compatible</compatible> + <description>delete a pattern ,it's a backward-compatible change</description> + </rule> + <rule> + <rule-id>pattern-rule3</rule-id> + <statements> + <statement>pattern</statement> + </statements> + <condition>changed</condition> + <compatible>unknown</compatible> + <description>pattern is changed ,it's a unknown change</description> + </rule> + <rule> + <rule-id>modifier-rule1</rule-id> + <statements> + <statement>modifier</statement> + </statements> + <condition>any</condition> + <compatible>non-backward-compatible</compatible> + <description>any change of modifier will be treated as a non-backward-compatible change</description> + </rule> + <rule> + <rule-id>key-rule</rule-id> + <statements> + <statement>key</statement> + </statements> + <condition>any</condition> + <compatible>non-backward-compatible</compatible> + <description>any change of key will be treated as a non-backward-compatible change</description> + </rule> + <rule> + <rule-id>mandatory-rule1</rule-id> + <statements> + <statement>mandatory</statement> + </statements> + <condition>reduce</condition> + <compatible>non-backward-compatible</compatible> + <description>from mandatory false to mandatory true, it's non-backward-compatible change</description> + </rule> + <rule> + <rule-id>mandatory-rule2</rule-id> + <statements> + <statement>mandatory</statement> + </statements> + <condition>expand</condition> + <compatible>backward-compatible</compatible> + <description>from mandatory true to mandatory false, it's backward-compatible change</description> + </rule> + <rule> + <rule-id>unique-rule1</rule-id> + <statements> + <statement>unique</statement> + </statements> + <condition>added</condition> + <compatible>non-backward-compatible</compatible> + <description>add a new unique, it's a non-backward-compatible change</description> + </rule> + <rule> + <rule-id>unique-rule2</rule-id> + <statements> + <statement>unique</statement> + </statements> + <condition>deleted</condition> + <compatible>backward-compatible</compatible> + <description>delete a unique, it's a backward-compatible change</description> + </rule> + <rule> + <rule-id>unique-rule3</rule-id> + <statements> + <statement>unique</statement> + </statements> + <condition>reduce</condition> + <compatible>non-backward-compatible</compatible> + <description>unique attrs are added, it's a non-backward-compatible change</description> + </rule> + <rule> + <rule-id>unique-rule4</rule-id> + <statements> + <statement>unique</statement> + </statements> + <condition>expand</condition> + <compatible>backward-compatible</compatible> + <description>unique attrs are deleted, it's a non-backward-compatible change</description> + </rule> + <rule> + <rule-id>config-rule1</rule-id> + <statements> + <statement>config</statement> + </statements> + <condition>expand</condition> + <compatible>backward-compatible</compatible> + <description>config from false to true, it's a backward-compatible change.</description> + </rule> + <rule> + <rule-id>config-rule2</rule-id> + <statements> + <statement>config</statement> + </statements> + <condition>reduce</condition> + <compatible>non-backward-compatible</compatible> + <description>config from true to false, it's a non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>support-filter-rule1</rule-id> + <statements> + <statement>huawei-extension:support-filter</statement> + </statements> + <condition>expand</condition> + <compatible>backward-compatible</compatible> + <description>support-filter from false to true, it's backward-compatible change.</description> + </rule> + <rule> + <rule-id>support-filter-rule2</rule-id> + <statements> + <statement>huawei-extension:support-filter</statement> + </statements> + <condition>reduce</condition> + <compatible>non-backward-compatible</compatible> + <description>support-filter from true to false, it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>path-rule1</rule-id> + <statements> + <statement>path</statement> + </statements> + <condition>expand</condition> + <compatible>backward-compatible</compatible> + <description>the node-set which the path points to is expanded, it's backward-compatible change.</description> + </rule> + <rule> + <rule-id>path-rule2</rule-id> + <statements> + <statement>path</statement> + </statements> + <condition>reduce</condition> + <compatible>non-backward-compatible</compatible> + <description>the node-set which the path points to is reduced, it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>path-rule3</rule-id> + <statements> + <statement>path</statement> + </statements> + <condition>changed</condition> + <compatible>non-backward-compatible</compatible> + <description>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.</description> + </rule> + <rule> + <rule-id>require-instance-rule1</rule-id> + <statements> + <statement>require-instance</statement> + </statements> + <condition>expand</condition> + <compatible>backward-compatible</compatible> + <description>require-instance from true to false, it's backward-compatible change.</description> + </rule> + <rule> + <rule-id>require-instance-rule2</rule-id> + <statements> + <statement>require-instance</statement> + </statements> + <condition>reduce</condition> + <compatible>non-backward-compatible</compatible> + <description>require-instance from false to true, it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>units-rule1</rule-id> + <statements> + <statement>units</statement> + </statements> + <condition>added</condition> + <compatible>backward-compatible</compatible> + <description>add a units, it's backward-compatible change.</description> + </rule> + <rule> + <rule-id>units-rule2</rule-id> + <statements> + <statement>units</statement> + </statements> + <condition>deleted</condition> + <compatible>non-backward-compatible</compatible> + <description>delete units, it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>units-rule3</rule-id> + <statements> + <statement>units</statement> + </statements> + <condition>changed</condition> + <compatible>non-backward-compatible</compatible> + <description>change units, it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>when-must-rule1</rule-id> + <statements> + <statement>when</statement> + <statement>must</statement> + </statements> + <condition>added</condition> + <compatible>non-backward-compatible</compatible> + <description>add a when or must, it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>when-must-rule2</rule-id> + <statements> + <statement>when</statement> + <statement>must</statement> + </statements> + <condition>deleted</condition> + <compatible>backward-compatible</compatible> + <description>delete a when or must, it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>when-must-rule3</rule-id> + <statements> + <statement>when</statement> + <statement>must</statement> + </statements> + <condition>changed</condition> + <compatible>unknown</compatible> + <description>when or must is changed, it's unknown change.</description> + </rule> + <rule> + <rule-id>if-feature-rule1</rule-id> + <statements> + <statement>if-feature</statement> + </statements> + <condition>added</condition> + <compatible>non-backward-compatible</compatible> + <description>add a if-feature,it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>if-feature-rule2</rule-id> + <statements> + <statement>if-feature</statement> + </statements> + <condition>deleted</condition> + <compatible>backward-compatible</compatible> + <description>delete a if-feature,it's backward-compatible change.</description> + </rule> + <rule> + <rule-id>if-feature-rule3</rule-id> + <statements> + <statement>if-feature</statement> + </statements> + <condition>changed</condition> + <compatible>non-backward-compatible</compatible> + <description> a if-feature changed,it's non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>belongs-to-rule</rule-id> + <statements> + <statement>belongs-to</statement> + </statements> + <condition>any</condition> + <compatible>non-backward-compatible</compatible> + <description>any change for belongs-to is non-backward-compatible.</description> + </rule> + <rule> + <rule-id>prefix-rule</rule-id> + <statements> + <statement>prefix</statement> + </statements> + <condition>changed</condition> + <compatible>non-backward-compatible</compatible> + <description>any change for prefix is non-backward-compatible.</description> + </rule> + <rule> + <rule-id>yang-version-rule</rule-id> + <statements> + <statement>yang-version</statement> + </statements> + <condition>changed</condition> + <compatible>non-backward-compatible</compatible> + <description>any change for yang-version is non-backward-compatible</description> + </rule> + <rule> + <rule-id>namespace-rule</rule-id> + <statements> + <statement>namespace</statement> + </statements> + <condition>changed</condition> + <compatible>non-backward-compatible</compatible> + <description>any change for namespace is non-backward-compatible.</description> + </rule> + <rule> + <rule-id>identity-rule1</rule-id> + <statements> + <statement>identity</statement> + </statements> + <condition>added</condition> + <compatible>backward-compatible</compatible> + <description>add a new identity, it's a backward-compatible change.</description> + </rule> + <rule> + <rule-id>identity-rule2</rule-id> + <statements> + <statement>identity</statement> + </statements> + <condition>deleted</condition> + <compatible>non-backward-compatible</compatible> + <description>delete a new identity, it's a non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>base-rule1</rule-id> + <statements> + <statement>base</statement> + </statements> + <condition>added</condition> + <compatible>backward-compatible</compatible> + <description>add a new base, it's a backward-compatible change.</description> + </rule> + <rule> + <rule-id>base-rule2</rule-id> + <statements> + <statement>base</statement> + </statements> + <condition>deleted</condition> + <compatible>non-backward-compatible</compatible> + <description>delete a base, it's a non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>extension-rule1</rule-id> + <statements> + <statement>extension</statement> + </statements> + <condition>added</condition> + <compatible>backward-compatible</compatible> + <description>add a new extension, it's a backward-compatible change.</description> + </rule> + <rule> + <rule-id>extension-rule2</rule-id> + <statements> + <statement>extension</statement> + </statements> + <condition>deleted</condition> + <compatible>non-backward-compatible</compatible> + <description>delete a new extension, it's a non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>argument-rule</rule-id> + <statements> + <statement>argument</statement> + </statements> + <condition>any</condition> + <compatible>non-backward-compatible</compatible> + <description>any chang for argument is a non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>yin-element-rule</rule-id> + <statements> + <statement>yin-element</statement> + </statements> + <condition>change</condition> + <compatible>non-backward-compatible</compatible> + <description>any chang for yin-element is a non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>revision-date-rule</rule-id> + <statements> + <statement>revision-date</statement> + </statements> + <condition>change</condition> + <compatible>non-backward-compatible</compatible> + <description>any chang for revision-date is a non-backward-compatible change.</description> + </rule> + <rule> + <rule-id>ordered-by-rule</rule-id> + <statements> + <statement>ordered-by</statement> + </statements> + <condition>change</condition> + <compatible>non-backward-compatible</compatible> + <description>any chang for ordered-by is a non-backward-compatible change.</description> + </rule> +</rules>
\ No newline at end of file |