/* * Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved. * * Licensed 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 * * https://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. */ import java.io.File import java.util.regex.Matcher import java.util.regex.Pattern import org.gradle.api.DefaultTask import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.FileVisitDetails import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction import org.gradle.kotlin.dsl.listProperty import org.gradle.kotlin.dsl.mapProperty open class MergeSourcesJars : DefaultTask() { @get:InputFiles val inputJars: ConfigurableFileCollection = project.objects.fileCollection() @get:InputFiles val mergedBinaryJars: ConfigurableFileCollection = project.objects.fileCollection() @get:Input val relocatedPackages: MapProperty = project.objects.mapProperty() @get:Input var sourceFileExtensions: ListProperty = project.objects.listProperty().convention(listOf(".java", ".kt")) @get:OutputFile val outputJar: RegularFileProperty = project.objects.fileProperty() @TaskAction @Suppress("unused") fun merge() { val binaryPaths = collectBinaryPaths() val relocatedPkgs = relocatedPackages.get() val relocatedPaths = relocatedPkgs.entries.associate { (key, value) -> toPath(key) to toPath(value) } // use negative lookbehind to match any that don't precede with // a word or a period character. should catch most cases. val importPattern = Pattern.compile( "(? { val result = mutableSetOf() for (jar in mergedBinaryJars) { // as of Gradle 2.4 doesn't visit dirs despite the claims project.zipTree(jar).visit { val details = this if (details.isDirectory) return@visit // avoid adding empty dirs result.add(details.relativePath.parent!!.pathString) } } return result } private fun fixImports( relocatedPkgs: Map, details: FileVisitDetails, sourceText: String, importPattern: Pattern, ): String { val matcher = importPattern.matcher(sourceText) val buffer = StringBuffer() logger.debug("Inspecting file: {}", details.relativePath) while (matcher.find()) { val newStat = relocatedPkgs[matcher.group(2)] logger.debug("Old: {}", matcher.group()) logger.debug("New: {}", newStat) matcher.appendReplacement(buffer, Matcher.quoteReplacement(newStat)) } matcher.appendTail(buffer) return buffer.toString() } private fun toPath(packageName: String): String = packageName.replace(".", "/") }