diff --git a/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.kt b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.kt new file mode 100644 index 000000000..a28f3b26f --- /dev/null +++ b/api/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.kt @@ -0,0 +1,199 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License") you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.github.jengelman.gradle.plugins.shadow.transformers + +import java.io.PrintWriter +import java.nio.charset.Charset +import java.text.SimpleDateFormat +import java.util.Date +import java.util.TreeSet +import org.apache.tools.zip.ZipEntry +import org.apache.tools.zip.ZipOutputStream +import org.gradle.api.file.FileTreeElement +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Optional + +/** + * Merges `META-INF/NOTICE.TXT` files. + * + * Modified from `org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer.java` + * + * @author John Engelman + */ +public class ApacheNoticeResourceTransformer : Transformer { + private val entries = mutableSetOf() + private val organizationEntries = mutableMapOf>() + private val charset get() = if (encoding.isNullOrEmpty()) Charsets.UTF_8 else Charset.forName(encoding) + + /** + * MSHADE-101 :: NullPointerException when projectName is missing + */ + @Input + public var projectName: String = "" + + @Input + public var addHeader: Boolean = true + + @Input + public var preamble1: String = """ + // ------------------------------------------------------------------ + // NOTICE file corresponding to the section 4d of The Apache License, + // Version 2.0, in this case for + """.trimIndent() + + @Input + public var preamble2: String = "\n// ------------------------------------------------------------------\n" + + @Input + public var preamble3: String = "This product includes software developed at\n" + + @Input + public var organizationName: String = "The Apache Software Foundation" + + @Input + public var organizationURL: String = "http://www.apache.org/" + + @Input + public var inceptionYear: String = "2006" + + @Optional + @Input + public var copyright: String? = null + + /** + * The file encoding of the `NOTICE` file. + */ + @Optional + @Input + public var encoding: String? = null + + override fun canTransformResource(element: FileTreeElement): Boolean { + val path = element.relativePath.pathString + return NOTICE_PATH.equals(path, ignoreCase = true) || NOTICE_TXT_PATH.equals(path, ignoreCase = true) + } + + override fun transform(context: TransformerContext) { + if (entries.isEmpty()) { + val year = SimpleDateFormat("yyyy").format(Date()).let { + if (inceptionYear != it) "$inceptionYear-$it" else it + } + // add headers + if (addHeader) { + entries.add(preamble1 + projectName + preamble2) + } else { + entries.add("") + } + // fake second entry, we'll look for a real one later + entries.add("$projectName\nCopyright $year $organizationName\n") + entries.add("$preamble3$organizationName ($organizationURL).\n") + } + + val reader = requireNotNull(context.inputStream).bufferedReader(charset) + var line = reader.readLine() + val sb = StringBuffer() + var currentOrg: MutableSet? = null + var lineCount = 0 + while (line != null) { + val trimmedLine = line.trim() + if (!trimmedLine.startsWith("//")) { + if (trimmedLine.isNotEmpty()) { + if (trimmedLine.startsWith("- ")) { + // resource-bundle 1.3 mode + if (lineCount == 1 && sb.toString().contains("This product includes/uses software(s) developed by")) { + currentOrg = organizationEntries.getOrPut(sb.toString().trim()) { TreeSet() } + sb.setLength(0) + } else if (sb.isNotEmpty() && currentOrg != null) { + currentOrg.add(sb.toString()) + sb.setLength(0) + } + } + sb.append(line).append("\n") + lineCount++ + } else { + val ent = sb.toString() + if (ent.startsWith(projectName) && ent.contains("Copyright ")) { + copyright = ent + } + if (currentOrg == null) { + entries.add(ent) + } else { + currentOrg.add(ent) + } + sb.setLength(0) + lineCount = 0 + currentOrg = null + } + } + + line = reader.readLine() + } + if (sb.isNotEmpty()) { + if (currentOrg == null) { + entries.add(sb.toString()) + } else { + currentOrg.add(sb.toString()) + } + } + } + + override fun hasTransformedResource(): Boolean = true + + override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { + val zipEntry = ZipEntry(NOTICE_PATH) + zipEntry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, zipEntry.time) + os.putNextEntry(zipEntry) + + val writer = PrintWriter(os.writer(charset)) + + var count = 0 + for (line in entries) { + count++ + if (line == copyright && count != 2) { + continue + } + + if (count == 2 && copyright != null) { + writer.print(copyright) + writer.print('\n') + } else { + writer.print(line) + writer.print('\n') + } + if (count == 3) { + // do org stuff + for ((key, value) in organizationEntries) { + writer.print(key) + writer.print('\n') + for (l in value) { + writer.print(l) + } + writer.print('\n') + } + } + } + + writer.flush() + entries.clear() + } + + private companion object { + private const val NOTICE_PATH = "META-INF/NOTICE" + private const val NOTICE_TXT_PATH = "META-INF/NOTICE.txt" + } +} diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy deleted file mode 100644 index 3f894ce7a..000000000 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License") you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.github.jengelman.gradle.plugins.shadow.transformers - -import org.apache.tools.zip.ZipEntry -import org.apache.tools.zip.ZipOutputStream -import org.codehaus.plexus.util.StringUtils -import org.gradle.api.file.FileTreeElement -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.Optional - -import java.text.SimpleDateFormat - -/** - * Merges META-INF/NOTICE.TXT files. - *

- * Modified from org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer.java - * - * @author John Engelman - */ -class ApacheNoticeResourceTransformer implements Transformer { - - private Set entries = new LinkedHashSet() - - private Map> organizationEntries = new LinkedHashMap>() - - @Input - String projectName = "" // MSHADE-101 :: NullPointerException when projectName is missing - - @Input - boolean addHeader = true - - @Input - String preamble1 = "// ------------------------------------------------------------------\n" + - "// NOTICE file corresponding to the section 4d of The Apache License,\n" + - "// Version 2.0, in this case for " - - @Input - String preamble2 = "\n// ------------------------------------------------------------------\n" - - @Input - String preamble3 = "This product includes software developed at\n" - - @Input - String organizationName = "The Apache Software Foundation" - - @Input - String organizationURL = "http://www.apache.org/" - - @Input - String inceptionYear = "2006" - - @Optional - @Input - String copyright - - /** - * The file encoding of the NOTICE file. - */ - @Optional - @Input - String encoding - - private static final String NOTICE_PATH = "META-INF/NOTICE" - - private static final String NOTICE_TXT_PATH = "META-INF/NOTICE.txt" - - @Override - boolean canTransformResource(FileTreeElement element) { - def path = element.relativePath.pathString - if (NOTICE_PATH.equalsIgnoreCase(path) || NOTICE_TXT_PATH.equalsIgnoreCase(path)) { - return true - } - - return false - } - - @Override - void transform(TransformerContext context) { - if (entries.isEmpty()) { - String year = new SimpleDateFormat("yyyy").format(new Date()) - if (inceptionYear != year) { - year = inceptionYear + "-" + year - } - - //add headers - if (addHeader) { - entries.add(preamble1 + projectName + preamble2) - } else { - entries.add("") - } - //fake second entry, we'll look for a real one later - entries.add(projectName + "\nCopyright " + year + " " + organizationName + "\n") - entries.add(preamble3 + organizationName + " (" + organizationURL + ").\n") - } - - BufferedReader reader - if (StringUtils.isNotEmpty(encoding)) { - reader = new BufferedReader(new InputStreamReader(context.inputStream, encoding)) - } else { - reader = new BufferedReader(new InputStreamReader(context.inputStream)) - } - - String line = reader.readLine() - StringBuffer sb = new StringBuffer() - Set currentOrg = null - int lineCount = 0 - while (line != null) { - String trimedLine = line.trim() - - if (!trimedLine.startsWith("//")) { - if (trimedLine.length() > 0) { - if (trimedLine.startsWith("- ")) { - //resource-bundle 1.3 mode - if (lineCount == 1 - && sb.toString().indexOf("This product includes/uses software(s) developed by") != -1) { - currentOrg = organizationEntries.get(sb.toString().trim()) - if (currentOrg == null) { - currentOrg = new TreeSet() - organizationEntries.put(sb.toString().trim(), currentOrg) - } - sb = new StringBuffer() - } else if (sb.length() > 0 && currentOrg != null) { - currentOrg.add(sb.toString()) - sb = new StringBuffer() - } - - } - sb.append(line).append("\n") - lineCount++ - } else { - String ent = sb.toString() - if (ent.startsWith(projectName) && ent.indexOf("Copyright ") != -1) { - copyright = ent - } - if (currentOrg == null) { - entries.add(ent) - } else { - currentOrg.add(ent) - } - sb = new StringBuffer() - lineCount = 0 - currentOrg = null - } - } - - line = reader.readLine() - } - if (sb.length() > 0) { - if (currentOrg == null) { - entries.add(sb.toString()) - } else { - currentOrg.add(sb.toString()) - } - } - } - - @Override - boolean hasTransformedResource() { - return true - } - - @Override - void modifyOutputStream(ZipOutputStream os, boolean preserveFileTimestamps) { - ZipEntry zipEntry = new ZipEntry(NOTICE_PATH) - zipEntry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, zipEntry.time) - os.putNextEntry(zipEntry) - - Writer pow - if (StringUtils.isNotEmpty(encoding)) { - pow = new OutputStreamWriter(os, encoding) - } else { - pow = new OutputStreamWriter(os) - } - PrintWriter writer = new PrintWriter(pow) - - int count = 0 - for (String line : entries) { - ++count - if (line == copyright && count != 2) { - continue - } - - if (count == 2 && copyright != null) { - writer.print(copyright) - writer.print('\n') - } else { - writer.print(line) - writer.print('\n') - } - if (count == 3) { - //do org stuff - for (Map.Entry> entry : organizationEntries.entrySet()) { - writer.print(entry.getKey()) - writer.print('\n') - for (String l : entry.getValue()) { - writer.print(l) - } - writer.print('\n') - } - } - } - - writer.flush() - - entries.clear() - } -}