From 0b7e8dd8ca5fd9fd930b9036d3196ad959328f71 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro 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 @@ public class APIDiff { } } - static void getComparison(String prevVersion, String curVersion, File prevJar, File curJar) throws IOException { + // 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 prevPublicApiPackages = getPublicPackages(prevJar); + Set curPublicApiPackages = getPublicPackages(curJar); + + Set allPublicApiPackages = new HashSet<>(); + allPublicApiPackages.addAll(prevPublicApiPackages); + allPublicApiPackages.addAll(curPublicApiPackages); + + Set onlyPrevApiPackages = new HashSet<>(); + Set onlyCurApiPackages = new HashSet<>(); + Set 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(); - //comparatorOptions.setAccessModifier(AccessModifier.); + // 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 jApiClasses = jarArchiveComparator.compare( new JApiCmpArchive(prevJar, prevVersion), new JApiCmpArchive(curJar, curVersion) ); - Set prevPublicApiPackages = getPublicPackages(prevJar); - Set curPublicApiPackages = getPublicPackages(curJar); - - // TODO handle diff in this list - Set 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()); - + 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 generateOutput(Options options, List jApiClasses, JarArchiveComparator jarArchiveComparator) { -// for (JApiClass cls: jApiClasses) { -// cls.is -// } -// + private static void updateToMax(AtomicReference 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 jApiClasses) { + AtomicReference apiChange = new AtomicReference(PublicApiChangeType.NONE); + + Filter.filter(jApiClasses, new Filter.FilterVisitor() { + @Override + public void visit(Iterator itrtr, JApiClass jac) { + updateToMax(apiChange, jac); + } + + @Override + public void visit(Iterator itrtr, JApiMethod jam) { + updateToMax(apiChange, jam); + } + + @Override + public void visit(Iterator itrtr, JApiConstructor jac) { + updateToMax(apiChange, jac); + } + + @Override + public void visit(Iterator itrtr, JApiImplementedInterface jaii) { + updateToMax(apiChange, jaii); + } + + @Override + public void visit(Iterator itrtr, JApiField jaf) { + updateToMax(apiChange, jaf); + } + + @Override + public void visit(Iterator itrtr, JApiAnnotation jaa) { + updateToMax(apiChange, jaa); + } + + @Override + public void visit(JApiSuperclass jas) { + updateToMax(apiChange, jas); + } + }); + + return apiChange.get(); + } + + 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 onlyPrevApiPackages; + private final Set onlyCurrApiPackages; + private final Set commonApiPackages; + + public ComparisonRecord(String prevVersion, String curVersion, File prevJar, File curJar, String humanReadableApiChange, PublicApiChangeType changeType, Set onlyPrevApiPackages, Set onlyCurrApiPackages, Set 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 getOnlyPrevApiPackages() { + return onlyPrevApiPackages; + } + + public Set getOnlyCurrApiPackages() { + return onlyCurrApiPackages; + } + + public Set 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 oldDeclaration; - private final Optional oldSerialId; - - private final Optional newDeclaration; - private final Optional newSerialId; - - public ClassChangeDTO(JApiChangeStatus changeStatus, Optional oldDeclaration, Optional oldSerialId, Optional newDeclaration, Optional newSerialId) { - this.changeStatus = changeStatus; - this.oldDeclaration = oldDeclaration; - this.oldSerialId = oldSerialId; - this.newDeclaration = newDeclaration; - this.newSerialId = newSerialId; - } - - public JApiChangeStatus getChangeStatus() { - return changeStatus; - } - - public Optional getOldDeclaration() { - return oldDeclaration; - } - - public Optional getOldSerialId() { - return oldSerialId; - } - - public Optional getNewDeclaration() { - return newDeclaration; - } - - public Optional getNewSerialId() { - return newSerialId; - } - - - } - -// public static class SuperclassChangeDTO { -// -// private final Optional oldFullyQualifiedClassName; -// private final Optional newFullyQualifiedClassName; -// -// public SuperclassChangeDTO(Optional oldFullyQualifiedClassName, Optional newFullyQualifiedClassName) { -// this.oldFullyQualifiedClassName = oldFullyQualifiedClassName; -// this.newFullyQualifiedClassName = newFullyQualifiedClassName; -// } -// -// public Optional getOldFullyQualifiedClassName() { -// return oldFullyQualifiedClassName; -// } -// -// public Optional 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 oldMethodDeclaration; - private final Optional newMethodDeclaration; - - public MethodChangeDTO(JApiChangeStatus changeStatus, Optional oldMethodDeclaration, Optional newMethodDeclaration) { - this.changeStatus = changeStatus; - this.oldMethodDeclaration = oldMethodDeclaration; - this.newMethodDeclaration = newMethodDeclaration; - } - - public JApiChangeStatus getChangeStatus() { - return changeStatus; - } - - public Optional getOldMethodDeclaration() { - return oldMethodDeclaration; - } - - public Optional getNewMethodDeclaration() { - return newMethodDeclaration; - } - - } - - public static class FieldChangeDTO { - - private final JApiChangeStatus changeStatus; - private final Optional oldFieldDeclaration; - private final Optional newFieldDeclaration; - - public FieldChangeDTO(JApiChangeStatus changeStatus, Optional oldFieldDeclaration, Optional newFieldDeclaration) { - this.changeStatus = changeStatus; - this.oldFieldDeclaration = oldFieldDeclaration; - this.newFieldDeclaration = newFieldDeclaration; - } - - public JApiChangeStatus getChangeStatus() { - return changeStatus; - } - - public Optional getOldFieldDeclaration() { - return oldFieldDeclaration; - } - - public Optional 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