/*
* Copyright 2013 Tomas Rohovsky
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.googlecode.japi.checker.cli;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.VFS;
import com.googlecode.japi.checker.BCChecker;
import com.googlecode.japi.checker.Rule;
import com.googlecode.japi.checker.Severity;
import com.googlecode.japi.checker.Utils;
import com.googlecode.japi.checker.rules.AllRules;
import com.googlecode.japi.checker.rules.CheckMethodVariableArity;
/**
*
* @author Tomas Rohovsky
* @author William Bernardet
*
*/
public class Main {
private static final String HELP_CMDLINE = "japi-checker-cli [-bin] [-cp <arg>] [-h] [-rcp <arg>] REFERENCE_LIBRARY NEW_LIBRARY";
private static final String HELP_HEADER = "Check API and ABI compatiblity of Java libraries.";
private String[] args;
static {
System.setProperty("org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.NoOpLog");
}
public Main(String[] args) {
this.args = args;
}
private String getVersion() {
InputStream is = this
.getClass()
.getClassLoader()
.getResourceAsStream(
"META-INF/maven/com.googlecode.japi-checker/japi-checker-cli/pom.properties");
if (is != null) {
try {
Properties properties = new Properties();
properties.load(is);
return properties.getProperty("version");
} catch (IOException e) {
// Swallow the error...
}
}
return "development";
}
private String getHeader() {
return HELP_HEADER;
}
private File writeToTempFile(FileObject fo) throws IOException {
File temp = File.createTempFile("lib-", fo.getName().getExtension());
temp.deleteOnExit();
InputStream is = fo.getContent().getInputStream();
OutputStream os = new FileOutputStream(temp);
int c = 0;
try {
while ((c = is.read()) != -1) {
os.write(c);
}
} finally {
os.close();
is.close();
}
return temp;
}
public int run() {
System.out.println("japi-checker-cli " + getVersion()
+ " - https://code.google.com/p/japi-checker/");
System.out.println("");
boolean reportSourceIncompatibilities = true;
// configuring the CLI options
Options options = new Options();
options.addOption("bin", false,
"check only binary compatibility (default - source and binary compatibility)");
options.addOption("rcp", true, "reference classpath.");
options.addOption("cp", true, "classpath.");
options.addOption("h", "help", false, "This help message.");
CommandLineParser parser = new GnuParser();
CommandLine cmdLine = null;
try {
cmdLine = parser.parse(options, args);
if (cmdLine.hasOption("h")) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp(HELP_CMDLINE, getHeader(), options, null);
return 0;
}
if (cmdLine.getArgs().length != 2) {
throw new ParseException(
"Missing REFERENCE_LIBRARY and/or NEW_LIBRARY.");
}
if (cmdLine.hasOption("bin")) {
reportSourceIncompatibilities = false;
}
} catch (ParseException e) {
System.err.println("Error parsing command line: " + e.getMessage());
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp(HELP_CMDLINE, getHeader(), options, null);
return -1;
}
// proceeding of arguments
/*
* List<File> referenceClasspath = new ArrayList<File>(); List<File>
* newArtifactClasspath = new ArrayList<File>(); List<AntPatternMatcher>
* includes = new ArrayList<AntPatternMatcher>();
* List<AntPatternMatcher> excludes = new
* ArrayList<AntPatternMatcher>();
*/
String referencePath = cmdLine.getArgs()[0];
String newPath = cmdLine.getArgs()[1];
File reference = new File(referencePath);
File newArtifact = new File(newPath);
if (!reference.isDirectory() && !Utils.isArchive(reference)) {
try {
FileObject fo = VFS.getManager().resolveFile(referencePath);
reference = writeToTempFile(fo);
} catch (FileSystemException e) {
System.err.println("Error: " + e.getMessage()
+ " - reference can be either a directory"
+ ", a jar (or a zip kind of archive) file, or a URL.");
return -1;
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
return -1;
}
}
if (!newArtifact.isDirectory() && !Utils.isArchive(newArtifact)) {
try {
FileObject fo = VFS.getManager().resolveFile(newPath);
newArtifact = writeToTempFile(fo);
} catch (FileSystemException e) {
System.err.println("Error: " + e.getMessage()
+ " - new artifact can be either a directory"
+ ", a jar (or a zip kind of archive) file or a URL.");
return -1;
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
return -1;
}
}
BCChecker checker = new BCChecker();
// Populating the classpaths, reference and then for tested artifact.
if (cmdLine.hasOption("rcp")) {
for (String filename : cmdLine.getOptionValues("rcp")) {
checker.addToReferenceClasspath(new File(filename));
}
}
if (cmdLine.hasOption("cp")) {
for (String filename : cmdLine.getOptionValues("cp")) {
checker.addToNewArtifactClasspath(new File(filename));
}
}
// checker initialization
CLIReporter reporter = new CLIReporter();
// checking
// Load rules
List<Rule> rules = new ArrayList<Rule>();
if (reportSourceIncompatibilities) {
rules.add(new CheckMethodVariableArity());
} else {
rules.add(new AllRules());
rules.add(new CheckMethodVariableArity());
}
// Running the check...
try {
checker.setReporter(reporter);
checker.setRules(rules);
checker.checkBacwardCompatibility(reference, newArtifact);
System.out.println("Error count: "
+ reporter.getCount(Severity.ERROR));
System.out.println("Warning count: "
+ reporter.getCount(Severity.WARNING));
if (reporter.getCount(Severity.ERROR) > 0) {
return -1;
}
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
return -1;
}
return 0;
}
public static void main(String[] args) {
System.exit(new Main(args).run());
}
}