Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(grailsbootstrap): update main-class finder #13472

Merged
merged 1 commit into from
Apr 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ package org.grails.io.support

import grails.util.BuildSettings
import groovy.transform.CompileStatic
import groovy.transform.Memoized
import groovyjarjarasm.asm.ClassReader
import groovyjarjarasm.asm.ClassVisitor
import groovyjarjarasm.asm.MethodVisitor
import groovyjarjarasm.asm.Opcodes
import groovyjarjarasm.asm.Type
import groovyjarjarasm.asm.*

import java.nio.file.Paths
import java.util.concurrent.ConcurrentHashMap
Expand All @@ -26,6 +21,7 @@ class MainClassFinder {
private static final String MAIN_METHOD_NAME = "main"

static final Map<String, String> mainClasses = new ConcurrentHashMap<>()
public static final String ROOT_FOLDER_PATH = "build/classes/main"

/**
* Searches for the main class relative to the give path that is within the project tree
Expand All @@ -40,7 +36,7 @@ class MainClassFinder {
}

def pathStr = path.toString()
if(mainClasses.containsKey(pathStr)) {
if (mainClasses.containsKey(pathStr)) {
return mainClasses.get(pathStr)
}

Expand All @@ -56,9 +52,9 @@ class MainClassFinder {
searchDirs = [classesDir]
}

if(rootDir) {
if (rootDir) {
def rootClassesDir = new File(rootDir, BuildSettings.BUILD_CLASSES_PATH)
if(rootClassesDir.exists()) {
if (rootClassesDir.exists()) {
searchDirs << rootClassesDir
}

Expand All @@ -74,7 +70,7 @@ class MainClassFinder {
mainClass = findMainClass(dir)
if (mainClass) break
}
if(mainClass != null) {
if (mainClass != null) {
mainClasses.put(pathStr, mainClass)
}
return mainClass
Expand All @@ -84,14 +80,13 @@ class MainClassFinder {
}

private static File findRootDirectory(File file) {
if(file) {
if (file) {
def parent = file.parentFile

while(parent != null) {
if(new File(parent, "build.gradle").exists() || new File(parent, "grails-app").exists()) {
while (parent != null) {
if (new File(parent, "build.gradle").exists() || new File(parent, "grails-app").exists()) {
return parent
}
else {
} else {
parent = parent.parentFile
}
}
Expand All @@ -100,63 +95,59 @@ class MainClassFinder {
}

static String findMainClass(File rootFolder = BuildSettings.CLASSES_DIR) {
if( rootFolder == null) {
if (rootFolder == null) {
// try current directory
rootFolder = new File("build/classes/main")
rootFolder = new File(ROOT_FOLDER_PATH)
}


def rootFolderPath = rootFolder.canonicalPath
if(mainClasses.containsKey(rootFolderPath)) {
return mainClasses.get(rootFolderPath)
}

if (!rootFolder.exists()) {
return null // nothing to do
}

if (!rootFolder.isDirectory()) {
throw new IllegalArgumentException("Invalid root folder '$rootFolder'")
}
String prefix = "${rootFolderPath}/"
def stack = new ArrayDeque<File>()

final String rootFolderCanonicalPath = rootFolder.canonicalPath
if (mainClasses.containsKey(rootFolderCanonicalPath)) {
return mainClasses.get(rootFolderCanonicalPath)
}
ArrayDeque<File> stack = new ArrayDeque<>()
stack.push rootFolder

while (!stack.empty) {
File file = stack.pop()
final File file = stack.pop()
if (file.isFile()) {
InputStream inputStream = file.newInputStream()
try {
def classReader = new ClassReader(inputStream)

if (isMainClass(classReader)) {
def mainClassName = classReader.getClassName().replace('/', '.').replace('\\', '.')
mainClasses.put(rootFolderPath, mainClassName)
mainClasses.put(rootFolderCanonicalPath, mainClassName)
return mainClassName
}
} finally {
inputStream?.close()
}
}
if (file.isDirectory()) {
def files = file.listFiles()?.findAll { File f ->
(f.isDirectory() && !f.name.startsWith('.') && !f.hidden) ||
(f.isFile() && f.name.endsWith(GrailsResourceUtils.CLASS_EXTENSION))
}

if(files) {
for(File sub in files) {
stack.push(sub)
}
}

Arrays.stream(file.listFiles())
.filter(MainClassFinder::isClassFile)
.forEach(stack::push)
}
}
return null
}

protected static boolean isClassFile(File f) {
(f.isDirectory() && !f.name.startsWith('.') && !f.hidden) ||
(f.isFile() && f.name.endsWith(GrailsResourceUtils.CLASS_EXTENSION))
}


protected static boolean isMainClass(ClassReader classReader) {
if(classReader.superName?.startsWith('grails/boot/config/')) {
if (classReader.superName?.startsWith('grails/boot/config/')) {
def mainMethodFinder = new MainMethodFinder()
classReader.accept(mainMethodFinder, ClassReader.SKIP_CODE)
return mainMethodFinder.found
Expand All @@ -165,7 +156,7 @@ class MainClassFinder {
}

@CompileStatic
static class MainMethodFinder extends ClassVisitor {
static class MainMethodFinder extends ClassVisitor {

boolean found = false

Expand All @@ -175,7 +166,7 @@ class MainClassFinder {

@Override
MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if(!found) {
if (!found) {
if (isAccess(access, Opcodes.ACC_PUBLIC, Opcodes.ACC_STATIC)
&& MAIN_METHOD_NAME.equals(name)
&& MAIN_METHOD_TYPE.getDescriptor().equals(desc)) {
Expand All @@ -188,7 +179,7 @@ class MainClassFinder {
}


private boolean isAccess(int access, int... requiredOpsCodes) {
private boolean isAccess(int access, int ... requiredOpsCodes) {
return !requiredOpsCodes.any { int requiredOpsCode -> (access & requiredOpsCode) == 0 }
}
}
Expand Down
Loading