com.github.ksoichiro.eclipse.aar.GenerateTask.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-eclipse-aar-plugin Show documentation
Show all versions of gradle-eclipse-aar-plugin Show documentation
Gradle plugin to use Android AAR libraries on Eclipse
package com.github.ksoichiro.eclipse.aar
import org.apache.maven.artifact.versioning.ComparableVersion
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.artifacts.SelfResolvingDependency
import org.gradle.api.file.CopySpec
import org.gradle.api.tasks.TaskAction
import java.util.regex.Matcher
class GenerateTask extends BaseTask {
Map> fileDependencies
Map> projectDependencies
Map allConfigurationsDependencies
GenerateTask() {
description = 'Used for Eclipse. Copies all AAR dependencies for library directory.'
}
@TaskAction
def exec() {
extension = project.eclipseAar
fileDependencies = [:]
projectDependencies = [:]
findTargetProjects()
allConfigurationsDependencies = [:]
def aggregateResolvedDependencies
aggregateResolvedDependencies = { Set it, String indent ->
it.each { ResolvedDependency dependency ->
if (!allConfigurationsDependencies.containsKey(getQualifiedDependencyName(dependency))) {
println "${indent}${getQualifiedDependencyName(dependency)}"
allConfigurationsDependencies[getQualifiedDependencyName(dependency)] = dependency
}
if (dependency.children) {
aggregateResolvedDependencies(dependency.children, indent + " ")
}
}
}
projects.each { AndroidProject p ->
androidConfigurations(p).each { Configuration configuration ->
println "Aggregating resolved dependencies for project ${p.project.name} from ${configuration.name} configuration"
aggregateResolvedDependencies(configuration.resolvedConfiguration.firstLevelModuleDependencies, " ")
}
}
projects.each { AndroidProject p ->
androidConfigurations(p).each { Configuration configuration ->
println "Classifying dependencies for project ${p.project.name} from ${configuration.name} configuration"
configuration.fileCollection {
// Exclude file dependency
it instanceof ProjectDependency || !(it instanceof SelfResolvingDependency)
}.each { File file ->
def convertedPath = file.path.tr(System.getProperty('file.separator'), '.')
def convertedPathExtStripped = convertedPath.lastIndexOf('.').with {
it != -1 ? convertedPath[0.. convertedPathExtStripped.endsWith("${d.name}-release") }
if (localDependency instanceof ProjectDependency) {
// ProjectDependency should be not be exploded, just include in project.properties with relative path
AndroidProject dependencyProject = projects.find { it.project.name == ((ProjectDependency) localDependency).dependencyProject.name }
def d = new AndroidDependency()
d.with {
name = dependencyProject.project.name
artifactType = AndroidArtifactType.PROJECT
}
if (!projectDependencies[p]) {
projectDependencies[p] = [] as Set
}
projectDependencies[p] << d
} else {
if (!fileDependencies[p]) {
fileDependencies[p] = [] as Set
}
fileDependencies[p] << getDependencyFromFile(file)
}
}
}
}
if (extension.jarDependenciesDir) {
projects.findAll { AndroidProject p ->
p.project.file(extension.jarDependenciesDir).exists()
}.each { AndroidProject p ->
p.project.file(extension.jarDependenciesDir).listFiles().findAll { File file ->
file.name.endsWith('.jar')
}.each { File file ->
def dependency = new AndroidDependency()
dependency.with {
it.file = file
artifactType = AndroidArtifactType.RAW_JAR
}
fileDependencies[p] << dependency
}
}
}
projects.each { AndroidProject p ->
fileDependencies[p] = getLatestDependencies(fileDependencies, fileDependencies[p])
}
projects.each { AndroidProject p ->
fileDependencies[p].each { AndroidDependency d -> copyJarIfNewer(p, d) }
}
projects.each { AndroidProject p ->
fileDependencies[p].findAll {
it.artifactType == AndroidArtifactType.AAR
}?.each { AndroidDependency d ->
generateProjectPropertiesFile(p, d)
generateEclipseClasspathFile(p, d)
generateEclipseProjectFile(p, d)
}
generateEclipseClasspathFileForParent(p)
generateEclipseProjectFileForParent(p)
generateProjectPropertiesFileForParent(p)
}
}
static String getQualifiedDependencyName(ResolvedDependency dependency) {
"${dependency.moduleGroup}:${dependency.moduleName}:${dependency.moduleVersion}"
}
Collection androidConfigurations(AndroidProject p) {
extension.targetConfigurations.collect { p.project.configurations.getByName(it) }
}
static String getBaseName(String filename) {
filename.lastIndexOf('.').with { it != -1 ? filename[0..
if ("${v.moduleName}-${v.moduleVersion}" == baseFilename) {
// This may be the dependency of the file
// Find group from file path and check qualified name matches
if (target ==~ /.*-${v.moduleGroup}-${v.moduleName}-${v.moduleVersion}-.*/) {
// This is the one
dependency = new AndroidDependency()
dependency.with {
group = v.moduleGroup
name = v.moduleName
version = v.moduleVersion
it.file = file
artifactType = file.name.endsWith('jar') ? AndroidArtifactType.JAR : AndroidArtifactType.AAR
}
}
}
}
if (!dependency) {
println "ERROR: Could not find dependency: ${target}"
}
return dependency
}
Set getLatestDependencies(Map> dependencies, Set projectDependencies) {
Set allDependencies = []
for (Set d : dependencies.values()) {
d.findAll {
null != it && !it.isRawJar()
}.each { AndroidDependency dependency ->
allDependencies << dependency
}
}
Set latestDependencies = []
projectDependencies.each { AndroidDependency dependency ->
if (null != dependency) {
if (dependency.isRawJar()) {
latestDependencies << dependency
} else {
String latestJarVersion = "0"
def duplicateDependencies = allDependencies.findAll {
dependency.isSameArtifact(getDependencyFromFile(it.file))
}
AndroidDependency latestDependency
if (1 < duplicateDependencies.size()) {
duplicateDependencies.each {
def d = getDependencyFromFile(it.file)
if (versionIsNewerThan(d?.version, latestJarVersion)) {
latestJarVersion = d?.version
}
}
latestDependency = duplicateDependencies.find { getDependencyFromFile(it.file)?.version == latestJarVersion }
} else {
latestJarVersion = dependency.version
latestDependency = dependency
}
if (latestDependency) {
latestDependency.version = latestJarVersion
latestDependencies << latestDependency
}
}
}
}
latestDependencies
}
void copyJarIfNewer(AndroidProject p, AndroidDependency dependency) {
def dependencyProjectName = dependency.getQualifiedName()
boolean isAarDependency = dependency.artifactType == AndroidArtifactType.AAR
def copyClosure = isAarDependency ? { destDir ->
p.project.copy { CopySpec it ->
it.from p.project.zipTree(dependency.file)
it.exclude 'classes.jar'
it.into "${extension.aarDependenciesDir}/${dependencyProjectName}"
}
p.project.copy { CopySpec it ->
it.from p.project.zipTree(dependency.file)
it.include 'classes.jar'
it.into destDir
it.rename { String fileName ->
fileName.replace('classes.jar', "${dependencyProjectName}.jar")
}
}
} : { destDir ->
p.project.copy { CopySpec it ->
it.from dependency.file
it.into destDir
it.rename { "${dependencyProjectName}.jar" }
}
}
println "Adding dependency: ${dependency.file.path}"
copyClosure('libs')
if (isAarDependency) {
p.project.copy { CopySpec it ->
it.from p.project.zipTree(dependency.file)
it.exclude 'classes.jar'
it.into "${extension.aarDependenciesDir}/${dependencyProjectName}"
}
copyClosure("${extension.aarDependenciesDir}/${dependencyProjectName}/libs")
}
}
static boolean versionIsNewerThan(String v1, String v2) {
def cv1 = new ComparableVersion(v1)
def cv2 = new ComparableVersion(v2)
return cv2.compareTo(cv1) < 0
}
void generateProjectPropertiesFile(AndroidProject p, AndroidDependency dependency) {
p.project.file("${extension.aarDependenciesDir}/${dependency.getQualifiedName()}/project.properties").text = """\
target=${extension.androidTarget}
android.library=true
"""
}
void generateEclipseClasspathFile(AndroidProject p, AndroidDependency dependency) {
p.project.file("${extension.aarDependenciesDir}/${dependency.getQualifiedName()}/.classpath").text = """\
\t
\t
\t
\t
\t
"""
}
void generateEclipseProjectFile(AndroidProject p, AndroidDependency dependency) {
def projectName = extension.projectName ?: p.project.name
def name = dependency.getQualifiedName()
p.project.file("${extension.aarDependenciesDir}/${name}/.project").text = projectFileText("${extension.projectNamePrefix}${projectName}-${name}")
}
void generateEclipseClasspathFileForParent(AndroidProject p) {
// Use srcDirs definition for classpath entry
def androidSrcDirs = []
p.project.android?.sourceSets?.findAll { it.name in ['main', 'debug'] }?.each {
if (it.java?.srcDirs) {
it.java.srcDirs.each { srcDir ->
if (srcDir.exists()) {
androidSrcDirs << srcDir
}
}
}
}
if (0 == androidSrcDirs.size()) {
androidSrcDirs = ['src/main/java']
}
if (!androidSrcDirs.contains('gen')) {
androidSrcDirs << 'gen'
}
def androidSrcPaths = []
androidSrcDirs.each {
androidSrcPaths << (it.toString() - p.project.projectDir.path).replaceFirst("^[/\\\\]", '')
}
def classpathFile = p.project.file('.classpath')
List srcPaths = []
if (classpathFile.exists()) {
// Aggregate src paths and dependencies
def classPaths = new XmlSlurper().parseText(classpathFile.text)
def srcPathEntries = classPaths.classpathentry?.findAll { it.@kind?.text() == 'src' }
srcPaths = srcPathEntries.collect { [email protected]() }
def libClassPathEntries = classPaths.classpathentry?.findAll { it.@kind?.text() == 'lib' }
} else {
// Create minimum classpath file
srcPaths = androidSrcPaths
def srcPathEntries = androidSrcPaths.collect { """
\t """ }.join('')
classpathFile.text = """\
${srcPathEntries}
\t
\t
\t
\t
"""
}
androidSrcPaths = androidSrcPaths.findAll { srcPaths.find { path -> path == it} == null }
if (androidSrcPaths) {
def entriesToAdd = androidSrcPaths.collect { it -> "\t" }
def lines = classpathFile.readLines()?.findAll { it != '' }
lines += entriesToAdd
lines += "${System.getProperty('line.separator')}"
classpathFile.text = lines.join(System.getProperty('line.separator'))
}
}
void generateEclipseProjectFileForParent(AndroidProject p) {
def file = p.project.file(".project")
if (file.exists()) {
return
}
def projectName = extension.projectName ?: p.project.name
file.text = projectFileText("${extension.projectNamePrefix}${projectName}")
}
void generateProjectPropertiesFileForParent(AndroidProject p) {
def projectPropertiesFile = p.project.file('project.properties')
List libNames = []
List projectNames = []
int maxReference = 0
boolean shouldAddLibrary = false
if (p.project.plugins.hasPlugin('com.android.library')) {
shouldAddLibrary = true
}
if (projectPropertiesFile.exists()) {
Properties props = new Properties()
projectPropertiesFile.withInputStream { stream -> props.load(stream) }
props.propertyNames().findAll {
it =~ /^android\.library\.reference\.[0-9]+/
}.each {
Matcher mValue = props[it] =~ /^${extension.aarDependenciesDir}\\/(.*)/
if (mValue.matches()) {
libNames << mValue[0][1]
Matcher mName = it =~ /^android\.library\.reference\.([0-9]+)/
if (mName.matches()) {
int ref = mName[0][1].toInteger()
if (maxReference < ref) {
maxReference = ref
}
}
} else {
mValue = props[it] =~ /^\.\.\/(.*)/
if (mValue.matches()) {
projectNames << mValue[0][1]
Matcher mName = it =~ /^android\.library\.reference\.([0-9]+)/
if (mName.matches()) {
int ref = mName[0][1].toInteger()
if (maxReference < ref) {
maxReference = ref
}
}
}
}
}
if (shouldAddLibrary && props.containsKey('android.library')) {
shouldAddLibrary = false
}
} else {
// Create minimum properties file
projectPropertiesFile.text = """\
target=${extension.androidTarget}
"""
}
def entriesToAdd = []
if (shouldAddLibrary) {
entriesToAdd << 'android.library=true'
}
List list = projectDependencies[p]?.collect { it.getQualifiedName().replaceFirst('^:', '') }
list = list?.findAll { projectNames.find { prj -> prj == it } == null }
list?.each {
maxReference++
entriesToAdd << "android.library.reference.${maxReference}=../${it}"
}
List aars = fileDependencies[p].findAll { it.artifactType == AndroidArtifactType.AAR }?.collect { it.getQualifiedName() }
aars = aars?.findAll { libNames.find { lib -> lib == it } == null }
aars?.each {
maxReference++
entriesToAdd << "android.library.reference.${maxReference}=${extension.aarDependenciesDir}/${it}"
}
if (0 < entriesToAdd.size()) {
def content = projectPropertiesFile.text
if (!content.endsWith(System.getProperty('line.separator'))) {
content += System.getProperty('line.separator')
}
projectPropertiesFile.text = content + entriesToAdd.join(System.getProperty('line.separator')) + System.getProperty('line.separator')
}
}
static String projectFileText(String projectName) {
"""\
\t${projectName}
\t
\t
\t
\t
\t\t
\t\t\tcom.android.ide.eclipse.adt.ResourceManagerBuilder
\t\t\t
\t\t\t
\t\t
\t\t
\t\t\tcom.android.ide.eclipse.adt.PreCompilerBuilder
\t\t\t
\t\t\t
\t\t
\t\t
\t\t\torg.eclipse.jdt.core.javabuilder
\t\t\t
\t\t\t
\t\t
\t\t
\t\t\tcom.android.ide.eclipse.adt.ApkBuilder
\t\t\t
\t\t\t
\t\t
\t
\t
\t\torg.eclipse.jdt.core.javanature
\t\tcom.android.ide.eclipse.adt.AndroidNature
\t
"""
}
}