From 6d06661b3d4a10db21224c9f5b0509d52c9e53e1 Mon Sep 17 00:00:00 2001 From: rochala Date: Tue, 5 Jul 2022 17:20:22 +0200 Subject: [PATCH 1/9] fix exit codes --- .../src/dotty/tools/MainGenericRunner.scala | 55 +++++++++++-------- .../dotty/tools/scripting/StringDriver.scala | 7 ++- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index 1dcab2d92a96..3f5065370599 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -118,21 +118,21 @@ object MainGenericRunner { @sharable val scalaOption = raw"""@.*""".r @sharable val colorOption = raw"""-color:.*""".r @tailrec - def process(args: List[String], settings: Settings): Settings = args match + def processArgs(args: List[String], settings: Settings): Settings = args match case Nil => settings case "-run" :: fqName :: tail => - process(tail, settings.withExecuteMode(ExecuteMode.Run).withTargetToRun(fqName)) + processArgs(tail, settings.withExecuteMode(ExecuteMode.Run).withTargetToRun(fqName)) case ("-cp" | "-classpath" | "--class-path") :: cp :: tail => val (tailargs, newEntries) = processClasspath(cp, tail) - process(tailargs, settings.copy(classPath = settings.classPath ++ newEntries.filter(_.nonEmpty))) + processArgs(tailargs, settings.copy(classPath = settings.classPath ++ newEntries.filter(_.nonEmpty))) case ("-version" | "--version") :: _ => settings.copy( executeMode = ExecuteMode.Repl, residualArgs = List("-version") ) case ("-v" | "-verbose" | "--verbose") :: tail => - process( + processArgs( tail, settings.copy( verbose = true, @@ -140,18 +140,18 @@ object MainGenericRunner { ) ) case "-save" :: tail => - process(tail, settings.withSave) + processArgs(tail, settings.withSave) case "-nosave" :: tail => - process(tail, settings.noSave) + processArgs(tail, settings.noSave) case "-with-compiler" :: tail => - process(tail, settings.withCompiler) + processArgs(tail, settings.withCompiler) case (o @ javaOption(striped)) :: tail => - process(tail, settings.withJavaArgs(striped).withScalaArgs(o)) + processArgs(tail, settings.withJavaArgs(striped).withScalaArgs(o)) case (o @ scalaOption(_*)) :: tail => val remainingArgs = (CommandLineParser.expandArg(o) ++ tail).toList - process(remainingArgs, settings) + processArgs(remainingArgs, settings) case (o @ colorOption(_*)) :: tail => - process(tail, settings.withScalaArgs(o)) + processArgs(tail, settings.withScalaArgs(o)) case "-e" :: expression :: tail => val mainSource = s"@main def main(args: String *): Unit =\n ${expression}" settings @@ -169,13 +169,13 @@ object MainGenericRunner { .withScriptArgs(tail*) else val newSettings = if arg.startsWith("-") then settings else settings.withPossibleEntryPaths(arg).withModeShouldBePossibleRun - process(tail, newSettings.withResidualArgs(arg)) - end process + processArgs(tail, newSettings.withResidualArgs(arg)) + end processArgs - def main(args: Array[String]): Unit = + def process(args: Array[String]): Boolean = val scalaOpts = envOrNone("SCALA_OPTS").toArray.flatMap(_.split(" ")).filter(_.nonEmpty) val allArgs = scalaOpts ++ args - val settings = process(allArgs.toList, Settings()) + val settings = processArgs(allArgs.toList, Settings()) if settings.exitCode != 0 then System.exit(settings.exitCode) def removeCompiler(cp: Array[String]) = @@ -185,12 +185,13 @@ object MainGenericRunner { else cp - def run(settings: Settings): Unit = settings.executeMode match + def run(settings: Settings): Option[Throwable] = settings.executeMode match case ExecuteMode.Repl => val properArgs = List("-classpath", settings.classPath.mkString(classpathSeparator)).filter(Function.const(settings.classPath.nonEmpty)) ++ settings.residualArgs repl.Main.main(properArgs.toArray) + None case ExecuteMode.PossibleRun => val newClasspath = (settings.classPath :+ ".").flatMap(_.split(classpathSeparator).filter(_.nonEmpty)).map(File(_).toURI.toURL) @@ -207,10 +208,11 @@ object MainGenericRunner { case None => settings.withExecuteMode(ExecuteMode.Repl) run(newSettings) + case ExecuteMode.Run => val scalaClasspath = ClasspathFromClassloader(Thread.currentThread().getContextClassLoader).split(classpathSeparator) val newClasspath = (settings.classPath.flatMap(_.split(classpathSeparator).filter(_.nonEmpty)) ++ removeCompiler(scalaClasspath) :+ ".").map(File(_).toURI.toURL) - val res = ObjectRunner.runAndCatch(newClasspath, settings.targetToRun, settings.residualArgs).flatMap { + ObjectRunner.runAndCatch(newClasspath, settings.targetToRun, settings.residualArgs).flatMap { case ex: ClassNotFoundException if ex.getMessage == settings.targetToRun => val file = settings.targetToRun Jar(file).mainClass match @@ -220,7 +222,7 @@ object MainGenericRunner { Some(IllegalArgumentException(s"No main class defined in manifest in jar: $file")) case ex => Some(ex) } - errorFn("", res) + case ExecuteMode.Script => val targetScript = Paths.get(settings.targetScript).toFile val targetJar = settings.targetScript.replaceAll("[.][^\\/]*$", "")+".jar" @@ -232,11 +234,10 @@ object MainGenericRunner { sys.props("script.path") = targetScript.toPath.toAbsolutePath.normalize.toString val scalaClasspath = ClasspathFromClassloader(Thread.currentThread().getContextClassLoader).split(classpathSeparator) val newClasspath = (settings.classPath.flatMap(_.split(classpathSeparator).filter(_.nonEmpty)) ++ removeCompiler(scalaClasspath) :+ ".").map(File(_).toURI.toURL) - val res = if mainClass.nonEmpty then + if mainClass.nonEmpty then ObjectRunner.runAndCatch(newClasspath :+ File(targetJar).toURI.toURL, mainClass, settings.scriptArgs) else Some(IllegalArgumentException(s"No main class defined in manifest in jar: $precompiledJar")) - errorFn("", res) else val properArgs = @@ -247,6 +248,8 @@ object MainGenericRunner { ++ List("-script", settings.targetScript) ++ settings.scriptArgs scripting.Main.main(properArgs.toArray) + None + case ExecuteMode.Expression => val cp = settings.classPath match { case Nil => "" @@ -265,12 +268,16 @@ object MainGenericRunner { else run(settings.withExecuteMode(ExecuteMode.Repl)) - run(settings) + run(settings) match + case e @ Some(ex) => errorFn("", e) + case _ => true - - def errorFn(str: String, e: Option[Throwable] = None, isFailure: Boolean = true): Boolean = { + def errorFn(str: String, e: Option[Throwable] = None): Boolean = if (str.nonEmpty) Console.err.println(str) e.foreach(_.printStackTrace()) - !isFailure - } + false + + def main(args: Array[String]): Unit = + if (!process(args)) System.exit(1) + } diff --git a/compiler/src/dotty/tools/scripting/StringDriver.scala b/compiler/src/dotty/tools/scripting/StringDriver.scala index b8b64994f285..b16c37ecb41c 100755 --- a/compiler/src/dotty/tools/scripting/StringDriver.scala +++ b/compiler/src/dotty/tools/scripting/StringDriver.scala @@ -12,7 +12,7 @@ import Util.* class StringDriver(compilerArgs: Array[String], scalaSource: String) extends Driver: override def sourcesRequired: Boolean = false - def compileAndRun(classpath: List[String] = Nil): Unit = + def compileAndRun(classpath: List[String] = Nil): Option[Throwable] = val outDir = Files.createTempDirectory("scala3-expression") outDir.toFile.deleteOnExit() @@ -26,7 +26,7 @@ class StringDriver(compilerArgs: Array[String], scalaSource: String) extends Dri val output = ctx.settings.outputDir.value if ctx.reporter.hasErrors then - throw StringDriverException("Errors encountered during compilation") + Some(StringDriverException("Errors encountered during compilation")) try val classpath = s"${ctx.settings.classpath.value}${pathsep}${sys.props("java.class.path")}" @@ -34,12 +34,13 @@ class StringDriver(compilerArgs: Array[String], scalaSource: String) extends Dri sys.props("java.class.path") = classpathEntries.map(_.toString).mkString(pathsep) val (mainClass, mainMethod) = detectMainClassAndMethod(outDir, classpathEntries, scalaSource) mainMethod.invoke(null, Array.empty[String]) + None catch case e: java.lang.reflect.InvocationTargetException => throw e.getCause finally deleteFile(outDir.toFile) - case None => + case None => None end compileAndRun end StringDriver From 01c18557835255e3408b591729f8c1b94298274f Mon Sep 17 00:00:00 2001 From: rochala Date: Wed, 6 Jul 2022 17:53:39 +0200 Subject: [PATCH 2/9] fix dead code, return Either instead of throwing error --- compiler/src/dotty/tools/scripting/Main.scala | 13 +++--- .../tools/scripting/ScriptingDriver.scala | 41 +++++++++---------- .../dotty/tools/scripting/StringDriver.scala | 28 +++++++------ compiler/src/dotty/tools/scripting/Util.scala | 14 ++++--- 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/compiler/src/dotty/tools/scripting/Main.scala b/compiler/src/dotty/tools/scripting/Main.scala index f5259974f16f..7a2d0f79f3e5 100755 --- a/compiler/src/dotty/tools/scripting/Main.scala +++ b/compiler/src/dotty/tools/scripting/Main.scala @@ -36,21 +36,18 @@ object Main: def main(args: Array[String]): Unit = val (compilerArgs, scriptFile, scriptArgs, saveJar, invokeFlag) = distinguishArgs(args) val driver = ScriptingDriver(compilerArgs, scriptFile, scriptArgs) - try driver.compileAndRun { (outDir:Path, classpathEntries:Seq[Path], mainClass: String) => + driver.compileAndRun { (outDir:Path, classpathEntries:Seq[Path], mainClass: String) => // write expanded classpath to java.class.path property, so called script can see it sys.props("java.class.path") = classpathEntries.map(_.toString).mkString(pathsep) if saveJar then // write a standalone jar to the script parent directory writeJarfile(outDir, scriptFile, scriptArgs, classpathEntries, mainClass) invokeFlag - } - catch - case ScriptingException(msg) => - println(s"Error: $msg") + } match + case Some(ex) => + println(ex.getMessage) sys.exit(1) - - case e: java.lang.reflect.InvocationTargetException => - throw e.getCause + case _ => private def writeJarfile(outDir: Path, scriptFile: File, scriptArgs:Array[String], classpathEntries:Seq[Path], mainClassName: String): Unit = diff --git a/compiler/src/dotty/tools/scripting/ScriptingDriver.scala b/compiler/src/dotty/tools/scripting/ScriptingDriver.scala index 38765ac6dafa..e4c357494ff1 100755 --- a/compiler/src/dotty/tools/scripting/ScriptingDriver.scala +++ b/compiler/src/dotty/tools/scripting/ScriptingDriver.scala @@ -11,7 +11,7 @@ import dotty.tools.io.{ PlainDirectory, Directory, ClassPath } import Util.* class ScriptingDriver(compilerArgs: Array[String], scriptFile: File, scriptArgs: Array[String]) extends Driver: - def compileAndRun(pack:(Path, Seq[Path], String) => Boolean = null): Unit = + def compileAndRun(pack:(Path, Seq[Path], String) => Boolean = null): Option[Throwable] = val outDir = Files.createTempDirectory("scala3-scripting") outDir.toFile.deleteOnExit() setup(compilerArgs :+ scriptFile.getAbsolutePath, initCtx.fresh) match @@ -20,26 +20,25 @@ class ScriptingDriver(compilerArgs: Array[String], scriptFile: File, scriptArgs: new PlainDirectory(Directory(outDir))) if doCompile(newCompiler, toCompile).hasErrors then - throw ScriptingException("Errors encountered during compilation") - - try - val classpath = s"${ctx.settings.classpath.value}${pathsep}${sys.props("java.class.path")}" - val classpathEntries: Seq[Path] = ClassPath.expandPath(classpath, expandStar=true).map { Paths.get(_) } - val (mainClass, mainMethod) = detectMainClassAndMethod(outDir, classpathEntries, scriptFile.toString) - val invokeMain: Boolean = - Option(pack) match - case Some(func) => - func(outDir, classpathEntries, mainClass) - case None => - true - end match - if invokeMain then mainMethod.invoke(null, scriptArgs) - catch - case e: java.lang.reflect.InvocationTargetException => - throw e.getCause - finally - deleteFile(outDir.toFile) - case None => + Some(ScriptingException("Errors encountered during compilation")) + else + try + val classpath = s"${ctx.settings.classpath.value}${pathsep}${sys.props("java.class.path")}" + val classpathEntries: Seq[Path] = ClassPath.expandPath(classpath, expandStar=true).map { Paths.get(_) } + detectMainClassAndMethod(outDir, classpathEntries, scriptFile.toString) match + case Right((mainClass, mainMethod)) => + val invokeMain: Boolean = Option(pack).map { func => + func(outDir, classpathEntries, mainClass) + }.getOrElse(true) + if invokeMain then mainMethod.invoke(null, scriptArgs) + None + case Left(ex) => Some(ex) + catch + case e: java.lang.reflect.InvocationTargetException => + Some(e.getCause) + finally + deleteFile(outDir.toFile) + case None => None end compileAndRun end ScriptingDriver diff --git a/compiler/src/dotty/tools/scripting/StringDriver.scala b/compiler/src/dotty/tools/scripting/StringDriver.scala index b16c37ecb41c..c61360c903e9 100755 --- a/compiler/src/dotty/tools/scripting/StringDriver.scala +++ b/compiler/src/dotty/tools/scripting/StringDriver.scala @@ -27,19 +27,21 @@ class StringDriver(compilerArgs: Array[String], scalaSource: String) extends Dri val output = ctx.settings.outputDir.value if ctx.reporter.hasErrors then Some(StringDriverException("Errors encountered during compilation")) - - try - val classpath = s"${ctx.settings.classpath.value}${pathsep}${sys.props("java.class.path")}" - val classpathEntries: Seq[Path] = ClassPath.expandPath(classpath, expandStar=true).map { Paths.get(_) } - sys.props("java.class.path") = classpathEntries.map(_.toString).mkString(pathsep) - val (mainClass, mainMethod) = detectMainClassAndMethod(outDir, classpathEntries, scalaSource) - mainMethod.invoke(null, Array.empty[String]) - None - catch - case e: java.lang.reflect.InvocationTargetException => - throw e.getCause - finally - deleteFile(outDir.toFile) + else + try + val classpath = s"${ctx.settings.classpath.value}${pathsep}${sys.props("java.class.path")}" + val classpathEntries: Seq[Path] = ClassPath.expandPath(classpath, expandStar=true).map { Paths.get(_) } + sys.props("java.class.path") = classpathEntries.map(_.toString).mkString(pathsep) + detectMainClassAndMethod(outDir, classpathEntries, scalaSource) match + case Right((mainClass, mainMethod)) => + mainMethod.invoke(null, Array.empty[String]) + None + case Left(ex) => Some(ex) + catch + case e: java.lang.reflect.InvocationTargetException => + throw e.getCause + finally + deleteFile(outDir.toFile) case None => None end compileAndRun diff --git a/compiler/src/dotty/tools/scripting/Util.scala b/compiler/src/dotty/tools/scripting/Util.scala index 71ae4413de55..fbbeb13ca13c 100755 --- a/compiler/src/dotty/tools/scripting/Util.scala +++ b/compiler/src/dotty/tools/scripting/Util.scala @@ -8,7 +8,6 @@ import java.net.{ URLClassLoader } import java.lang.reflect.{ Modifier, Method } object Util: - def deleteFile(target: File): Unit = if target.isDirectory then for member <- target.listFiles.toList @@ -16,7 +15,11 @@ object Util: target.delete() end deleteFile - def detectMainClassAndMethod(outDir: Path, classpathEntries: Seq[Path], srcFile: String): (String, Method) = + def detectMainClassAndMethod( + outDir: Path, + classpathEntries: Seq[Path], + srcFile: String + ): Either[Throwable, (String, Method)] = val classpathUrls = (classpathEntries :+ outDir).map { _.toUri.toURL } val cl = URLClassLoader(classpathUrls.toArray) @@ -48,11 +51,10 @@ object Util: mains match case Nil => - throw StringDriverException(s"No main methods detected for [${srcFile}]") + Left(StringDriverException(s"No main methods detected for [${srcFile}]")) case _ :: _ :: _ => - throw StringDriverException( - s"internal error: Detected the following main methods:\n${mains.mkString("\n")}") - case m :: Nil => m + Left(StringDriverException(s"Internal error: Detected the following main methods:\n${mains.mkString("\n")}")) + case mainMethod :: Nil => Right(mainMethod) end match end detectMainClassAndMethod From 479fb8c3fec5c79a9e99ecf52a3c49d983ad28ba Mon Sep 17 00:00:00 2001 From: rochala Date: Fri, 8 Jul 2022 10:02:45 +0200 Subject: [PATCH 3/9] add exit code tests, fix exit code for tastyprinter flag, improve temp file creation for expression for better error messages --- .../tools/dotc/core/tasty/TastyPrinter.scala | 18 +- compiler/src/dotty/tools/io/Path.scala | 2 +- compiler/src/dotty/tools/scripting/Main.scala | 9 +- .../dotty/tools/scripting/StringDriver.scala | 10 +- .../scripting/compileError.scala | 1 + .../scripting/positiveTest.scala | 1 + .../scripting/runtimeError.scala | 1 + .../scripting/scriptCompileError.sc | 1 + .../scripting/scriptPositive.sc | 1 + .../scripting/scriptRuntimeError.sc | 1 + .../tools/scripting/BashExitCodeTests.scala | 156 ++++++++++++++++++ 11 files changed, 183 insertions(+), 18 deletions(-) create mode 100644 compiler/test-resources/scripting/compileError.scala create mode 100644 compiler/test-resources/scripting/positiveTest.scala create mode 100644 compiler/test-resources/scripting/runtimeError.scala create mode 100644 compiler/test-resources/scripting/scriptCompileError.sc create mode 100644 compiler/test-resources/scripting/scriptPositive.sc create mode 100644 compiler/test-resources/scripting/scriptRuntimeError.sc create mode 100644 compiler/test/dotty/tools/scripting/BashExitCodeTests.scala diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala index f2650ee714ab..5876b69edfde 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala @@ -37,20 +37,22 @@ object TastyPrinter: for arg <- args do if arg == "-color:never" then () // skip else if arg.startsWith("-") then println(s"bad option '$arg' was ignored") - else if arg.endsWith(".tasty") then { + else if arg.endsWith(".tasty") then val path = Paths.get(arg) - if Files.exists(path) then printTasty(arg, Files.readAllBytes(path).nn) - else println("File not found: " + arg) - } - else if arg.endsWith(".jar") then { + if Files.exists(path) then + printTasty(arg, Files.readAllBytes(path).nn) + else + println("File not found: " + arg) + System.exit(1) + else if arg.endsWith(".jar") then val jar = JarArchive.open(Path(arg), create = false) try for file <- jar.iterator() if file.name.endsWith(".tasty") do printTasty(s"$arg ${file.path}", file.toByteArray) finally jar.close() - - } - else println(s"Not a '.tasty' or '.jar' file: $arg") + else + println(s"Not a '.tasty' or '.jar' file: $arg") + System.exit(1) if printLastLine then println(line) diff --git a/compiler/src/dotty/tools/io/Path.scala b/compiler/src/dotty/tools/io/Path.scala index dddb870afc65..8c36ea26a788 100644 --- a/compiler/src/dotty/tools/io/Path.scala +++ b/compiler/src/dotty/tools/io/Path.scala @@ -170,7 +170,7 @@ class Path private[io] (val jpath: JPath) { // returns the filename without the extension. def stripExtension: String = name stripSuffix ("." + extension) // returns the Path with the extension. - def addExtension(ext: String): Path = new Path(jpath.resolveSibling(name + ext)) + def addExtension(ext: String): Path = new Path(jpath.resolveSibling(name + "." + ext)) // changes the existing extension out for a new one, or adds it // if the current path has none. def changeExtension(ext: String): Path = diff --git a/compiler/src/dotty/tools/scripting/Main.scala b/compiler/src/dotty/tools/scripting/Main.scala index 7a2d0f79f3e5..05d871b20aff 100755 --- a/compiler/src/dotty/tools/scripting/Main.scala +++ b/compiler/src/dotty/tools/scripting/Main.scala @@ -43,11 +43,10 @@ object Main: // write a standalone jar to the script parent directory writeJarfile(outDir, scriptFile, scriptArgs, classpathEntries, mainClass) invokeFlag - } match - case Some(ex) => - println(ex.getMessage) - sys.exit(1) - case _ => + }.map { + case ScriptingException(msg) => println(msg) + case ex => ex.printStackTrace + }.foreach(_ => System.exit(1)) private def writeJarfile(outDir: Path, scriptFile: File, scriptArgs:Array[String], classpathEntries:Seq[Path], mainClassName: String): Unit = diff --git a/compiler/src/dotty/tools/scripting/StringDriver.scala b/compiler/src/dotty/tools/scripting/StringDriver.scala index c61360c903e9..eccd8445c87d 100755 --- a/compiler/src/dotty/tools/scripting/StringDriver.scala +++ b/compiler/src/dotty/tools/scripting/StringDriver.scala @@ -8,6 +8,7 @@ import dotty.tools.dotc.Driver import dotty.tools.dotc.core.Contexts, Contexts.{ Context, ctx } import dotty.tools.io.{ PlainDirectory, Directory, ClassPath } import Util.* +import dotty.tools.dotc.util.SourceFile class StringDriver(compilerArgs: Array[String], scalaSource: String) extends Driver: override def sourcesRequired: Boolean = false @@ -18,11 +19,12 @@ class StringDriver(compilerArgs: Array[String], scalaSource: String) extends Dri setup(compilerArgs, initCtx.fresh) match case Some((toCompile, rootCtx)) => - given Context = rootCtx.fresh.setSetting(rootCtx.settings.outputDir, - new PlainDirectory(Directory(outDir))) + given Context = rootCtx.fresh.setSetting(rootCtx.settings.outputDir, new PlainDirectory(Directory(outDir))) val compiler = newCompiler - compiler.newRun.compileFromStrings(List(scalaSource)) + + val source = SourceFile.virtual("expression", scalaSource) + compiler.newRun.compileSources(List(source)) val output = ctx.settings.outputDir.value if ctx.reporter.hasErrors then @@ -39,7 +41,7 @@ class StringDriver(compilerArgs: Array[String], scalaSource: String) extends Dri case Left(ex) => Some(ex) catch case e: java.lang.reflect.InvocationTargetException => - throw e.getCause + Some(e.getCause) finally deleteFile(outDir.toFile) case None => None diff --git a/compiler/test-resources/scripting/compileError.scala b/compiler/test-resources/scripting/compileError.scala new file mode 100644 index 000000000000..d703006dc2d4 --- /dev/null +++ b/compiler/test-resources/scripting/compileError.scala @@ -0,0 +1 @@ +@main def compileError = prin \ No newline at end of file diff --git a/compiler/test-resources/scripting/positiveTest.scala b/compiler/test-resources/scripting/positiveTest.scala new file mode 100644 index 000000000000..f3dbe50aa643 --- /dev/null +++ b/compiler/test-resources/scripting/positiveTest.scala @@ -0,0 +1 @@ +@main def positiveTest = println("Hello World!") \ No newline at end of file diff --git a/compiler/test-resources/scripting/runtimeError.scala b/compiler/test-resources/scripting/runtimeError.scala new file mode 100644 index 000000000000..f6bdba466455 --- /dev/null +++ b/compiler/test-resources/scripting/runtimeError.scala @@ -0,0 +1 @@ +@main def runtimeError = throw RuntimeException() diff --git a/compiler/test-resources/scripting/scriptCompileError.sc b/compiler/test-resources/scripting/scriptCompileError.sc new file mode 100644 index 000000000000..36a59d06f3c4 --- /dev/null +++ b/compiler/test-resources/scripting/scriptCompileError.sc @@ -0,0 +1 @@ +@main def main = prin \ No newline at end of file diff --git a/compiler/test-resources/scripting/scriptPositive.sc b/compiler/test-resources/scripting/scriptPositive.sc new file mode 100644 index 000000000000..a4dd0823f7a8 --- /dev/null +++ b/compiler/test-resources/scripting/scriptPositive.sc @@ -0,0 +1 @@ +@main def scriptPositive = println("Hello world!") \ No newline at end of file diff --git a/compiler/test-resources/scripting/scriptRuntimeError.sc b/compiler/test-resources/scripting/scriptRuntimeError.sc new file mode 100644 index 000000000000..0cd940cc20cf --- /dev/null +++ b/compiler/test-resources/scripting/scriptRuntimeError.sc @@ -0,0 +1 @@ +@main def scriptRuntimeError = throw RuntimeException() \ No newline at end of file diff --git a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala new file mode 100644 index 000000000000..54e2231af7e4 --- /dev/null +++ b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala @@ -0,0 +1,156 @@ +package dotty +package tools +package scripting + +import java.io.File +import java.nio.file.Files +import org.junit.Test +import org.junit.Assert.assertEquals + +import ScriptTestEnv.* + + +object BashExitCodeTests: + def testFiles = scripts("/scripting") + + /* + * Compiles the class checking exit code + * + * @param testName name of the test containing the extension + * @param expectedExitCode expected exit code from the output + * @param deleteTempDir if temporary directory created for compilation output should delete in this scope + * + * @return Created temporary directory + */ + private def testCompilationExitCode(testName: String, expectedExitCode: Int, deleteTempDir: Boolean = false): File = + val temporaryDir = Files.createTempDirectory(testName) + assertTestExists(testName) { testFile => + try { + val testFilePath = testFile.absPath + val commandline = (Seq(scalacPath, "-d", temporaryDir, testFilePath)).mkString(" ") + val (validTest, exitCode, _, _) = bashCommand(commandline) + if verifyValid(validTest) then + assertEquals(expectedExitCode, exitCode) + } finally { + if deleteTempDir then Util.deleteFile(temporaryDir.toFile) + } + } + temporaryDir.toFile + + /* + * Runs the command and checks the exit code + * + * @param args arguments for command line + * @param expectedExitCode expected exit code from the output + */ + private def testCommandExitCode(args: Seq[String], expectedExitCode: Int): Unit = + val commandline = args.mkString(" ") + val (validTest, exitCode, output, erroutput) = bashCommand(commandline) + if verifyValid(validTest) then + assertEquals(expectedExitCode, exitCode) + + + /* Compiles and then runs the code checking the exit code + * + * @param testFileName name of the test + * @param runExitCode expected exit code from the runner output + */ + private def testCompileAndRun(testFileName: String, runExitCode: Int): Unit = + val outputDirectory = testCompilationExitCode(testFileName, 0) + + def testRuntimeExitCode(className: String, expectedExitCode: Int): Unit = + val testClassFile = outputDirectory.files.find(_.getName == s"$className.class") + assert(testClassFile.isDefined) + val commandline = (Seq(scalaPath, "-classpath", outputDirectory.getAbsolutePath, className)).mkString(" ") + val (validTest, exitCode, o, e) = bashCommand(commandline) + if verifyValid(validTest) then + assertEquals(expectedExitCode, exitCode) + + try { + val generatedClassName = testFileName.split('.').head + testRuntimeExitCode(generatedClassName, runExitCode) + } finally { + Util.deleteFile(outputDirectory) + } + + /* + * Checks if scripting test resources contains test with given `testName` + * And then runs function `test` + * + * @param testName name of the test containing the extension + * @param test check to be run on found test file + */ + private def assertTestExists(testName: String)(test: File => Unit) = + val file = testFiles.find(_.getName == testName) + assert(file.isDefined) + test(file.get) + +class BashExitCodeTests: + import BashExitCodeTests.* + + @Test def verifyExitCodeOnCompileError: Unit = + testCompilationExitCode("compileError.scala", 1, true) + + @Test def verifyExitCodeOnRuntimeError: Unit = + testCompileAndRun("runtimeError.scala", 1) + + @Test def verifyExitCode: Unit = + testCompileAndRun("positiveTest.scala", 0) + + @Test def verifyExitCodeOnScriptError: Unit = + assertTestExists("scriptRuntimeError.sc") { file => + testCommandExitCode(Seq(scalacPath, "-script", file.absPath), 1) + } + + @Test def verifyExitCodeOnScriptErrorCompiler: Unit = + assertTestExists("scriptRuntimeError.sc") { file => + testCommandExitCode(Seq(scalacPath, "-script", file.absPath), 1) + } + + @Test def verifyExitCodeOnScript: Unit = + assertTestExists("scriptPositive.sc") { file => + testCommandExitCode(Seq(scalaPath, file.absPath), 0) + } + + @Test def verifyExitCodeOnScriptCompiler: Unit = + assertTestExists("scriptPositive.sc") { file => + testCommandExitCode(Seq(scalacPath, "-script", file.absPath), 0) + } + + @Test def verifyExitCodeOnDecompilation: Unit = + val testName = "positiveTest" + val outputDirectory = testCompilationExitCode(s"$testName.scala", 0) + val tastyFilePath = outputDirectory.toPath.resolve(s"$testName.tasty").toString + testCommandExitCode(Seq(scalacPath, "-decompile", tastyFilePath), 0) + + @Test def verifyExitCodeOnPrintTasty: Unit = + val testName = "positiveTest" + val outputDirectory = testCompilationExitCode(s"$testName.scala", 0) + val tastyFilePath = outputDirectory.toPath.resolve(s"$testName.tasty").toString + testCommandExitCode(Seq(scalacPath, "-print-tasty", tastyFilePath), 0) + + @Test def verifyExitCodeOnDecompilationFailure: Unit = + val tempFile = Files.createTempFile("temp-file", ".class").toFile + testCommandExitCode(Seq(scalacPath, "-decompile", "non-existing-file.tasty"), 1) + testCommandExitCode(Seq(scalacPath, "-decompile", tempFile.absPath), 1) + Util.deleteFile(tempFile) + + @Test def verifyExitCodeOnPrintTastyFailure: Unit = + val tempFile = Files.createTempFile("temp-file", ".class").toFile + testCommandExitCode(Seq(scalacPath, "-print-tasty", "non-existing-file.tasty"), 1) + testCommandExitCode(Seq(scalacPath, "-print-tasty", tempFile.absPath), 1) + Util.deleteFile(tempFile) + + @Test def verifyExitCodeOnExpressionCompileError: Unit = + testCommandExitCode(Seq(scalaPath, "-e", "'prinln(10*10)'"), 1) + + @Test def verifyExitCodeOnExpressionRuntimeError: Unit = + testCommandExitCode(Seq(scalaPath, "-e", "'1/0'"), 1) + + @Test def verifyExitCodeOnExpression: Unit = + testCommandExitCode(Seq(scalaPath, "-e", "'println(10*10)'"), 0) + + @Test def verifyExitCodeOnInfo: Unit = + List("--help", "--version", "-Xplugin-list", "-Vphases").foreach { flag => + testCommandExitCode(Seq(scalaPath, flag), 0) + } From 72875840e7c0724238091d0dacc2da6955976da4 Mon Sep 17 00:00:00 2001 From: rochala Date: Fri, 8 Jul 2022 10:17:08 +0200 Subject: [PATCH 4/9] add unsafe nulls import --- compiler/test/dotty/tools/scripting/BashExitCodeTests.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala index 54e2231af7e4..6e00b89ef282 100644 --- a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala +++ b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala @@ -2,6 +2,8 @@ package dotty package tools package scripting +import scala.language.unsafeNulls + import java.io.File import java.nio.file.Files import org.junit.Test From 6fa07cff1d7c48c2e244ee11126ec20226c71948 Mon Sep 17 00:00:00 2001 From: rochala Date: Fri, 8 Jul 2022 11:10:52 +0200 Subject: [PATCH 5/9] move exit code tests into separate directory to don't check if they compile by other scripting tests --- .../scripting/{ => exit-code-tests}/compileError.scala | 0 .../scripting/{ => exit-code-tests}/positiveTest.scala | 0 .../scripting/{ => exit-code-tests}/runtimeError.scala | 0 .../scripting/{ => exit-code-tests}/scriptCompileError.sc | 0 .../scripting/{ => exit-code-tests}/scriptPositive.sc | 0 .../scripting/{ => exit-code-tests}/scriptRuntimeError.sc | 0 compiler/test/dotty/tools/scripting/BashExitCodeTests.scala | 2 +- touchedFile.out | 0 8 files changed, 1 insertion(+), 1 deletion(-) rename compiler/test-resources/scripting/{ => exit-code-tests}/compileError.scala (100%) rename compiler/test-resources/scripting/{ => exit-code-tests}/positiveTest.scala (100%) rename compiler/test-resources/scripting/{ => exit-code-tests}/runtimeError.scala (100%) rename compiler/test-resources/scripting/{ => exit-code-tests}/scriptCompileError.sc (100%) rename compiler/test-resources/scripting/{ => exit-code-tests}/scriptPositive.sc (100%) rename compiler/test-resources/scripting/{ => exit-code-tests}/scriptRuntimeError.sc (100%) create mode 100644 touchedFile.out diff --git a/compiler/test-resources/scripting/compileError.scala b/compiler/test-resources/scripting/exit-code-tests/compileError.scala similarity index 100% rename from compiler/test-resources/scripting/compileError.scala rename to compiler/test-resources/scripting/exit-code-tests/compileError.scala diff --git a/compiler/test-resources/scripting/positiveTest.scala b/compiler/test-resources/scripting/exit-code-tests/positiveTest.scala similarity index 100% rename from compiler/test-resources/scripting/positiveTest.scala rename to compiler/test-resources/scripting/exit-code-tests/positiveTest.scala diff --git a/compiler/test-resources/scripting/runtimeError.scala b/compiler/test-resources/scripting/exit-code-tests/runtimeError.scala similarity index 100% rename from compiler/test-resources/scripting/runtimeError.scala rename to compiler/test-resources/scripting/exit-code-tests/runtimeError.scala diff --git a/compiler/test-resources/scripting/scriptCompileError.sc b/compiler/test-resources/scripting/exit-code-tests/scriptCompileError.sc similarity index 100% rename from compiler/test-resources/scripting/scriptCompileError.sc rename to compiler/test-resources/scripting/exit-code-tests/scriptCompileError.sc diff --git a/compiler/test-resources/scripting/scriptPositive.sc b/compiler/test-resources/scripting/exit-code-tests/scriptPositive.sc similarity index 100% rename from compiler/test-resources/scripting/scriptPositive.sc rename to compiler/test-resources/scripting/exit-code-tests/scriptPositive.sc diff --git a/compiler/test-resources/scripting/scriptRuntimeError.sc b/compiler/test-resources/scripting/exit-code-tests/scriptRuntimeError.sc similarity index 100% rename from compiler/test-resources/scripting/scriptRuntimeError.sc rename to compiler/test-resources/scripting/exit-code-tests/scriptRuntimeError.sc diff --git a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala index 6e00b89ef282..b358dc6bb2ef 100644 --- a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala +++ b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala @@ -13,7 +13,7 @@ import ScriptTestEnv.* object BashExitCodeTests: - def testFiles = scripts("/scripting") + def testFiles = scripts("/scripting/exit-code-tests") /* * Compiles the class checking exit code diff --git a/touchedFile.out b/touchedFile.out new file mode 100644 index 000000000000..e69de29bb2d1 From 6d7a873a07770267af1ffe7d1a7e696a911301aa Mon Sep 17 00:00:00 2001 From: rochala Date: Fri, 8 Jul 2022 19:08:56 +0200 Subject: [PATCH 6/9] refactor tests to guarantee file deletion, fix leftover test output from ScriptingTests --- .../tools/scripting/BashExitCodeTests.scala | 148 +++++++++++------- .../tools/scripting/ScriptingTests.scala | 4 +- touchedFile.out | 0 3 files changed, 92 insertions(+), 60 deletions(-) delete mode 100644 touchedFile.out diff --git a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala index b358dc6bb2ef..86d947cbc3bc 100644 --- a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala +++ b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala @@ -8,36 +8,63 @@ import java.io.File import java.nio.file.Files import org.junit.Test import org.junit.Assert.assertEquals +import org.junit.experimental.categories.Category import ScriptTestEnv.* object BashExitCodeTests: - def testFiles = scripts("/scripting/exit-code-tests") + private def testFiles = scripts("/scripting/exit-code-tests") /* * Compiles the class checking exit code * - * @param testName name of the test containing the extension + * @param testName name of the test * @param expectedExitCode expected exit code from the output - * @param deleteTempDir if temporary directory created for compilation output should delete in this scope - * - * @return Created temporary directory */ - private def testCompilationExitCode(testName: String, expectedExitCode: Int, deleteTempDir: Boolean = false): File = - val temporaryDir = Files.createTempDirectory(testName) + private def compileAndVerifyExitCode( + testName: String, + expectedExitCode: Int, + )(using temporaryDir: File): Unit = assertTestExists(testName) { testFile => - try { - val testFilePath = testFile.absPath - val commandline = (Seq(scalacPath, "-d", temporaryDir, testFilePath)).mkString(" ") - val (validTest, exitCode, _, _) = bashCommand(commandline) - if verifyValid(validTest) then - assertEquals(expectedExitCode, exitCode) - } finally { - if deleteTempDir then Util.deleteFile(temporaryDir.toFile) - } + val testFilePath = testFile.absPath + val commandline = (Seq(scalacPath, "-d", temporaryDir, testFilePath)).mkString(" ") + val (validTest, exitCode, _, _) = bashCommand(commandline) + if verifyValid(validTest) then + assertEquals(expectedExitCode, exitCode) } - temporaryDir.toFile + + /* + * Runs compiled code checking the exit code + * + * @param className name of compiled class + * @param runExitCode expected exit code from the runner + */ + private def runClassAndVerifyExitCode( + className: String, + expectedExitCode: Int + )(using temporaryDir: File): Unit = + val testClassFile = temporaryDir.files.find(_.getName == s"$className.class") + assert(testClassFile.isDefined) + val commandline = (Seq(scalaPath, "-classpath", temporaryDir.getAbsolutePath, className)).mkString(" ") + val (validTest, exitCode, o, e) = bashCommand(commandline) + if verifyValid(validTest) then + assertEquals(expectedExitCode, exitCode) + + /* + * Compiles and then runs code verifying runner status code + * + * @param testName name of the test + * @param className name of compiled class + * @param expectedRunExitCode expected exit code from the runner + */ + private def compileRunAndVerifyExitCode( + testName: String, + className: String, + expectedRunExitCode: Int, + )(using File): Unit = + compileAndVerifyExitCode(testName, 0) + runClassAndVerifyExitCode(className, expectedRunExitCode) /* * Runs the command and checks the exit code @@ -51,30 +78,6 @@ object BashExitCodeTests: if verifyValid(validTest) then assertEquals(expectedExitCode, exitCode) - - /* Compiles and then runs the code checking the exit code - * - * @param testFileName name of the test - * @param runExitCode expected exit code from the runner output - */ - private def testCompileAndRun(testFileName: String, runExitCode: Int): Unit = - val outputDirectory = testCompilationExitCode(testFileName, 0) - - def testRuntimeExitCode(className: String, expectedExitCode: Int): Unit = - val testClassFile = outputDirectory.files.find(_.getName == s"$className.class") - assert(testClassFile.isDefined) - val commandline = (Seq(scalaPath, "-classpath", outputDirectory.getAbsolutePath, className)).mkString(" ") - val (validTest, exitCode, o, e) = bashCommand(commandline) - if verifyValid(validTest) then - assertEquals(expectedExitCode, exitCode) - - try { - val generatedClassName = testFileName.split('.').head - testRuntimeExitCode(generatedClassName, runExitCode) - } finally { - Util.deleteFile(outputDirectory) - } - /* * Checks if scripting test resources contains test with given `testName` * And then runs function `test` @@ -87,20 +90,51 @@ object BashExitCodeTests: assert(file.isDefined) test(file.get) + /* + * Runs test for created temporary file + * and ensures it deletion after function execution + * + * @param test check to be run on found test file + */ + private def withTempFile(test: File => Unit) = + val tempFile = Files.createTempFile("temp-file", ".class").toFile + try { + test(tempFile) + } finally { + Util.deleteFile(tempFile) + } + + /* + * Runs test with implicit temporary directory + * and ensures it deletion after the function execution + * + * @param test test to be run with given temporary directory + */ + private def withTempDirectory(test: File ?=> Unit) = + given file: File = Files.createTempDirectory("exit-code-tests").toFile + try { test } finally { Util.deleteFile(file) } + + /* + * Returns path to the generated tasty file for given directory and classname + */ + private def getGeneratedTastyPath(className: String)(using temporaryDir: File): String = + temporaryDir.toPath.resolve(s"$className.tasty").toString + +@Category(Array(classOf[BootstrappedOnlyTests])) class BashExitCodeTests: import BashExitCodeTests.* @Test def verifyExitCodeOnCompileError: Unit = - testCompilationExitCode("compileError.scala", 1, true) + withTempDirectory(compileAndVerifyExitCode("compileError.scala", 1)) @Test def verifyExitCodeOnRuntimeError: Unit = - testCompileAndRun("runtimeError.scala", 1) + withTempDirectory(compileRunAndVerifyExitCode("runtimeError.scala", "runtimeError", 1)) @Test def verifyExitCode: Unit = - testCompileAndRun("positiveTest.scala", 0) + withTempDirectory(compileRunAndVerifyExitCode("positiveTest.scala", "positiveTest", 0)) @Test def verifyExitCodeOnScriptError: Unit = - assertTestExists("scriptRuntimeError.sc") { file => + assertTestExists("scriptRuntimeError.sc"){ file => testCommandExitCode(Seq(scalacPath, "-script", file.absPath), 1) } @@ -120,28 +154,24 @@ class BashExitCodeTests: } @Test def verifyExitCodeOnDecompilation: Unit = - val testName = "positiveTest" - val outputDirectory = testCompilationExitCode(s"$testName.scala", 0) - val tastyFilePath = outputDirectory.toPath.resolve(s"$testName.tasty").toString - testCommandExitCode(Seq(scalacPath, "-decompile", tastyFilePath), 0) + withTempDirectory { + compileAndVerifyExitCode("positiveTest.scala", 0) + testCommandExitCode(Seq(scalacPath, "-decompile", getGeneratedTastyPath("positiveTest")), 0) + } @Test def verifyExitCodeOnPrintTasty: Unit = - val testName = "positiveTest" - val outputDirectory = testCompilationExitCode(s"$testName.scala", 0) - val tastyFilePath = outputDirectory.toPath.resolve(s"$testName.tasty").toString - testCommandExitCode(Seq(scalacPath, "-print-tasty", tastyFilePath), 0) + withTempDirectory { + compileAndVerifyExitCode("positiveTest.scala", 0) + testCommandExitCode(Seq(scalacPath, "-print-tasty", getGeneratedTastyPath("positiveTest")), 0) + } @Test def verifyExitCodeOnDecompilationFailure: Unit = - val tempFile = Files.createTempFile("temp-file", ".class").toFile + withTempFile(file => testCommandExitCode(Seq(scalacPath, "-decompile", file.absPath), 1)) testCommandExitCode(Seq(scalacPath, "-decompile", "non-existing-file.tasty"), 1) - testCommandExitCode(Seq(scalacPath, "-decompile", tempFile.absPath), 1) - Util.deleteFile(tempFile) @Test def verifyExitCodeOnPrintTastyFailure: Unit = - val tempFile = Files.createTempFile("temp-file", ".class").toFile + withTempFile(file => testCommandExitCode(Seq(scalacPath, "-print-tasty", file.absPath), 1)) testCommandExitCode(Seq(scalacPath, "-print-tasty", "non-existing-file.tasty"), 1) - testCommandExitCode(Seq(scalacPath, "-print-tasty", tempFile.absPath), 1) - Util.deleteFile(tempFile) @Test def verifyExitCodeOnExpressionCompileError: Unit = testCommandExitCode(Seq(scalaPath, "-e", "'prinln(10*10)'"), 1) diff --git a/compiler/test/dotty/tools/scripting/ScriptingTests.scala b/compiler/test/dotty/tools/scripting/ScriptingTests.scala index 2fb12b401754..16eeb48f0b2a 100644 --- a/compiler/test/dotty/tools/scripting/ScriptingTests.scala +++ b/compiler/test/dotty/tools/scripting/ScriptingTests.scala @@ -122,7 +122,7 @@ class ScriptingTests: /* * Compile touchFile.sc to create executable jar, verify jar execution succeeds. */ - @Test def scriptingNoCompileJar = + @Test def scriptingNoCompileJar: Unit = val scriptFile = touchFileScript showScriptUnderTest(scriptFile) val expectedJar = script2jar(scriptFile) @@ -146,6 +146,8 @@ class ScriptingTests: if touchedFile.exists then printf("success: executable jar created file %s\n", touchedFile) assert( touchedFile.exists, s"expected to find file ${touchedFile}" ) + touchedFile.delete + assert( !touchedFile.exists, s"unable to delete ${touchedFile}" ) /////////////////////////////////// def touchFileScript = testFiles.find(_.getName == "touchFile.sc").get diff --git a/touchedFile.out b/touchedFile.out deleted file mode 100644 index e69de29bb2d1..000000000000 From 7d9656855383eb39d3d0c3b79a106f74e6303e1c Mon Sep 17 00:00:00 2001 From: rochala Date: Fri, 8 Jul 2022 19:16:58 +0200 Subject: [PATCH 7/9] undo changes added by mistake --- compiler/src/dotty/tools/io/Path.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/io/Path.scala b/compiler/src/dotty/tools/io/Path.scala index 8c36ea26a788..dddb870afc65 100644 --- a/compiler/src/dotty/tools/io/Path.scala +++ b/compiler/src/dotty/tools/io/Path.scala @@ -170,7 +170,7 @@ class Path private[io] (val jpath: JPath) { // returns the filename without the extension. def stripExtension: String = name stripSuffix ("." + extension) // returns the Path with the extension. - def addExtension(ext: String): Path = new Path(jpath.resolveSibling(name + "." + ext)) + def addExtension(ext: String): Path = new Path(jpath.resolveSibling(name + ext)) // changes the existing extension out for a new one, or adds it // if the current path has none. def changeExtension(ext: String): Path = From c39ff5b1e5d0edffbc46f6e3668c2871e4160b71 Mon Sep 17 00:00:00 2001 From: rochala Date: Mon, 11 Jul 2022 13:04:49 +0200 Subject: [PATCH 8/9] don't print compile error stacktrace for -e flag --- .../src/dotty/tools/MainGenericRunner.scala | 10 +-- compiler/src/dotty/tools/scripting/Main.scala | 9 +- scoverage.coverage | 88 +++++++++++++++++++ 3 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 scoverage.coverage diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index 3f5065370599..6f4366a00b77 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -15,7 +15,7 @@ import dotty.tools.io.Jar import dotty.tools.runner.ScalaClassLoader import java.nio.file.Paths import dotty.tools.dotc.config.CommandLineParser -import dotty.tools.scripting.StringDriver +import dotty.tools.scripting.{StringDriver, StringDriverException, ScriptingException} enum ExecuteMode: case Guess @@ -247,8 +247,7 @@ object MainGenericRunner { ++ settings.scalaArgs ++ List("-script", settings.targetScript) ++ settings.scriptArgs - scripting.Main.main(properArgs.toArray) - None + scripting.Main.process(properArgs.toArray) case ExecuteMode.Expression => val cp = settings.classPath match { @@ -269,8 +268,9 @@ object MainGenericRunner { run(settings.withExecuteMode(ExecuteMode.Repl)) run(settings) match - case e @ Some(ex) => errorFn("", e) - case _ => true + case Some(ex: (StringDriverException | ScriptingException)) => errorFn(ex.getMessage) + case e @ Some(ex) => errorFn("", e) + case _ => true def errorFn(str: String, e: Option[Throwable] = None): Boolean = if (str.nonEmpty) Console.err.println(str) diff --git a/compiler/src/dotty/tools/scripting/Main.scala b/compiler/src/dotty/tools/scripting/Main.scala index 05d871b20aff..8db12f400c64 100755 --- a/compiler/src/dotty/tools/scripting/Main.scala +++ b/compiler/src/dotty/tools/scripting/Main.scala @@ -33,7 +33,7 @@ object Main: (compilerArgs, file, scriptArgs, saveJar, invokeFlag) end distinguishArgs - def main(args: Array[String]): Unit = + def process(args: Array[String]): Option[Throwable] = val (compilerArgs, scriptFile, scriptArgs, saveJar, invokeFlag) = distinguishArgs(args) val driver = ScriptingDriver(compilerArgs, scriptFile, scriptArgs) driver.compileAndRun { (outDir:Path, classpathEntries:Seq[Path], mainClass: String) => @@ -43,10 +43,13 @@ object Main: // write a standalone jar to the script parent directory writeJarfile(outDir, scriptFile, scriptArgs, classpathEntries, mainClass) invokeFlag - }.map { + } + + def main(args: Array[String]): Unit = + process(args).map { case ScriptingException(msg) => println(msg) case ex => ex.printStackTrace - }.foreach(_ => System.exit(1)) + }.foreach(_ => System.exit(1)) private def writeJarfile(outDir: Path, scriptFile: File, scriptArgs:Array[String], classpathEntries:Seq[Path], mainClassName: String): Unit = diff --git a/scoverage.coverage b/scoverage.coverage new file mode 100644 index 000000000000..b1294eb3e5c7 --- /dev/null +++ b/scoverage.coverage @@ -0,0 +1,88 @@ +# Coverage data, format version: 3.0 +# Statement data: +# - id +# - source path +# - package name +# - class name +# - class type (Class, Object or Trait) +# - full class name +# - method name +# - start offset +# - end offset +# - line number +# - symbol name +# - tree name +# - is branch +# - invocations count +# - is ignored +# - description (can be multi-line) +# ' ' sign +# ------------------------------------------ +0 +../dotty/src/main/scala/Macro.scala +example +Test$ +Object +example.Test$ +x +212 +217 +13 +x +DefDef +false +0 +false + + +1 +src/main/scala/Main.scala +example +Test$ +Object +example.Test$ +foo +52 +59 +5 +foo +DefDef +false +0 +false +def foo + +2 +src/main/scala/Main.scala +example +Test$ +Object +example.Test$ +hello +99 +112 +8 +println +Apply +false +0 +false +println("JD") + +3 +src/main/scala/Main.scala +example +Test$ +Object +example.Test$ +hello +75 +90 +7 +hello +DefDef +false +0 +false +@main def hello + From 6507a32ceaec76af344f3eb1ef74b044b4052ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Rochala?= <48657087+rochala@users.noreply.github.com> Date: Mon, 11 Jul 2022 13:22:32 +0200 Subject: [PATCH 9/9] Delete scoverage.coverage --- scoverage.coverage | 88 ---------------------------------------------- 1 file changed, 88 deletions(-) delete mode 100644 scoverage.coverage diff --git a/scoverage.coverage b/scoverage.coverage deleted file mode 100644 index b1294eb3e5c7..000000000000 --- a/scoverage.coverage +++ /dev/null @@ -1,88 +0,0 @@ -# Coverage data, format version: 3.0 -# Statement data: -# - id -# - source path -# - package name -# - class name -# - class type (Class, Object or Trait) -# - full class name -# - method name -# - start offset -# - end offset -# - line number -# - symbol name -# - tree name -# - is branch -# - invocations count -# - is ignored -# - description (can be multi-line) -# ' ' sign -# ------------------------------------------ -0 -../dotty/src/main/scala/Macro.scala -example -Test$ -Object -example.Test$ -x -212 -217 -13 -x -DefDef -false -0 -false - - -1 -src/main/scala/Main.scala -example -Test$ -Object -example.Test$ -foo -52 -59 -5 -foo -DefDef -false -0 -false -def foo - -2 -src/main/scala/Main.scala -example -Test$ -Object -example.Test$ -hello -99 -112 -8 -println -Apply -false -0 -false -println("JD") - -3 -src/main/scala/Main.scala -example -Test$ -Object -example.Test$ -hello -75 -90 -7 -hello -DefDef -false -0 -false -@main def hello -