1 /*
<lambda>null2  * Copyright 2019 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 
17 package androidx.build
18 
19 import java.io.File
20 import java.io.FileInputStream
21 import java.util.zip.ZipEntry
22 import java.util.zip.ZipInputStream
23 import org.gradle.api.DefaultTask
24 import org.gradle.api.file.DirectoryProperty
25 import org.gradle.api.tasks.CacheableTask
26 import org.gradle.api.tasks.InputDirectory
27 import org.gradle.api.tasks.PathSensitive
28 import org.gradle.api.tasks.PathSensitivity
29 import org.gradle.api.tasks.TaskAction
30 
31 /** Task for verifying license and version files in Androidx artifacts */
32 @CacheableTask
33 abstract class VerifyLicenseAndVersionFilesTask : DefaultTask() {
34     @get:[InputDirectory PathSensitive(PathSensitivity.RELATIVE)]
35     abstract val repositoryDirectory: DirectoryProperty
36 
37     @TaskAction
38     fun verifyFiles() {
39         verifyVersionFilesPresent()
40         verifyLicenseFilesPresent()
41     }
42 
43     private fun verifyVersionFilesPresent() {
44         repositoryDirectory.asFile.get().walk().forEach { file ->
45             var expectedPrefix = "androidx"
46             if (file.path.contains("/libyuv/"))
47                 expectedPrefix = "libyuv_libyuv" // external library that we don't publish
48             if (file.extension == "aar") {
49                 val inputStream = FileInputStream(file)
50                 val aarFileInputStream = ZipInputStream(inputStream)
51                 var entry: ZipEntry? = aarFileInputStream.nextEntry
52                 while (entry != null) {
53                     if (entry.name == "classes.jar") {
54                         var foundVersionFile = false
55                         val classesJarInputStream = ZipInputStream(aarFileInputStream)
56                         var jarEntry = classesJarInputStream.nextEntry
57                         while (jarEntry != null) {
58                             if (
59                                 jarEntry.name.startsWith("META-INF/$expectedPrefix.") &&
60                                     jarEntry.name.endsWith(".version")
61                             ) {
62                                 foundVersionFile = true
63                                 break
64                             }
65                             jarEntry = classesJarInputStream.nextEntry
66                         }
67                         if (!foundVersionFile) {
68                             throw Exception(
69                                 "Missing classes.jar/META-INF/$expectedPrefix.*version " +
70                                     "file in ${file.absolutePath}"
71                             )
72                         }
73                         break
74                     }
75                     entry = aarFileInputStream.nextEntry
76                 }
77             }
78         }
79     }
80 
81     private fun verifyLicenseFilesPresent() {
82         repositoryDirectory.asFile.get().walk().forEach { file ->
83             if (file.extension in listOf("aar", "jar", "klib")) {
84                 if (!zipContainsLicense(file)) {
85                     throw Exception(
86                         "Missing META-INF/*/LICENSE.txt or default/licenses/*/LICENSE.txt " +
87                             "file in ${file.absolutePath}"
88                     )
89                 }
90             }
91         }
92     }
93 
94     private fun zipContainsLicense(file: File): Boolean {
95         val inputStream = FileInputStream(file)
96         val zipInputStream = ZipInputStream(inputStream)
97         var entry: ZipEntry? = zipInputStream.nextEntry
98         while (entry != null) {
99             if (licensePatterns.any { it.matches(entry!!.name) }) {
100                 return true
101             }
102             entry = zipInputStream.nextEntry
103         }
104         return false
105     }
106 }
107 
108 private val licensePatterns =
109     listOf(Regex("META-INF/.*/LICENSE.txt"), Regex("default/licenses/.*/LICENSE.txt"))
110