1/*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package androidx.build
18
19import com.android.build.gradle.LibraryPlugin
20import org.gradle.api.Project
21import org.gradle.api.artifacts.ProjectDependency
22import org.gradle.api.artifacts.maven.MavenDeployer
23import org.gradle.api.tasks.Upload
24import org.gradle.kotlin.dsl.withGroovyBuilder
25import java.io.File
26
27fun apply(project: Project, extension: SupportLibraryExtension) {
28    project.afterEvaluate {
29        if (extension.publish) {
30            if (extension.mavenGroup == null) {
31                throw Exception("You must specify mavenGroup for ${project.name}  project")
32            }
33            if (extension.mavenVersion == null) {
34                throw Exception("You must specify mavenVersion for ${project.name}  project")
35            }
36            project.group = extension.mavenGroup!!
37            project.version = extension.mavenVersion.toString()
38        }
39    }
40
41    project.apply(mapOf("plugin" to "maven"))
42
43    // Set uploadArchives options.
44    val uploadTask = project.tasks.getByName("uploadArchives") as Upload
45
46    val repo = project.uri(project.rootProject.property("supportRepoOut") as File)
47            ?: throw Exception("supportRepoOut not set")
48
49    uploadTask.repositories {
50        it.withGroovyBuilder {
51            "mavenDeployer" {
52                "repository"(mapOf("url" to repo))
53            }
54        }
55    }
56
57    project.afterEvaluate {
58        if (extension.publish) {
59            uploadTask.repositories.withType(MavenDeployer::class.java) { mavenDeployer ->
60                mavenDeployer.isUniqueVersion = true
61
62                mavenDeployer.getPom().project {
63                    it.withGroovyBuilder {
64                        "name"(extension.name)
65                        "description"(extension.description)
66                        "url"(extension.url)
67                        "inceptionYear"(extension.inceptionYear)
68
69                        "licenses" {
70                            "license" {
71                                "name"("The Apache Software License, Version 2.0")
72                                "url"("http://www.apache.org/licenses/LICENSE-2.0.txt")
73                                "distribution"("repo")
74                            }
75                            for (license in extension.getLicenses()) {
76                                "license" {
77                                    "name"(license.name)
78                                    "url"(license.url)
79                                    "distribution"("repo")
80                                }
81                            }
82                        }
83
84                        "scm" {
85                            "url"("http://source.android.com")
86                            "connection"(ANDROID_GIT_URL)
87                        }
88
89                        "developers" {
90                            "developer" {
91                                "name"("The Android Open Source Project")
92                            }
93                        }
94                    }
95                }
96
97                // TODO(aurimas): remove this when Gradle bug is fixed.
98                // https://github.com/gradle/gradle/issues/3170
99                uploadTask.doFirst {
100                    val allDeps = HashSet<ProjectDependency>()
101                    collectDependenciesForConfiguration(allDeps, project, "api")
102                    collectDependenciesForConfiguration(allDeps, project, "implementation")
103                    collectDependenciesForConfiguration(allDeps, project, "compile")
104
105                    mavenDeployer.getPom().whenConfigured {
106                        it.dependencies.forEach { dep ->
107                            if (dep == null) {
108                                return@forEach
109                            }
110
111                            val getGroupIdMethod =
112                                    dep::class.java.getDeclaredMethod("getGroupId")
113                            val groupId: String = getGroupIdMethod.invoke(dep) as String
114                            val getArtifactIdMethod =
115                                    dep::class.java.getDeclaredMethod("getArtifactId")
116                            val artifactId: String = getArtifactIdMethod.invoke(dep) as String
117
118                            if (isAndroidProject(groupId, artifactId, allDeps)) {
119                                val setTypeMethod = dep::class.java.getDeclaredMethod("setType",
120                                        java.lang.String::class.java)
121                                setTypeMethod.invoke(dep, "aar")
122                            }
123                        }
124                    }
125                }
126            }
127
128            // Before the upload, make sure the repo is ready.
129            uploadTask.dependsOn(project.rootProject.tasks.getByName("prepareRepo"))
130
131            // Make the mainUpload depend on this uploadTask one.
132            project.rootProject.tasks.getByName("mainUpload").dependsOn(uploadTask)
133        } else {
134            uploadTask.enabled = false
135        }
136    }
137}
138
139private fun collectDependenciesForConfiguration(
140        projectDependencies: MutableSet<ProjectDependency>,
141        project: Project,
142        name: String
143) {
144    val config = project.configurations.findByName(name)
145    if (config != null) {
146        config.dependencies.withType(ProjectDependency::class.java).forEach {
147            dep -> projectDependencies.add(dep)
148        }
149    }
150}
151
152private fun isAndroidProject(
153        groupId: String,
154        artifactId: String,
155        deps: Set<ProjectDependency>
156): Boolean {
157    for (dep in deps) {
158        if (dep.group == groupId && dep.name == artifactId) {
159            return dep.getDependencyProject().plugins.hasPlugin(LibraryPlugin::class.java)
160        }
161    }
162    return false
163}
164
165private const val ANDROID_GIT_URL =
166        "scm:git:https://android.googlesource.com/platform/frameworks/support"