You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
7.5 KiB
Groovy
229 lines
7.5 KiB
Groovy
package org.xbib.gradle.plugin.shadow.internal
|
|
|
|
import org.objectweb.asm.ClassReader
|
|
|
|
import java.util.jar.JarEntry
|
|
import java.util.jar.JarInputStream
|
|
import java.nio.file.Files
|
|
import java.nio.file.Path
|
|
import java.util.stream.Stream
|
|
import java.util.stream.StreamSupport
|
|
|
|
class Clazzpath {
|
|
|
|
private final Set<ClazzpathUnit> units
|
|
|
|
private final Map<String, Clazz> missing
|
|
|
|
private final Map<String, Clazz> clazzes
|
|
|
|
Clazzpath() {
|
|
units = new HashSet<ClazzpathUnit>()
|
|
missing = new HashMap<String, Clazz>()
|
|
clazzes = new HashMap<String, Clazz>()
|
|
}
|
|
|
|
boolean removeClazzpathUnit(ClazzpathUnit unit) {
|
|
Set<Clazz> unitClazzes = unit.getClazzes()
|
|
for (Clazz clazz : unitClazzes) {
|
|
clazz.removeClazzpathUnit(unit)
|
|
if (clazz.getClazzpathUnits().size() == 0) {
|
|
clazzes.remove(clazz.toString())
|
|
}
|
|
}
|
|
units.remove(unit)
|
|
}
|
|
|
|
ClazzpathUnit addClazzpathUnit(File file) throws IOException {
|
|
addClazzpathUnit(file.toPath())
|
|
}
|
|
|
|
ClazzpathUnit addClazzpathUnit(File file, String s) throws IOException {
|
|
addClazzpathUnit(file.toPath(), s)
|
|
}
|
|
|
|
ClazzpathUnit addClazzpathUnit(Path path) throws IOException {
|
|
addClazzpathUnit(path, path.toString())
|
|
}
|
|
|
|
ClazzpathUnit addClazzpathUnit(Path path1, String s) throws IOException {
|
|
Path path = path1.toAbsolutePath()
|
|
if (Files.isRegularFile(path)) {
|
|
return addClazzpathUnit(Files.newInputStream(path), s)
|
|
} else if (Files.isDirectory(path)) {
|
|
String prefix = Utils.separatorsToUnix(Utils.normalize(path.toString() + File.separatorChar))
|
|
List<Resource> list = []
|
|
path.traverse { p ->
|
|
if (Files.isRegularFile(p) && isValidResourceName(p.getFileName().toString())) {
|
|
list << new Resource(p.toString().substring(prefix.length())) {
|
|
@Override
|
|
InputStream getInputStream() throws IOException {
|
|
Files.newInputStream(p)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return addClazzpathUnit(list, s, true)
|
|
}
|
|
throw new IllegalArgumentException("neither file nor directory")
|
|
}
|
|
|
|
ClazzpathUnit addClazzpathUnit(InputStream inputStream, String s) throws IOException {
|
|
final JarInputStream jarInputStream = new JarInputStream(inputStream)
|
|
try {
|
|
Stream stream = toEntryStream(jarInputStream).map { e -> e.getName() }
|
|
.filter { name -> isValidResourceName(name) }
|
|
.map { name -> new Resource(name) {
|
|
@Override
|
|
InputStream getInputStream() throws IOException {
|
|
jarInputStream
|
|
}
|
|
}
|
|
}
|
|
addClazzpathUnit(stream.&iterator, s, false)
|
|
} finally {
|
|
jarInputStream.close()
|
|
}
|
|
}
|
|
|
|
ClazzpathUnit addClazzpathUnit(Iterable<Resource> resources, String s, boolean shouldCloseResourceStream)
|
|
throws IOException {
|
|
Map<String, Clazz> unitClazzes = new HashMap<String, Clazz>()
|
|
Map<String, Clazz> unitDependencies = new HashMap<String, Clazz>()
|
|
ClazzpathUnit unit = new ClazzpathUnit(s, unitClazzes, unitDependencies)
|
|
for (Resource resource : resources) {
|
|
String clazzName = resource.name
|
|
Clazz clazz = getClazz(clazzName)
|
|
if (clazz == null) {
|
|
clazz = missing.get(clazzName)
|
|
if (clazz != null) {
|
|
// already marked missing
|
|
clazz = missing.remove(clazzName)
|
|
} else {
|
|
clazz = new Clazz(clazzName)
|
|
}
|
|
}
|
|
clazz.addClazzpathUnit(unit)
|
|
clazzes.put(clazzName, clazz)
|
|
unitClazzes.put(clazzName, clazz)
|
|
DependenciesClassRemapper dependenciesClassAdapter = new DependenciesClassRemapper()
|
|
InputStream inputStream = resource.getInputStream()
|
|
try {
|
|
new ClassReader(inputStream.readAllBytes()).accept(dependenciesClassAdapter, ClassReader.EXPAND_FRAMES | ClassReader.SKIP_DEBUG)
|
|
} finally {
|
|
if (shouldCloseResourceStream) {
|
|
inputStream.close()
|
|
}
|
|
}
|
|
Set<String> depNames = dependenciesClassAdapter.getDependencies()
|
|
for (String depName : depNames) {
|
|
Clazz dep = getClazz(depName)
|
|
if (dep == null) {
|
|
// there is no such clazz yet
|
|
dep = missing.get(depName)
|
|
}
|
|
if (dep == null) {
|
|
// it is also not recorded to be missing
|
|
dep = new Clazz(depName)
|
|
dep.addClazzpathUnit(unit)
|
|
missing.put(depName, dep)
|
|
}
|
|
if (dep != clazz) {
|
|
unitDependencies.put(depName, dep)
|
|
clazz.addDependency(dep)
|
|
}
|
|
}
|
|
}
|
|
units.add(unit)
|
|
unit
|
|
}
|
|
|
|
Set<Clazz> getClazzes() {
|
|
new HashSet<Clazz>(clazzes.values())
|
|
}
|
|
|
|
Set<Clazz> getClashedClazzes() {
|
|
Set<Clazz> all = new HashSet<Clazz>()
|
|
for (Clazz clazz : clazzes.values()) {
|
|
if (clazz.getClazzpathUnits().size() > 1) {
|
|
all.add(clazz)
|
|
}
|
|
}
|
|
all
|
|
}
|
|
|
|
Set<Clazz> getMissingClazzes() {
|
|
new HashSet<Clazz>(missing.values())
|
|
}
|
|
|
|
Clazz getClazz(String clazzName) {
|
|
(Clazz) clazzes.get(clazzName)
|
|
}
|
|
|
|
ClazzpathUnit[] getUnits() {
|
|
units.toArray(new ClazzpathUnit[units.size()])
|
|
}
|
|
|
|
private Stream<JarEntry> toEntryStream(JarInputStream jarInputStream) {
|
|
StreamSupport.stream(Spliterators.spliteratorUnknownSize(new JarEntryIterator(jarInputStream),
|
|
Spliterator.IMMUTABLE), false)
|
|
}
|
|
|
|
private class JarEntryIterator implements Iterator<JarEntry> {
|
|
|
|
JarInputStream jarInputStream
|
|
JarEntry entry
|
|
|
|
JarEntryIterator(JarInputStream jarInputStream) {
|
|
this.jarInputStream = jarInputStream
|
|
this.entry = null
|
|
}
|
|
|
|
@Override
|
|
boolean hasNext() {
|
|
try {
|
|
if (entry == null) {
|
|
entry = jarInputStream.getNextJarEntry()
|
|
}
|
|
return entry != null
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e)
|
|
}
|
|
}
|
|
|
|
@Override
|
|
JarEntry next() {
|
|
try {
|
|
JarEntry result = entry != null ? entry : jarInputStream.getNextJarEntry()
|
|
entry = null
|
|
return result
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
private static abstract class Resource {
|
|
|
|
private static int ext = '.class'.length()
|
|
|
|
String name
|
|
|
|
Resource(String name) {
|
|
// foo/bar/Foo.class -> // foo.bar.Foo
|
|
this.name = name.substring(0, name.length() - ext).replace('/', '.')
|
|
}
|
|
|
|
abstract InputStream getInputStream() throws IOException
|
|
|
|
@Override
|
|
String toString() {
|
|
name
|
|
}
|
|
}
|
|
|
|
private static boolean isValidResourceName(String name) {
|
|
(name != null) && name.endsWith('.class') && !name.contains('-')
|
|
}
|
|
}
|