Skip to content

Commit

Permalink
Add support for AAR files
Browse files Browse the repository at this point in the history
This adds support for comparing AAR files. The embedded classes.jar
is simply extracted and then treated as if it was the original jar
file.

This also adds a test suite.

Fix: #1
  • Loading branch information
io7m committed Jun 26, 2020
1 parent 7864fb5 commit c407cc2
Show file tree
Hide file tree
Showing 11 changed files with 641 additions and 29 deletions.
8 changes: 8 additions & 0 deletions com.io7m.scando.cmdline/pom.xml
Expand Up @@ -22,6 +22,14 @@
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp</artifactId>
Expand Down
147 changes: 119 additions & 28 deletions com.io7m.scando.cmdline/src/main/java/com/io7m/scando/cmdline/Main.java
Expand Up @@ -31,14 +31,27 @@
import japicmp.util.Optional;
import japicmp.versioning.SemanticVersion;
import japicmp.versioning.Version;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.FilenameUtils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

public final class Main
{
Expand All @@ -63,28 +76,28 @@ public static final class Parameters

@Parameter(
names = "--oldJar",
description = "The old jar file",
description = "The old jar/aar file",
required = true
)
private Path oldJarPath;

@Parameter(
names = "--oldJarVersion",
description = "The old jar version",
description = "The old jar/aar version",
required = true
)
private String oldJarVersion;

@Parameter(
names = "--newJar",
description = "The new jar file",
description = "The new jar/aar file",
required = true
)
private Path newJarPath;

@Parameter(
names = "--newJarVersion",
description = "The new jar version",
description = "The new jar/aar version",
required = true
)
private String newJarVersion;
Expand Down Expand Up @@ -124,7 +137,7 @@ private static SemanticVersion semanticVersionOf(
);
}

public static void main(
public static int mainExitless(
final String[] args)
throws Exception
{
Expand All @@ -140,13 +153,13 @@ public static void main(

if (parameters.help) {
commander.usage();
System.exit(0);
return 0;
}

} catch (final Exception e) {
System.err.println("ERROR: " + e.getMessage());
System.err.println("INFO: Try --help for usage information");
System.exit(1);
return 1;
}

parameters.newJarPath = parameters.newJarPath.toAbsolutePath();
Expand All @@ -162,14 +175,33 @@ public static void main(
final SemanticVersion oldJarVersionValue =
semanticVersionOf(new Version(parameters.oldJarVersion));

if (hashOf(parameters.oldJarPath).equals(hashOf(parameters.newJarPath))) {
System.err.println("INFO: The input files are identical; any version number change is acceptable");
return 0;
}

final File oldTargetFile;
if (parameters.oldJarPath.toString().endsWith(".aar")) {
oldTargetFile = unpackAAR(parameters.oldJarPath);
} else {
oldTargetFile = parameters.oldJarPath.toFile();
}

final File newTargetFile;
if (parameters.newJarPath.toString().endsWith(".aar")) {
newTargetFile = unpackAAR(parameters.newJarPath);
} else {
newTargetFile = parameters.newJarPath.toFile();
}

final JApiCmpArchive oldArchives =
new JApiCmpArchive(
parameters.oldJarPath.toFile(),
oldTargetFile,
oldJarVersionValue.toString()
);
final JApiCmpArchive newArchives =
new JApiCmpArchive(
parameters.newJarPath.toFile(),
newTargetFile,
newJarVersionValue.toString()
);

Expand All @@ -182,19 +214,7 @@ public static void main(
options.setNewArchives(Collections.singletonList(newArchives));

if (parameters.excludeList != null) {
try (Stream<String> lineStream = Files.lines(parameters.excludeList)) {
final List<String> lines = lineStream.collect(Collectors.toList());
for (final String line : lines) {
final String lineTrimmed = line.trim();
if (lineTrimmed.isEmpty()) {
continue;
}
if (lineTrimmed.startsWith("#")) {
continue;
}
options.addExcludeFromArgument(Optional.of(lineTrimmed), true);
}
}
loadExcludeList(parameters, options);
}

final JarArchiveComparatorOptions comparatorOptions =
Expand All @@ -206,15 +226,86 @@ public static void main(

writeReports(options, jApiClasses, parameters, oldArchives, newArchives);

System.exit(
runSemanticVersionCheck(
jApiClasses,
newJarVersionValue,
oldJarVersionValue
)
return runSemanticVersionCheck(
jApiClasses,
newJarVersionValue,
oldJarVersionValue
);
}

private static String hashOf(final Path path)
throws IOException, NoSuchAlgorithmException
{
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
try (InputStream stream = Files.newInputStream(path)) {
final byte[] buffer = new byte[4096];
while (true) {
final int r = stream.read(buffer);
if (r == -1) {
break;
}
digest.update(buffer, 0, r);
}
}
return Hex.encodeHexString(digest.digest());
}

public static void main(
final String[] args)
throws Exception
{
System.exit(mainExitless(args));
}

private static void loadExcludeList(
final Parameters parameters,
final Options options)
throws IOException
{
try (Stream<String> lineStream = Files.lines(parameters.excludeList)) {
final List<String> lines = lineStream.collect(Collectors.toList());
for (final String line : lines) {
final String lineTrimmed = line.trim();
if (lineTrimmed.isEmpty()) {
continue;
}
if (lineTrimmed.startsWith("#")) {
continue;
}
options.addExcludeFromArgument(Optional.of(lineTrimmed), true);
}
}
}

private static File unpackAAR(
final Path original)
throws IOException
{
final String filenameWithoutExtension =
FilenameUtils.removeExtension(original.toString());
final String newFilename =
String.format("%s.jar", filenameWithoutExtension);
final String newFilenameTmp =
String.format("%s.jar.tmp", filenameWithoutExtension);
final FileSystem fileSystem =
original.getFileSystem();
final Path output =
fileSystem.getPath(newFilename);
final Path outputTmp =
fileSystem.getPath(newFilenameTmp);

System.err.printf("INFO: Unpacking %s -> %s%n", original, newFilename);

try (ZipFile file = new ZipFile(original.toFile())) {
final ZipEntry entry = file.getEntry("classes.jar");
try (InputStream stream = file.getInputStream(entry)) {
Files.copy(stream, outputTmp);
Files.move(outputTmp, output, REPLACE_EXISTING, ATOMIC_MOVE);
}
}
return output.toFile();
}

private static int runSemanticVersionCheck(
final List<JApiClass> jApiClasses,
final SemanticVersion newJarVersionValue,
Expand Down
49 changes: 49 additions & 0 deletions com.io7m.scando.tests/pom.xml
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.io7m.scando</groupId>
<artifactId>com.io7m.scando</artifactId>
<version>0.0.3</version>
</parent>

<artifactId>com.io7m.scando.tests</artifactId>
<description>Ultra-minimalist semantic versioning checker (Test suite)</description>
<name>com.io7m.scando.tests</name>
<url>https://www.github.com/io7m/scando</url>

<properties>
<mdep.analyze.skip>true</mdep.analyze.skip>
</properties>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>com.io7m.scando.cmdline</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
</dependency>
</dependencies>

</project>

0 comments on commit c407cc2

Please sign in to comment.