diff --git a/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.kt b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.kt new file mode 100644 index 000000000..be5353bf8 --- /dev/null +++ b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.kt @@ -0,0 +1,64 @@ +package com.github.jengelman.gradle.plugins.shadow.impl + +import com.github.jengelman.gradle.plugins.shadow.ShadowStats +import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContext +import com.github.jengelman.gradle.plugins.shadow.relocation.RelocatePathContext +import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowCopyAction +import java.util.regex.Pattern +import org.objectweb.asm.commons.Remapper + +/** + * Modified from `org.apache.maven.plugins.shade.DefaultShader.java#RelocatorRemapper` + * + * @author John Engelman + */ +open class RelocatorRemapper( + private val relocators: List, + private val stats: ShadowStats, +) : Remapper() { + private val classPattern: Pattern = Pattern.compile("(\\[*)?L(.+)") + + open fun hasRelocators(): Boolean = relocators.isNotEmpty() + + override fun mapValue(value: Any): Any { + return if (value is String) { + map(value) + } else { + super.mapValue(value) + } + } + + override fun map(name: String): String { + var newName = name + var prefix = "" + var suffix = "" + + val matcher = classPattern.matcher(newName) + if (matcher.matches()) { + prefix = matcher.group(1) + "L" + suffix = "" + newName = matcher.group(2) + } + + for (relocator in relocators) { + if (relocator.canRelocateClass(newName)) { + val classContext = RelocateClassContext.builder().className(newName).stats(stats).build() + return prefix + relocator.relocateClass(classContext) + suffix + } else if (relocator.canRelocatePath(newName)) { + val pathContext = RelocatePathContext.builder().path(newName).stats(stats).build() + return prefix + relocator.relocatePath(pathContext) + suffix + } + } + + return name + } + + open fun mapPath(path: String): String { + return map(path.substring(0, path.indexOf('.'))) + } + + open fun mapPath(path: ShadowCopyAction.RelativeArchivePath): String { + return mapPath(path.pathString) + } +} diff --git a/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.kt b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.kt new file mode 100644 index 000000000..087e27930 --- /dev/null +++ b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.kt @@ -0,0 +1,105 @@ +package com.github.jengelman.gradle.plugins.shadow.internal + +import groovy.lang.Closure +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.ResolvedArtifact +import org.gradle.api.artifacts.ResolvedDependency +import org.gradle.api.file.FileCollection +import org.gradle.api.specs.Spec +import org.gradle.api.specs.Specs + +internal sealed class AbstractDependencyFilter( + private val project: Project, +) : DependencyFilter { + protected val includeSpecs: MutableList> = mutableListOf() + protected val excludeSpecs: MutableList> = mutableListOf() + + protected abstract fun resolve( + dependencies: Set, + includedDependencies: MutableSet, + excludedDependencies: MutableSet, + ) + + override fun resolve(configuration: FileCollection): FileCollection { + val includedDeps = mutableSetOf() + val excludedDeps = mutableSetOf() + configuration as Configuration + resolve(configuration.resolvedConfiguration.firstLevelModuleDependencies, includedDeps, excludedDeps) + return project.files(configuration.files) - + project.files(excludedDeps.flatMap { it.moduleArtifacts.map(ResolvedArtifact::getFile) }) + } + + override fun resolve(configurations: Collection): FileCollection { + return configurations.map { resolve(it) } + .reduceOrNull { acc, fileCollection -> acc + fileCollection } + ?: project.files() + } + + /** + * Exclude dependencies that match the provided spec. + */ + override fun exclude(spec: Spec): DependencyFilter = apply { + excludeSpecs.add(spec) + } + + /** + * Include dependencies that match the provided spec. + */ + override fun include(spec: Spec): DependencyFilter = apply { + includeSpecs.add(spec) + } + + /** + * Create a spec that matches the provided project notation on group, name, and version. + */ + override fun project(notation: Map): Spec { + return dependency(dependency = project.dependencies.project(notation)) + } + + /** + * Create a spec that matches the default configuration for the provided project path on group, name, and version. + */ + override fun project(notation: String): Spec { + return dependency( + dependency = project.dependencies.project( + mapOf( + "path" to notation, + "configuration" to "default", + ), + ), + ) + } + + /** + * Create a spec that matches dependencies using the provided notation on group, name, and version. + */ + override fun dependency(notation: Any): Spec { + return dependency(dependency = project.dependencies.create(notation)) + } + + /** + * Create a spec that matches the provided dependency on group, name, and version. + */ + override fun dependency(dependency: Dependency): Spec { + return Spec { resolvedDependency -> + (dependency.group == null || resolvedDependency.moduleGroup.matches(dependency.group!!.toRegex())) && + resolvedDependency.moduleName.matches(dependency.name.toRegex()) && + (dependency.version == null || resolvedDependency.moduleVersion.matches(dependency.version!!.toRegex())) + } + } + + /** + * Create a spec that matches the provided closure. + */ + override fun dependency(closure: Closure<*>): Spec { + return Specs.convertClosureToSpec(closure) + } + + protected fun ResolvedDependency.isIncluded(): Boolean { + val include = includeSpecs.isEmpty() || includeSpecs.any { it.isSatisfiedBy(this) } + val exclude = excludeSpecs.isNotEmpty() && excludeSpecs.any { it.isSatisfiedBy(this) } + return include && !exclude + } +} diff --git a/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.kt b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.kt new file mode 100644 index 000000000..25604eaf2 --- /dev/null +++ b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.kt @@ -0,0 +1,20 @@ +package com.github.jengelman.gradle.plugins.shadow.internal + +import org.gradle.api.Project +import org.gradle.api.artifacts.ResolvedDependency + +internal class DefaultDependencyFilter( + project: Project, +) : AbstractDependencyFilter(project) { + override fun resolve( + dependencies: Set, + includedDependencies: MutableSet, + excludedDependencies: MutableSet, + ) { + dependencies.forEach { + if (if (it.isIncluded()) includedDependencies.add(it) else excludedDependencies.add(it)) { + resolve(it.children, includedDependencies, excludedDependencies) + } + } + } +} diff --git a/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt new file mode 100644 index 000000000..df6bf5bc2 --- /dev/null +++ b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt @@ -0,0 +1,30 @@ +package com.github.jengelman.gradle.plugins.shadow.internal + +import org.gradle.api.Project +import org.gradle.api.artifacts.ResolvedDependency + +internal class MinimizeDependencyFilter( + project: Project, +) : AbstractDependencyFilter(project) { + override fun resolve( + dependencies: Set, + includedDependencies: MutableSet, + excludedDependencies: MutableSet, + ) { + dependencies.forEach { + if (it.isIncluded() && !isParentExcluded(excludedDependencies, it)) { + includedDependencies.add(it) + } else { + excludedDependencies.add(it) + } + resolve(it.children, includedDependencies, excludedDependencies) + } + } + + private fun isParentExcluded( + excludedDependencies: Set, + dependency: ResolvedDependency, + ): Boolean { + return excludedDependencies.any { it in dependency.parents } + } +} diff --git a/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.kt b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.kt new file mode 100644 index 000000000..504459d60 --- /dev/null +++ b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.kt @@ -0,0 +1,91 @@ +package com.github.jengelman.gradle.plugins.shadow.internal + +import java.io.File +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.ProjectDependency +import org.gradle.api.artifacts.SelfResolvingDependency +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.InputFiles +import org.vafer.jdependency.Clazzpath +import org.vafer.jdependency.ClazzpathUnit + +/** Tracks unused classes in the project classpath. */ +internal class UnusedTracker private constructor( + classDirs: Iterable, + classJars: FileCollection, + private val _toMinimize: FileCollection, +) { + private val projectUnits: List + private val cp = Clazzpath() + + init { + projectUnits = classDirs.map { cp.addClazzpathUnit(it) } + classJars.map { cp.addClazzpathUnit(it) } + } + + @get:InputFiles + val toMinimize: FileCollection get() = _toMinimize + + fun findUnused(): Set { + val unused = cp.clazzes.toMutableSet() + for (cpu in projectUnits) { + unused.removeAll(cpu.clazzes) + unused.removeAll(cpu.transitiveDependencies) + } + return unused.map { it.name }.toSet() + } + + fun addDependency(jarOrDir: File) { + if (_toMinimize.contains(jarOrDir)) { + cp.addClazzpathUnit(jarOrDir) + } + } + + companion object { + @JvmStatic + fun forProject( + apiJars: FileCollection, + sourceSetsClassesDirs: Iterable, + toMinimize: FileCollection, + ): UnusedTracker { + return UnusedTracker(sourceSetsClassesDirs, apiJars, toMinimize) + } + + @JvmStatic + fun getApiJarsFromProject(project: Project): FileCollection { + val apiDependencies = project.configurations.findByName("api")?.dependencies + ?: return project.files() + val runtimeConfiguration = project.configurations.findByName("runtimeClasspath") + ?: project.configurations.getByName("runtime") + val apiJars = mutableListOf() + apiDependencies.forEach { dep -> + when (dep) { + is ProjectDependency -> { + apiJars.addAll(getApiJarsFromProject(dep.dependencyProject)) + addJar(runtimeConfiguration, dep, apiJars) + } + is SelfResolvingDependency -> { + apiJars.addAll(dep.resolve()) + } + else -> { + addJar(runtimeConfiguration, dep, apiJars) + apiJars.add(runtimeConfiguration.find { it.name.startsWith("${dep.name}-") } as File) + } + } + } + return project.files(apiJars) + } + + private fun addJar(config: Configuration, dep: Dependency, result: MutableList) { + config.find { isProjectDependencyFile(it, dep) }?.let { result.add(it) } + } + + private fun isProjectDependencyFile(file: File, dep: Dependency): Boolean { + val fileName = file.name + val dependencyName = dep.name + return fileName == "$dependencyName.jar" || + (fileName.startsWith("$dependencyName-") && fileName.endsWith(".jar")) + } + } +} diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy deleted file mode 100644 index 5e23269e4..000000000 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.github.jengelman.gradle.plugins.shadow.impl - -import com.github.jengelman.gradle.plugins.shadow.ShadowStats -import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContext -import com.github.jengelman.gradle.plugins.shadow.relocation.RelocatePathContext -import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowCopyAction.RelativeArchivePath -import org.objectweb.asm.commons.Remapper - -import java.util.regex.Matcher -import java.util.regex.Pattern - -/** - * Modified from org.apache.maven.plugins.shade.DefaultShader.java#RelocatorRemapper - * - * @author John Engelman - */ -class RelocatorRemapper extends Remapper { - - private final Pattern classPattern = Pattern.compile("(\\[*)?L(.+)") - - List relocators - ShadowStats stats - - RelocatorRemapper(List relocators, ShadowStats stats) { - this.relocators = relocators - this.stats = stats - } - - boolean hasRelocators() { - return !relocators.empty - } - - @Override - Object mapValue(Object object) { - if (object instanceof String) { - String name = (String) object - String value = name - - String prefix = "" - String suffix = "" - - Matcher m = classPattern.matcher(name) - if (m.matches()) { - prefix = m.group(1) + "L" - suffix = "" - name = m.group(2) - } - - for (Relocator r : relocators) { - if (r.canRelocateClass(name)) { - RelocateClassContext classContext = RelocateClassContext.builder().className(name).stats(stats).build() - value = prefix + r.relocateClass(classContext) + suffix - break - } else if (r.canRelocatePath(name)) { - RelocatePathContext pathContext = RelocatePathContext.builder().path(name).stats(stats).build() - value = prefix + r.relocatePath(pathContext) + suffix - break - } - } - - return value - } - - return super.mapValue(object) - } - - @Override - String map(String name) { - String value = name - - String prefix = "" - String suffix = "" - - Matcher m = classPattern.matcher(name) - if (m.matches()) { - prefix = m.group(1) + "L" - suffix = "" - name = m.group(2) - } - - for (Relocator r : relocators) { - if (r.canRelocatePath(name)) { - RelocatePathContext pathContext = RelocatePathContext.builder().path(name).stats(stats).build() - value = prefix + r.relocatePath(pathContext) + suffix - break - } - } - - return value - } - - String mapPath(String path) { - map(path.substring(0, path.indexOf('.'))) - } - - String mapPath(RelativeArchivePath path) { - mapPath(path.pathString) - } - -} diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy deleted file mode 100644 index 160d34c15..000000000 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy +++ /dev/null @@ -1,128 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.internal - -import groovy.util.logging.Slf4j -import org.gradle.api.Project -import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.ResolvedDependency -import org.gradle.api.file.FileCollection -import org.gradle.api.specs.Spec -import org.gradle.api.specs.Specs - -@Slf4j -abstract class AbstractDependencyFilter implements DependencyFilter { - private final Project project - - protected final List> includeSpecs = [] - protected final List> excludeSpecs = [] - - AbstractDependencyFilter(Project project) { - assert project - this.project = project - } - - abstract protected void resolve(Set dependencies, - Set includedDependencies, - Set excludedDependencies) - - @Override - FileCollection resolve(FileCollection configuration) { - Set includedDeps = [] - Set excludedDeps = [] - resolve(configuration.resolvedConfiguration.firstLevelModuleDependencies, includedDeps, excludedDeps) - return project.files(configuration.files) - project.files(excludedDeps.collect { - it.moduleArtifacts*.file - }.flatten()) - } - - @Override - FileCollection resolve(Collection configurations) { - configurations.collect { - resolve(it) - }.sum() as FileCollection ?: project.files() - } - - /** - * Exclude dependencies that match the provided spec. - * - * @param spec - * @return - */ - @Override - DependencyFilter exclude(Spec spec) { - excludeSpecs << spec - return this - } - - /** - * Include dependencies that match the provided spec. - * - * @param spec - * @return - */ - @Override - DependencyFilter include(Spec spec) { - includeSpecs << spec - return this - } - - /** - * Create a spec that matches the provided project notation on group, name, and version - * @param notation - * @return - */ - @Override - Spec project(Map notation) { - dependency(project.dependencies.project(notation)) - } - - /** - * Create a spec that matches the default configuration for the provided project path on group, name, and version - * - * @param notation - * @return - */ - @Override - Spec project(String notation) { - dependency(project.dependencies.project(path: notation, configuration: 'default')) - } - - /** - * Create a spec that matches dependencies using the provided notation on group, name, and version - * @param notation - * @return - */ - @Override - Spec dependency(Object notation) { - dependency(project.dependencies.create(notation)) - } - - /** - * Create a spec that matches the provided dependency on group, name, and version - * @param dependency - * @return - */ - @Override - Spec dependency(Dependency dependency) { - this.dependency({ ResolvedDependency it -> - (!dependency.group || it.moduleGroup.matches(dependency.group)) && - (!dependency.name || it.moduleName.matches(dependency.name)) && - (!dependency.version || it.moduleVersion.matches(dependency.version)) - }) - } - - /** - * Create a spec that matches the provided closure - * @param spec - * @return - */ - @Override - Spec dependency(Closure spec) { - return Specs.convertClosureToSpec(spec) - } - - protected boolean isIncluded(ResolvedDependency dependency) { - boolean include = includeSpecs.empty || includeSpecs.any { it.isSatisfiedBy(dependency) } - boolean exclude = !excludeSpecs.empty && excludeSpecs.any { it.isSatisfiedBy(dependency) } - return include && !exclude - } -} diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.groovy deleted file mode 100644 index 4734fedd1..000000000 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.groovy +++ /dev/null @@ -1,25 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.internal - -import groovy.util.logging.Slf4j -import org.gradle.api.Project -import org.gradle.api.artifacts.ResolvedDependency - -@Slf4j -class DefaultDependencyFilter extends AbstractDependencyFilter { - - DefaultDependencyFilter(Project project) { - super(project) - } - - @Override - protected void resolve(Set dependencies, - Set includedDependencies, - Set excludedDependencies) { - dependencies.each { - if (isIncluded(it) ? includedDependencies.add(it) : excludedDependencies.add(it)) { - resolve(it.children, includedDependencies, excludedDependencies) - } - } - } - -} diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.groovy deleted file mode 100644 index 4853c3a77..000000000 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.groovy +++ /dev/null @@ -1,29 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.internal - -import groovy.util.logging.Slf4j -import org.gradle.api.Project -import org.gradle.api.artifacts.ResolvedDependency - -@Slf4j -class MinimizeDependencyFilter extends AbstractDependencyFilter { - - MinimizeDependencyFilter(Project project) { - super(project) - } - - @Override - protected void resolve(Set dependencies, - Set includedDependencies, - Set excludedDependencies) { - - dependencies.each { - if (isIncluded(it) && !isParentExcluded(excludedDependencies, it) ? includedDependencies.add(it) : excludedDependencies.add(it)) { - resolve(it.children, includedDependencies, excludedDependencies) - } - } - } - - private static boolean isParentExcluded(Set excludedDependencies, ResolvedDependency dependency) { - excludedDependencies.any { dependency.parents.contains(it) } - } -} \ No newline at end of file diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy deleted file mode 100644 index fcfbe6ea1..000000000 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy +++ /dev/null @@ -1,85 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.internal - -import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.ProjectDependency -import org.gradle.api.artifacts.SelfResolvingDependency -import org.gradle.api.file.FileCollection -import org.gradle.api.tasks.InputFiles -import org.vafer.jdependency.Clazz -import org.vafer.jdependency.Clazzpath -import org.vafer.jdependency.ClazzpathUnit - -/** Tracks unused classes in the project classpath. */ -class UnusedTracker { - private final FileCollection toMinimize - private final List projectUnits - private final Clazzpath cp = new Clazzpath() - - private UnusedTracker(Iterable classDirs, FileCollection classJars, FileCollection toMinimize) { - this.toMinimize = toMinimize - projectUnits = classDirs.collect { cp.addClazzpathUnit(it) } - projectUnits.addAll(classJars.collect { cp.addClazzpathUnit(it) }) - } - - Set findUnused() { - Set unused = cp.clazzes - for (cpu in projectUnits) { - unused.removeAll(cpu.clazzes) - unused.removeAll(cpu.transitiveDependencies) - } - return unused.collect { it.name }.toSet() - } - - void addDependency(File jarOrDir) { - if (toMinimize.contains(jarOrDir)) { - cp.addClazzpathUnit(jarOrDir) - } - } - - static UnusedTracker forProject(FileCollection apiJars, Iterable sourceSetsClassesDirs, FileCollection toMinimize) { - return new UnusedTracker(sourceSetsClassesDirs, apiJars, toMinimize) - } - - @InputFiles - FileCollection getToMinimize() { - return toMinimize - } - - private static boolean isProjectDependencyFile(File file, Dependency dep) { - def fileName = file.name - def dependencyName = dep.name - - return (fileName == "${dependencyName}.jar") || - (fileName.startsWith("${dependencyName}-") && fileName.endsWith('.jar')) - } - - private static void addJar(Configuration config, Dependency dep, List result) { - def file = config.find { isProjectDependencyFile(it, dep) } as File - if (file != null) { - result.add(file) - } - } - - static FileCollection getApiJarsFromProject(Project project) { - def apiDependencies = project.configurations.asMap['api']?.dependencies ?: null - if (apiDependencies == null) return project.files() - - def runtimeConfiguration = project.configurations.asMap['runtimeClasspath'] ?: project.configurations.runtime - def apiJars = new LinkedList() - apiDependencies.each { dep -> - if (dep instanceof ProjectDependency) { - apiJars.addAll(getApiJarsFromProject(dep.dependencyProject)) - addJar(runtimeConfiguration, dep, apiJars) - } else if (dep instanceof SelfResolvingDependency) { - apiJars.addAll(dep.resolve()) - } else { - addJar(runtimeConfiguration, dep, apiJars) - apiJars.add(runtimeConfiguration.find { it.name.startsWith("${dep.name}-") } as File) - } - } - - return project.files(apiJars) - } -}