1/*
2 * Copyright (C) 2016 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 android.support.doclava
18
19import org.gradle.api.tasks.Input
20import org.gradle.api.tasks.InputFiles
21import org.gradle.api.tasks.javadoc.Javadoc
22import org.gradle.api.tasks.Optional
23import org.gradle.api.tasks.OutputDirectory
24import org.gradle.api.tasks.OutputFile
25import org.gradle.external.javadoc.JavadocOptionFileOption
26
27public class DoclavaTask extends Javadoc {
28
29    // external/doclava/src/com/google/doclava/Errors.java
30    public static final def DEFAULT_DOCLAVA_ERRORS = Collections.unmodifiableSet([
31            101,    // unresolved link
32            103,    // unknown tag
33            104,    // unknown param name
34    ] as Set)
35
36    public static final def DEFAULT_DOCLAVA_WARNINGS = Collections.unmodifiableSet([
37            121,    // hidden type param
38    ] as Set)
39
40
41    public static final def DEFAULT_DOCLAVA_HIDDEN = Collections.unmodifiableSet([
42            111,    // hidden super class
43            113,    // @deprecation mismatch
44    ] as Set)
45
46
47    // All lowercase name to match MinimalJavadocOptions#docletpath
48    private Collection<File> mDocletpath
49
50    // doclava error types which will cause the build to fail
51    @Input
52    Collection doclavaErrors = DEFAULT_DOCLAVA_ERRORS
53    @Input
54    Collection doclavaWarnings = DEFAULT_DOCLAVA_WARNINGS
55    // spammy doclava warnings which we want to hide
56    @Input
57    Collection doclavaHidden = DEFAULT_DOCLAVA_HIDDEN
58
59    /**
60     * If non-null, the list of packages that will be treated as if they were
61     * marked with {@literal @hide}.<br>
62     * Packages names will be matched exactly; sub-packages are not automatically recognized.
63     */
64    @Optional
65    @Input
66    Collection hiddenPackages
67
68    /**
69     * If non-null and not-empty, the whitelist of packages that will be present in the generated
70     * stubs; if null or empty, then all packages have stubs generated.<br>
71     * Wildcards are accepted.
72     */
73    @Optional
74    @Input
75    Set<String> stubPackages
76
77    @Input
78    boolean generateDocs = true
79
80    /**
81     * If non-null, the location of where to place the generated api file.
82     * If this is non-null, then {@link #removedApiFile} must be non-null as well.
83     */
84    @Optional
85    @OutputFile
86    File apiFile
87
88    /**
89     * If non-null, the location of where to place the generated removed api file.
90     * If this is non-null, then {@link #apiFile} must be non-null as well.
91     */
92    @Optional
93    @OutputFile
94    File removedApiFile
95
96    /**
97     * If non-null, the location of the generated keep list.
98     */
99    @Optional
100    @OutputFile
101    File keepListFile
102
103    /**
104     * If non-null, the location to put the generated stub sources.
105     */
106    @Optional
107    @OutputDirectory
108    File stubsDir
109
110    public DoclavaTask() {
111        failOnError = true
112        options.doclet = "com.google.doclava.Doclava"
113        options.encoding("UTF-8")
114        options.quiet()
115        // doclava doesn't understand '-doctitle'
116        title = null
117        maxMemory = "1280m"
118        // If none of generateDocs, apiFile, keepListFile, or stubJarsDir are true, then there is
119        // no work to do.
120        onlyIf( { getGenerateDocs() ||
121                getApiFile() != null ||
122                getKeepListFile() != null ||
123                getStubsDir() != null } )
124    }
125
126    /**
127     * The doclet path which has the {@code com.gogole.doclava.Doclava} class.
128     * This option will override any doclet path set in this instance's {@link #options JavadocOptions}.
129     * @see MinimalJavadocOptions#getDocletpath()
130     */
131    @InputFiles
132    public Collection<File> getDocletpath() {
133        return mDocletpath
134    }
135
136    /**
137     * Sets the doclet path which has the {@code com.gogole.doclava.Doclava} class.
138     * This option will override any doclet path set in this instance's {@link #options JavadocOptions}.
139     * @see MinimalJavadocOptions#setDocletpath(java.util.List)
140     */
141    public void setDocletpath(Collection<File> docletpath) {
142        mDocletpath = docletpath
143        // Go ahead and keep the docletpath in our JavadocOptions object in sync.
144        options.docletpath = docletpath as List
145    }
146
147    public void setDoclavaErrors(Collection errors) {
148        // Make it serializable.
149        doclavaErrors = errors as int[]
150    }
151
152    public void setDoclavaWarnings(Collection warnings) {
153        // Make it serializable.
154        doclavaWarnings = warnings as int[]
155    }
156
157    public void setDoclavaHidden(Collection hidden) {
158        // Make it serializable.
159        doclavaHidden = hidden as int[]
160    }
161
162    /**
163     * "Configures" this DoclavaTask with parameters that might not be at their final values
164     * until this task is run.
165     */
166    private configureDoclava() {
167        options.docletpath = getDocletpath() as List
168
169        // configure doclava error/warning/hide levels
170        JavadocOptionFileOption hide = options.addMultilineMultiValueOption("hide")
171        hide.setValue(getDoclavaHidden().collect({ [it.toString()] }))
172
173        JavadocOptionFileOption warning = options.addMultilineMultiValueOption("warning")
174        warning.setValue(getDoclavaWarnings().collect({ [it.toString()] }))
175
176        JavadocOptionFileOption error = options.addMultilineMultiValueOption("error")
177        error.setValue(getDoclavaErrors().collect({ [it.toString()] }))
178
179        Collection hiddenPackages = getHiddenPackages()
180        if (hiddenPackages) {
181            JavadocOptionFileOption hidePackage =
182                    options.addMultilineMultiValueOption("hidePackage")
183            hidePackage.setValue(hiddenPackages.collect({ [it.toString()] }))
184        }
185
186        if (!getGenerateDocs()) {
187            options.addOption(new DoclavaJavadocOptionFileOption('nodocs'))
188        }
189
190        // If requested, generate the API files.
191        File apiFile = getApiFile()
192        if (apiFile != null) {
193            options.addStringOption('api', apiFile.absolutePath)
194
195            File removedApiFile = getRemovedApiFile()
196            if (removedApiFile != null) {
197                options.addStringOption('removedApi', removedApiFile.absolutePath)
198            }
199        }
200
201        // If requested, generate the keep list.
202        File keepListFile = getKeepListFile()
203        if (keepListFile != null) {
204            options.addStringOption('proguard', keepListFile.absolutePath)
205        }
206        // If requested, generate stubs.
207        File stubsDir = getStubsDir()
208        if (stubsDir != null) {
209            options.addStringOption('stubs', stubsDir.absolutePath)
210            Set<String> stubPackages = getStubPackages()
211            if (stubPackages) {
212                options.addStringOption('stubpackages', stubPackages.join(':'))
213            }
214        }
215        // Always treat this as an Android docs task.
216        options.addOption(new DoclavaJavadocOptionFileOption('android'))
217    }
218
219    @Override
220    public void generate() {
221        configureDoclava()
222        super.generate()
223    }
224}
225