diff --git a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/APIDiff.java b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/APIDiff.java index 1ccdd5d82e06381339e8cfcc4caef31087db1548..2f990d2a38ad158fb4ee237f4f5773a9cac795de 100644 --- a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/APIDiff.java +++ b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/APIDiff.java @@ -7,6 +7,7 @@ import japicmp.cmp.JApiCmpArchive; import japicmp.cmp.JarArchiveComparator; import japicmp.cmp.JarArchiveComparatorOptions; +import japicmp.config.Options; import japicmp.model.JApiClass; import java.io.File; import java.io.FileFilter; @@ -44,7 +45,7 @@ private static Set<String> getJars(File dir) { .collect(Collectors.toSet()); } - static Set<String> getPublicPackages(File jarFile) throws IOException, IllegalStateException { + private static Set<String> getPublicPackages(File jarFile) throws IOException, IllegalStateException { String publicPackageStr = ManifestLoader.loadFromJar(jarFile).getValue("OpenIDE-Module-Public-Packages"); if (publicPackageStr == null) { throw new IllegalStateException(MessageFormat.format("Manifest for {0} does not have key of 'OpenIDE-Module-Public-Packages'", jarFile.getAbsolutePath())); @@ -56,15 +57,107 @@ static Set<String> getPublicPackages(File jarFile) throws IOException, IllegalSt } } - private static void getComparison(String prevVersion, String curVersion, File prevJar, File curJar) { + static void getComparison(String prevVersion, String curVersion, File prevJar, File curJar) throws IOException { JarArchiveComparatorOptions comparatorOptions = new JarArchiveComparatorOptions(); + //comparatorOptions.setAccessModifier(AccessModifier.); comparatorOptions.getIgnoreMissingClasses().setIgnoreAllMissingClasses(true); JarArchiveComparator jarArchiveComparator = new JarArchiveComparator(comparatorOptions); List<JApiClass> jApiClasses = jarArchiveComparator.compare( new JApiCmpArchive(prevJar, prevVersion), new JApiCmpArchive(curJar, curVersion) ); + + Set<String> prevPublicApiPackages = getPublicPackages(prevJar); + Set<String> curPublicApiPackages = getPublicPackages(curJar); + + // TODO handle diff in this list + Set<String> allPublicApiPackages = new HashSet<>(); + allPublicApiPackages.addAll(prevPublicApiPackages); + allPublicApiPackages.addAll(curPublicApiPackages); + jApiClasses = jApiClasses.stream() + .filter(cls -> allPublicApiPackages.contains(cls.getNewClass().or(cls.getOldClass()).get().getPackageName())) + .collect(Collectors.toList()); + + Options options = Options.newDefault(); + options.setOutputOnlyModifications(true); + System.out.println("Comparing " + prevJar.getName()); - System.out.println(jApiClasses); + ChangeOutputGenerator stdoutOutputGenerator = new ChangeOutputGenerator(options, jApiClasses); + String output = stdoutOutputGenerator.generate(); + System.out.println(output); } + + private static void generateOutput(Options options, List<JApiClass> jApiClasses, JarArchiveComparator jarArchiveComparator) { +// for (JApiClass cls: jApiClasses) { +// cls.is +// } +// + +// if (options.isSemanticVersioning()) { +// SemverOut semverOut = new SemverOut(options, jApiClasses); +// String output = semverOut.generate(); +// System.out.println(output); +// return; +// } +// if (options.getXmlOutputFile().isPresent() || options.getHtmlOutputFile().isPresent()) { +// SemverOut semverOut = new SemverOut(options, jApiClasses); +// XmlOutputGeneratorOptions xmlOutputGeneratorOptions = new XmlOutputGeneratorOptions(); +// xmlOutputGeneratorOptions.setCreateSchemaFile(true); +// xmlOutputGeneratorOptions.setSemanticVersioningInformation(semverOut.generate()); +// XmlOutputGenerator xmlGenerator = new XmlOutputGenerator(jApiClasses, options, xmlOutputGeneratorOptions); +// try (XmlOutput xmlOutput = xmlGenerator.generate()) { +// XmlOutputGenerator.writeToFiles(options, xmlOutput); +// } catch (Exception e) { +// throw new JApiCmpException(JApiCmpException.Reason.IoException, "Could not close output streams: " + e.getMessage(), e); +// } +// } +// StdoutOutputGenerator stdoutOutputGenerator = new StdoutOutputGenerator(options, jApiClasses); +// String output = stdoutOutputGenerator.generate(); +// System.out.println(output); + +// if (options.isErrorOnBinaryIncompatibility() +// || options.isErrorOnSourceIncompatibility() +// || options.isErrorOnExclusionIncompatibility() +// || options.isErrorOnModifications() +// || options.isErrorOnSemanticIncompatibility()) { +// IncompatibleErrorOutput errorOutput = new IncompatibleErrorOutput(options, jApiClasses, jarArchiveComparator); +// errorOutput.generate(); +// } + } + + + +// enum ChangeType { CHANGE, ADD, REMOVE } +// +// public class ClassChangeDTO { +// private final String packageStr; +// private final String fullyQualifiedClassName; +// private final ChangeType changeType; +// +// private final ClassDataDTO prevClassRecord; +// private final ClassDataDTO currClassRecord; +// +// +// } +// +// public class ClassDataDTO { +// private final String packageStr; +// private final String fullyQualifiedClassName; +// private final AccessModifier accessModifier; +// } +// + + + + + + + + + + + + + + } diff --git a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ApiChangeDTO.java b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ApiChangeDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..2d3588f6a7a1da5e93efe198b703c1c5dfbd18da --- /dev/null +++ b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ApiChangeDTO.java @@ -0,0 +1,153 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package org.sleuthkit.autopsy.apiupdate; + +import japicmp.model.JApiChangeStatus; +import java.util.Optional; + +/** + * + * @author gregd + */ +public class ApiChangeDTO { + //NEW, REMOVED, UNCHANGED, MODIFIED + + public interface PublicApiChangeable { + + PublicApiChangeType getChangeType(); + } + + public static class ClassChangeDTO { + + private final JApiChangeStatus changeStatus; + private final Optional<String> oldDeclaration; + private final Optional<Long> oldSerialId; + + private final Optional<String> newDeclaration; + private final Optional<Long> newSerialId; + + public ClassChangeDTO(JApiChangeStatus changeStatus, Optional<String> oldDeclaration, Optional<Long> oldSerialId, Optional<String> newDeclaration, Optional<Long> newSerialId) { + this.changeStatus = changeStatus; + this.oldDeclaration = oldDeclaration; + this.oldSerialId = oldSerialId; + this.newDeclaration = newDeclaration; + this.newSerialId = newSerialId; + } + + public JApiChangeStatus getChangeStatus() { + return changeStatus; + } + + public Optional<String> getOldDeclaration() { + return oldDeclaration; + } + + public Optional<Long> getOldSerialId() { + return oldSerialId; + } + + public Optional<String> getNewDeclaration() { + return newDeclaration; + } + + public Optional<Long> getNewSerialId() { + return newSerialId; + } + + + } + +// public static class SuperclassChangeDTO { +// +// private final Optional<String> oldFullyQualifiedClassName; +// private final Optional<String> newFullyQualifiedClassName; +// +// public SuperclassChangeDTO(Optional<String> oldFullyQualifiedClassName, Optional<String> newFullyQualifiedClassName) { +// this.oldFullyQualifiedClassName = oldFullyQualifiedClassName; +// this.newFullyQualifiedClassName = newFullyQualifiedClassName; +// } +// +// public Optional<String> getOldFullyQualifiedClassName() { +// return oldFullyQualifiedClassName; +// } +// +// public Optional<String> getNewFullyQualifiedClassName() { +// return newFullyQualifiedClassName; +// } +// +// } +// +// public static class InterfaceChangeDTO { +// +// private final JApiChangeStatus changeStatus; +// private final String fullyQualifiedName; +// +// public InterfaceChangeDTO(JApiChangeStatus changeStatus, String fullyQualifiedName) { +// this.changeStatus = changeStatus; +// this.fullyQualifiedName = fullyQualifiedName; +// } +// +// public JApiChangeStatus getChangeStatus() { +// return changeStatus; +// } +// +// public String getFullyQualifiedName() { +// return fullyQualifiedName; +// } +// +// } + public static class MethodChangeDTO { + + private final JApiChangeStatus changeStatus; + private final Optional<String> oldMethodDeclaration; + private final Optional<String> newMethodDeclaration; + + public MethodChangeDTO(JApiChangeStatus changeStatus, Optional<String> oldMethodDeclaration, Optional<String> newMethodDeclaration) { + this.changeStatus = changeStatus; + this.oldMethodDeclaration = oldMethodDeclaration; + this.newMethodDeclaration = newMethodDeclaration; + } + + public JApiChangeStatus getChangeStatus() { + return changeStatus; + } + + public Optional<String> getOldMethodDeclaration() { + return oldMethodDeclaration; + } + + public Optional<String> getNewMethodDeclaration() { + return newMethodDeclaration; + } + + } + + public static class FieldChangeDTO { + + private final JApiChangeStatus changeStatus; + private final Optional<String> oldFieldDeclaration; + private final Optional<String> newFieldDeclaration; + + public FieldChangeDTO(JApiChangeStatus changeStatus, Optional<String> oldFieldDeclaration, Optional<String> newFieldDeclaration) { + this.changeStatus = changeStatus; + this.oldFieldDeclaration = oldFieldDeclaration; + this.newFieldDeclaration = newFieldDeclaration; + } + + public JApiChangeStatus getChangeStatus() { + return changeStatus; + } + + public Optional<String> getOldFieldDeclaration() { + return oldFieldDeclaration; + } + + public Optional<String> getNewFieldDeclaration() { + return newFieldDeclaration; + } + + } + +} diff --git a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ChangeOutputGenerator.java b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ChangeOutputGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..428b52e222ab6b55200cf4dfcbf26a281460106e --- /dev/null +++ b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ChangeOutputGenerator.java @@ -0,0 +1,614 @@ +package org.sleuthkit.autopsy.apiupdate; + +import japicmp.cli.CliParser; +import japicmp.config.Options; +import japicmp.model.*; +import japicmp.model.JApiAnnotationElementValue.Type; +import static japicmp.model.JApiChangeStatus.MODIFIED; +import static japicmp.model.JApiChangeStatus.NEW; +import static japicmp.model.JApiChangeStatus.REMOVED; +import static japicmp.model.JApiChangeStatus.UNCHANGED; +import japicmp.output.OutputFilter; +import japicmp.output.OutputGenerator; +import javassist.bytecode.annotation.MemberValue; + +import java.util.Comparator; +import java.util.List; + +import static japicmp.util.GenericTemplateHelper.haveGenericTemplateInterfacesChanges; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; +import org.sleuthkit.autopsy.apiupdate.ApiChangeDTO.FieldChangeDTO; +import org.sleuthkit.autopsy.apiupdate.ApiChangeDTO.InterfaceChangeDTO; +import org.sleuthkit.autopsy.apiupdate.ApiChangeDTO.SuperclassChangeDTO; + +// taken from https://raw.githubusercontent.com/siom79/japicmp/master/japicmp/src/main/java/japicmp/output/stdout/StdoutOutputGenerator.java +public class ChangeOutputGenerator extends OutputGenerator<ApiChangeDTO> { + + static final String NO_CHANGES = "No changes."; + static final String WARNING = "WARNING"; + + public ChangeOutputGenerator(Options options, List<JApiClass> jApiClasses) { + super(options, jApiClasses); + } + + @Override + public String generate() { + OutputFilter outputFilter = new OutputFilter(options); + outputFilter.filter(jApiClasses); + StringBuilder sb = new StringBuilder(); + sb.append(options.getDifferenceDescription()).append('\n'); + if (options.getIgnoreMissingClasses().isIgnoreAllMissingClasses()) { + sb.append(WARNING).append(": You are using the option '").append(CliParser.IGNORE_MISSING_CLASSES) + .append("', i.e. superclasses and interfaces that could not be found on the classpath are ignored.") + .append(" Hence changes caused by these superclasses and interfaces are not reflected in the output.\n"); + } else if (options.getIgnoreMissingClasses().getIgnoreMissingClassRegularExpression().size() > 0) { + sb.append(WARNING).append(": You have ignored certain classes, i.e. superclasses and interfaces that could not ") + .append("be found on the classpath are ignored. Hence changes caused by these superclasses and interfaces are not reflected in the output.\n"); + } + if (jApiClasses.size() > 0) { + for (JApiClass jApiClass : jApiClasses) { + processClass(sb, jApiClass); + processConstructors(sb, jApiClass); + processMethods(sb, jApiClass); + processAnnotations(sb, jApiClass, 1); + } + } else { + sb.append(NO_CHANGES); + } + return sb.toString(); + } + + private void processAnnotations(StringBuilder sb, JApiHasAnnotations jApiClass, int numberofTabs) { + List<JApiAnnotation> annotations = jApiClass.getAnnotations(); + for (JApiAnnotation jApiAnnotation : annotations) { + appendAnnotation(sb, signs(jApiAnnotation), jApiAnnotation, numberofTabs); + List<JApiAnnotationElement> elements = jApiAnnotation.getElements(); + for (JApiAnnotationElement jApiAnnotationElement : elements) { + appendAnnotationElement(sb, signs(jApiAnnotationElement), jApiAnnotationElement, numberofTabs + 1); + } + } + } + + private void processConstructors(StringBuilder sb, JApiClass jApiClass) { + List<JApiConstructor> constructors = jApiClass.getConstructors(); + for (JApiConstructor jApiConstructor : constructors) { + appendBehavior(sb, signs(jApiConstructor), jApiConstructor, "CONSTRUCTOR:"); + processAnnotations(sb, jApiConstructor, 2); + processExceptions(sb, jApiConstructor, 2); + processGenericTemplateChanges(sb, jApiConstructor, 2); + } + } + + private void processMethods(StringBuilder sb, JApiClass jApiClass) { + List<JApiMethod> methods = jApiClass.getMethods(); + for (JApiMethod jApiMethod : methods) { + appendBehavior(sb, signs(jApiMethod), jApiMethod, "METHOD:"); + processAnnotations(sb, jApiMethod, 2); + processExceptions(sb, jApiMethod, 2); + processGenericTemplateChanges(sb, jApiMethod, 2); + } + } + + private void processExceptions(StringBuilder sb, JApiBehavior jApiBehavior, int indent) { + for (JApiException exception : jApiBehavior.getExceptions()) { + appendException(sb, signs(exception), exception, indent); + } + } + + private void appendException(StringBuilder sb, String signs, JApiException jApiException, int indent) { + sb.append(tabs(indent)).append(signs).append(" ").append(jApiException.getChangeStatus()).append(" EXCEPTION: ").append(jApiException.getName()).append("\n"); + } + + private void processClass(StringBuilder sb, JApiClass jApiClass) { + appendClass(sb, signs(jApiClass), jApiClass); + } + + private void appendBehavior(StringBuilder sb, String signs, JApiBehavior jApiBehavior, String classMemberType) { + sb.append("\t").append(signs).append(" ").append(jApiBehavior.getChangeStatus()).append(" ").append(classMemberType).append(" ") + .append(accessModifierAsString(jApiBehavior)).append(abstractModifierAsString(jApiBehavior)).append(staticModifierAsString(jApiBehavior)) + .append(finalModifierAsString(jApiBehavior)).append(syntheticModifierAsString(jApiBehavior)).append(bridgeModifierAsString(jApiBehavior)) + .append(returnType(jApiBehavior)).append(jApiBehavior.getName()).append("("); + int paramCount = 0; + for (JApiParameter jApiParameter : jApiBehavior.getParameters()) { + if (paramCount > 0) { + sb.append(", "); + } + sb.append(jApiParameter.getType()); + appendGenericTypes(sb, jApiParameter); + paramCount++; + } + sb.append(")\n"); + } + + private void appendGenericTypes(StringBuilder sb, JApiHasGenericTypes jApiHasGenericTypes) { + if (!jApiHasGenericTypes.getNewGenericTypes().isEmpty() || !jApiHasGenericTypes.getOldGenericTypes().isEmpty()) { + if (jApiHasGenericTypes instanceof JApiCompatibility) { + List<JApiCompatibilityChange> compatibilityChanges = ((JApiCompatibility) jApiHasGenericTypes).getCompatibilityChanges(); + appendGenericTypesForCompatibilityChanges(sb, jApiHasGenericTypes, compatibilityChanges); + } + } + } + + private void appendGenericTypesForCompatibilityChanges(StringBuilder sb, JApiHasGenericTypes jApiHasGenericTypes, List<JApiCompatibilityChange> compatibilityChanges) { + if (compatibilityChanges.contains(JApiCompatibilityChange.METHOD_PARAMETER_GENERICS_CHANGED) + || compatibilityChanges.contains(JApiCompatibilityChange.METHOD_RETURN_TYPE_GENERICS_CHANGED) + || compatibilityChanges.contains(JApiCompatibilityChange.FIELD_GENERICS_CHANGED) + || compatibilityChanges.contains(JApiCompatibilityChange.CLASS_GENERIC_TEMPLATE_GENERICS_CHANGED)) { + appendGenericTypes(sb, false, jApiHasGenericTypes.getNewGenericTypes()); + appendGenericTypes(sb, true, jApiHasGenericTypes.getOldGenericTypes()); + } else { + if (!jApiHasGenericTypes.getNewGenericTypes().isEmpty()) { + appendGenericTypes(sb, false, jApiHasGenericTypes.getNewGenericTypes()); + } + if (!jApiHasGenericTypes.getOldGenericTypes().isEmpty()) { + appendGenericTypes(sb, false, jApiHasGenericTypes.getOldGenericTypes()); + } + } + } + + private void appendGenericTypes(StringBuilder sb, boolean withChangeInParenthesis, List<JApiGenericType> genericTypes) { + if (!genericTypes.isEmpty()) { + if (withChangeInParenthesis) { + sb.append("(<- "); + } + sb.append("<"); + int count = 0; + for (JApiGenericType genericType : genericTypes) { + if (count > 0) { + sb.append(","); + } + appendGenericType(sb, genericType); + if (!genericType.getGenericTypes().isEmpty()) { + appendGenericTypes(sb, false, genericType.getGenericTypes()); + } + count++; + } + sb.append(">"); + if (withChangeInParenthesis) { + sb.append(")"); + } + } + } + + private void appendGenericType(StringBuilder sb, JApiGenericType jApiGenericType) { + if (jApiGenericType.getGenericWildCard() == JApiGenericType.JApiGenericWildCard.NONE) { + sb.append(jApiGenericType.getType()); + } else if (jApiGenericType.getGenericWildCard() == JApiGenericType.JApiGenericWildCard.UNBOUNDED) { + sb.append("?"); + } else if (jApiGenericType.getGenericWildCard() == JApiGenericType.JApiGenericWildCard.EXTENDS) { + sb.append("? extends ").append(jApiGenericType.getType()); + } else if (jApiGenericType.getGenericWildCard() == JApiGenericType.JApiGenericWildCard.SUPER) { + sb.append("? super ").append(jApiGenericType.getType()); + } + } + + private String returnType(JApiBehavior jApiBehavior) { + StringBuilder sb = new StringBuilder(); + if (jApiBehavior instanceof JApiMethod) { + JApiMethod method = (JApiMethod) jApiBehavior; + JApiReturnType jApiReturnType = method.getReturnType(); + if (jApiReturnType.getChangeStatus() == JApiChangeStatus.UNCHANGED) { + sb.append(jApiReturnType.getNewReturnType()); + appendGenericTypes(sb, jApiReturnType); + sb.append(" "); + } else if (jApiReturnType.getChangeStatus() == JApiChangeStatus.MODIFIED) { + sb.append(jApiReturnType.getNewReturnType()); + appendGenericTypes(sb, jApiReturnType); + sb.append(" (<-"); + sb.append(jApiReturnType.getOldReturnType()); + appendGenericTypes(sb, jApiReturnType); + sb.append(") "); + } else if (jApiReturnType.getChangeStatus() == JApiChangeStatus.NEW) { + sb.append(jApiReturnType.getNewReturnType()); + appendGenericTypes(sb, jApiReturnType); + sb.append(" "); + } else { + sb.append(jApiReturnType.getOldReturnType()); + appendGenericTypes(sb, jApiReturnType); + sb.append(" "); + } + } + return sb.toString(); + } + + private void appendAnnotation(StringBuilder sb, String signs, JApiAnnotation jApiAnnotation, int numberOfTabs) { + sb.append(String.format("%s%s %s ANNOTATION: %s\n", tabs(numberOfTabs), signs, jApiAnnotation.getChangeStatus(), jApiAnnotation.getFullyQualifiedName())); + } + + private void appendAnnotationElement(StringBuilder sb, String signs, JApiAnnotationElement jApiAnnotationElement, int numberOfTabs) { + sb.append(String.format("%s%s %s ELEMENT: %s=", tabs(numberOfTabs), signs, jApiAnnotationElement.getChangeStatus(), jApiAnnotationElement.getName())); + Optional<MemberValue> oldValue = jApiAnnotationElement.getOldValue(); + Optional<MemberValue> newValue = jApiAnnotationElement.getNewValue(); + if (oldValue.isPresent() && newValue.isPresent()) { + if (jApiAnnotationElement.getChangeStatus() == JApiChangeStatus.UNCHANGED) { + sb.append(elementValueList2String(jApiAnnotationElement.getNewElementValues())); + } else if (jApiAnnotationElement.getChangeStatus() == JApiChangeStatus.REMOVED) { + sb.append(String.format("%s (-)", elementValueList2String(jApiAnnotationElement.getOldElementValues()))); + } else if (jApiAnnotationElement.getChangeStatus() == JApiChangeStatus.NEW) { + sb.append(String.format("%s (+)", elementValueList2String(jApiAnnotationElement.getNewElementValues()))); + } else if (jApiAnnotationElement.getChangeStatus() == JApiChangeStatus.MODIFIED) { + sb.append(String.format("%s (<- %s)", elementValueList2String(jApiAnnotationElement.getNewElementValues()), elementValueList2String(jApiAnnotationElement.getOldElementValues()))); + } + } else if (!oldValue.isPresent() && newValue.isPresent()) { + sb.append(String.format("%s (+)", elementValueList2String(jApiAnnotationElement.getNewElementValues()))); + } else if (oldValue.isPresent() && !newValue.isPresent()) { + sb.append(String.format("%s (-)", elementValueList2String(jApiAnnotationElement.getOldElementValues()))); + } else { + sb.append(" n.a."); + } + sb.append("\n"); + } + + private void appendClass(StringBuilder sb, String signs, JApiClass jApiClass) { + sb.append(signs).append(" ").append(jApiClass.getChangeStatus()).append(" ") + .append(processClassType(jApiClass)).append(": ") + .append(accessModifierAsString(jApiClass)) + .append(abstractModifierAsString(jApiClass)) + .append(staticModifierAsString(jApiClass)) + .append(finalModifierAsString(jApiClass)) + .append(syntheticModifierAsString(jApiClass)) + .append(jApiClass.getFullyQualifiedName()).append(" ") + .append(javaObjectSerializationStatus(jApiClass)).append("\n"); + + processGenericTemplateChanges(sb, jApiClass, 1); + processInterfaceChanges(sb, jApiClass); + processSuperclassChanges(sb, jApiClass); + processFieldChanges(sb, jApiClass); + } + + private String getClassString(JApiClass clz, boolean oldClass) { + if (jApiClass.getChangeStatus() == NEW && oldClass || jApiClass.getChangeStatus() == REMOVED && !oldClass) { + return null; + } + + String accessModifier = str(get(clz.getAccessModifier(), oldClass).orElse(null)); + String abstractModifier = str(get(clz.getAbstractModifier(), oldClass).orElse(null)); + String staticModifier = str(get(clz.getStaticModifier(), oldClass).orElse(null)); + String finalModifier = str(get(clz.getFinalModifier(), oldClass).orElse(null)); + String syntheticModifier = str(get(clz.getSyntheticModifier(), oldClass).orElse(null)); + + String name = clz.getFullyQualifiedName(); + + String genericModifier = strOpt(get(clz.getGenericTemplates(); + + String implementsModifier = TBD; + String extendsModifier = TBD; + + return Stream.of( + accessModifier, + abstractModifier, + staticModifier, + finalModifier, + syntheticModifier, + "class", + name + (StringUtils.isBlank(genericModifier) ? "" : genericModifier), + implementsModifier, + extendsModifier) + .filter(StringUtils::isNotBlank) + .collect(Collectors.joining(" ")); + } + +// private List<GenericTemplateChangeDTO> getGenericTemplateChanges(JApiHasGenericTemplates jApiHasGenericTemplates) { +// return jApiHasGenericTemplates.getGenericTemplates().stream() +// .filter(template -> template.getChangeStatus() != JApiChangeStatus.UNCHANGED) +// .map(template -> new GenericTemplateChangeDTO()) +// .collect(Collectors.toList()); +// +// if (!genericTemplates.isEmpty()) { +// sb.append(tabs(numberOfTabs)).append("GENERIC TEMPLATES: "); +// genericTemplates.sort(Comparator.comparing(JApiGenericTemplate::getName)); +// int count = 0; +// for (JApiGenericTemplate jApiGenericTemplate : genericTemplates) { +// if (count > 0) { +// sb.append(", "); +// } +// count++; +// sb.append(signs(jApiGenericTemplate)); +// if (sb.charAt(sb.length() - 1) != ' ') { +// sb.append(" "); +// } +// sb.append(jApiGenericTemplate.getName()).append(":"); +// JApiChangeStatus changeStatus = jApiGenericTemplate.getChangeStatus(); +// if (changeStatus == JApiChangeStatus.NEW || changeStatus == JApiChangeStatus.UNCHANGED) { +// sb.append(jApiGenericTemplate.getNewType()); +// if (jApiGenericTemplate instanceof JApiCompatibility) { +// appendGenericTypesForCompatibilityChanges(sb, jApiGenericTemplate, ((JApiCompatibility) jApiHasGenericTemplates).getCompatibilityChanges()); +// } +// } else if (changeStatus == JApiChangeStatus.REMOVED) { +// sb.append(jApiGenericTemplate.getOldType()); +// if (jApiGenericTemplate instanceof JApiCompatibility) { +// appendGenericTypesForCompatibilityChanges(sb, jApiGenericTemplate, ((JApiCompatibility) jApiHasGenericTemplates).getCompatibilityChanges()); +// } +// } else { +// sb.append(jApiGenericTemplate.getNewType()); +// appendGenericTypes(sb, false, jApiGenericTemplate.getNewGenericTypes()); +// sb.append(" (<-").append(jApiGenericTemplate.getOldType()); +// appendGenericTypes(sb, false, jApiGenericTemplate.getOldGenericTypes()); +// sb.append(")"); +// } +// if (!jApiGenericTemplate.getOldInterfaceTypes().isEmpty() || !jApiGenericTemplate.getNewInterfaceTypes().isEmpty()) { +// if (haveGenericTemplateInterfacesChanges(jApiGenericTemplate.getOldInterfaceTypes(), jApiGenericTemplate.getNewInterfaceTypes())) { +// appendGenericTemplatesInterfaces(sb, jApiGenericTemplate, false, true); +// sb.append(" (<-"); +// appendGenericTemplatesInterfaces(sb, jApiGenericTemplate, true, false); +// sb.append(")"); +// } else { +// appendGenericTemplatesInterfaces(sb, jApiGenericTemplate, false, true); +// } +// } +// } +// sb.append("\n"); +// } +// } +// private void appendGenericTemplatesInterfaces(StringBuilder sb, JApiGenericTemplate jApiGenericTemplate, boolean printOld, boolean printNew) { +// if (printOld) { +// for (JApiGenericType jApiGenericType : jApiGenericTemplate.getOldInterfaceTypes()) { +// sb.append(" & "); +// sb.append(jApiGenericType.getType()); +// appendGenericTypes(sb, false, jApiGenericType.getGenericTypes()); +// } +// } +// if (printNew) { +// for (JApiGenericType jApiGenericType : jApiGenericTemplate.getNewInterfaceTypes()) { +// sb.append(" & "); +// sb.append(jApiGenericType.getType()); +// appendGenericTypes(sb, false, jApiGenericType.getGenericTypes()); +// } +// } +// } +// private String str(JApiHasGenericTemplates jApiHasGenericTemplates) { +// jApiHasGenericTemplates.getGenericTemplates().get(0).g +// } + private FieldChangeDTO getFieldChange(JApiField field) { + return new FieldChangeDTO( + field.getChangeStatus(), + Optional.ofNullable(getFieldString(field, true)), + Optional.ofNullable(getFieldString(field, false))); + } + + private String getFieldString(JApiField field, boolean oldField) { + if (field.getChangeStatus() == NEW && oldField || field.getChangeStatus() == REMOVED && !oldField) { + return null; + } + + String accessModifier = str(get(field.getAccessModifier(), oldField).orElse(null)); + String staticModifier = str(get(field.getStaticModifier(), oldField).orElse(null)); + String finalModifier = str(get(field.getFinalModifier(), oldField).orElse(null)); + String syntheticModifier = str(get(field.getSyntheticModifier(), oldField).orElse(null)); + String fieldType = strOpt(field.getType(), oldField).orElse(""); + String name = field.getName(); + + return Stream.of(accessModifier, staticModifier, finalModifier, syntheticModifier, fieldType, name) + .filter(StringUtils::isNotBlank) + .collect(Collectors.joining(" ")); + } + + private String str(AccessModifier modifier) { + if (modifier == null || modifier == AccessModifier.PACKAGE_PROTECTED) { + return ""; + } else { + return modifier.name().toLowerCase(); + } + } + + private String str(StaticModifier modifier) { + return (modifier == StaticModifier.STATIC) + ? "static" + : ""; + } + + private String str(FinalModifier modifier) { + return (modifier == FinalModifier.FINAL) + ? "final" + : ""; + } + + private String str(SyntheticModifier modifier) { + return (modifier == SyntheticModifier.SYNTHETIC) + ? "synthetic" + : ""; + } + + private String str(AbstractModifier modifier) { + return (modifier == AbstractModifier.ABSTRACT) + ? "abstract" + : ""; + } + + private Optional<String> strOpt(JApiType tp, boolean oldField) { + return oldField ? convert(tp.getOldTypeOptional()) : convert(tp.getNewTypeOptional()); + } + + private <T> Optional<T> get(JApiModifier<T> modifier, boolean oldField) { + return oldField ? convert(modifier.getOldModifier()) : convert(modifier.getNewModifier()); + } + +// private Optional<SuperclassChangeDTO> getSuperClassChange(JApiSuperclass jApiSuperclass) { +// return jApiSuperclass.getChangeStatus() != JApiChangeStatus.UNCHANGED +// ? Optional.ofNullable(new SuperclassChangeDTO( +// convert(jApiSuperclass.getOldSuperclassName()), +// convert(jApiSuperclass.getNewSuperclassName()))) +// : Optional.empty(); +// } +// +// private List<InterfaceChangeDTO> getInterfaceChanges(JApiClass jApiClass) { +// return jApiClass.getInterfaces().stream() +// .filter(intfc -> intfc.getChangeStatus() != JApiChangeStatus.UNCHANGED) +// .map(intfc -> new InterfaceChangeDTO(intfc.getChangeStatus(), intfc.getFullyQualifiedName())) +// .collect(Collectors.toList()); +// } + private <T> Optional<T> convert(japicmp.util.Optional<T> apiOpt) { + T val = apiOpt.or((T) null); + return java.util.Optional.ofNullable(val); + } + +// +// private void processClassFileFormatVersionChanges(StringBuilder sb, JApiClass jApiClass) { +// JApiClassFileFormatVersion classFileFormatVersion = jApiClass.getClassFileFormatVersion(); +// sb.append(tabs(1)) +// .append(signs(classFileFormatVersion)) +// .append(" CLASS FILE FORMAT VERSION: "); +// if (classFileFormatVersion.getMajorVersionNew() != -1 && classFileFormatVersion.getMinorVersionNew() != -1) { +// sb.append(classFileFormatVersion.getMajorVersionNew()).append(".").append(classFileFormatVersion.getMinorVersionNew()); +// } else { +// sb.append("n.a."); +// } +// sb.append(" <- "); +// if (classFileFormatVersion.getMajorVersionOld() != -1 && classFileFormatVersion.getMinorVersionOld() != -1) { +// sb.append(classFileFormatVersion.getMajorVersionOld()).append(".").append(classFileFormatVersion.getMinorVersionOld()); +// } else { +// sb.append("n.a."); +// } +// sb.append("\n"); +// } +// private String processClassType(JApiClass jApiClass) { +// JApiClassType classType = jApiClass.getClassType(); +// switch (classType.getChangeStatus()) { +// case NEW: +// return classType.getNewType(); +// case REMOVED: +// return classType.getOldType(); +// case MODIFIED: +// return classType.getNewType() + " (<- " + classType.getOldType() + ") "; +// case UNCHANGED: +// return classType.getOldType(); +// } +// return "n.a."; +// } +// +// // TODO do we need this +// private String getJavaObjectSerializationStatus(JApiClass jApiClass) { +// return jApiClass.getJavaObjectSerializationCompatible().getDescription(); +// } +// private String elementValueList2String(List<JApiAnnotationElementValue> values) { +// StringBuilder sb = new StringBuilder(); +// for (JApiAnnotationElementValue value : values) { +// if (sb.length() > 0) { +// sb.append(","); +// } +// if (value.getName().isPresent()) { +// sb.append(value.getName().get()).append("="); +// } +// if (value.getType() != Type.Array && value.getType() != Type.Annotation) { +// if (value.getType() == Type.Enum) { +// sb.append(value.getFullyQualifiedName()).append(".").append(value.getValueString()); +// } else { +// sb.append(value.getValueString()); +// } +// } else { +// if (value.getType() == Type.Array) { +// sb.append("{").append(elementValueList2String(value.getValues())).append("}"); +// } else if (value.getType() == Type.Annotation) { +// sb.append("@").append(value.getFullyQualifiedName()).append("(").append(elementValueList2String(value.getValues())).append(")"); +// } +// } +// } +// return sb.toString(); +// } +// +// private String tabs(int numberOfTabs) { +// if (numberOfTabs <= 0) { +// return ""; +// } else if (numberOfTabs == 1) { +// return "\t"; +// } else if (numberOfTabs == 2) { +// return "\t\t"; +// } else { +// StringBuilder sb = new StringBuilder(); +// for (int i = 0; i < numberOfTabs; i++) { +// sb.append("\t"); +// } +// return sb.toString(); +// } +// } +// private String signs(JApiHasChangeStatus hasChangeStatus) { +// JApiChangeStatus changeStatus = hasChangeStatus.getChangeStatus(); +// String retVal = "???"; +// switch (changeStatus) { +// case UNCHANGED: +// retVal = "==="; +// break; +// case NEW: +// retVal = "+++"; +// break; +// case REMOVED: +// retVal = "---"; +// break; +// case MODIFIED: +// retVal = "***"; +// break; +// } +// boolean binaryCompatible = true; +// boolean sourceCompatible = true; +// if (hasChangeStatus instanceof JApiCompatibility) { +// JApiCompatibility jApiCompatibility = (JApiCompatibility) hasChangeStatus; +// binaryCompatible = jApiCompatibility.isBinaryCompatible(); +// sourceCompatible = jApiCompatibility.isSourceCompatible(); +// } +// if (binaryCompatible) { +// if (sourceCompatible) { +// retVal += " "; +// } else { +// retVal += "*"; +// } +// } else { +// retVal += "!"; +// } +// return retVal; +// } +// +// private String bridgeModifierAsString(JApiHasBridgeModifier modifier) { +// JApiModifier<BridgeModifier> bridgeModifier = modifier.getBridgeModifier(); +// return modifierAsString(bridgeModifier, BridgeModifier.NON_BRIDGE); +// } +// private <T> String modifierAsString(JApiModifier<T> modifier, T notPrintValue) { +// if (modifier.getOldModifier().isPresent() && modifier.getNewModifier().isPresent()) { +// if (modifier.getChangeStatus() == JApiChangeStatus.MODIFIED) { +// return modifier.getNewModifier().get() + " (<- " + modifier.getOldModifier().get() + ") "; +// } else if (modifier.getChangeStatus() == JApiChangeStatus.NEW) { +// if (modifier.getNewModifier().get() != notPrintValue) { +// return modifier.getNewModifier().get() + "(+) "; +// } +// } else if (modifier.getChangeStatus() == JApiChangeStatus.REMOVED) { +// if (modifier.getOldModifier().get() != notPrintValue) { +// return modifier.getOldModifier().get() + "(-) "; +// } +// } else { +// if (modifier.getNewModifier().get() != notPrintValue) { +// return modifier.getNewModifier().get() + " "; +// } +// } +// } else if (modifier.getOldModifier().isPresent()) { +// if (modifier.getOldModifier().get() != notPrintValue) { +// return modifier.getOldModifier().get() + "(-) "; +// } +// } else if (modifier.getNewModifier().isPresent()) { +// if (modifier.getNewModifier().get() != notPrintValue) { +// return modifier.getNewModifier().get() + "(+) "; +// } +// } +// return ""; +// } +// private String fieldTypeChangeAsString(JApiField field) { +// JApiType type = field.getType(); +// if (type.getOldTypeOptional().isPresent() && type.getNewTypeOptional().isPresent()) { +// if (type.getChangeStatus() == JApiChangeStatus.MODIFIED) { +// return type.getNewTypeOptional().get() + " (<- " + type.getOldTypeOptional().get() + ")"; +// } else if (type.getChangeStatus() == JApiChangeStatus.NEW) { +// return type.getNewTypeOptional().get() + "(+)"; +// } else if (type.getChangeStatus() == JApiChangeStatus.REMOVED) { +// return type.getOldTypeOptional().get() + "(-)"; +// } else { +// return type.getNewTypeOptional().get(); +// } +// } else if (type.getOldTypeOptional().isPresent() && !type.getNewTypeOptional().isPresent()) { +// return type.getOldTypeOptional().get(); +// } else if (!type.getOldTypeOptional().isPresent() && type.getNewTypeOptional().isPresent()) { +// return type.getNewTypeOptional().get(); +// } +// return "n.a."; +// } +} diff --git a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/Main.java b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/Main.java index 77b91e61ebf91fe50fc4aa33ac247034fe64241c..ee0f93ce7fead28e847f2898d14e0eb96ae2085e 100644 --- a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/Main.java +++ b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/Main.java @@ -3,14 +3,11 @@ */ package org.sleuthkit.autopsy.apiupdate; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.commons.cli.ParseException; import org.sleuthkit.autopsy.apiupdate.CLIProcessor.CLIArgs; -import org.sleuthkit.autopsy.apiupdate.ModuleUpdates.ModuleVersionNumbers; -import org.sleuthkit.autopsy.apiupdate.ModuleUpdates.ReleaseVal; /** * @@ -19,7 +16,7 @@ public class Main { public static void main(String[] args) { - args = "-c C:\\Users\\gregd\\Documents\\Source\\autopsy\\build\\cluster\\modules -p C:\\Users\\gregd\\Desktop\\prevVers -cv 4.21.0 -pv 4.20.0 -s C:\\Users\\gregd\\Documents\\Source\\autopsy".split(" "); + args = "-c C:\\Users\\gregd\\Desktop\\apidiff\\new -p C:\\Users\\gregd\\Desktop\\apidiff\\old -cv 4.21.0 -pv 4.20.0 -s C:\\Users\\gregd\\Documents\\Source\\autopsy".split(" "); CLIArgs cliArgs; try { cliArgs = CLIProcessor.parseCli(args); @@ -33,31 +30,35 @@ public static void main(String[] args) { return; } - Map<String, ModuleVersionNumbers> versNums = Stream.of( - new ModuleVersionNumbers( - "org.sleuthkit.autopsy.core", - new ModuleUpdates.SemVer(1,2,3), - 4, - new ReleaseVal("org.sleuthkit.autopsy.core", 5)), - new ModuleVersionNumbers( - "org.sleuthkit.autopsy.corelibs", - new ModuleUpdates.SemVer(6,7,8), - 9, - new ReleaseVal("org.sleuthkit.autopsy.corelibs", 10))) - .collect(Collectors.toMap(v -> v.getModuleName(), v -> v, (v1, v2) -> v1)); - - ModuleUpdates.setVersions(cliArgs.getSrcPath(), versNums); +// Map<String, ModuleVersionNumbers> versNums = Stream.of( +// new ModuleVersionNumbers( +// "org.sleuthkit.autopsy.core", +// new ModuleUpdates.SemVer(1,2,3), +// 4, +// new ReleaseVal("org.sleuthkit.autopsy.core", 5)), +// new ModuleVersionNumbers( +// "org.sleuthkit.autopsy.corelibs", +// new ModuleUpdates.SemVer(6,7,8), +// 9, +// new ReleaseVal("org.sleuthkit.autopsy.corelibs", 10))) +// .collect(Collectors.toMap(v -> v.getModuleName(), v -> v, (v1, v2) -> v1)); +// +// ModuleUpdates.setVersions(cliArgs.getSrcPath(), versNums); -// for (String commonJarFileName : APIDiff.getCommonJars(cliArgs.getPreviousVersPath(), cliArgs.getCurrentVersPath())) { -// try { + for (String commonJarFileName : APIDiff.getCommonJars(cliArgs.getPreviousVersPath(), cliArgs.getCurrentVersPath())) { + try { // ModuleVersionNumbers m = ModuleUpdates.getVersionsFromJar(cliArgs.getPreviousVersPath().toPath().resolve(commonJarFileName).toFile()); // System.out.println(MessageFormat.format("release: {0}, spec: {1}, implementation: {2}", m.getRelease().getFullReleaseStr(), m.getSpec().getSemVerStr(), m.getImplementation())); -// -// } catch (IOException ex) { -// Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); -// } -// -// } + APIDiff.getComparison( + cliArgs.getPreviousVersion(), + cliArgs.getCurrentVersion(), + cliArgs.getPreviousVersPath().toPath().resolve(commonJarFileName).toFile(), + cliArgs.getCurrentVersPath().toPath().resolve(commonJarFileName).toFile()); + } catch (IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + + } diff --git a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/PublicApiChangeType.java b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/PublicApiChangeType.java new file mode 100644 index 0000000000000000000000000000000000000000..d3379ac93ef1d497fc2c96acb7774e746d79388d --- /dev/null +++ b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/PublicApiChangeType.java @@ -0,0 +1,13 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package org.sleuthkit.autopsy.apiupdate; + +/** + * + * @author gregd + */ +public enum PublicApiChangeType { + NONE, COMPATIBLE_CHANGE, INCOMPATIBLE_CHANGE; +}