This is an automated email from the ASF dual-hosted git repository. jdaugherty pushed a commit to branch corrupt-jar-fixes in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 611227e8830380838109eebe629128421690faa4 Author: James Daugherty <[email protected]> AuthorDate: Thu May 15 16:27:25 2025 -0400 update find main class task and strictly validate the existence --- .../org/grails/io/support/MainClassFinder.groovy | 32 ++++---- .../gradle/plugin/core/GrailsGradlePlugin.groovy | 90 +++++++++++++++------- .../gradle/plugin/run/FindMainClassTask.groovy | 75 +++++++++++------- 3 files changed, 129 insertions(+), 68 deletions(-) diff --git a/grails-gradle/model/src/main/groovy/org/grails/io/support/MainClassFinder.groovy b/grails-gradle/model/src/main/groovy/org/grails/io/support/MainClassFinder.groovy index eadb7a006c..5c16d71a31 100644 --- a/grails-gradle/model/src/main/groovy/org/grails/io/support/MainClassFinder.groovy +++ b/grails-gradle/model/src/main/groovy/org/grails/io/support/MainClassFinder.groovy @@ -1,27 +1,29 @@ /* - * 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 + * 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 * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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. + * 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 org.grails.io.support import grails.util.BuildSettings import groovy.transform.CompileStatic -import groovyjarjarasm.asm.* +import groovyjarjarasm.asm.ClassReader +import groovyjarjarasm.asm.ClassVisitor +import groovyjarjarasm.asm.MethodVisitor +import groovyjarjarasm.asm.Opcodes +import groovyjarjarasm.asm.Type import java.nio.file.Paths import java.util.concurrent.ConcurrentHashMap diff --git a/grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/core/GrailsGradlePlugin.groovy b/grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/core/GrailsGradlePlugin.groovy index 89b9cf6424..c44253a4c4 100644 --- a/grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/core/GrailsGradlePlugin.groovy +++ b/grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/core/GrailsGradlePlugin.groovy @@ -1,20 +1,18 @@ /* - * 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 + * 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 * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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. + * 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 org.grails.gradle.plugin.core @@ -28,7 +26,11 @@ import io.spring.gradle.dependencymanagement.DependencyManagementPlugin import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension import org.apache.tools.ant.filters.EscapeUnicode import org.apache.tools.ant.filters.ReplaceTokens -import org.gradle.api.* +import org.gradle.api.Action +import org.gradle.api.NamedDomainObjectProvider +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.Task import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.DependencyResolveDetails @@ -39,7 +41,12 @@ import org.gradle.api.file.RegularFile import org.gradle.api.plugins.ExtraPropertiesExtension import org.gradle.api.plugins.GroovyPlugin import org.gradle.api.provider.Provider -import org.gradle.api.tasks.* +import org.gradle.api.tasks.AbstractCopyTask +import org.gradle.api.tasks.JavaExec +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.SourceSetOutput +import org.gradle.api.tasks.TaskContainer +import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.compile.GroovyCompile import org.gradle.api.tasks.testing.Test import org.gradle.language.jvm.tasks.ProcessResources @@ -54,7 +61,10 @@ import org.grails.gradle.plugin.run.FindMainClassTask import org.grails.gradle.plugin.util.SourceSets import org.grails.io.support.FactoriesLoaderSupport import org.springframework.boot.gradle.dsl.SpringBootExtension +import org.springframework.boot.gradle.plugin.ResolveMainClassName import org.springframework.boot.gradle.plugin.SpringBootPlugin +import org.springframework.boot.gradle.tasks.bundling.BootArchive +import org.springframework.boot.gradle.tasks.run.BootRun import javax.inject.Inject @@ -342,13 +352,12 @@ class GrailsGradlePlugin extends GroovyPlugin { protected void configureMicronaut(Project project) { final String micronautVersion = project.properties['micronautVersion'] if (micronautVersion) { - project.configurations.all({ Configuration configuration -> + project.configurations.configureEach({ Configuration configuration -> configuration.resolutionStrategy.eachDependency({ DependencyResolveDetails details -> String dependencyName = details.requested.name String group = details.requested.group if (group == 'io.micronaut' && dependencyName.startsWith('micronaut')) { details.useVersion(micronautVersion) - return } } as Action<DependencyResolveDetails>) } as Action<Configuration>) @@ -533,6 +542,11 @@ class GrailsGradlePlugin extends GroovyPlugin { protected void configureConsoleTask(Project project) { TaskContainer tasks = project.tasks if (!project.configurations.names.contains('console')) { + if (!tasks.names.contains('findMainClass')) { + project.logger.info("Project ${project.name} does not contain the findMainClass task so the console & shell tasks will not be created.") + return + } + NamedDomainObjectProvider<Configuration> consoleConfiguration = project.configurations.register('console') def consoleTask = createConsoleTask(project, tasks, consoleConfiguration) def shellTask = createShellTask(project, tasks, consoleConfiguration) @@ -540,6 +554,10 @@ class GrailsGradlePlugin extends GroovyPlugin { tasks.named('findMainClass').configure { it.doLast { ExtraPropertiesExtension extraProperties = (ExtraPropertiesExtension) project.getExtensions().getByName("ext") + if (!extraProperties.has('mainClassName')) { + return // disabled because we don't expect to run a grails app (likely a plugin) + } + def mainClassName = extraProperties.get('mainClassName') if (mainClassName) { consoleTask.get().args mainClassName @@ -597,14 +615,34 @@ class GrailsGradlePlugin extends GroovyPlugin { protected void registerFindMainClassTask(Project project) { TaskContainer taskContainer = project.tasks - def findMainClassTask = taskContainer.findByName("findMainClass") - if (findMainClassTask == null) { - findMainClassTask = project.tasks.register("findMainClass", FindMainClassTask).get() - findMainClassTask.mustRunAfter(project.tasks.withType(GroovyCompile)) - } else if (!FindMainClassTask.class.isAssignableFrom(findMainClassTask.class)) { - def grailsFindMainClass = project.tasks.register("grailsFindMainClass", FindMainClassTask).get() - grailsFindMainClass.dependsOn(findMainClassTask) - findMainClassTask.finalizedBy(grailsFindMainClass) + + def existingTask = taskContainer.findByName("findMainClass") + if (existingTask == null) { + TaskProvider<FindMainClassTask> findMainClassTask = project.tasks.register("findMainClass", FindMainClassTask) + + Provider<RegularFile> mainClassFileContainer = project.layout.buildDirectory.file('resolvedMainClassName') + Provider<String> mainClassProvider = project.providers.fileContents(mainClassFileContainer).asText.map { + it.trim() + } + project.tasks.withType(BootArchive).configureEach { BootArchive bootTask -> + bootTask.dependsOn(findMainClassTask) + bootTask.inputs.file(mainClassFileContainer) + bootTask.mainClass.convention(mainClassProvider) + } + project.tasks.withType(BootRun).configureEach { BootRun it -> + it.dependsOn(findMainClassTask) + it.inputs.file(mainClassFileContainer) + it.mainClass.convention(mainClassProvider) + } + + findMainClassTask.configure { + it.mustRunAfter(project.tasks.withType(GroovyCompile)) + } + project.tasks.withType(ResolveMainClassName).configureEach { + it.dependsOn findMainClassTask + } + } else if (!FindMainClassTask.class.isAssignableFrom(existingTask.class)) { + project.logger.warn("Grails Projects typically register a findMainClass task to force the MainClass resolution for Spring Boot. This task already exists so this will not occur.") } } diff --git a/grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/run/FindMainClassTask.groovy b/grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/run/FindMainClassTask.groovy index 1e42fd9961..79713f75ff 100644 --- a/grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/run/FindMainClassTask.groovy +++ b/grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/run/FindMainClassTask.groovy @@ -1,20 +1,18 @@ /* - * 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 + * 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 * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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. + * 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 org.grails.gradle.plugin.run @@ -25,10 +23,18 @@ import org.gradle.api.file.FileCollection import org.gradle.api.file.RegularFile import org.gradle.api.plugins.ExtraPropertiesExtension import org.gradle.api.provider.Provider -import org.gradle.api.tasks.* +import org.gradle.api.tasks.CacheableTask +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.SourceSetOutput +import org.gradle.api.tasks.TaskAction import org.grails.gradle.plugin.util.SourceSets import org.grails.io.support.MainClassFinder -import org.springframework.boot.gradle.tasks.run.BootRun +import org.springframework.boot.gradle.dsl.SpringBootExtension +import org.springframework.boot.gradle.plugin.SpringBootPlugin /** * A task that finds the main task, differs slightly from Boot's version as expects a subclass of GrailsConfiguration @@ -43,14 +49,29 @@ class FindMainClassTask extends DefaultTask { @TaskAction void setMainClassProperty() { Project project = this.project - if(project.tasks.names.contains('bootRun')) { - BootRun bootRun = project.tasks.named("bootRun", BootRun).get() - String mainClass = findMainClass() - if (mainClass != null) { - bootRun.mainClass.set(mainClass) - ExtraPropertiesExtension extraProperties = (ExtraPropertiesExtension) project.getExtensions().getByName("ext") - extraProperties.set("mainClassName", mainClass) - } + + def bootRunTask = project.tasks.findByName('bootRun') + if (!bootRunTask || !bootRunTask.enabled) { + project.logger.info('The bootRun task will not so this must not be a runnable grails application. Skipping finding main class.') + return + } + + def bootJarTask = project.tasks.findByName(SpringBootPlugin.BOOT_JAR_TASK_NAME) + def bootWarTask = project.tasks.findByName(SpringBootPlugin.BOOT_WAR_TASK_NAME) + if ((!bootJarTask || !bootJarTask.enabled) && (!bootWarTask || !bootWarTask.enabled)) { + project.logger.info("There is neither a ${SpringBootPlugin.BOOT_JAR_TASK_NAME} or ${SpringBootPlugin.BOOT_WAR_TASK_NAME} task that will run. Skipping finding main Application class.") + return + } + + String mainClass = findMainClass() + if (mainClass) { + ExtraPropertiesExtension extraProperties = (ExtraPropertiesExtension) project.getExtensions().getByName('ext') + extraProperties.set('mainClassName', mainClass) + + SpringBootExtension springBootExtension = project.getExtensions().getByType(SpringBootExtension) + springBootExtension.mainClass.convention(mainClass) + } else { + project.logger.warn("No main class found. Please set 'springBoot.mainClass'.") } } @@ -67,7 +88,7 @@ class FindMainClassTask extends DefaultTask { @OutputFile Provider<RegularFile> getMainClassCacheFile() { - project.layout.buildDirectory.file('.mainClass') + project.layout.buildDirectory.file('resolvedMainClassName') } protected String findMainClass() { @@ -103,7 +124,7 @@ class FindMainClassTask extends DefaultTask { if (mainClass != null) { mainClassFile.text = mainClass } else { - throw new RuntimeException("Could not find Application main class. Please set 'springBoot.mainClass'.") + throw new RuntimeException("Could not find Application main class. Please set 'springBoot.mainClass' or disable BootJar & BootArchive tasks.") } } return mainClass @@ -111,7 +132,7 @@ class FindMainClassTask extends DefaultTask { } protected FileCollection resolveClassesDirs(SourceSetOutput output, Project project) { - output?.classesDirs ?: project.files(new File(project.buildDir, "classes/main")) + output?.classesDirs ?: project.files(new File(project.buildDir, 'classes/main')) } protected MainClassFinder createMainClassFinder() {
