From 0b7e8dd8ca5fd9fd930b9036d3196ad959328f71 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro <gregd@basistech.com> Date: Fri, 1 Sep 2023 12:24:21 -0400 Subject: [PATCH] updates --- .../sleuthkit/autopsy/apiupdate/APIDiff.java | 273 +++++--- .../autopsy/apiupdate/ApiChangeDTO.java | 153 ---- .../autopsy/apiupdate/CLIProcessor.java | 43 +- .../apiupdate/ChangeOutputGenerator.java | 662 ------------------ .../org/sleuthkit/autopsy/apiupdate/Main.java | 109 +-- .../autopsy/apiupdate/ModuleUpdates.java | 42 +- .../apiupdate/PublicApiChangeType.java | 24 +- 7 files changed, 341 insertions(+), 965 deletions(-) delete mode 100644 release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ApiChangeDTO.java delete mode 100644 release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ChangeOutputGenerator.java 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 2f990d2a38..1affbd7c4a 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 @@ -4,20 +4,40 @@ */ package org.sleuthkit.autopsy.apiupdate; +import com.google.common.collect.Comparators; import japicmp.cmp.JApiCmpArchive; import japicmp.cmp.JarArchiveComparator; import japicmp.cmp.JarArchiveComparatorOptions; import japicmp.config.Options; +import japicmp.filter.BehaviorFilter; +import japicmp.filter.ClassFilter; +import japicmp.filter.FieldFilter; +import japicmp.model.JApiAnnotation; import japicmp.model.JApiClass; +import japicmp.model.JApiConstructor; +import japicmp.model.JApiField; +import japicmp.model.JApiHasChangeStatus; +import japicmp.model.JApiImplementedInterface; +import japicmp.model.JApiMethod; +import japicmp.model.JApiSuperclass; +import japicmp.output.Filter; +import japicmp.output.stdout.StdoutOutputGenerator; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.text.MessageFormat; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.Stream; +import javassist.CtBehavior; +import javassist.CtClass; +import javassist.CtField; +import javassist.CtMember; +import javassist.Modifier; /** * @@ -57,107 +77,186 @@ private static Set<String> getPublicPackages(File jarFile) throws IOException, I } } - 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) - ); + // only fields, methods that are public or protected + static boolean excludeMember(CtMember member) { + return !Modifier.isPublic(member.getModifiers()) && !Modifier.isProtected(member.getModifiers()); + } + static ComparisonRecord getComparison(String prevVersion, String curVersion, File prevJar, File curJar) throws IOException { + // scope only to previous or current public packages 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()); + Set<String> onlyPrevApiPackages = new HashSet<>(); + Set<String> onlyCurApiPackages = new HashSet<>(); + Set<String> commonApiPackages = new HashSet<>(); + for (String apiPackage : allPublicApiPackages) { + boolean inPrev = prevPublicApiPackages.contains(apiPackage); + boolean inCur = curPublicApiPackages.contains(apiPackage); + if (inPrev && !inCur) { + onlyPrevApiPackages.add(apiPackage); + } else if (!inPrev && inCur) { + onlyCurApiPackages.add(apiPackage); + } else { + commonApiPackages.add(apiPackage); + } + } + + JarArchiveComparatorOptions comparatorOptions = new JarArchiveComparatorOptions(); + // only classes in prev or current public api + comparatorOptions.getFilters().getExcludes().add((ClassFilter) (CtClass ctClass) -> !allPublicApiPackages.contains(ctClass.getPackageName())); + // only public classes + comparatorOptions.getFilters().getExcludes().add((ClassFilter) (CtClass ctClass) -> !Modifier.isPublic(ctClass.getModifiers())); + // only fields, methods that are public or protected and class is not final + comparatorOptions.getFilters().getExcludes().add((FieldFilter) (CtField ctField) -> excludeMember(ctField)); + comparatorOptions.getFilters().getExcludes().add((BehaviorFilter) (CtBehavior ctBehavior) -> excludeMember(ctBehavior)); + + comparatorOptions.getIgnoreMissingClasses().setIgnoreAllMissingClasses(true); + + JarArchiveComparator jarArchiveComparator = new JarArchiveComparator(comparatorOptions); + List<JApiClass> jApiClasses = jarArchiveComparator.compare( + new JApiCmpArchive(prevJar, prevVersion), + new JApiCmpArchive(curJar, curVersion) + ); + + PublicApiChangeType changeType = getChangeType(jApiClasses); + Options options = Options.newDefault(); options.setOutputOnlyModifications(true); - System.out.println("Comparing " + prevJar.getName()); - ChangeOutputGenerator stdoutOutputGenerator = new ChangeOutputGenerator(options, jApiClasses); - String output = stdoutOutputGenerator.generate(); - System.out.println(output); + StdoutOutputGenerator stdoutOutputGenerator = new StdoutOutputGenerator(options, jApiClasses); + String humanReadableApiChange = stdoutOutputGenerator.generate(); + return new ComparisonRecord(prevVersion, curVersion, prevJar, curJar, humanReadableApiChange, changeType, onlyPrevApiPackages, onlyCurApiPackages, commonApiPackages); + } + + private static void updateToMax(AtomicReference<PublicApiChangeType> apiChangeRef, JApiHasChangeStatus tp) { + PublicApiChangeType apiChangeType; + switch (tp.getChangeStatus()) { + case UNCHANGED: + apiChangeType = PublicApiChangeType.NONE; + break; + case NEW: + apiChangeType = PublicApiChangeType.COMPATIBLE_CHANGE; + break; + case MODIFIED: + case REMOVED: + default: + apiChangeType = PublicApiChangeType.INCOMPATIBLE_CHANGE; + break; + }; + + final PublicApiChangeType finalApiChangeType = apiChangeType; + apiChangeRef.updateAndGet((refType) -> Comparators.max(refType, finalApiChangeType)); + } + + static PublicApiChangeType getChangeType(List<JApiClass> jApiClasses) { + AtomicReference<PublicApiChangeType> apiChange = new AtomicReference<PublicApiChangeType>(PublicApiChangeType.NONE); + + Filter.filter(jApiClasses, new Filter.FilterVisitor() { + @Override + public void visit(Iterator<JApiClass> itrtr, JApiClass jac) { + updateToMax(apiChange, jac); + } + + @Override + public void visit(Iterator<JApiMethod> itrtr, JApiMethod jam) { + updateToMax(apiChange, jam); + } + + @Override + public void visit(Iterator<JApiConstructor> itrtr, JApiConstructor jac) { + updateToMax(apiChange, jac); + } + + @Override + public void visit(Iterator<JApiImplementedInterface> itrtr, JApiImplementedInterface jaii) { + updateToMax(apiChange, jaii); + } + + @Override + public void visit(Iterator<JApiField> itrtr, JApiField jaf) { + updateToMax(apiChange, jaf); + } + + @Override + public void visit(Iterator<JApiAnnotation> itrtr, JApiAnnotation jaa) { + updateToMax(apiChange, jaa); + } + + @Override + public void visit(JApiSuperclass jas) { + updateToMax(apiChange, jas); + } + }); + + return apiChange.get(); } - private static void generateOutput(Options options, List<JApiClass> jApiClasses, JarArchiveComparator jarArchiveComparator) { -// for (JApiClass cls: jApiClasses) { -// cls.is -// } -// + public static class ComparisonRecord { + + private final String prevVersion; + private final String curVersion; + private final File prevJar; + private final File curJar; + private final String humanReadableApiChange; + private final PublicApiChangeType changeType; + private final Set<String> onlyPrevApiPackages; + private final Set<String> onlyCurrApiPackages; + private final Set<String> commonApiPackages; + + public ComparisonRecord(String prevVersion, String curVersion, File prevJar, File curJar, String humanReadableApiChange, PublicApiChangeType changeType, Set<String> onlyPrevApiPackages, Set<String> onlyCurrApiPackages, Set<String> commonApiPackages) { + this.prevVersion = prevVersion; + this.curVersion = curVersion; + this.prevJar = prevJar; + this.curJar = curJar; + this.humanReadableApiChange = humanReadableApiChange; + this.changeType = changeType; + this.onlyPrevApiPackages = onlyPrevApiPackages; + this.onlyCurrApiPackages = onlyCurrApiPackages; + this.commonApiPackages = commonApiPackages; + } + + public String getPrevVersion() { + return prevVersion; + } + + public String getCurVersion() { + return curVersion; + } + + public File getPrevJar() { + return prevJar; + } + + public File getCurJar() { + return curJar; + } + + public String getHumanReadableApiChange() { + return humanReadableApiChange; + } + + public PublicApiChangeType getChangeType() { + return changeType; + } + + public Set<String> getOnlyPrevApiPackages() { + return onlyPrevApiPackages; + } + + public Set<String> getOnlyCurrApiPackages() { + return onlyCurrApiPackages; + } + + public Set<String> getCommonApiPackages() { + return commonApiPackages; + } + -// 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 deleted file mode 100644 index 2d3588f6a7..0000000000 --- a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ApiChangeDTO.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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/CLIProcessor.java b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/CLIProcessor.java index 1b5597e235..ba09ebe11d 100644 --- a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/CLIProcessor.java +++ b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/CLIProcessor.java @@ -5,6 +5,7 @@ package org.sleuthkit.autopsy.apiupdate; import java.io.File; +import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -37,7 +38,7 @@ public class CLIProcessor { .hasArg(true) .longOpt("curr-path") .option("c") - .required(true) + .required(false) .build(); static Option PREV_VERS_OPT = Option.builder() @@ -46,7 +47,7 @@ public class CLIProcessor { .hasArg(true) .longOpt("prev-version") .option("pv") - .required(true) + .required(false) .build(); static Option CUR_VERS_OPT = Option.builder() @@ -55,7 +56,7 @@ public class CLIProcessor { .hasArg(true) .longOpt("curr-version") .option("cv") - .required(true) + .required(false) .build(); static Option SRC_LOC_OPT = Option.builder() @@ -67,15 +68,27 @@ public class CLIProcessor { .required(true) .build(); + static Option UPDATE_OPT = Option.builder() + .desc("Update source code versions") + .hasArg(false) + .longOpt("update") + .option("u") + .required(false) + .build(); + static List<Option> ALL_OPTIONS = Arrays.asList( PREV_VERS_PATH_OPT, CUR_VERS_PATH_OPT, PREV_VERS_OPT, CUR_VERS_OPT, - SRC_LOC_OPT + SRC_LOC_OPT, + UPDATE_OPT ); static Options CLI_OPTIONS = getCliOptions(ALL_OPTIONS); + private static final String DEFAULT_CURR_VERSION = "Current Version"; + private static final String DEFAULT_PREV_VERSION = "Previous Version"; + private static final String BUILD_REL_PATH = "build/cluster/modules"; private static Options getCliOptions(List<Option> opts) { Options toRet = new Options(); @@ -112,15 +125,19 @@ static CLIArgs parseCli(String[] args) throws ParseException { CommandLine helpCmd = parser.parse(HELP_OPTIONS, args, true); boolean isHelp = helpCmd.hasOption(HELP_OPT); if (isHelp) { - return new CLIArgs(null, null, null, null, null, true); + return new CLIArgs(null, null, null, null, null, false, true); } CommandLine cmd = parser.parse(CLI_OPTIONS, args); - String curVers = cmd.getOptionValue(CUR_VERS_OPT); - String prevVers = cmd.getOptionValue(PREV_VERS_OPT); - String curVersPath = cmd.getOptionValue(CUR_VERS_PATH_OPT); + String curVers = cmd.hasOption(CUR_VERS_OPT) ? cmd.getOptionValue(CUR_VERS_OPT) : DEFAULT_CURR_VERSION; + String prevVers = cmd.hasOption(PREV_VERS_OPT) ? cmd.getOptionValue(PREV_VERS_OPT) : DEFAULT_PREV_VERSION; + String curVersPath = cmd.hasOption(CUR_VERS_PATH_OPT) + ? cmd.getOptionValue(CUR_VERS_PATH_OPT) + : Paths.get(cmd.getOptionValue(SRC_LOC_OPT), BUILD_REL_PATH).toString(); + String prevVersPath = cmd.getOptionValue(PREV_VERS_PATH_OPT); String srcPath = cmd.getOptionValue(SRC_LOC_OPT); + boolean makeUpdate = cmd.hasOption(UPDATE_OPT); File curVersFile = new File(curVersPath); File prevVersFile = new File(prevVersPath); File srcPathFile = new File(srcPath); @@ -137,7 +154,7 @@ static CLIArgs parseCli(String[] args) throws ParseException { throw new ParseException("No directory found at " + srcPathFile.getAbsolutePath()); } - return new CLIArgs(curVers, prevVers, curVersFile, prevVersFile, srcPathFile, false); + return new CLIArgs(curVers, prevVers, curVersFile, prevVersFile, srcPathFile, makeUpdate, false); } public static class CLIArgs { @@ -148,14 +165,16 @@ public static class CLIArgs { private final File previousVersPath; private final boolean isHelp; private final File srcPath; + private final boolean makeUpdate; - public CLIArgs(String currentVersion, String previousVersion, File currentVersPath, File previousVersPath, File srcPath, boolean isHelp) { + public CLIArgs(String currentVersion, String previousVersion, File currentVersPath, File previousVersPath, File srcPath, boolean makeUpdate, boolean isHelp) { this.currentVersion = currentVersion; this.previousVersion = previousVersion; this.currentVersPath = currentVersPath; this.previousVersPath = previousVersPath; this.srcPath = srcPath; this.isHelp = isHelp; + this.makeUpdate = makeUpdate; } public String getCurrentVersion() { @@ -178,6 +197,10 @@ public boolean isIsHelp() { return isHelp; } + public boolean isMakeUpdate() { + return makeUpdate; + } + public File getSrcPath() { return srcPath; } 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 deleted file mode 100644 index 15b8fe44ef..0000000000 --- a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ChangeOutputGenerator.java +++ /dev/null @@ -1,662 +0,0 @@ -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 javassist.CtClass; -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) { - // TODO serial version id - // TODO annotations - 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 type = str(clz.getClassType(), oldClass); - String name = clz.getFullyQualifiedName(); - - String genericModifier = strGeneric(clz.getGenericTemplates(), oldClass); - - String implementsModifier = strImplements(clz.getInterfaces(), oldClass); - String extendsModifier = str(clz.getSuperclass(), oldClass); - - return Stream.of( - accessModifier, - abstractModifier, - staticModifier, - finalModifier, - syntheticModifier, - type, - name + (StringUtils.isBlank(genericModifier) ? "" : genericModifier), - implementsModifier, - extendsModifier) - .filter(StringUtils::isNotBlank) - .collect(Collectors.joining(" ")); - } - - - private String str(JApiSuperclass supClz, boolean oldClass) { - Optional<CtClass> ctClass = convert(oldClass ? supClz.getOldSuperclass() : supClz.getNewSuperclass()); - String supClassExt = ctClass.map(ctClz -> str(ctClz)).orElse(null); - return StringUtils.isBlank(supClassExt) ? null : "extends " + supClassExt; - } - - private String strImplements(List<JApiImplementedInterface> interfaces, boolean oldClass) { - if (interfaces.isEmpty()) { - return null; - } - - String interfaceStr = interfaces.stream() - .filter(i -> (oldClass && i.getChangeStatus() == NEW) || (!oldClass && i.getChangeStatus() == REMOVED)) - .map(i -> str(i.getCtClass())) - .collect(Collectors.joining(", ")); - - return StringUtils.isNotBlank(interfaceStr) ? "implements " + interfaceStr : null; - } - - - private String str(CtClass ctClass) { - return ctClass.getName() + (StringUtils.isBlank(ctClass.getGenericSignature()) ? "" : "<" + ctClass.getGenericSignature() + ">"); - } - - private String str(JApiClassType classType, boolean oldClass) { - return Optional.ofNullable(classType) - .flatMap(ct -> convert(oldClass ? ct.getOldTypeOptional() : ct.getNewTypeOptional())) - .map(ct -> ct.name().toLowerCase()) - .orElse("class"); - } - - private String strGeneric(List<JApiGenericTemplate> templates, boolean oldClass) { - if (templates.isEmpty()) { - return null; - } - - String genericParams = templates.stream() - .map(t -> convert(oldClass ? - str(t.getName(), convert(t.getOldTypeOptional()), t.getOldInterfaceTypes()) : - str(t.getName(), convert(t.getNewTypeOptional()), t.getNewInterfaceTypes()) - ) - .filter(Optional::isPresent) - .map(t -> t.get()) - .collect(Collectors.joining(", ")); - - return StringUtils.isBlank(genericParams) - ? null - : "<" + genericParams + ">"; - } - - private String strGeneric(String name, Optional<String> mainType, List<JApiGenericType> genericType) { - - } - - // jApiGenericTemplate.getName() + ":" + interfaceTypes.join( "&") -// -// private List<GenericTemplateChangeDTO> getGenericTemplateChanges(JApiHasGenericTemplates jApiHasGenericTemplates) { -// 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 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) { - 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(null); - 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 null; - } else { - return modifier.name().toLowerCase(); - } - } - - private String str(StaticModifier modifier) { - return (modifier == StaticModifier.STATIC) - ? "static" - : null; - } - - private String str(FinalModifier modifier) { - return (modifier == FinalModifier.FINAL) - ? "final" - : null; - } - - private String str(SyntheticModifier modifier) { - return (modifier == SyntheticModifier.SYNTHETIC) - ? "synthetic" - : null; - } - - private String str(AbstractModifier modifier) { - return (modifier == AbstractModifier.ABSTRACT) - ? "abstract" - : null; - } - - 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 ee0f93ce7f..48d5735ece 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 @@ -4,10 +4,15 @@ package org.sleuthkit.autopsy.apiupdate; import java.io.IOException; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.cli.ParseException; +import org.sleuthkit.autopsy.apiupdate.APIDiff.ComparisonRecord; import org.sleuthkit.autopsy.apiupdate.CLIProcessor.CLIArgs; +import org.sleuthkit.autopsy.apiupdate.ModuleUpdates.ModuleVersionNumbers; /** * @@ -15,6 +20,8 @@ */ public class Main { + private static final Logger LOGGER = Logger.getLogger(Main.class.getName()); + public static void main(String[] args) { 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; @@ -29,67 +36,69 @@ public static void main(String[] args) { System.exit(-1); 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> newVersionNumMapping = new HashMap<>(); + 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())); - APIDiff.getComparison( - cliArgs.getPreviousVersion(), - cliArgs.getCurrentVersion(), + ModuleVersionNumbers prevVersionNums = ModuleUpdates.getVersionsFromJar(cliArgs.getPreviousVersPath().toPath().resolve(commonJarFileName).toFile()); + + ComparisonRecord record = APIDiff.getComparison( + cliArgs.getPreviousVersion(), + cliArgs.getCurrentVersion(), cliArgs.getPreviousVersPath().toPath().resolve(commonJarFileName).toFile(), cliArgs.getCurrentVersPath().toPath().resolve(commonJarFileName).toFile()); + + ModuleVersionNumbers projectedVersionNums = ModuleUpdates.getModuleVersionUpdate(prevVersionNums, record.getChangeType()); + + outputDiff(commonJarFileName, record, prevVersionNums, projectedVersionNums); + + newVersionNumMapping.put(commonJarFileName, projectedVersionNums); } catch (IOException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } - - } - - - -// for (String commonJarFileName : getCommonJars(cliArgs.getPreviousVersPath(), cliArgs.getCurrentVersPath())) { -//// getComparison( -//// cliArgs.getPreviousVersion(), -//// cliArgs.getCurrentVersion(), -//// cliArgs.getPreviousVersPath().toPath().resolve(commonJarFileName).toFile(), -//// cliArgs.getCurrentVersPath().toPath().resolve(commonJarFileName).toFile()); -// try { -// Set<String> pubPackages = getPublicPackages(cliArgs.getPreviousVersPath().toPath().resolve(commonJarFileName).toFile()); -// System.out.println(pubPackages); -// } catch (IOException ex) { -// Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); -// } catch (IllegalStateException ex) { -// Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); -// } -// } - - } + } - - - private static void mainRun() { + if (cliArgs.isMakeUpdate()) { + ModuleUpdates.setVersions(cliArgs.getSrcPath(), newVersionNumMapping); + } - // get public API diff's, for each jar - // limit to public packages - // one of the following: - // generate text output of difference - // update version numbers in manifest file/references accordingly } + private static void outputDiff( + String commonJarFileName, + ComparisonRecord record, + ModuleVersionNumbers prevVersionNums, + ModuleVersionNumbers projectedVersionNums + ) { + LOGGER.log(Level.INFO, MessageFormat.format("\n" + + "====================================\n" + + "DIFF FOR: {0}\n" + + "Public API Change Type: {1}\n" + + "Previous Version Numbers:\n" + + " - release: {2}\n" + + " - specification: {3}\n" + + " - implementation: {4}\n" + + "Current Version Numbers:\n" + + " - release: {5}\n" + + " - specification: {6}\n" + + " - implementation: {7}\n" + + "====================================\n" + + "Public API packages only in previous: {8}\n" + + "Public API packages only in current: {9}\n" + + "{10}\n\n", + commonJarFileName, + record.getChangeType(), + prevVersionNums.getRelease().getFullReleaseStr(), + prevVersionNums.getSpec().getSemVerStr(), + prevVersionNums.getImplementation(), + projectedVersionNums.getRelease().getFullReleaseStr(), + projectedVersionNums.getSpec().getSemVerStr(), + projectedVersionNums.getImplementation(), + record.getOnlyPrevApiPackages(), + record.getOnlyCurrApiPackages(), + record.getHumanReadableApiChange() + )); + } } diff --git a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ModuleUpdates.java b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ModuleUpdates.java index 7453523351..efc1c02ed0 100644 --- a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ModuleUpdates.java +++ b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ModuleUpdates.java @@ -155,7 +155,47 @@ public static ModuleVersionNumbers getVersionsFromJar(File jarFile) throws IOExc return new ModuleVersionNumbers(jarFile.getName(), specSemVer, implementation, release); } - private static void updateVersions() { + static ModuleVersionNumbers getModuleVersionUpdate(ModuleVersionNumbers prev, PublicApiChangeType apiChangeType) { + switch (apiChangeType) { + case NONE: + return new ModuleVersionNumbers( + prev.getModuleName(), + prev.getSpec(), + prev.getImplementation() + 1, + prev.getRelease() + ); + case COMPATIBLE_CHANGE: + return new ModuleVersionNumbers( + prev.getModuleName(), + new SemVer( + prev.getSpec().getMajor(), + prev.getSpec().getMinor() + 1, + prev.getSpec().getPatch() + ), + prev.getImplementation() + 1, + new ReleaseVal( + prev.getRelease().getModuleName(), + prev.getRelease().getReleaseVersion() + ) + ); + case INCOMPATIBLE_CHANGE: + return new ModuleVersionNumbers( + prev.getModuleName(), + new SemVer( + prev.getSpec().getMajor() + 1, + prev.getSpec().getMinor(), + prev.getSpec().getPatch() + ), + prev.getImplementation() + 1, + new ReleaseVal( + prev.getRelease().getModuleName(), + prev.getRelease().getReleaseVersion() == null ? null : prev.getRelease().getReleaseVersion() + 1 + ) + ); + default: + throw new IllegalArgumentException("Unknown api change type: " + apiChangeType); + } + // [specification major/minor/patch, implementation, release] // assumed defaults??? // NON_COMPATIBLE: 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 index d3379ac93e..011f7a59ca 100644 --- 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 @@ -4,10 +4,30 @@ */ package org.sleuthkit.autopsy.apiupdate; +import java.util.Comparator; +import org.apache.commons.lang3.ObjectUtils; + /** * * @author gregd */ -public enum PublicApiChangeType { - NONE, COMPATIBLE_CHANGE, INCOMPATIBLE_CHANGE; +public enum PublicApiChangeType implements Comparator<PublicApiChangeType> { + NONE(0), COMPATIBLE_CHANGE(1), INCOMPATIBLE_CHANGE(2); + + private int level; + + PublicApiChangeType(int level) { + this.level = level; + } + + public int getLevel() { + return level; + } + + @Override + public int compare(PublicApiChangeType o1, PublicApiChangeType o2) { + o1 = ObjectUtils.defaultIfNull(o1, PublicApiChangeType.NONE); + o2 = ObjectUtils.defaultIfNull(o2, PublicApiChangeType.NONE); + return Integer.compare(o1.getLevel(), o2.getLevel()); + } } -- GitLab