1/*
2 * Copyright (C) 2015 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 */
16package android.databinding
17
18import org.gradle.api.DefaultTask;
19import org.gradle.api.artifacts.ResolvedArtifact
20import org.gradle.api.tasks.TaskAction;
21
22class ExportLicensesTask extends DefaultTask {
23    List<ResolvedArtifact> artifacts = new ArrayList();
24
25    static def knownLicenses = [
26            [
27                    libraries: ["kotlin-stdlib", "kotlin-runtime", "kotlin-annotation-processing", "kotlin-gradle-plugin", "kotlin-gradle-plugin-api",
28                    "kdoc", "kotlin-gradle-plugin-core", "kotlin-jdk-annotations", "kotlin-compiler", "kotlin-compiler-embeddable"],
29                    licenses : ["https://raw.githubusercontent.com/JetBrains/kotlin/master/license/LICENSE.txt",
30                                "http://www.apache.org/licenses/LICENSE-2.0.txt"],
31                    notices  : ["https://raw.githubusercontent.com/JetBrains/kotlin/master/license/NOTICE.txt"]
32            ],
33            [
34                    libraries: ["antlr4", "antlr4-runtime", "antlr-runtime", "antlr4-annotations"],
35                    licenses : ["https://raw.githubusercontent.com/antlr/antlr4/master/LICENSE.txt"]
36            ],
37            [
38                    libraries: ["antlr"],
39                    licenses: ["http://www.antlr3.org/license.html", "http://www.antlr2.org/license.html"]
40            ],
41            [
42                    libraries: ["java.g4"],
43                    licenses : ["https://raw.githubusercontent.com/antlr/antlr4/master/LICENSE.txt"]
44            ],
45            [
46                    libraries: ["ST4", "stringtemplate"],
47                    licenses : ["https://raw.githubusercontent.com/antlr/stringtemplate4/master/LICENSE.txt"]
48            ],
49            [
50                    libraries: ["org.abego.treelayout.core"],
51                    licenses : ["http://treelayout.googlecode.com/files/LICENSE.TXT"]
52            ],
53            [
54                    libraries: ["junit"],
55                    licenses : ["https://raw.githubusercontent.com/junit-team/junit/master/LICENSE-junit.txt"],
56                    notices  : ["https://raw.githubusercontent.com/junit-team/junit/master/NOTICE.txt"]
57            ],
58            [
59                    libraries: ["commons-io"],
60                    licenses : ["http://svn.apache.org/viewvc/commons/proper/io/trunk/LICENSE.txt?view=co"],
61                    notices  : ["http://svn.apache.org/viewvc/commons/proper/io/trunk/NOTICE.txt?view=co"]
62            ],
63            [
64                    libraries: ["commons-codec"],
65                    licenses: ["http://svn.apache.org/viewvc/commons/proper/codec/trunk/LICENSE.txt?view=co"],
66                    notices: ["http://svn.apache.org/viewvc/commons/proper/codec/trunk/NOTICE.txt?view=co"]
67            ],
68            [
69                    libraries: ["commons-lang3"],
70                    licenses : ["https://git-wip-us.apache.org/repos/asf?p=commons-lang.git;a=blob_plain;f=LICENSE.txt;hb=refs/heads/master"],
71                    notices  : ["https://git-wip-us.apache.org/repos/asf?p=commons-lang.git;a=blob_plain;f=NOTICE.txt;hb=refs/heads/master"]
72            ],
73            [
74                    libraries: ["guava"],
75                    licenses : ["http://www.apache.org/licenses/LICENSE-2.0.txt"]
76            ],
77            [
78                    libraries: ["hamcrest-core"],
79                    licenses : ["https://raw.githubusercontent.com/hamcrest/JavaHamcrest/master/LICENSE.txt"]
80            ],
81            [
82                    libraries: ["avalon-framework"],
83                    licenses : ["http://archive.apache.org/dist/avalon/LICENSE.txt"]
84            ],
85            [
86                    libraries: ["log4j"],
87                    licenses: ["https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=blob_plain;f=LICENSE.txt;hb=HEAD"],
88                    notices: ["https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=blob_plain;f=NOTICE.txt;hb=HEAD"]
89            ],
90            [
91                    libraries: ["ant", "ant-launcher"],
92                    licenses: ["http://www.apache.org/licenses/LICENSE-2.0.html"]
93            ],
94            [
95                    libraries: ["xz"],
96                    licenses: ["http://git.tukaani.org/?p=xz-java.git;a=blob_plain;f=COPYING;hb=HEAD"]
97            ],
98            [
99                    libraries: ["logkit"],
100                    licenseText: ["unknown. see: http://commons.apache.org/proper/commons-logging/dependencies.html"]
101            ],
102            [
103                    libraries: ["juniversalchardet"],
104                    licenses: ["https://mozorg.cdn.mozilla.net/media/MPL/1.1/index.0c5913925d40.txt"]
105            ],
106    ]
107
108    Map<String, Object> usedLicenses = new HashMap<>();
109    static Map<String, Object> licenseLookup = new HashMap<>();
110    static {
111        knownLicenses.each {license ->
112            license.libraries.each {
113                licenseLookup.put(it, license)
114            }
115        }
116    }
117
118    ExportLicensesTask() {
119    }
120
121    public void add(ResolvedArtifact artifact) {
122        artifacts.add(artifact)
123        println("adding artifact $artifact")
124    }
125
126    @TaskAction
127    public void exportNotice() {
128        project.configurations.compile.getResolvedConfiguration()
129                .getFirstLevelModuleDependencies().each {
130            if (!it.getModuleGroup().equals("com.android.tools.build")) {
131                it.getAllModuleArtifacts().each { add(it) }
132            }
133        }
134        resolveLicenses()
135        def notice = buildNotice(usedLicenses)
136        def noticeFile = new File("${project.projectDir}/src/main/resources",'NOTICE.txt')
137        noticeFile.delete()
138        println ("writing notice file to: ${noticeFile.getAbsolutePath()}")
139        noticeFile << notice
140    }
141
142    public void resolveLicenses() {
143        artifacts.each { artifact ->
144            if (!shouldSkip(artifact)) {
145                def license = licenseLookup.get(artifact.name)
146                if (license  == null) {
147                    throw new RuntimeException("Cannot find license for ${artifact.getModuleVersion().id} in ${artifact.getFile()}")
148                }
149                usedLicenses.put(artifact, license)
150            }
151        }
152    }
153
154    public static Object findLicenseFor(String artifactId) {
155        return licenseLookup.get(artifactId)
156    }
157
158    public static String urlToText(String url) {
159        return new URL(url).getText()
160    }
161
162    public boolean shouldSkip(ResolvedArtifact artifact) {
163        return artifact.getModuleVersion().id.group.startsWith("com.android");
164    }
165
166    public static String buildNotice(Map<String, Object> licenses) {
167        // now build the output
168        StringBuilder notice = new StringBuilder();
169        notice.append("List of 3rd party licenses:")
170        licenses.each {
171            notice.append("\n-----------------------------------------------------------------------------")
172            notice.append("\n* ${it.key}")
173            notice.append("\n")
174            def license = it.value
175            if (license.notices != null) {
176                license.notices.each {
177                    notice.append("\n ****** NOTICE:\n${urlToText(it)}")
178                }
179            }
180            license.licenses.each {
181                notice.append("\n ****** LICENSE:\n${urlToText(it)}")
182            }
183            license.licenseText.each {
184                notice.append("\n ****** LICENSE:\n${it}")
185            }
186            notice.append("\n\n\n")
187        }
188        return notice.toString()
189    }
190}