diff options
Diffstat (limited to 'dev-java/java-dep-check')
-rw-r--r-- | dev-java/java-dep-check/Manifest | 3 | ||||
-rw-r--r-- | dev-java/java-dep-check/files/Main-0.5.java | 442 | ||||
-rw-r--r-- | dev-java/java-dep-check/java-dep-check-0.4-r1.ebuild | 32 | ||||
-rw-r--r-- | dev-java/java-dep-check/java-dep-check-0.5.ebuild | 32 |
4 files changed, 509 insertions, 0 deletions
diff --git a/dev-java/java-dep-check/Manifest b/dev-java/java-dep-check/Manifest index ed962d282c1e..68424b0b509b 100644 --- a/dev-java/java-dep-check/Manifest +++ b/dev-java/java-dep-check/Manifest @@ -1,5 +1,8 @@ AUX Main-0.3.java 11702 BLAKE2B f0f67f098fdf20cb6ad78ec6f0e20afa29cae2c7b62bbafea7a0e6ec5c3ab83029e7929d1e7d78b93b7551c62802a5b2a9f7ba40e16d99c7037ebcb8d2d71e1a SHA512 a70c0161fe72e8f4b4476cbdad5ae3074fbb7321214723a7b1b7778fd06de4eb616479de2b5d6ce9a6dab2e919d721ce2b177a515039a0b9592aa2b5e1017e88 AUX Main-0.4.java 14943 BLAKE2B ec9f08f76a38e16f17e68e05e06985f11700532c6f6827518cd8303635d240f7c425a205dbc2c41df870b1029d83a3b04b5d20a76f10275786a8d7c457472501 SHA512 340e6912285ee5c61116cd838c2abf68c573e57053d0b923fcd3929e19253d7cf29a281b226a3624a69b358f112bdf4a554b6c23b850933d60d7a1fd059f7a1e +AUX Main-0.5.java 14974 BLAKE2B c8cab47bca61f5c792d214f817768ed9455bb31f407ea5259e760ee8e66c6ab7cd811079bd8d1764fbf0c70da4aad1d9ab5500385c3894292b6e8e8e51c54e6f SHA512 3111783b22e01b357bae675fabd9af86536d4db82cc7dad1f4dac4c3a64efd84f3b6f35e5b5698dafc696d3ecde49589bcb167967130004e3fd1716db9d868f6 EBUILD java-dep-check-0.3-r1.ebuild 645 BLAKE2B 06181b8bd751a72d4a2876d4d44dbce6a037abcc23a09b9e91994a3987a03442dd58d6b191ea9ead5d2187254455c625c6cca587d61136ae236148e28eb92505 SHA512 6da35a65c72ef3d61f4544d49fadac6d743d8b348130ae811b620d62b428227ad4a8cc889d78dd409291dc59a621f459c27993033d7daa2eee5f23ce4d786ebe +EBUILD java-dep-check-0.4-r1.ebuild 649 BLAKE2B d16786af2d2378bf0d70520970e3a9d682aeef99befed7387fbebbeffe779b88f2e5d3f7e73a0af92cc27ad2728c5cb9216a46692e229f34e9f8d844b1f51b99 SHA512 b27edcf5cd769cd34d1ab2c4a041cb633ae3b3e6b8c670600e5341fd4f16b253b0d245aa6b32e60aa696c7e800f4739ec3d73172ecf38f4935c68820c9d3cb46 EBUILD java-dep-check-0.4.ebuild 642 BLAKE2B adffd940e68f3e7653a1b723acb360b31d7d402e3415649608d161c0c5dfa7cbc0ca476ac47b284d2af5f76632300f96d77350e130e8839aad36dd0520b9a842 SHA512 61463bfcced95396791da6dcd12135c0724294956c74743492c4fb8a21199aa855250797e6aa6a5b34ad4a5b2e6c0bc34bd77745e4769f4aae6335821ce048e1 +EBUILD java-dep-check-0.5.ebuild 649 BLAKE2B d16786af2d2378bf0d70520970e3a9d682aeef99befed7387fbebbeffe779b88f2e5d3f7e73a0af92cc27ad2728c5cb9216a46692e229f34e9f8d844b1f51b99 SHA512 b27edcf5cd769cd34d1ab2c4a041cb633ae3b3e6b8c670600e5341fd4f16b253b0d245aa6b32e60aa696c7e800f4739ec3d73172ecf38f4935c68820c9d3cb46 MISC metadata.xml 236 BLAKE2B 5a64c4404c26415501f50132968e687d4f1b852738cb0e1a5aef8cc4de9e4ea623066f46068fce3d80514ff122d85304e3fd12282c4b1513a4084523ef8bef07 SHA512 1755c2590e59060f697294c5ad125b83f2d50e05a71f7091b7de75953941914cd2db3a893bd6154a2c90fa4aff5e313e75e3e174dbba1edd5c112787da5be253 diff --git a/dev-java/java-dep-check/files/Main-0.5.java b/dev-java/java-dep-check/files/Main-0.5.java new file mode 100644 index 000000000000..bcd6b4f2a9d6 --- /dev/null +++ b/dev-java/java-dep-check/files/Main-0.5.java @@ -0,0 +1,442 @@ +/** + * This file is part of javadepchecker + * + * Copyright (C) 2016 Gentoo Foundation + * + * javadepchecker 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.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.Properties; + +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; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +/** + * Main Class of javadepchecker + * Gentoo Java Utility to scan class files for unneeded dependencies and + * ophaned class files + * + * @author Petteri Räty <betelgeuse@gentoo.org> + * @author Serkan Kaba <serkan@gentoo.org> + * @author William L. Thomson Jr., <wlt@o-sinc.com> + */ +public final class Main extends ClassVisitor { + + static private String image = ""; + private Set<String> mDeps = new HashSet<>(); + private Set<String> mCurrent = new HashSet<>(); + + /** + * Empty Constructor, sets ASM op code version + */ + public Main() { + super(Opcodes.ASM5); + } + + /** + * Get jar names from the Gentoo package and store in a collection + * + * @param pkg Gentoo package name + * @return a collection of jar names + */ + private static Collection<String> getPackageJars(String pkg) { + ArrayList<String> jars = new ArrayList<>(); + 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!=null/* package somehow missing*/ && + !output.trim().isEmpty()) { + jars.addAll(Arrays.asList(output.split(":"))); + } + } catch (InterruptedException | IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + return jars; + } + + /** + * Scan jar for classes to be processed by ASM + * + * @param jar jar file to be processed + * @throws IOException + */ + public void processJar(JarFile jar) throws IOException { + Collections.list(jar.entries()) + .stream() + .filter((JarEntry entry) -> (!entry.isDirectory() && entry.getName().endsWith("class"))) + .forEach((JarEntry entry) -> { + InputStream is = null; + try { + Main.this.mCurrent.add(entry.getName()); + is = jar.getInputStream(entry); + new ClassReader(is).accept(Main.this, 0); + } catch (IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } finally { + try { + if(is!=null) + is.close(); + } catch (IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + } + }); + } + + /** + * Check if a dependency is needed by a given package + * + * @param pkg Gentoo package name + * @param deps collection of dependencies for the package + * @return boolean if the dependency is needed or not + * @throws IOException + */ + private static boolean depNeeded(String pkg, + Collection<String> deps) throws IOException { + Collection<String> jars = getPackageJars(pkg); + + // We have a virtual with VM provider here + if (jars.isEmpty()) { + return true; + } + for (String jarName : jars) { + 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; + } + + /** + * Check for orphaned class files not owned by any package in dependencies + * + * @param pkg Gentoo package name + * @param deps collection of dependencies for the package + * @return boolean if the dependency is found or not + * @throws IOException + */ + private static boolean depsFound(Collection<String> pkgs, + Collection<String> deps) throws IOException { + boolean found = true; + Collection<String> jars = new ArrayList<>(); + + pkgs.forEach((String pkg) -> { + jars.addAll(getPackageJars(pkg)); + }); + + if (jars.isEmpty()) { + return false; + } + ArrayList<String> jarClasses = new ArrayList<>(); + jars.forEach((String jarName) -> { + try { + JarFile jar = new JarFile(jarName); + Collections.list(jar.entries()).forEach((JarEntry entry) -> { + jarClasses.add(entry.getName()); + }); + } catch (IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + }); + for (String dep : deps) { + if (!jarClasses.contains(dep)) { + boolean systemClass = false; + + if (!dep.startsWith("org/apache/commons/cli/") && !dep.startsWith("org/objectweb/asm/")) { + try { + Class.forName(dep.replaceAll("\\.class$", "").replace('/', '.')); + systemClass = true; + } catch (final ClassNotFoundException ex) { + // it's not a syste class + } + } + + if (!systemClass) { + if (found) { + System.out.println("Class files not found via DEPEND in package.env"); + } + System.out.println("\t" + dep); + found = false; + } + } + } + return found; + } + + /** + * Core method, this one fires off all others and is the one called from + * Main. Check this package for unneeded dependencies and orphaned class + * files + * + * @param env + * @return + */ + private static boolean checkPkg(File env) { + boolean needed = true; + boolean found = true; + HashSet<String> pkgs = new HashSet<>(); + Collection<String> deps = null; + InputStream is = null; + + try { + // load package.env + Properties props = new Properties(); + is = new FileInputStream(env); + props.load(is); + + // load package deps, add to hashset if exist + String depend = props.getProperty("DEPEND"); + if(depend!=null && + !depend.isEmpty()) { + for (String atom : depend.replaceAll("\"","").split(":")) { + String pkg = atom; + if (atom.contains("@")) { + pkg = atom.split("@")[1]; + } + pkgs.add(pkg); + } + } + + // load package classpath + String classpath = props.getProperty("CLASSPATH"); + if(classpath!=null && + !classpath.isEmpty()) { + Main classParser = new Main(); + for (String jar : classpath.replaceAll("\"","").split(":")) { + if (jar.endsWith(".jar")) { + classParser.processJar(new JarFile(image + jar)); + } + } + deps = classParser.getDeps(); + } + + for (String pkg : pkgs) { + if (!depNeeded(pkg, deps)) { + if (needed) { + System.out.println("Possibly unneeded dependencies found"); + } + System.out.println("\t" + pkg); + needed = false; + } + } + found = depsFound(pkgs, deps); + + } catch (IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } finally { + try { + if(is!=null) + is.close(); + } catch (IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + } + return needed && found; + } + + /** Main method, parse command line opts, invoke the package checker + * @param args the command line arguments + * @throws java.io.IOException + */ + 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); + } + + /** + * Add dependency to deps hashset + * + * @param dep dependent class name + */ + private void addDep(String dep) { + mDeps.add(dep + ".class"); + } + + /** + * Add dependency type to deps hashset + * + * @param dep dependent class name + */ + private void addDep(Type dep) { + if (dep.getSort() == Type.ARRAY) { + addDep(dep.getElementType()); + } + if (dep.getSort() == Type.OBJECT) { + addDep(dep.getInternalName()); + } + } + + /** + * Get deps not contained in the current hashset + * + * @return a collection of deps + */ + private Collection<String> getDeps() { + ArrayList<String> result = new ArrayList<>(); + mDeps.stream().filter((s) -> (!mCurrent.contains(s))).forEach((s) -> { + result.add(s); + }); + return result; + } + + @Override + public void visit(int version, + int access, + String name, + String signature, + String superName, + String[] interfaces) { + if(superName != null) { + addDep(superName); + } + for (String iface : interfaces) { + addDep(iface); + } + } + + @Override + public FieldVisitor visitField(int access, + String name, + String desc, + String signature, + Object value) { + addDep(Type.getType(desc)); + return null; + } + + @Override + public MethodVisitor visitMethod(int access, + String name, + String desc, + String signature, + String[] exceptions) { + for (Type param : Type.getArgumentTypes(desc)) { + addDep(param); + } + + if (exceptions != null) { + for (String exception : exceptions) { + addDep(exception); + } + } + addDep(Type.getReturnType(desc)); + return new MethodVisitor(Opcodes.ASM5) { + @Override + public void visitLocalVariable(String name, + String desc, + String signature, + Label start, + Label end, + int index) { + addDep(Type.getType(desc)); + } + + @Override + public void visitFieldInsn(int opcode, + String owner, + String name, + String desc) { + addDep(Type.getObjectType(owner)); + addDep(Type.getType(desc)); + } + + @Override + public void visitMethodInsn(int opcode, + String owner, + String name, + String desc, + boolean itf) { + addDep(Type.getObjectType(owner)); + } + + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, + String desc, + boolean visible) { + return Main.this.visitAnnotation(desc, visible); + } + }; + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + addDep(Type.getType(desc)); + return null; + } +} diff --git a/dev-java/java-dep-check/java-dep-check-0.4-r1.ebuild b/dev-java/java-dep-check/java-dep-check-0.4-r1.ebuild new file mode 100644 index 000000000000..eb7e53a80eee --- /dev/null +++ b/dev-java/java-dep-check/java-dep-check-0.4-r1.ebuild @@ -0,0 +1,32 @@ +# Copyright 2016-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=7 + +inherit java-pkg-2 java-pkg-simple + +DESCRIPTION="Java Dependency checker" +HOMEPAGE="https://wiki.gentoo.org/wiki/Project:Java" + +LICENSE="GPL-2" +SLOT="0" +KEYWORDS="~amd64 ~x86" + +COMMON_DEP=" + dev-java/commons-cli:1 + dev-java/asm:4" +RDEPEND=">=virtual/jre-1.8:* + ${COMMON_DEP}" +DEPEND=">=virtual/jdk-1.8:* + ${COMMON_DEP}" + +JAVA_GENTOO_CLASSPATH="asm-4,commons-cli-1" + +src_unpack() { + cp "${FILESDIR}/Main-${PV}.java" Main.java || die +} + +src_install() { + java-pkg-simple_src_install + java-pkg_dolauncher ${PN} --main javadepchecker.Main +} diff --git a/dev-java/java-dep-check/java-dep-check-0.5.ebuild b/dev-java/java-dep-check/java-dep-check-0.5.ebuild new file mode 100644 index 000000000000..eb7e53a80eee --- /dev/null +++ b/dev-java/java-dep-check/java-dep-check-0.5.ebuild @@ -0,0 +1,32 @@ +# Copyright 2016-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=7 + +inherit java-pkg-2 java-pkg-simple + +DESCRIPTION="Java Dependency checker" +HOMEPAGE="https://wiki.gentoo.org/wiki/Project:Java" + +LICENSE="GPL-2" +SLOT="0" +KEYWORDS="~amd64 ~x86" + +COMMON_DEP=" + dev-java/commons-cli:1 + dev-java/asm:4" +RDEPEND=">=virtual/jre-1.8:* + ${COMMON_DEP}" +DEPEND=">=virtual/jdk-1.8:* + ${COMMON_DEP}" + +JAVA_GENTOO_CLASSPATH="asm-4,commons-cli-1" + +src_unpack() { + cp "${FILESDIR}/Main-${PV}.java" Main.java || die +} + +src_install() { + java-pkg-simple_src_install + java-pkg_dolauncher ${PN} --main javadepchecker.Main +} |