You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gentoo-overlay/dev-java/java-dep-check/files/Main.java

234 lines
8.2 KiB

/*
* Main.java The main application class.
*
* Created on May 1, 2007, 6:32 PM
*
* Copyright (C) 2007,2008 Petteri Räty <betelgeuse@gentoo.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package javadepchecker;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.bcel.classfile.ClassParser;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.TreeSet;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.DescendingVisitor;
import org.apache.bcel.classfile.EmptyVisitor;
import org.apache.bcel.classfile.JavaClass;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
/**
*
* @author betelgeuse
*/
public final class Main extends EmptyVisitor {
static private String image = "";
private ConstantPool pool;
private TreeSet<String> deps = new TreeSet<String>();
private HashSet<String> current = new HashSet<String>();
/** Creates a new instance of Main */
public Main() {
}
private static Collection<String> getPackageJars(String pkg) {
ArrayList<String> jars = new ArrayList<String>();
try {
Process p = Runtime.getRuntime().exec("java-config -p " + pkg);
p.waitFor();
BufferedReader in;
in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String output = in.readLine();
if (!output.trim().equals("")) {
for (String jar : output.split(":")) {
jars.add(jar);
}
}
} catch (InterruptedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return jars;
}
public void processJar(JarFile jar) throws IOException {
for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements();) {
JarEntry entry = e.nextElement();
String name = entry.getName();
if (!entry.isDirectory() && name.endsWith(".class")) {
this.current.add(name);
InputStream stream = jar.getInputStream(entry);
ClassParser parser = new ClassParser(stream, name);
JavaClass jclass = parser.parse();
this.pool = jclass.getConstantPool();
new DescendingVisitor(jclass, this).visitConstantPool(this.pool);
}
}
}
private static boolean depNeeded(String pkg, Collection<String> deps) throws IOException {
for (String jarName : getPackageJars(pkg)) {
JarFile jar = new JarFile(jarName);
for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements();) {
String name = e.nextElement().getName();
if (deps.contains(name)) {
return true;
}
}
}
return false;
}
private static boolean checkPkg(File env) {
boolean needed = true;
HashSet<String> pkgs = new HashSet<String>();
Collection<String> deps = null;
BufferedReader in = null;
try {
Pattern dep_re = Pattern.compile("^DEPEND=\"([^\"]*)\"$");
Pattern cp_re = Pattern.compile("^CLASSPATH=\"([^\"]*)\"$");
String line;
in = new BufferedReader(new FileReader(env));
while ((line = in.readLine()) != null) {
Matcher m = dep_re.matcher(line);
if (m.matches()) {
String atoms = m.group(1);
for (String atom : atoms.split(":")) {
String pkg = atom;
if (atom.contains("@")) {
pkg = atom.split("@")[1];
}
pkgs.add(pkg);
}
continue;
}
m = cp_re.matcher(line);
if (m.matches()) {
Main classParser = new Main();
for (String jar : m.group(1).split(":")) {
classParser.processJar(new JarFile(image + jar));
}
deps = classParser.getDeps();
}
}
for (String pkg : pkgs) {
if (!depNeeded(pkg, deps)) {
System.out.println(pkg);
needed = false;
}
}
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
in.close();
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
return needed;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException {
int exit = 0;
try {
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption("h", "help", false, "print help");
options.addOption("i", "image", true, "image directory");
options.addOption("v","verbose", false, "print verbose output");
CommandLine line = parser.parse(options, args);
String[] files = line.getArgs();
if (line.hasOption("h") || files.length == 0) {
HelpFormatter h = new HelpFormatter();
h.printHelp("java-dep-check [-i <image] <package.env>+", options);
} else {
image = line.getOptionValue("i", "");
for (String arg : files) {
if(line.hasOption('v'))
System.out.println("Checking " + arg);
if (!checkPkg(new File(arg))) {
exit = 1;
}
}
}
} catch (ParseException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
System.exit(exit);
}
/**
* Find referenced class from signature if the signature is for a array
* type.
* @see http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html
*/
private String stripArray(String signature) {
String[] result = signature.split("^\\[+L");
if (result.length == 2) {
return result[1].substring(0, result[1].length() - 1);
} else {
return signature;
}
}
@Override
public void visitConstantClass(ConstantClass obj) {
String className = obj.getBytes(pool);
deps.add(stripArray(className) + ".class");
}
private Collection<String> getDeps() {
ArrayList<String> result = new ArrayList<String>();
for (String s : deps) {
if (!current.contains(s)) {
result.add(s);
}
}
return result;
}
}