1*30877f79SAndroid Build Coastguard Worker// Copyright (C) 2017 The Android Open Source Project
2*30877f79SAndroid Build Coastguard Worker//
3*30877f79SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*30877f79SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*30877f79SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*30877f79SAndroid Build Coastguard Worker//
7*30877f79SAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*30877f79SAndroid Build Coastguard Worker//
9*30877f79SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*30877f79SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*30877f79SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*30877f79SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*30877f79SAndroid Build Coastguard Worker// limitations under the License.
14*30877f79SAndroid Build Coastguard Workerapply from: "${buildscript.sourceFile.parentFile}/constants.gradle"
15*30877f79SAndroid Build Coastguard Workerapply from: "${buildscript.sourceFile.parentFile}/javadoc_util.gradle"
16*30877f79SAndroid Build Coastguard Worker
17*30877f79SAndroid Build Coastguard Workerclass CombinedJavadocPlugin implements Plugin<Project> {
18*30877f79SAndroid Build Coastguard Worker
19*30877f79SAndroid Build Coastguard Worker  static final String JAVADOC_TASK_NAME = "generateCombinedJavadoc"
20*30877f79SAndroid Build Coastguard Worker  static final String DACKKA_TASK_NAME = "generateCombinedDackka"
21*30877f79SAndroid Build Coastguard Worker
22*30877f79SAndroid Build Coastguard Worker  // Dackka snapshots are listed at https://androidx.dev/dackka/builds.
23*30877f79SAndroid Build Coastguard Worker  static final String DACKKA_JAR_URL =
24*30877f79SAndroid Build Coastguard Worker      "https://androidx.dev/dackka/builds/8003564/artifacts/dackka-0.0.14.jar"
25*30877f79SAndroid Build Coastguard Worker
26*30877f79SAndroid Build Coastguard Worker  @Override
27*30877f79SAndroid Build Coastguard Worker  void apply(Project project) {
28*30877f79SAndroid Build Coastguard Worker    project.gradle.projectsEvaluated {
29*30877f79SAndroid Build Coastguard Worker      Set<Project> libraryModules = getLibraryModules(project)
30*30877f79SAndroid Build Coastguard Worker      if (!libraryModules.isEmpty()) {
31*30877f79SAndroid Build Coastguard Worker        def guavaReferenceUrl = "https://guava.dev/releases/$project.ext.guavaVersion/api/docs"
32*30877f79SAndroid Build Coastguard Worker
33*30877f79SAndroid Build Coastguard Worker        project.task(JAVADOC_TASK_NAME, type: Javadoc) {
34*30877f79SAndroid Build Coastguard Worker          description = "Generates combined Javadoc."
35*30877f79SAndroid Build Coastguard Worker          title = "ExoPlayer library"
36*30877f79SAndroid Build Coastguard Worker          source = libraryModules.generateJavadoc.source
37*30877f79SAndroid Build Coastguard Worker          classpath = project.files([])
38*30877f79SAndroid Build Coastguard Worker          destinationDir = project.file("$project.buildDir/docs/javadoc")
39*30877f79SAndroid Build Coastguard Worker          options {
40*30877f79SAndroid Build Coastguard Worker            links "https://developer.android.com/reference", guavaReferenceUrl
41*30877f79SAndroid Build Coastguard Worker            encoding = "UTF-8"
42*30877f79SAndroid Build Coastguard Worker          }
43*30877f79SAndroid Build Coastguard Worker          options.addBooleanOption "-no-module-directories", true
44*30877f79SAndroid Build Coastguard Worker          exclude "**/BuildConfig.java"
45*30877f79SAndroid Build Coastguard Worker          exclude "**/R.java"
46*30877f79SAndroid Build Coastguard Worker          doFirst {
47*30877f79SAndroid Build Coastguard Worker            libraryModules.each { libraryModule ->
48*30877f79SAndroid Build Coastguard Worker              libraryModule.android.libraryVariants.all { variant ->
49*30877f79SAndroid Build Coastguard Worker                def name = variant.buildType.name
50*30877f79SAndroid Build Coastguard Worker                if (name == "release") {
51*30877f79SAndroid Build Coastguard Worker                  classpath +=
52*30877f79SAndroid Build Coastguard Worker                      libraryModule.project.files(
53*30877f79SAndroid Build Coastguard Worker                          variant.javaCompileProvider.get().classpath.files,
54*30877f79SAndroid Build Coastguard Worker                          libraryModule.project.android.getBootClasspath())
55*30877f79SAndroid Build Coastguard Worker                }
56*30877f79SAndroid Build Coastguard Worker              }
57*30877f79SAndroid Build Coastguard Worker            }
58*30877f79SAndroid Build Coastguard Worker          }
59*30877f79SAndroid Build Coastguard Worker          doLast {
60*30877f79SAndroid Build Coastguard Worker            libraryModules.each { libraryModule ->
61*30877f79SAndroid Build Coastguard Worker              project.copy {
62*30877f79SAndroid Build Coastguard Worker                from "${libraryModule.projectDir}/src/main/javadoc"
63*30877f79SAndroid Build Coastguard Worker                into "${project.buildDir}/docs/javadoc"
64*30877f79SAndroid Build Coastguard Worker              }
65*30877f79SAndroid Build Coastguard Worker            }
66*30877f79SAndroid Build Coastguard Worker            project.fixJavadoc()
67*30877f79SAndroid Build Coastguard Worker          }
68*30877f79SAndroid Build Coastguard Worker        }
69*30877f79SAndroid Build Coastguard Worker
70*30877f79SAndroid Build Coastguard Worker        def dackkaOutputDir = project.file("$project.buildDir/docs/dackka")
71*30877f79SAndroid Build Coastguard Worker        project.task(DACKKA_TASK_NAME, type: JavaExec) {
72*30877f79SAndroid Build Coastguard Worker          doFirst {
73*30877f79SAndroid Build Coastguard Worker            // Recreate the output directory to remove any leftover files from a previous run.
74*30877f79SAndroid Build Coastguard Worker            project.delete dackkaOutputDir
75*30877f79SAndroid Build Coastguard Worker            project.mkdir dackkaOutputDir
76*30877f79SAndroid Build Coastguard Worker
77*30877f79SAndroid Build Coastguard Worker            // Download the Dackka JAR.
78*30877f79SAndroid Build Coastguard Worker            new URL(DACKKA_JAR_URL).withInputStream {
79*30877f79SAndroid Build Coastguard Worker              i -> classpath.getSingleFile().withOutputStream { it << i }
80*30877f79SAndroid Build Coastguard Worker            }
81*30877f79SAndroid Build Coastguard Worker
82*30877f79SAndroid Build Coastguard Worker            // Build lists of source files and dependencies.
83*30877f79SAndroid Build Coastguard Worker            def sources = []
84*30877f79SAndroid Build Coastguard Worker            def dependencies = []
85*30877f79SAndroid Build Coastguard Worker            libraryModules.each { libraryModule ->
86*30877f79SAndroid Build Coastguard Worker              libraryModule.android.libraryVariants.all { variant ->
87*30877f79SAndroid Build Coastguard Worker                def name = variant.buildType.name
88*30877f79SAndroid Build Coastguard Worker                if (name == "release") {
89*30877f79SAndroid Build Coastguard Worker                  def classpathFiles =
90*30877f79SAndroid Build Coastguard Worker                      project.files(variant.javaCompileProvider.get().classpath.files)
91*30877f79SAndroid Build Coastguard Worker                  variant.sourceSets.inject(sources) {
92*30877f79SAndroid Build Coastguard Worker                    acc, val -> acc << val.javaDirectories
93*30877f79SAndroid Build Coastguard Worker                  }
94*30877f79SAndroid Build Coastguard Worker                  dependencies << classpathFiles.filter { f -> !(f.path.contains("/buildout/")) }
95*30877f79SAndroid Build Coastguard Worker                  dependencies << libraryModule.project.android.getBootClasspath()
96*30877f79SAndroid Build Coastguard Worker                }
97*30877f79SAndroid Build Coastguard Worker              }
98*30877f79SAndroid Build Coastguard Worker            }
99*30877f79SAndroid Build Coastguard Worker
100*30877f79SAndroid Build Coastguard Worker            // Set command line arguments to Dackka.
101*30877f79SAndroid Build Coastguard Worker            def guavaPackageListFile = getGuavaPackageListFile(getTemporaryDir())
102*30877f79SAndroid Build Coastguard Worker            def globalLinksString = "$guavaReferenceUrl^$guavaPackageListFile^^"
103*30877f79SAndroid Build Coastguard Worker            def sourcesString = project.files(sources.flatten())
104*30877f79SAndroid Build Coastguard Worker                .filter({ f -> project.file(f).exists() }).join(";")
105*30877f79SAndroid Build Coastguard Worker            def dependenciesString = project.files(dependencies).asPath.replace(':', ';')
106*30877f79SAndroid Build Coastguard Worker            args("-moduleName", "",
107*30877f79SAndroid Build Coastguard Worker                "-outputDir", "$dackkaOutputDir",
108*30877f79SAndroid Build Coastguard Worker                "-globalLinks", "$globalLinksString",
109*30877f79SAndroid Build Coastguard Worker                "-loggingLevel", "WARN",
110*30877f79SAndroid Build Coastguard Worker                "-sourceSet", "-src $sourcesString -classpath $dependenciesString",
111*30877f79SAndroid Build Coastguard Worker                "-offlineMode")
112*30877f79SAndroid Build Coastguard Worker            environment("DEVSITE_TENANT", "androidx/media3")
113*30877f79SAndroid Build Coastguard Worker          }
114*30877f79SAndroid Build Coastguard Worker          description = "Generates combined javadoc for developer.android.com."
115*30877f79SAndroid Build Coastguard Worker          classpath = project.files(new File(getTemporaryDir(), "dackka.jar"))
116*30877f79SAndroid Build Coastguard Worker          doLast {
117*30877f79SAndroid Build Coastguard Worker            libraryModules.each { libraryModule ->
118*30877f79SAndroid Build Coastguard Worker              project.copy {
119*30877f79SAndroid Build Coastguard Worker                from "${libraryModule.projectDir}/src/main/javadoc"
120*30877f79SAndroid Build Coastguard Worker                into "${dackkaOutputDir}/reference/"
121*30877f79SAndroid Build Coastguard Worker              }
122*30877f79SAndroid Build Coastguard Worker              project.copy {
123*30877f79SAndroid Build Coastguard Worker                from "${libraryModule.projectDir}/src/main/javadoc"
124*30877f79SAndroid Build Coastguard Worker                into "${dackkaOutputDir}/reference/kotlin/"
125*30877f79SAndroid Build Coastguard Worker              }
126*30877f79SAndroid Build Coastguard Worker            }
127*30877f79SAndroid Build Coastguard Worker          }
128*30877f79SAndroid Build Coastguard Worker        }
129*30877f79SAndroid Build Coastguard Worker      }
130*30877f79SAndroid Build Coastguard Worker    }
131*30877f79SAndroid Build Coastguard Worker  }
132*30877f79SAndroid Build Coastguard Worker
133*30877f79SAndroid Build Coastguard Worker  // Returns Android library modules that declare a generateJavadoc task.
134*30877f79SAndroid Build Coastguard Worker  private static Set<Project> getLibraryModules(Project project) {
135*30877f79SAndroid Build Coastguard Worker    project.subprojects.findAll {
136*30877f79SAndroid Build Coastguard Worker      it.plugins.findPlugin("com.android.library") &&
137*30877f79SAndroid Build Coastguard Worker      it.tasks.findByName("generateJavadoc")
138*30877f79SAndroid Build Coastguard Worker    }
139*30877f79SAndroid Build Coastguard Worker  }
140*30877f79SAndroid Build Coastguard Worker
141*30877f79SAndroid Build Coastguard Worker  // Returns a file containing the list of packages that should be linked to Guava documentation.
142*30877f79SAndroid Build Coastguard Worker  private static File getGuavaPackageListFile(File directory) {
143*30877f79SAndroid Build Coastguard Worker    def packageListFile = new File(directory, "guava")
144*30877f79SAndroid Build Coastguard Worker    packageListFile.text = ["com.google.common.base", "com.google.common.collect",
145*30877f79SAndroid Build Coastguard Worker                            "com.google.common.io", "com.google.common.math",
146*30877f79SAndroid Build Coastguard Worker                            "com.google.common.net", "com.google.common.primitives",
147*30877f79SAndroid Build Coastguard Worker                            "com.google.common.truth", "com.google.common.util.concurrent"]
148*30877f79SAndroid Build Coastguard Worker        .join('\n')
149*30877f79SAndroid Build Coastguard Worker    return packageListFile
150*30877f79SAndroid Build Coastguard Worker  }
151*30877f79SAndroid Build Coastguard Worker
152*30877f79SAndroid Build Coastguard Worker}
153*30877f79SAndroid Build Coastguard Worker
154*30877f79SAndroid Build Coastguard Workerapply plugin: CombinedJavadocPlugin
155