Skip to content

Commit

Permalink
Add --offline option
Browse files Browse the repository at this point in the history
  • Loading branch information
MaciejG604 committed Sep 19, 2023
1 parent 42598bb commit aa5b7bd
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,23 @@ import bloop.rifle.{BloopRifleConfig, BloopServer, BloopThreads}
import ch.epfl.scala.bsp4j.BuildClient

import scala.build.Logger
import scala.build.errors.FetchingDependenciesError
import scala.build.internal.Constants
import scala.concurrent.duration.DurationInt
import scala.util.Try

final class BloopCompilerMaker(
config: BloopRifleConfig,
threads: BloopThreads,
strictBloopJsonCheck: Boolean
strictBloopJsonCheck: Boolean,
offline: Boolean
) extends ScalaCompilerMaker {
def create(
workspace: os.Path,
classesDir: os.Path,
buildClient: BuildClient,
logger: Logger
): BloopCompiler = {
): ScalaCompiler = {
val createBuildServer =
() =>
BloopServer.buildServer(
Expand All @@ -30,6 +33,20 @@ final class BloopCompilerMaker(
threads,
logger.bloopRifleLogger
)
new BloopCompiler(createBuildServer, 20.seconds, strictBloopJsonCheck)

Try(new BloopCompiler(createBuildServer, 20.seconds, strictBloopJsonCheck))
.toEither
.left.flatMap {
case e if offline =>
e.getCause match
case _: FetchingDependenciesError =>
logger.debug("Couldn't fetch Bloop from cache, fallback to using scalac")
Right(
SimpleScalaCompilerMaker("java", Nil)
.create(workspace, classesDir, buildClient, logger)
)
case _ => Left(e)
case e => Left(e)
}.fold(t => throw t, identity)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ final case class TestInputs(
withCustomInputs(fromDirectory, None, skipCreatingSources) { (root, inputs) =>
val compilerMaker = bloopConfigOpt match {
case Some(bloopConfig) =>
new BloopCompilerMaker(bloopConfig, buildThreads.bloop, strictBloopJsonCheck = true)
new BloopCompilerMaker(
bloopConfig,
buildThreads.bloop,
strictBloopJsonCheck = true,
offline = false
)
case None =>
SimpleScalaCompilerMaker("java", Nil)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package scala.cli.commands.shared
import caseapp.*
import com.github.plokhotnyuk.jsoniter_scala.core.*
import com.github.plokhotnyuk.jsoniter_scala.macros.*
import coursier.cache.{CacheLogger, FileCache}
import coursier.cache.{CacheLogger, CachePolicy, FileCache}

import scala.cli.commands.tags
import scala.concurrent.duration.Duration
Expand All @@ -26,7 +26,12 @@ final case class CoursierOptions(
@HelpMessage("Enable checksum validation of artifacts downloaded by coursier")
@Tag(tags.implementation)
@Hidden
coursierValidateChecksums: Option[Boolean] = None
coursierValidateChecksums: Option[Boolean] = None,

@Group(HelpGroup.Dependency.toString)
@HelpMessage("Disable using the network to download dependencies, use only the cache")
@Tag(tags.experimental)
offline: Option[Boolean] = None
) {
// format: on

Expand All @@ -42,6 +47,12 @@ final case class CoursierOptions(
baseCache = baseCache.withTtl(ttl0)
for (loc <- cache.filter(_.trim.nonEmpty))
baseCache = baseCache.withLocation(loc)

offline.foreach {
case true => baseCache = baseCache.withCachePolicies(Seq(CachePolicy.LocalOnly))
case false => baseCache
}

baseCache
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,8 @@ final case class SharedOptions(
verbosity = Some(logging.verbosity),
strictBloopJsonCheck = strictBloopJsonCheck,
interactive = Some(() => interactive),
exclude = exclude.map(Positioned.commandLine)
exclude = exclude.map(Positioned.commandLine),
offline = coursier.offline
),
notForBloopOptions = bo.PostBuildOptions(
scalaJsLinkerOptions = linkerOptions(js),
Expand Down Expand Up @@ -543,7 +544,8 @@ final case class SharedOptions(
new BloopCompilerMaker(
value(bloopRifleConfig()),
threads.bloop,
strictBloopJsonCheckOrDefault
strictBloopJsonCheckOrDefault,
coursier.offline.getOrElse(false)
)
else
SimpleScalaCompilerMaker("java", Nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1818,4 +1818,134 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
}
}
}

test("offline mode should fail on missing artifacts") {
// Kill bloop deamon to test scalac fallback
os.proc(TestUtil.cli, "--power", "bloop", "exit")
.call(cwd = os.pwd)

val depScalaVersion = actualScalaVersion match {
case sv if sv.startsWith("2.12") => "2.12"
case sv if sv.startsWith("2.13") => "2.13"
case sv if sv.startsWith("3") => "3"
}

val dep = s"com.lihaoyi:os-lib_$depScalaVersion:0.9.1"
val inputs = TestInputs(
os.rel / "NoDeps.scala" ->
"""//> using jvm zulu:11
|object NoDeps extends App {
| println("Hello from NoDeps")
|}
|""".stripMargin,
os.rel / "WithDeps.scala" ->
s"""//> using jvm zulu:11
|//> using dep $dep
|
|object WithDeps extends App {
| println("Hello from WithDeps")
|}
|""".stripMargin
)
inputs.fromRoot { root =>
val cachePath = root / ".cache"
os.makeDir(cachePath)

val extraEnv = Map("COURSIER_CACHE" -> cachePath.toString)

val emptyCacheWalkSize = os.walk(cachePath).size

val noArtifactsRes = os.proc(
TestUtil.cli,
"--power",
"NoDeps.scala",
extraOptions,
"--offline",
"--cache",
cachePath.toString
)
.call(cwd = root, check = false, mergeErrIntoOut = true)
expect(noArtifactsRes.exitCode == 1)

// Cache unchanged
expect(emptyCacheWalkSize == os.walk(cachePath).size)

// Download the artifacts for scala
os.proc(TestUtil.cs, "install", s"scala:$actualScalaVersion")
.call(cwd = root, env = extraEnv)
os.proc(TestUtil.cs, "install", s"scalac:$actualScalaVersion")
.call(cwd = root, env = extraEnv)

// Download JVM that won't suit Bloop, also no Bloop artifacts are present
os.proc(TestUtil.cs, "java-home", "--jvm", "zulu:11")
.call(cwd = root, env = extraEnv)

val scalaJvmCacheWalkSize = os.walk(cachePath).size

val scalaAndJvmRes = os.proc(
TestUtil.cli,
"--power",
"NoDeps.scala",
extraOptions,
"--offline",
"--cache",
cachePath.toString,
"-v",
"-v"
)
.call(cwd = root, mergeErrIntoOut = true)
expect(scalaAndJvmRes.exitCode == 0)
expect(scalaAndJvmRes.out.trim().contains(
"Couldn't fetch Bloop from cache, fallback to using scalac"
))
expect(scalaAndJvmRes.out.trim().contains("Hello from NoDeps"))

// Cache unchanged
expect(scalaJvmCacheWalkSize == os.walk(cachePath).size)

// Missing dependencies
val missingDepsRes = os.proc(
TestUtil.cli,
"--power",
"WithDeps.scala",
extraOptions,
"--offline",
"--cache",
cachePath.toString
)
.call(cwd = root, check = false, mergeErrIntoOut = true)
expect(missingDepsRes.exitCode == 1)
expect(missingDepsRes.out.trim().contains("Error downloading com.lihaoyi:os-lib"))

// Cache unchanged
expect(scalaJvmCacheWalkSize == os.walk(cachePath).size)

// Download dependencies
os.proc(TestUtil.cs, "fetch", dep)
.call(cwd = root, env = extraEnv)

val withDependencyCacheWalkSize = os.walk(cachePath).size

val depsRes = os.proc(
TestUtil.cli,
"--power",
"WithDeps.scala",
extraOptions,
"--offline",
"--cache",
cachePath.toString,
"-v",
"-v"
)
.call(cwd = root, mergeErrIntoOut = true)
expect(depsRes.exitCode == 0)
expect(
depsRes.out.trim().contains("Couldn't fetch Bloop from cache, fallback to using scalac")
)
expect(depsRes.out.trim().contains("Hello from WithDeps"))

// Cache changed
expect(withDependencyCacheWalkSize == os.walk(cachePath).size)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package scala.build.options

import com.github.plokhotnyuk.jsoniter_scala.core.*
import coursier.cache.{ArchiveCache, FileCache}
import coursier.cache.{ArchiveCache, FileCache, UnArchiver}
import coursier.core.{Repository, Version}
import coursier.parse.RepositoryParser
import coursier.util.{Artifact, Task}
Expand Down Expand Up @@ -305,6 +305,8 @@ final case class BuildOptions(
val svOpt: Option[String] = scalaOptions.scalaVersion match {
case Some(MaybeScalaVersion(None)) =>
None
case Some(MaybeScalaVersion(Some(svInput))) if internal.offline.getOrElse(false) =>
Some(svInput)
case Some(MaybeScalaVersion(Some(svInput))) =>
val sv = value {
svInput match {
Expand Down Expand Up @@ -345,16 +347,19 @@ final case class BuildOptions(
)
}
}
// match {
// // A maven-metadata containing available scala versions may not be available in the cache,
// // so we can skip the version validation hoping that it is correct
// // The maven metadata is absent even after cs install scala(c):3.3.0
// case Left(e) if internal.offline.getOrElse(false) =>
// println(s"!!! Caught exception: $e")
// e.printStackTrace(System.out)
// svInput
// case leftOrRight => value(leftOrRight)
// }
Some(sv)

case None =>
val allStableVersions =
ScalaVersionUtil.allMatchingVersions(None, finalCache, value(finalRepositories))
.filter(ScalaVersionUtil.isStable)
val sv = value {
ScalaVersionUtil.default(allStableVersions)
}
Some(sv)
case None => Some(Constants.defaultScalaVersion)
}

svOpt match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ final case class InternalOptions(
*/
keepResolution: Boolean = false,
extraSourceFiles: Seq[Positioned[os.Path]] = Nil,
exclude: Seq[Positioned[String]] = Nil
exclude: Seq[Positioned[String]] = Nil,
offline: Option[Boolean] = None
) {
def verbosityOrDefault: Int = verbosity.getOrElse(0)
def strictBloopJsonCheckOrDefault: Boolean =
Expand Down
50 changes: 27 additions & 23 deletions website/docs/reference/cli-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,33 @@ Aliases: `-f`

Force overwriting values for key

## Coursier options

Available in commands:

[`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall)

<!-- Automatically generated, DO NOT EDIT MANUALLY -->

### `--ttl`

[Internal]
Specify a TTL for changing dependencies, such as snapshots

### `--cache`

[Internal]
Set the coursier cache location

### `--coursier-validate-checksums`

[Internal]
Enable checksum validation of artifacts downloaded by coursier

### `--offline`

Disable using the network to download dependencies, use only the cache

## Cross options

Available in commands:
Expand Down Expand Up @@ -1848,29 +1875,6 @@ Aliases: `--name`
[Internal]
Name of BSP

### Coursier options

Available in commands:

[`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall)

<!-- Automatically generated, DO NOT EDIT MANUALLY -->

### `--ttl`

[Internal]
Specify a TTL for changing dependencies, such as snapshots

### `--cache`

[Internal]
Set the coursier cache location

### `--coursier-validate-checksums`

[Internal]
Enable checksum validation of artifacts downloaded by coursier

### Default file options

Available in commands:
Expand Down

0 comments on commit aa5b7bd

Please sign in to comment.