From 7846f800860d2d7ee68e589ee233643cbf4e332c Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Wed, 27 Nov 2024 15:37:03 +0100 Subject: [PATCH] Fix dependency main class detection throwing an NPE when JAR manifest doesn't list the main class correctly (#3319) --- .../scala/build/internal/MainClass.scala | 9 ++++---- .../cli/integration/RunTestDefinitions.scala | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/modules/build/src/main/scala/scala/build/internal/MainClass.scala b/modules/build/src/main/scala/scala/build/internal/MainClass.scala index 1faba2ae2a..ed46bbd61e 100644 --- a/modules/build/src/main/scala/scala/build/internal/MainClass.scala +++ b/modules/build/src/main/scala/scala/build/internal/MainClass.scala @@ -71,10 +71,11 @@ object MainClass { def findInDependency(jar: os.Path): Option[String] = jar match { case jar if os.isFile(jar) && jar.last.endsWith(".jar") => - val jarFile = new JarFile(jar.toIO) - val manifest = jarFile.getManifest() - val mainClass = manifest.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS) - Option(mainClass).map(_.asInstanceOf[String]) + for { + manifest <- Option(new JarFile(jar.toIO).getManifest) + mainAttributes <- Option(manifest.getMainAttributes) + mainClass: String <- Option(mainAttributes.getValue(Attributes.Name.MAIN_CLASS)) + } yield mainClass case _ => None } diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala index eebd4d5df3..07261cf347 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala @@ -2270,4 +2270,25 @@ abstract class RunTestDefinitions } } } + + if (actualScalaVersion.startsWith("3")) test( + "fail with a valid error when multiple main classes are present and a dependency doesn't define main classes in the manifest" + ) { + val (main1, main2) = "main1" -> "main2" + val input = "example.scala" + TestInputs( + os.rel / input -> + s"""//> using dep io.get-coursier:coursier_2.13:2.1.18 + |@main def $main1() = println("$main1") + |@main def $main2() = println("$main2") + |""".stripMargin + ).fromRoot { root => + val res = os.proc(TestUtil.cli, "run", input, extraOptions) + .call(cwd = root, stderr = os.Pipe, check = false) + val err = res.err.trim() + expect(err.contains("Found several main classes")) + expect(err.contains(main1)) + expect(err.contains(main2)) + } + } }