Skip to content

Commit

Permalink
Allow shebangs and using directives in scala files
Browse files Browse the repository at this point in the history
  • Loading branch information
lwronski committed Nov 30, 2021
1 parent 4cb92ac commit 8264b42
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,22 @@ case object ScalaPreprocessor extends Preprocessor {
Option[String]
)]] = either {

val afterStrictUsing = value(processStrictUsing(content, scopeRoot))
val (content0, isSheBang) = SheBang.ignoreSheBangLines(content)

val afterStrictUsing = value(processStrictUsing(content0, scopeRoot))
val afterUsing = value {
processUsing(path, afterStrictUsing.map(_._2).getOrElse(content), scopeRoot)
processUsing(path, afterStrictUsing.map(_._2).getOrElse(content0), scopeRoot)
.sequence
}
val afterProcessImports = value {
processSpecialImports(
afterUsing.flatMap(_._4).orElse(afterStrictUsing.map(_._2)).getOrElse(content),
afterUsing.flatMap(_._4).orElse(afterStrictUsing.map(_._2)).getOrElse(content0),
path
)
}

if (afterStrictUsing.isEmpty && afterUsing.isEmpty && afterProcessImports.isEmpty) None
if (afterStrictUsing.isEmpty && afterUsing.isEmpty && afterProcessImports.isEmpty)
None
else {
val allRequirements = afterUsing.map(_._1).toSeq ++ afterProcessImports.map(_._1).toSeq
val summedRequirements = allRequirements.foldLeft(BuildRequirements())(_ orElse _)
Expand All @@ -151,6 +154,7 @@ case object ScalaPreprocessor extends Preprocessor {
.map(_._3)
.orElse(afterUsing.flatMap(_._4))
.orElse(afterStrictUsing.map(_._2))
.orElse(if (isSheBang) Some(content0) else None)
val scopedRequirements = afterUsing.map(_._2).getOrElse(Nil)
Some((summedRequirements, scopedRequirements, summedOptions, lastContentOpt))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import scala.build.Inputs
import scala.build.errors.BuildException
import scala.build.internal.{AmmUtil, CodeWrapper, CustomCodeWrapper, Name}
import scala.build.options.{BuildOptions, BuildRequirements}
import scala.util.matching.Regex

final case class ScriptPreprocessor(codeWrapper: CodeWrapper) extends Preprocessor {
def preprocess(input: Inputs.SingleElement)
Expand Down Expand Up @@ -54,23 +53,6 @@ final case class ScriptPreprocessor(codeWrapper: CodeWrapper) extends Preprocess

object ScriptPreprocessor {

private val sheBangRegex: Regex = s"""(^(#!.*(\\r\\n?|\\n)?)+(\\s*!#.*)?)""".r

private def ignoreSheBangLines(content: String): String =
if (content.startsWith("#!")) {
val regexMatch = sheBangRegex.findFirstMatchIn(content)
regexMatch match {
case Some(firstMatch) =>
content.replace(
firstMatch.toString(),
System.lineSeparator() * firstMatch.toString().split(System.lineSeparator()).length
)
case None => content
}
}
else
content

private def preprocess(
reportingPath: Either[String, os.Path],
content: String,
Expand All @@ -79,7 +61,7 @@ object ScriptPreprocessor {
scopePath: ScopePath
): Either[BuildException, List[PreprocessedSource.InMemory]] = either {

val contentIgnoredSheBangLines = ignoreSheBangLines(content)
val (contentIgnoredSheBangLines, _) = SheBang.ignoreSheBangLines(content)

val (pkg, wrapper) = AmmUtil.pathToPackageWrapper(subPath)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package scala.build.preprocessing

import scala.util.matching.Regex

object SheBang {
private val sheBangRegex: Regex = s"""(^(#!.*(\\r\\n?|\\n)?)+(\\s*!#.*)?)""".r

def ignoreSheBangLines(content: String): (String, Boolean) =
if (content.startsWith("#!")) {
val regexMatch = sheBangRegex.findFirstMatchIn(content)
regexMatch match {
case Some(firstMatch) =>
content.replace(
firstMatch.toString(),
System.lineSeparator() * firstMatch.toString().split(System.lineSeparator()).length
) -> true
case None => (content, false)
}
}
else
(content, false)

}
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class SourcesTests extends munit.FunSuite {
}
}

test("should skip SheBang in .sc") {
test("should skip SheBang in .sc and .scala") {
val testInputs = TestInputs(
os.rel / "something1.sc" ->
"""#!/usr/bin/env scala-cli
Expand All @@ -227,14 +227,14 @@ class SourcesTests extends munit.FunSuite {
|#! nix-shell -i scala-cli
|
|println("Hello World")""".stripMargin,
os.rel / "something4.sc" ->
os.rel / "something4.scala" ->
"""#!/usr/bin/scala-cli
|#! nix-shell -i scala-cli
|
|!#
|
|println("Hello World")""".stripMargin,
os.rel / "something5.sc" ->
os.rel / "something5.scala" ->
"""#!/usr/bin/scala-cli
|
|println("Hello World #!")""".stripMargin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1207,7 +1207,7 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
}
}

if (!Properties.isWin)
if (!Properties.isWin) {
test("CLI args passed to shebang script") {
val inputs = TestInputs(
Seq(
Expand All @@ -1222,6 +1222,25 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
expect(p.out.text().trim == "List(1, 2, 3, -v)")
}
}
test("CLI args passed to shebang in Scala file") {
val inputs = TestInputs(
Seq(
os.rel / "f.scala" -> s"""|#!/usr/bin/env -S ${TestUtil.cli.mkString(" ")} shebang
|object Hello {
| def main(args: Array[String]) = {
| println(args.toList)
| }
|}
|""".stripMargin
)
)
inputs.fromRoot { root =>
os.perms.set(root / "f.scala", os.PermSet.fromString("rwx------"))
val p = os.proc("./f.scala", "1", "2", "3", "-v").call(cwd = root)
expect(p.out.text().trim == "List(1, 2, 3, -v)")
}
}
}

test("Runs with JVM 8") {
val inputs = TestInputs(
Expand Down

0 comments on commit 8264b42

Please sign in to comment.