com.io7m.scando.cmdline.Main Maven / Gradle / Ivy
/*
* Copyright © 2020 Mark Raynsford http://io7m.com
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package com.io7m.scando.cmdline;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import japicmp.cmp.JApiCmpArchive;
import japicmp.cmp.JarArchiveComparator;
import japicmp.cmp.JarArchiveComparatorOptions;
import japicmp.config.Options;
import japicmp.model.JApiClass;
import japicmp.output.semver.SemverOut;
import japicmp.output.stdout.StdoutOutputGenerator;
import japicmp.output.xml.XmlOutput;
import japicmp.output.xml.XmlOutputGenerator;
import japicmp.output.xml.XmlOutputGeneratorOptions;
import japicmp.util.Optional;
import japicmp.versioning.SemanticVersion;
import japicmp.versioning.Version;
import java.io.BufferedWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
public final class Main
{
private Main()
{
}
public static final class Parameters
{
Parameters()
{
}
@Parameter(
names = "--oldJar",
description = "The old jar file",
required = true
)
private Path oldJarPath;
@Parameter(
names = "--oldJarVersion",
description = "The old jar version",
required = true
)
private String oldJarVersion;
@Parameter(
names = "--newJar",
description = "The new jar file",
required = true
)
private Path newJarPath;
@Parameter(
names = "--newJarVersion",
description = "The new jar version",
required = true
)
private String newJarVersion;
@Parameter(
names = "--textReport",
description = "The output file for the plain text report",
required = true
)
private Path textReport;
@Parameter(
names = "--htmlReport",
description = "The output file for the HTML report",
required = true
)
private Path htmlReport;
}
private static SemanticVersion semanticVersionOf(
final Version version)
{
final Optional versionOpt = version.getSemanticVersion();
if (versionOpt.isPresent()) {
return versionOpt.get();
}
throw new IllegalArgumentException(String.format(
"Version %s cannot be parsed as a semantic version",
version)
);
}
public static void main(
final String[] args)
throws Exception
{
final Parameters parameters = new Parameters();
JCommander.newBuilder()
.programName("scando")
.addObject(parameters)
.build()
.parse(args);
parameters.newJarPath = parameters.newJarPath.toAbsolutePath();
parameters.oldJarPath = parameters.oldJarPath.toAbsolutePath();
parameters.htmlReport = parameters.htmlReport.toAbsolutePath();
parameters.textReport = parameters.textReport.toAbsolutePath();
final SemanticVersion newJarVersionValue =
semanticVersionOf(new Version(parameters.newJarVersion));
final SemanticVersion oldJarVersionValue =
semanticVersionOf(new Version(parameters.oldJarVersion));
final JarArchiveComparatorOptions comparatorOptions =
new JarArchiveComparatorOptions();
comparatorOptions.getIgnoreMissingClasses()
.setIgnoreAllMissingClasses(true);
comparatorOptions.setNoAnnotations(true);
final JarArchiveComparator jarArchiveComparator =
new JarArchiveComparator(comparatorOptions);
final JApiCmpArchive oldArchives =
new JApiCmpArchive(
parameters.oldJarPath.toFile(),
oldJarVersionValue.toString()
);
final JApiCmpArchive newArchives =
new JApiCmpArchive(
parameters.newJarPath.toFile(),
newJarVersionValue.toString()
);
final List jApiClasses =
jarArchiveComparator.compare(oldArchives, newArchives);
writeReports(jApiClasses, parameters, oldArchives, newArchives);
System.exit(
runSemanticVersionCheck(
jApiClasses,
newJarVersionValue,
oldJarVersionValue
)
);
}
private static int runSemanticVersionCheck(
final List jApiClasses,
final SemanticVersion newJarVersionValue,
final SemanticVersion oldJarVersionValue)
{
final SemverOut semverOut =
new SemverOut(Options.newDefault(), jApiClasses);
final SemanticVersion semverVersion =
semanticVersionOf(new Version(semverOut.generate()));
final SemanticVersion.ChangeType givenChange =
oldJarVersionValue.computeChangeType(newJarVersionValue)
.get();
final SemanticVersion.ChangeType requiredChange =
new SemanticVersion(0, 0, 1)
.computeChangeType(semverVersion)
.get();
if (oldJarVersionValue.getMajor() > 0 || newJarVersionValue.getMajor() > 0) {
if (requiredChange.getRank() > givenChange.getRank()) {
System.err.println(String.format(
"ERROR: Version change between %s and %s is %s, but the changes made to code require a %s version change",
oldJarVersionValue,
newJarVersionValue,
givenChange,
requiredChange
));
return 1;
}
}
return 0;
}
private static void writeReports(
final List jApiClasses,
final Parameters parameters,
final JApiCmpArchive oldArchives,
final JApiCmpArchive newArchives)
throws Exception
{
final Options options = Options.newDefault();
options.getIgnoreMissingClasses().setIgnoreAllMissingClasses(true);
options.setOutputOnlyModifications(true);
options.setOldArchives(Collections.singletonList(oldArchives));
options.setHtmlOutputFile(Optional.of(parameters.htmlReport.toString()));
options.setNewArchives(Collections.singletonList(newArchives));
try (BufferedWriter outputStream =
Files.newBufferedWriter(parameters.textReport)) {
final StdoutOutputGenerator stdoutOutputGenerator =
new StdoutOutputGenerator(options, jApiClasses);
outputStream.write("Old jar: " + parameters.oldJarPath);
outputStream.newLine();
outputStream.write("Old version: " + parameters.oldJarVersion);
outputStream.newLine();
outputStream.write("New jar: " + parameters.newJarPath);
outputStream.newLine();
outputStream.write("New version: " + parameters.newJarVersion);
outputStream.newLine();
outputStream.newLine();
outputStream.write(stdoutOutputGenerator.generate());
}
final XmlOutputGeneratorOptions xmlOptions =
new XmlOutputGeneratorOptions();
final XmlOutputGenerator xmlOutputGenerator =
new XmlOutputGenerator(jApiClasses, options, xmlOptions);
try (XmlOutput xmlOutput = xmlOutputGenerator.generate()) {
XmlOutputGenerator.writeToFiles(options, xmlOutput);
}
System.err.println("INFO: Text report written to " + parameters.textReport);
System.err.println("INFO: HTML report written to " + parameters.htmlReport);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy