Skip to content

Commit 5f47bfd

Browse files
Merge pull request #13029 from philwalk/fail-if-scalac-not-found-fixes-12962
fail verifyScalacArgs if dist/target/pack/bin/scalac not found - fix for #12962
2 parents b13f37a + 4a875e5 commit 5f47bfd

File tree

2 files changed

+119
-62
lines changed

2 files changed

+119
-62
lines changed

compiler/test-resources/scripting/scriptPath.sc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@
22

33
def main(args: Array[String]): Unit =
44
args.zipWithIndex.foreach { case (arg,i) => printf("arg %d: [%s]\n",i,arg) }
5-
val path = Option(sys.props("script.path")) match {
6-
case None => printf("no script.path property is defined\n")
5+
6+
Option(sys.props("script.path")) match {
77
case Some(path) =>
8-
printf("script.path: %s\n",path)
9-
assert(path.endsWith("scriptPath.sc"),s"actual path [$path]")
8+
if ! path.endsWith("scriptPath.sc") then
9+
printf( s"incorrect script.path defined as [$path]")
10+
else
11+
printf("script.path: %s\n",path) // report the value
12+
case None =>
13+
printf("no script.path property is defined\n")
14+
// report relevant environment factors that might explain the error
15+
val psep: String = Option(sys.props("path.separator")).get
16+
val pathEntries = System.getenv("PATH").split(psep).toList
17+
System.err.printf("sun.java.command: %s\n", sys.props("sun.java.command"))
18+
System.err.printf("first 5 PATH entries:\n%s\n",pathEntries.take(5).mkString("\n"))
1019
}

compiler/test/dotty/tools/scripting/BashScriptsTests.scala

Lines changed: 106 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import org.junit.Test
1010

1111
import vulpix.TestConfiguration
1212

13+
import dotty.tools.dotc.config.Properties._
1314

1415
/** Verifies correct handling of command line arguments by `dist/bin/scala` and `dist/bin/scalac`.
1516
* +. arguments following a script path must be treated as script arguments
@@ -19,6 +20,13 @@ class BashScriptsTests:
1920
// classpath tests managed by scripting.ClasspathTests.scala
2021
def testFiles = scripts("/scripting")
2122

23+
printf("osname[%s]\n", osname)
24+
printf("using JAVA_HOME=%s\n", javaHome)
25+
printf("using SCALA_HOME=%s\n", scalaHome)
26+
printf("first 5 PATH entries:\n%s\n", pathEntries.take(5).mkString("\n"))
27+
printf("scala path: [%s]\n", scalaPath)
28+
printf("scalac path: [%s]\n", scalacPath)
29+
2230
lazy val expectedOutput = List(
2331
"arg 0:[a]",
2432
"arg 1:[b]",
@@ -31,65 +39,52 @@ class BashScriptsTests:
3139
lazy val testScriptArgs = Seq(
3240
"a", "b", "c", "-repl", "-run", "-script", "-debug"
3341
)
34-
lazy val (bashExe, bashPath) =
35-
val bexe = getBashPath
36-
val bpath = Paths.get(bexe)
37-
// printf("bashExe: [%s]\n", bexe)
38-
(bexe, bpath)
39-
4042
val showArgsScript = testFiles.find(_.getName == "showArgs.sc").get.absPath
4143

42-
val scalacPath = "dist/target/pack/bin/scalac" // which("scalac")
43-
val scalaPath = "dist/target/pack/bin/scala" // which("scala")
44-
45-
/* verify `dist/bin/scalac` */
44+
/* verify `dist/bin/scalac` non-interference with command line args following script name */
4645
@Test def verifyScalacArgs =
47-
printf("scalacPath[%s]\n", scalacPath)
4846
val commandline = (Seq(scalacPath, "-script", showArgsScript) ++ testScriptArgs).mkString(" ")
49-
if bashPath.toFile.exists then
50-
var cmd = Array(bashExe, "-c", commandline)
51-
val output = Process(cmd).lazyLines_!
47+
val (validTest, exitCode, stdout, stderr) = bashCommand(commandline)
48+
if validTest then
5249
var fail = false
5350
printf("\n")
54-
for (line, expect) <- output zip expectedOutput do
51+
for (line, expect) <- stdout zip expectedOutput do
5552
printf("expected: %-17s\nactual : %s\n", expect, line)
5653
if line != expect then
5754
fail = true
5855

5956
if fail then
60-
assert(output == expectedOutput)
57+
assert(stdout == expectedOutput)
6158

62-
/* verify `dist/bin/scala` */
59+
/* verify `dist/bin/scala` non-interference with command line args following script name */
6360
@Test def verifyScalaArgs =
6461
val commandline = (Seq(scalaPath, showArgsScript) ++ testScriptArgs).mkString(" ")
65-
if bashPath.toFile.exists then
66-
var cmd = Array(bashExe, "-c", commandline)
67-
val output = for {
68-
line <- Process(cmd).lazyLines_!
69-
} yield line
62+
val (validTest, exitCode, stdout, stderr) = bashCommand(commandline)
63+
if validTest then
7064
var fail = false
7165
printf("\n")
7266
var mismatches = List.empty[(String, String)]
73-
for (line, expect) <- output zip expectedOutput do
67+
for (line, expect) <- stdout zip expectedOutput do
7468
printf("expected: %-17s\nactual : %s\n", expect, line)
7569
if line != expect then
7670
fail = true
7771

7872
if fail then
79-
assert(output == expectedOutput)
73+
assert(stdout == expectedOutput)
8074

8175
/*
82-
* verify that scriptPath.sc sees a valid script.path property.
76+
* verify that scriptPath.sc sees a valid script.path property,
77+
* and that it's value is the path to "scriptPath.sc".
8378
*/
8479
@Test def verifyScriptPathProperty =
8580
val scriptFile = testFiles.find(_.getName == "scriptPath.sc").get
8681
val expected = s"/${scriptFile.getName}"
8782
printf("===> verify valid system property script.path is reported by script [%s]\n", scriptFile.getName)
88-
val (exitCode, stdout, stderr) = bashCommand(scriptFile.absPath)
89-
if exitCode == 0 && ! stderr.exists(_.contains("Permission denied")) then
90-
// var cmd = Array(bashExe, "-c", scriptFile.absPath)
91-
// val stdout = Process(cmd).lazyLines_!
92-
stdout.foreach { printf("######### [%s]\n", _) }
83+
printf("calling scriptFile: %s\n", scriptFile)
84+
val (validTest, exitCode, stdout, stderr) = bashCommand(scriptFile.absPath)
85+
if validTest then
86+
stdout.foreach { printf("stdout: [%s]\n", _) }
87+
stderr.foreach { printf("stderr: [%s]\n", _) }
9388
val valid = stdout.exists { _.endsWith(expected) }
9489
if valid then printf("# valid script.path reported by [%s]\n", scriptFile.getName)
9590
assert(valid, s"script ${scriptFile.absPath} did not report valid script.path value")
@@ -99,58 +94,111 @@ class BashScriptsTests:
9994
*/
10095
@Test def verifyScalaOpts =
10196
val scriptFile = testFiles.find(_.getName == "classpathReport.sc").get
102-
printf("===> verify valid system property script.path is reported by script [%s]\n", scriptFile.getName)
103-
val argsfile = createArgsFile() // avoid problems caused by drive letter
97+
printf("===> verify SCALA_OPTS='@argsfile' is properly handled by `dist/bin/scala`\n")
10498
val envPairs = List(("SCALA_OPTS", s"@$argsfile"))
105-
val (exitCode, stdout, stderr) = bashCommand(scriptFile.absPath, envPairs:_*)
106-
if exitCode != 0 || stderr.exists(_.contains("Permission denied")) then
107-
stderr.foreach { System.err.printf("stderr [%s]\n", _) }
108-
printf("unable to execute script, return value is %d\n", exitCode)
109-
else
110-
// val stdout: Seq[String] = Process(cmd, cwd, envPairs:_*).lazyLines_!.toList
111-
val expected = s"${cwd.toString}"
99+
val (validTest, exitCode, stdout, stderr) = bashCommand(scriptFile.absPath, envPairs)
100+
if validTest then
101+
val expected = s"${workingDirectory.toString}"
112102
val List(line1: String, line2: String) = stdout.take(2)
113103
val valid = line2.dropWhile( _ != ' ').trim.startsWith(expected)
114-
if valid then printf(s"\n===> success: classpath begins with %s, as reported by [%s]\n", cwd, scriptFile.getName)
104+
if valid then printf(s"\n===> success: classpath begins with %s, as reported by [%s]\n", workingDirectory, scriptFile.getName)
115105
assert(valid, s"script ${scriptFile.absPath} did not report valid java.class.path first entry")
116106

117-
lazy val cwd = Paths.get(dotty.tools.dotc.config.Properties.userDir).toFile
107+
def existingPath: String = envOrElse("PATH","").norm
108+
def adjustedPath = s"$javaHome/bin$psep$scalaHome/bin$psep$existingPath"
109+
def pathEntries = adjustedPath.split(psep).toList
118110

111+
lazy val argsfile = createArgsFile() // avoid problems caused by drive letter
119112
def createArgsFile(): String =
120113
val utfCharset = java.nio.charset.StandardCharsets.UTF_8.name
121-
val text = s"-classpath ${cwd.absPath}"
122114
val path = Files.createTempFile("scriptingTest", ".args")
115+
val text = s"-classpath ${workingDirectory.absPath}"
123116
Files.write(path, text.getBytes(utfCharset))
124117
path.toFile.getAbsolutePath.replace('\\', '/')
125118

126-
extension (str: String) def dropExtension: String =
127-
str.reverse.dropWhile(_ != '.').drop(1).reverse
119+
def fixHome(s: String): String =
120+
s.startsWith("~") match {
121+
case false => s
122+
case true => s.replaceFirst("~",userHome)
123+
}
124+
125+
extension(s: String) {
126+
def toPath: Path = Paths.get(fixHome(s)) // .toAbsolutePath
127+
def toFile: File = s.toPath.toFile
128+
def absPath: String = s.toFile.absPath
129+
def norm: String = s.replace('\\', '/') // bash expects forward slash
130+
def isFile: Boolean = s.toFile.isFile
131+
def exists: Boolean = s.toPath.toFile.exists
132+
def name: String = s.toFile.getName
133+
def dropExtension: String = s.reverse.dropWhile(_ != '.').drop(1).reverse
134+
}
135+
136+
extension(p: Path) {
137+
def listFiles: Seq[File] = p.toFile.listFiles.toList
138+
def norm: String = p.normalize.toString.replace('\\', '/')
139+
def name: String = p.toFile.getName
140+
}
141+
142+
extension(f: File) {
143+
def name = f.getName
144+
def norm: String = f.toPath.normalize.norm
145+
def absPath: String = f.getAbsolutePath.norm
146+
}
147+
148+
lazy val psep: String = propOrElse("path.separator","")
149+
lazy val osname = propOrElse("os.name", "").toLowerCase
150+
151+
lazy val scalacPath = s"$workingDirectory/dist/target/pack/bin/scalac".norm
152+
lazy val scalaPath = s"$workingDirectory/dist/target/pack/bin/scala".norm
128153

129-
extension(f: File) def absPath: String =
130-
f.getAbsolutePath.replace('\\', '/')
154+
// use optional working directory TEST_CWD, if defined
155+
lazy val workingDirectory: String = envOrElse("TEST_CWD", userDir)
131156

132-
lazy val osname = Option(sys.props("os.name")).getOrElse("").toLowerCase
157+
// use optional TEST_BASH if defined, otherwise, bash must be in PATH
158+
lazy val bashExe: String = envOrElse("TEST_BASH", whichBash)
133159

134-
def getBashPath: String =
160+
// test env SCALA_HOME is:
161+
// dist/target/pack, if present
162+
// else, SCALA_HOME if defined
163+
// else, not defined
164+
lazy val scalaHome =
165+
if scalacPath.isFile then scalacPath.replaceAll("/bin/scalac","")
166+
else envOrElse("SCALA_HOME", "").norm
167+
168+
lazy val javaHome = envOrElse("JAVA_HOME", "").norm
169+
170+
lazy val testEnvPairs = List(
171+
("JAVA_HOME", javaHome),
172+
("SCALA_HOME", scalaHome),
173+
("PATH", adjustedPath),
174+
).filter { case (name,valu) => valu.nonEmpty }
175+
176+
lazy val whichBash: String =
135177
var whichBash = ""
136-
//printf("osname[%s]\n", osname)
137178
if osname.startsWith("windows") then
138179
whichBash = which("bash.exe")
139180
else
140181
whichBash = which("bash")
141182

142183
whichBash
143184

144-
def bashCommand(cmdstr: String, envPairs: (String, String)*): (Int, Seq[String], Seq[String]) = {
145-
import scala.sys.process._
146-
val cmd = Seq(bashExe, "-c", cmdstr)
147-
val proc = Process(cmd, None, envPairs *)
185+
def bashCommand(cmdstr: String, additionalEnvPairs:List[(String, String)] = Nil): (Boolean, Int, Seq[String], Seq[String]) = {
148186
var (stdout, stderr) = (List.empty[String], List.empty[String])
149-
val exitVal = proc ! ProcessLogger (
150-
(out: String) => stdout ::= out,
151-
(err: String) => stderr ::= err
152-
)
153-
(exitVal, stdout.reverse, stderr.reverse)
187+
if bashExe.toFile.exists then
188+
val cmd = Seq(bashExe, "-c", cmdstr)
189+
val envPairs = testEnvPairs ++ additionalEnvPairs
190+
val proc = Process(cmd, None, envPairs *)
191+
val exitVal = proc ! ProcessLogger (
192+
(out: String) => stdout ::= out,
193+
(err: String) => stderr ::= err
194+
)
195+
val validTest = exitVal == 0 && ! stderr.exists(_.contains("Permission denied"))
196+
if ! validTest then
197+
printf("\nunable to execute script, return value is %d\n", exitVal)
198+
stderr.foreach { System.err.printf("stderr [%s]\n", _) }
199+
(validTest, exitVal, stdout.reverse, stderr.reverse)
200+
else
201+
(false, -1, Nil, Nil)
154202
}
155203

156204
def execCmd(command: String, options: String *): Seq[String] =

0 commit comments

Comments
 (0)