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 b41cea00d6c376f5bd7b7b10aed2e7848b7292a5..3b59850ac952a7923846a7eb8c35c92efa52005f 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 @@ -55,14 +55,22 @@ import javassist.Modifier; /** - * - * @author gregd + * Handles diffing the public API between two jar files. */ public class APIDiff { + // filters to a jar or nbm file private static final FileFilter JAR_FILTER = (File f) -> f.isFile() && (f.getName().toLowerCase().endsWith(".jar") || f.getName().toLowerCase().endsWith(".nbm")); + /** + * Identifies common jar files between two directories. Only files listed in + * the directory are considered. This method does not recurse. + * + * @param prevDir The previous version directory. + * @param currDir The current version directory. + * @return The jar file names. + */ static List<String> getCommonJars(File prevDir, File currDir) { Set<String> prevJars = getJars(prevDir); Set<String> currJars = getJars(currDir); @@ -74,12 +82,27 @@ static List<String> getCommonJars(File prevDir, File currDir) { return commonJars.stream().sorted().collect(Collectors.toList()); } + /** + * Returns all jar files listed in directory (does not recurse). + * + * @param dir The directory. + * @return The jar file names. + */ private static Set<String> getJars(File dir) { return Stream.of(dir.listFiles(JAR_FILTER)) .map(f -> f.getName()) .collect(Collectors.toSet()); } + /** + * Uses manfest.mf specification of "OpenIDE-Module-Public-Packages" to + * determine public API packages. + * + * @param jarFile The jar file. + * @return The set of package names. + * @throws IOException + * @throws IllegalStateException + */ private static Set<String> getPublicPackages(File jarFile) throws IOException, IllegalStateException { String publicPackageStr = ManifestLoader.loadFromJar(jarFile).getValue("OpenIDE-Module-Public-Packages"); if (publicPackageStr == null) { @@ -92,11 +115,26 @@ private static Set<String> getPublicPackages(File jarFile) throws IOException, I } } - // only fields, methods that are public or protected + /** + * Filter to identify non-public, non-protected members for exclusion. + * + * @param member The CtMember (field/method). + * @return True if should be excluded (private/package private). + */ static boolean excludeMember(CtMember member) { return !Modifier.isPublic(member.getModifiers()) && !Modifier.isProtected(member.getModifiers()); } + /** + * Compares two jar files. + * + * @param prevVersion The name of the previous version. + * @param curVersion The name of the current version. + * @param prevJar The previous version jar file. + * @param curJar The current version jar file. + * @return A record describing the comparison in public API. + * @throws IOException + */ 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); @@ -120,7 +158,7 @@ static ComparisonRecord getComparison(String prevVersion, String curVersion, Fil 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())); @@ -139,7 +177,7 @@ static ComparisonRecord getComparison(String prevVersion, String curVersion, Fil ); PublicApiChangeType changeType = getChangeType(jApiClasses); - + Options options = Options.newDefault(); options.setOldArchives(Arrays.asList(new JApiCmpArchive(prevJar, prevVersion))); options.setNewArchives(Arrays.asList(new JApiCmpArchive(curJar, curVersion))); @@ -150,6 +188,13 @@ static ComparisonRecord getComparison(String prevVersion, String curVersion, Fil return new ComparisonRecord(prevVersion, curVersion, prevJar, curJar, humanReadableApiChange, changeType, onlyPrevApiPackages, onlyCurApiPackages, commonApiPackages); } + /** + * Updates an atomic ref to the public api change type to the maximum change + * (where no change is min and incompatible change is max). + * + * @param apiChangeRef The atomic ref to a public api change type. + * @param tp The possibly new change type. + */ private static void updateToMax(AtomicReference<PublicApiChangeType> apiChangeRef, JApiHasChangeStatus tp) { PublicApiChangeType apiChangeType; switch (tp.getChangeStatus()) { @@ -164,14 +209,20 @@ private static void updateToMax(AtomicReference<PublicApiChangeType> apiChangeRe 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); + /** + * Determines the public api change type for the given classes. + * + * @param jApiClasses The classes. + * @return The public API change type. + */ + static PublicApiChangeType getChangeType(List<JApiClass> jApiClasses) { + AtomicReference<PublicApiChangeType> apiChange = new AtomicReference<>(PublicApiChangeType.NONE); Filter.filter(jApiClasses, new Filter.FilterVisitor() { @Override @@ -213,6 +264,10 @@ public void visit(JApiSuperclass jas) { return apiChange.get(); } + /** + * A record describing the public API comparison of a previous and current + * version. + */ public static class ComparisonRecord { private final String prevVersion; @@ -237,43 +292,70 @@ public ComparisonRecord(String prevVersion, String curVersion, File prevJar, Fil this.commonApiPackages = commonApiPackages; } + /** + * @return The previous version name. + */ public String getPrevVersion() { return prevVersion; } + /** + * @return The current version name. + */ public String getCurVersion() { return curVersion; } + /** + * @return The previous version jar file. + */ public File getPrevJar() { return prevJar; } + /** + * @return The current version jar file. + */ public File getCurJar() { return curJar; } + /** + * @return The human readable output describing the api changes. + */ public String getHumanReadableApiChange() { return humanReadableApiChange; } + /** + * @return The public api change type. + */ public PublicApiChangeType getChangeType() { return changeType; } + /** + * @return Names of packages only in previous public API. + */ public Set<String> getOnlyPrevApiPackages() { return onlyPrevApiPackages; } + /** + * @return Names of packages only in current public API. + */ public Set<String> getOnlyCurrApiPackages() { return onlyCurrApiPackages; } + /** + * @return Names of packages in common between previous and current + * public API. + */ public Set<String> getCommonApiPackages() { return commonApiPackages; } - - + } } 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 d45f9bd8b3c223edd6d0755e91ea5c03166f7082..db00a54d7db35b182d95ac3d8d15e6a03ff725f9 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 @@ -32,12 +32,11 @@ import org.apache.commons.cli.ParseException; /** - * - * @author gregd + * Processes CLI options. */ public class CLIProcessor { - static Option PREV_VERS_PATH_OPT = Option.builder() + private static final Option PREV_VERS_PATH_OPT = Option.builder() .argName("path") .desc("The path to the previous version jar files") .hasArg(true) @@ -46,7 +45,7 @@ public class CLIProcessor { .required(true) .build(); - static Option CUR_VERS_PATH_OPT = Option.builder() + private static final Option CUR_VERS_PATH_OPT = Option.builder() .argName("path") .desc("The path to the current version jar files") .hasArg(true) @@ -55,7 +54,7 @@ public class CLIProcessor { .required(false) .build(); - static Option PREV_VERS_OPT = Option.builder() + private static final Option PREV_VERS_OPT = Option.builder() .argName("version") .desc("The previous version number") .hasArg(true) @@ -64,7 +63,7 @@ public class CLIProcessor { .required(false) .build(); - static Option CUR_VERS_OPT = Option.builder() + private static final Option CUR_VERS_OPT = Option.builder() .argName("version") .desc("The current version number") .hasArg(true) @@ -73,7 +72,7 @@ public class CLIProcessor { .required(false) .build(); - static Option SRC_LOC_OPT = Option.builder() + private static final Option SRC_LOC_OPT = Option.builder() .argName("path") .desc("The path to the root of the autopsy repor") .hasArg(true) @@ -82,7 +81,7 @@ public class CLIProcessor { .required(true) .build(); - static Option UPDATE_OPT = Option.builder() + private static final Option UPDATE_OPT = Option.builder() .desc("Update source code versions") .hasArg(false) .longOpt("update") @@ -90,7 +89,7 @@ public class CLIProcessor { .required(false) .build(); - static List<Option> ALL_OPTIONS = Arrays.asList( + private static final List<Option> ALL_OPTIONS = Arrays.asList( PREV_VERS_PATH_OPT, CUR_VERS_PATH_OPT, PREV_VERS_OPT, @@ -99,11 +98,16 @@ public class CLIProcessor { UPDATE_OPT ); - static Options CLI_OPTIONS = getCliOptions(ALL_OPTIONS); + private static final 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"; + /** + * Creates an Options object from a list of options. + * @param opts The list of options. + * @return The options object. + */ private static Options getCliOptions(List<Option> opts) { Options toRet = new Options(); for (Option opt : opts) { @@ -113,7 +117,7 @@ private static Options getCliOptions(List<Option> opts) { return toRet; } - static Option HELP_OPT = Option.builder() + private static final Option HELP_OPT = Option.builder() .desc("Print help message") .hasArg(false) .longOpt("help") @@ -121,12 +125,16 @@ private static Options getCliOptions(List<Option> opts) { .required(false) .build(); - static Options HELP_OPTIONS = getCliOptions(Collections.singletonList(HELP_OPT)); + private static final Options HELP_OPTIONS = getCliOptions(Collections.singletonList(HELP_OPT)); - private static CommandLineParser parser = new DefaultParser(); + private static final CommandLineParser parser = new DefaultParser(); - private static HelpFormatter helpFormatter = new HelpFormatter(); + private static final HelpFormatter helpFormatter = new HelpFormatter(); + /** + * Prints help message. + * @param ex The exception or null if no exception. + */ static void printHelp(Exception ex) { if (ex != null && ex.getMessage() != null && !ex.getMessage().isBlank()) { System.out.println(ex.getMessage()); @@ -135,6 +143,12 @@ static void printHelp(Exception ex) { helpFormatter.printHelp("APIUpdate", CLI_OPTIONS); } + /** + * Parses the CLI args. + * @param args The arguments. + * @return The CLIArgs object. + * @throws ParseException + */ static CLIArgs parseCli(String[] args) throws ParseException { CommandLine helpCmd = parser.parse(HELP_OPTIONS, args, true); boolean isHelp = helpCmd.hasOption(HELP_OPT); @@ -171,6 +185,9 @@ static CLIArgs parseCli(String[] args) throws ParseException { return new CLIArgs(curVers, prevVers, curVersFile, prevVersFile, srcPathFile, makeUpdate, false); } + /** + * The CLI args object. + */ public static class CLIArgs { private final String currentVersion; @@ -191,30 +208,52 @@ public CLIArgs(String currentVersion, String previousVersion, File currentVersPa this.makeUpdate = makeUpdate; } + /** + * @return The current version name. + */ public String getCurrentVersion() { return currentVersion; } + /** + * @return The previous version name. + */ public String getPreviousVersion() { return previousVersion; } + /** + * @return The path to the directory containing the jars for current version. + */ public File getCurrentVersPath() { return currentVersPath; } + + /** + * @return The path to the directory containing the jars for previous version. + */ public File getPreviousVersPath() { return previousVersPath; } - public boolean isIsHelp() { + /** + * @return True if only print help message. + */ + public boolean isHelp() { return isHelp; } + /** + * @return True if module versions should be updated. + */ public boolean isMakeUpdate() { return makeUpdate; } + /** + * @return The path to the source directory root for autopsy. + */ public File getSrcPath() { return srcPath; } 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 39cd4262832681559eea107f72467ee09fef5ff3..86b6174b4bcb846c641fcb8a855a1e4d9769424f 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 @@ -30,19 +30,17 @@ import org.sleuthkit.autopsy.apiupdate.ModuleUpdates.ModuleVersionNumbers; /** - * - * @author gregd + * Main class. */ public class Main { private static final Logger LOGGER = Logger.getLogger(Main.class.getName()); public static void main(String[] args) { - args = "-p C:\\Users\\gregd\\Desktop\\apidiff\\old -s C:\\Users\\gregd\\Documents\\Source\\autopsy".split(" "); CLIArgs cliArgs; try { cliArgs = CLIProcessor.parseCli(args); - if (cliArgs.isIsHelp()) { + if (cliArgs.isHelp()) { CLIProcessor.printHelp(null); System.exit(0); } @@ -53,7 +51,7 @@ public static void main(String[] args) { } Map<String, ModuleVersionNumbers> newVersionNumMapping = new HashMap<>(); - + for (String commonJarFileName : APIDiff.getCommonJars(cliArgs.getPreviousVersPath(), cliArgs.getCurrentVersPath())) { try { ModuleVersionNumbers prevVersionNums = ModuleUpdates.getVersionsFromJar(cliArgs.getPreviousVersPath().toPath().resolve(commonJarFileName).toFile()); @@ -81,28 +79,40 @@ public static void main(String[] args) { } + /** + * Outputs the difference between previous and current version public API. + * + * @param commonJarFileName The common jar file name. + * @param record The comparison record. + * @param prevVersionNums The version numbers in previous version. + * @param projectedVersionNums The calculated version numbers for current + * version. + */ 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", + LOGGER.log(Level.INFO, MessageFormat.format(""" + + ==================================== + DIFF FOR: {0} + Public API Change Type: {1} + Previous Version Numbers: + - release: {2} + - specification: {3} + - implementation: {4} + Current Version Numbers: + - release: {5} + - specification: {6} + - implementation: {7} + ==================================== + Public API packages only in previous: {8} + Public API packages only in current: {9} + {10} + + """, commonJarFileName, record.getChangeType(), prevVersionNums.getRelease().getFullReleaseStr(), diff --git a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ManifestLoader.java b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ManifestLoader.java index 45b3de255079a2b8d5b4c85615b06e1a4f6c678f..6acd68c166c1d2b1b426aac36677f3376b39c715 100644 --- a/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ManifestLoader.java +++ b/release_scripts/APIUpdate/src/main/java/org/sleuthkit/autopsy/apiupdate/ManifestLoader.java @@ -29,22 +29,39 @@ import java.util.zip.ZipFile; /** - * - * @author gregd + * Loads manifest.mf files. */ public class ManifestLoader { private static final String JAR_MANIFEST_REL_PATH = "META-INF/MANIFEST.MF"; - public static Attributes loadInputStream(InputStream is) throws IOException { + /** + * Loads the manifest attributes from an input stream. + * @param is The input stream. + * @return The manifest attributes. + * @throws IOException + */ + public static Attributes loadManifestAttributes(InputStream is) throws IOException { Manifest manifest = loadManifest(is); return manifest.getMainAttributes(); } + /** + * Loads the manifest from an input stream. + * @param is The input stream. + * @return The manifest. + * @throws IOException + */ public static Manifest loadManifest(InputStream is) throws IOException { return new Manifest(is); } + /** + * Loads manifest attributes from a jar file. + * @param jarFile The jar file. + * @return The manifest attributes. + * @throws IOException + */ public static Attributes loadFromJar(File jarFile) throws IOException { ZipFile zipFile = new ZipFile(jarFile); @@ -53,7 +70,7 @@ public static Attributes loadFromJar(File jarFile) throws IOException { while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); if (JAR_MANIFEST_REL_PATH.equalsIgnoreCase(entry.getName())) { - return loadInputStream(zipFile.getInputStream(entry)); + return loadManifestAttributes(zipFile.getInputStream(entry)); } } 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 08c0c904af1e67c2b3a4801e2030dbb565d2d43a..9b03a49586380ea8b5c2c5961010abd13e1ba3b9 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 @@ -32,8 +32,6 @@ import java.util.jar.Attributes; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.logging.SimpleFormatter; -import java.util.logging.StreamHandler; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.parsers.DocumentBuilder; @@ -215,7 +213,7 @@ private static Map<String, File> getModuleDirs(File srcDir) throws IOException { File manifestFile = dir.toPath().resolve(MANIFEST_FILE_NAME).toFile(); if (manifestFile.isFile()) { try (FileInputStream manifestIs = new FileInputStream(manifestFile)) { - Attributes manifestAttrs = ManifestLoader.loadInputStream(manifestIs); + Attributes manifestAttrs = ManifestLoader.loadManifestAttributes(manifestIs); ReleaseVal releaseVal = parseReleaseVers(manifestAttrs.getValue(MANIFEST_RELEASE_KEY), manifestFile.getAbsolutePath()); moduleDirMapping.put(releaseVal.getModuleName(), dir); } 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 23b96ba5931ff7a26eab61d61ab8a57c7caa9134..03cd624de0daf3fe48cec1b8eb2c2895c800c186 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 @@ -22,18 +22,27 @@ import org.apache.commons.lang3.ObjectUtils; /** - * - * @author gregd + * A public API change type (no change, compatible change, incompatible change). */ public enum PublicApiChangeType implements Comparator<PublicApiChangeType> { NONE(0), COMPATIBLE_CHANGE(1), INCOMPATIBLE_CHANGE(2); private int level; + /** + * COnstructor. + * + * @param level The level for the api change (none is min, incompatible is + * max). + */ PublicApiChangeType(int level) { this.level = level; } + /** + * + * @return The level for the api change (none is min, incompatible is max). + */ public int getLevel() { return level; }