Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Package command - add support for multi modules #816

Merged
merged 2 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ object CommandUtils {
.getOrElse(programName)

lazy val shouldCheckUpdate: Boolean = scala.util.Random.nextInt() % 10 == 1

def printablePath(path: os.Path): String =
if (path.startsWith(Os.pwd)) "." + File.separator + path.relativeTo(Os.pwd).toString
else path.toString
}
60 changes: 39 additions & 21 deletions modules/cli/src/main/scala/scala/cli/commands/Package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,8 @@ object Package extends ScalaCommand[PackageOptions] {
.map(_ + extension)
}
.getOrElse(defaultName)
val destPath = os.Path(dest, Os.pwd)
val printableDest =
if (destPath.startsWith(Os.pwd)) "." + File.separator + destPath.relativeTo(Os.pwd).toString
else destPath.toString
val destPath = os.Path(dest, Os.pwd)
val printableDest = CommandUtils.printablePath(destPath)

def alreadyExistsCheck(): Unit = {
val alreadyExists = !force &&
Expand All @@ -214,36 +212,43 @@ object Package extends ScalaCommand[PackageOptions] {

val packageOptions = build.options.notForBloopOptions.packageOptions

packageType match {
val outputPath = packageType match {
case PackageType.Bootstrap =>
bootstrap(build, destPath, value(mainClass), () => alreadyExistsCheck())
destPath
case PackageType.LibraryJar =>
val content = Library.libraryJar(build)
alreadyExistsCheck()
if (force) os.write.over(destPath, content)
else os.write(destPath, content)
destPath
case PackageType.SourceJar =>
val now = System.currentTimeMillis()
val content = sourceJar(build, now)
alreadyExistsCheck()
if (force) os.write.over(destPath, content)
else os.write(destPath, content)
destPath
case PackageType.DocJar =>
val content = value(docJar(build, logger, extraArgs))
alreadyExistsCheck()
if (force) os.write.over(destPath, content)
else os.write(destPath, content)
destPath
case PackageType.Assembly =>
assembly(build, destPath, value(mainClass), () => alreadyExistsCheck())
destPath

case PackageType.Js =>
value(buildJs(build, destPath, value(mainClass), logger))

case PackageType.Native =>
buildNative(build, destPath, value(mainClass), logger)
destPath

case PackageType.GraalVMNativeImage =>
buildGraalVMNativeImage(build, destPath, value(mainClass), extraArgs, logger)
destPath

case nativePackagerType: PackageType.NativePackagerType =>
val bootstrapPath = os.temp.dir(prefix = "scala-packager") / "app"
Expand Down Expand Up @@ -319,20 +324,24 @@ object Package extends ScalaCommand[PackageOptions] {
case PackageType.Msi =>
WindowsPackage(windowsSettings).build()
}
destPath
case PackageType.Docker =>
docker(build, value(mainClass), logger)
destPath
}

val printableOutput = CommandUtils.printablePath(outputPath)

if (packageType.runnable.nonEmpty)
logger.message {
if (packageType.runnable.contains(true))
s"Wrote $dest, run it with" + System.lineSeparator() +
" " + printableDest
s"Wrote $outputPath, run it with" + System.lineSeparator() +
" " + printableOutput
else if (packageType == PackageType.Js)
s"Wrote $dest, run it with" + System.lineSeparator() +
" node " + printableDest
s"Wrote $outputPath, run it with" + System.lineSeparator() +
" node " + printableOutput
else
s"Wrote $dest"
s"Wrote $outputPath"
}

val mTimeDestPathOpt = if (packageType.runnable.isEmpty) None else Some(os.mtime(destPath))
Expand Down Expand Up @@ -525,7 +534,7 @@ object Package extends ScalaCommand[PackageOptions] {
destPath: os.Path,
mainClass: String,
logger: Logger
): Either[BuildException, Unit] = {
): Either[BuildException, os.Path] = {
val linkerConfig = build.options.scalaJsOptions.linkerConfig(logger)
linkJs(
build,
Expand Down Expand Up @@ -672,7 +681,7 @@ object Package extends ScalaCommand[PackageOptions] {
fullOpt: Boolean,
noOpt: Boolean,
logger: Logger
): Either[BuildException, Unit] =
): Either[BuildException, os.Path] =
Library.withLibraryJar(build, dest.last.toString.stripSuffix(".jar")) { mainJar =>
val classPath = os.Path(mainJar, os.pwd) +: build.artifacts.classPath
val linkingDir = os.temp.dir(prefix = "scala-cli-js-linking")
Expand All @@ -698,16 +707,25 @@ object Package extends ScalaCommand[PackageOptions] {
val relSourceMapJs = os.rel / "main.js.map"
val mainJs = linkingDir / relMainJs
val sourceMapJs = linkingDir / relSourceMapJs
if (os.exists(mainJs)) {
os.copy(mainJs, dest, replaceExisting = true)
if (build.options.scalaJsOptions.emitSourceMaps && os.exists(sourceMapJs)) {
val sourceMapDest =
build.options.scalaJsOptions.sourceMapsDest.getOrElse(os.Path(s"$dest.map"))
os.copy(sourceMapJs, sourceMapDest, replaceExisting = true)
logger.message(s"Emitted js source maps to: $sourceMapDest")

if (os.exists(mainJs))
if (os.walk(linkingDir).filterNot(_ == mainJs).filterNot(_ == sourceMapJs).nonEmpty) {
lwronski marked this conversation as resolved.
Show resolved Hide resolved
// copy linking dir to dest,
os.copy(linkingDir, dest, createFolders = true, replaceExisting = true)
logger.debug(s"Scala.js linker generate multiple files for js multi-modules. Copy files to $dest directory.")
dest / "main.js"
}
else {
os.copy(mainJs, dest, replaceExisting = true)
if (build.options.scalaJsOptions.emitSourceMaps && os.exists(sourceMapJs)) {
val sourceMapDest =
build.options.scalaJsOptions.sourceMapsDest.getOrElse(os.Path(s"$dest.map"))
os.copy(sourceMapJs, sourceMapDest, replaceExisting = true)
logger.message(s"Emitted js source maps to: $sourceMapDest")
}
os.remove.all(linkingDir)
dest
}
os.remove.all(linkingDir)
}
else {
val found = os.walk(linkingDir).map(_.relativeTo(linkingDir))
value(Left(new ScalaJsLinkingError(relMainJs, found)))
Expand Down
8 changes: 4 additions & 4 deletions modules/cli/src/main/scala/scala/cli/commands/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,9 @@ object Run extends ScalaCommand[RunOptions] {
build.options.scalaJsOptions.fullOpt.getOrElse(false),
build.options.scalaJsOptions.noOpt.getOrElse(false),
logger
).map { _ =>
).map { outputPath =>
val process = Runner.runJs(
jsDest.toIO,
outputPath.toIO,
args,
logger,
allowExecve = allowExecve,
Expand Down Expand Up @@ -282,8 +282,8 @@ object Run extends ScalaCommand[RunOptions] {
fullOpt,
noOpt,
logger
).map { _ =>
f(dest)
).map { outputPath =>
f(outputPath)
}
finally if (os.exists(dest)) os.remove(dest)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,49 @@ abstract class PackageTestDefinitions(val scalaVersionOpt: Option[String])
}
}

def multiModulesJsTest(): Unit = {
val fileName = "Hello.scala"
val message = "Hello World from JS"
val inputs = TestInputs(
Seq(
os.rel / fileName ->
s"""|//> using jsModuleKind "es"
|//> using jsModuleSplitStyleStr "smallestmodules"
|
|case class Foo(bar: String)
|
|object Hello extends App {
| println(Foo("$message").bar)
|}
|""".stripMargin
)
)
val destDir = fileName.stripSuffix(".scala")
inputs.fromRoot { root =>
os.proc(TestUtil.cli, "package", extraOptions, fileName, "--js", "-o", destDir).call(
cwd = root,
stdin = os.Inherit,
stdout = os.Inherit
)

val launcher = root / destDir / "main.js"
val nodePath = TestUtil.fromPath("node").getOrElse("node")
os.write(root / "package.json", "{\n\n \"type\": \"module\"\n\n}") // enable es module
val output = os.proc(nodePath, launcher.toString).call(cwd = root).out.text().trim
expect(output == message)
}
}

if (!TestUtil.isNativeCli || !Properties.isWin) {
test("simple JS") {
simpleJsTest()
}
test("source maps js") {
sourceMapJsTest()
}
test("multi modules js") {
multiModulesJsTest()
}
}

def simpleNativeTest(): Unit = {
Expand Down