All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.build.internal.MainClass.scala Maven / Gradle / Ivy

package scala.build.internal

import org.objectweb.asm
import org.objectweb.asm.ClassReader

import java.io.{ByteArrayInputStream, InputStream}
import java.util.zip.ZipEntry

import scala.build.input.Element
import scala.build.internal.zip.WrappedZipInputStream

object MainClass {

  private def stringArrayDescriptor = "([Ljava/lang/String;)V"

  private class MainMethodChecker extends asm.ClassVisitor(asm.Opcodes.ASM9) {
    private var foundMainClass = false
    private var nameOpt        = Option.empty[String]
    def found: Boolean         = foundMainClass
    override def visit(
      version: Int,
      access: Int,
      name: String,
      signature: String,
      superName: String,
      interfaces: Array[String]
    ): Unit = {
      nameOpt = Some(name.replace('/', '.').replace('\\', '.'))
    }
    override def visitMethod(
      access: Int,
      name: String,
      descriptor: String,
      signature: String,
      exceptions: Array[String]
    ): asm.MethodVisitor = {
      def isStatic = (access & asm.Opcodes.ACC_STATIC) != 0
      if (name == "main" && descriptor == stringArrayDescriptor && isStatic)
        foundMainClass = true
      null
    }
    def mainClassOpt: Option[String] =
      if (foundMainClass) nameOpt else None
  }

  def findInClass(path: os.Path): Iterator[String] =
    findInClass(os.read.inputStream(path))
  def findInClass(is: InputStream): Iterator[String] =
    try {
      val reader  = new ClassReader(is)
      val checker = new MainMethodChecker
      reader.accept(checker, 0)
      checker.mainClassOpt.iterator
    }
    finally is.close()

  def findInJar(path: os.Path): Iterator[String] = {
    val content        = os.read.bytes(path)
    val jarInputStream = WrappedZipInputStream.create(new ByteArrayInputStream(content))
    jarInputStream.entries().flatMap(ent =>
      if !ent.isDirectory && ent.getName.endsWith(".class") then {
        val content     = jarInputStream.readAllBytes()
        val inputStream = new ByteArrayInputStream(content)
        findInClass(inputStream)
      }
      else Iterator.empty
    )
  }

  def find(output: os.Path): Seq[String] =
    output match {
      case o if os.isFile(o) && o.last.endsWith(".class") =>
        findInClass(o).toVector
      case o if os.isFile(o) && o.last.endsWith(".jar") =>
        findInJar(o).toVector
      case o if os.isDir(o) =>
        os.walk(o)
          .iterator
          .filter(os.isFile)
          .flatMap {
            case classFilePath if classFilePath.last.endsWith(".class") =>
              findInClass(classFilePath)
            case _ => Iterator.empty
          }
          .toVector
      case _ => Vector.empty
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy