Skip to content

Commit b6928e5

Browse files
committed
Ensure main classes from .scala inputs take precedence before main classes found in JARs added to the classpath
1 parent c9c659c commit b6928e5

File tree

2 files changed

+46
-10
lines changed

2 files changed

+46
-10
lines changed

modules/build/src/main/scala/scala/build/Build.scala

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,14 @@ object Build {
5959
def outputOpt: Some[os.Path] = Some(output)
6060
def dependencyClassPath: Seq[os.Path] = sources.resourceDirs ++ artifacts.classPath
6161
def fullClassPath: Seq[os.Path] = Seq(output) ++ dependencyClassPath
62+
private lazy val mainClassesFoundInProject: Seq[String] = MainClass.find(output).sorted
63+
private lazy val mainClassesFoundOnExtraClasspath: Seq[String] =
64+
options.classPathOptions.extraClassPath.flatMap(MainClass.find).sorted
65+
private lazy val mainClassesFoundInUserExtraDependencies: Seq[String] =
66+
artifacts.jarsForUserExtraDependencies.flatMap(MainClass.findInDependency).sorted
6267
def foundMainClasses(): Seq[String] = {
63-
val found =
64-
MainClass.find(output).sorted ++
65-
options.classPathOptions.extraClassPath.flatMap(MainClass.find).sorted
66-
if (inputs.isEmpty && found.isEmpty)
67-
artifacts.jarsForUserExtraDependencies.flatMap(MainClass.findInDependency).sorted
68-
else found
68+
val found = mainClassesFoundInProject ++ mainClassesFoundOnExtraClasspath
69+
if inputs.isEmpty && found.isEmpty then mainClassesFoundInUserExtraDependencies else found
6970
}
7071
def retainedMainClass(
7172
mainClasses: Seq[String],
@@ -121,8 +122,11 @@ object Build {
121122
}
122123

123124
val filteredMainClasses =
124-
mainClasses.filter(!scriptInferredMainClasses.contains(_))
125-
if (filteredMainClasses.length == 1) {
125+
mainClasses
126+
.filterNot(scriptInferredMainClasses.contains(_))
127+
.filterNot(mainClassesFoundOnExtraClasspath.contains(_))
128+
.filterNot(mainClassesFoundInUserExtraDependencies.contains(_))
129+
if filteredMainClasses.length == 1 then {
126130
val pickedMainClass = filteredMainClasses.head
127131
if (scriptInferredMainClasses.nonEmpty) {
128132
val firstScript = scriptInferredMainClasses.head
@@ -139,8 +143,7 @@ object Build {
139143
}
140144
Right(pickedMainClass)
141145
}
142-
else
143-
Left(mainClasses)
146+
else Left(mainClasses)
144147
}
145148
def retainedMainClassOpt(
146149
mainClasses: Seq[String],

modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,4 +2303,37 @@ abstract class RunTestDefinitions
23032303
expect(res.out.trim() == expectedOutput)
23042304
}
23052305
}
2306+
2307+
test(
2308+
"prioritise main class in a .scala file over main classes in dependencies on the classpath"
2309+
) {
2310+
val expectedMessage = "Main"
2311+
TestInputs(
2312+
os.rel / "Main.scala" -> s"""object Main extends App { println("$expectedMessage") }"""
2313+
)
2314+
.fromRoot { root =>
2315+
val localCache = root / "local-cache"
2316+
val dependencyVersion = "42.7.4"
2317+
val csRes = os.proc(
2318+
TestUtil.cs,
2319+
"fetch",
2320+
"--cache",
2321+
localCache,
2322+
s"org.postgresql:postgresql:$dependencyVersion"
2323+
)
2324+
.call(cwd = root)
2325+
val dependencyJar = csRes.out.trim().linesIterator.toSeq.head
2326+
2327+
// pass classpath via -cp
2328+
val res = os.proc(TestUtil.cli, "run", ".", extraOptions, "-cp", dependencyJar)
2329+
.call(cwd = root)
2330+
expect(res.out.trim() == expectedMessage)
2331+
2332+
// pass classpath via args file
2333+
os.write(root / "args.txt", s"-cp $dependencyJar")
2334+
val res2 = os.proc(TestUtil.cli, "run", ".", extraOptions, "@args.txt")
2335+
.call(cwd = root)
2336+
expect(res2.out.trim() == expectedMessage)
2337+
}
2338+
}
23062339
}

0 commit comments

Comments
 (0)