Merge pull request #4196 from eed3si9n/wip/merge-1.1.x

Merge 1.1.x
This commit is contained in:
eugene yokota 2018-06-13 03:20:17 -04:00 committed by GitHub
commit 0d3d6bab02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 231 additions and 53 deletions

View File

@ -22,7 +22,7 @@ import sbt.internal.util.HNil
import sbt.internal.util.HListFormats._ import sbt.internal.util.HListFormats._
import sbt.util.FileInfo.{ exists, lastModified } import sbt.util.FileInfo.{ exists, lastModified }
import sbt.util.CacheImplicits._ import sbt.util.CacheImplicits._
import sbt.util.Tracked.inputChanged import sbt.util.Tracked.{ inputChanged, outputChanged }
sealed trait PackageOption sealed trait PackageOption
object Package { object Package {
@ -72,17 +72,18 @@ object Package {
(inChanged, inputs: Inputs) => (inChanged, inputs: Inputs) =>
import exists.format import exists.format
val sources :+: _ :+: manifest :+: HNil = inputs val sources :+: _ :+: manifest :+: HNil = inputs
inputChanged(cacheStoreFactory make "output") { (outChanged, jar: PlainFileInfo) => outputChanged(cacheStoreFactory make "output") { (outChanged, jar: PlainFileInfo) =>
if (inChanged || outChanged) if (inChanged || outChanged) {
makeJar(sources.toSeq, jar.file, manifest, log) makeJar(sources.toSeq, jar.file, manifest, log)
else jar.file
} else
log.debug("Jar uptodate: " + jar.file) log.debug("Jar uptodate: " + jar.file)
} }
} }
val map = conf.sources.toMap val map = conf.sources.toMap
val inputs = map :+: lastModified(map.keySet) :+: manifest :+: HNil val inputs = map :+: lastModified(map.keySet) :+: manifest :+: HNil
cachedMakeJar(inputs)(exists(conf.jar)) cachedMakeJar(inputs)(() => exists(conf.jar))
} }
def setVersion(main: Attributes): Unit = { def setVersion(main: Attributes): Unit = {
val version = Attributes.Name.MANIFEST_VERSION val version = Attributes.Name.MANIFEST_VERSION

View File

@ -69,7 +69,7 @@ $HelpCommand <regular expression>
This will be used as the default level for logging from commands, settings, and tasks. This will be used as the default level for logging from commands, settings, and tasks.
Any explicit `logLevel` configuration in a project overrides this setting. Any explicit `logLevel` configuration in a project overrides this setting.
-$level -$level OR --$level
Sets the global logging level as described above, but does so before any other commands are executed on startup, including project loading. Sets the global logging level as described above, but does so before any other commands are executed on startup, including project loading.
This is useful as a startup option: This is useful as a startup option:
@ -79,7 +79,9 @@ $HelpCommand <regular expression>
def runEarly(command: String) = s"$EarlyCommand($command)" def runEarly(command: String) = s"$EarlyCommand($command)"
private[sbt] def isEarlyCommand(s: String): Boolean = { private[sbt] def isEarlyCommand(s: String): Boolean = {
val levelOptions = Level.values.toSeq map { "-" + _ } val levelOptions = Level.values.toSeq flatMap { elem =>
List("-" + elem, "--" + elem)
}
(s.startsWith(EarlyCommand + "(") && s.endsWith(")")) || (s.startsWith(EarlyCommand + "(") && s.endsWith(")")) ||
(levelOptions contains s) (levelOptions contains s)
} }

View File

@ -69,7 +69,8 @@ object BasicCommands {
private[this] def earlyParser: State => Parser[String] = (s: State) => { private[this] def earlyParser: State => Parser[String] = (s: State) => {
val p1 = token(EarlyCommand + "(") flatMap (_ => otherCommandParser(s) <~ token(")")) val p1 = token(EarlyCommand + "(") flatMap (_ => otherCommandParser(s) <~ token(")"))
val p2 = token("-") flatMap (_ => levelParser) val p2 = token("-") flatMap (_ => levelParser)
p1 | p2 val p3 = token("--") flatMap (_ => levelParser)
p1 | p2 | p3
} }
private[this] def earlyHelp = Help(EarlyCommand, EarlyCommandBrief, EarlyCommandDetailed) private[this] def earlyHelp = Help(EarlyCommand, EarlyCommandBrief, EarlyCommandDetailed)

View File

@ -12,7 +12,7 @@ import java.nio.file.FileSystems
import sbt.BasicCommandStrings.ClearOnFailure import sbt.BasicCommandStrings.ClearOnFailure
import sbt.State.FailureWall import sbt.State.FailureWall
import sbt.internal.io.{ Source, SourceModificationWatch, WatchState } import sbt.internal.io.{ EventMonitor, Source, WatchState }
import sbt.internal.util.AttributeKey import sbt.internal.util.AttributeKey
import sbt.internal.util.Types.const import sbt.internal.util.Types.const
import sbt.io._ import sbt.io._
@ -33,6 +33,12 @@ trait Watched {
*/ */
def pollInterval: FiniteDuration = Watched.PollDelay def pollInterval: FiniteDuration = Watched.PollDelay
/**
* The duration for which the EventMonitor while ignore file events after a file triggers
* a new build.
*/
def antiEntropy: FiniteDuration = Watched.AntiEntropy
/** The message to show when triggered execution waits for sources to change.*/ /** The message to show when triggered execution waits for sources to change.*/
private[sbt] def watchingMessage(s: WatchState): String = Watched.defaultWatchingMessage(s) private[sbt] def watchingMessage(s: WatchState): String = Watched.defaultWatchingMessage(s)
@ -86,53 +92,70 @@ object Watched {
override def watchSources(s: State) = (base.watchSources(s) /: paths)(_ ++ _.watchSources(s)) override def watchSources(s: State) = (base.watchSources(s) /: paths)(_ ++ _.watchSources(s))
override def terminateWatch(key: Int): Boolean = base.terminateWatch(key) override def terminateWatch(key: Int): Boolean = base.terminateWatch(key)
override val pollInterval = (base +: paths).map(_.pollInterval).min override val pollInterval = (base +: paths).map(_.pollInterval).min
override val antiEntropy = (base +: paths).map(_.antiEntropy).min
override def watchingMessage(s: WatchState) = base.watchingMessage(s) override def watchingMessage(s: WatchState) = base.watchingMessage(s)
override def triggeredMessage(s: WatchState) = base.triggeredMessage(s) override def triggeredMessage(s: WatchState) = base.triggeredMessage(s)
} }
def empty: Watched = new AWatched def empty: Watched = new AWatched
val PollDelay: FiniteDuration = 500.milliseconds val PollDelay: FiniteDuration = 500.milliseconds
val AntiEntropy: FiniteDuration = 40.milliseconds
def isEnter(key: Int): Boolean = key == 10 || key == 13 def isEnter(key: Int): Boolean = key == 10 || key == 13
def printIfDefined(msg: String) = if (!msg.isEmpty) System.out.println(msg) def printIfDefined(msg: String) = if (!msg.isEmpty) System.out.println(msg)
def executeContinuously(watched: Watched, s: State, next: String, repeat: String): State = { def executeContinuously(watched: Watched, s: State, next: String, repeat: String): State = {
@tailrec def shouldTerminate: Boolean = @tailrec def shouldTerminate: Boolean =
(System.in.available > 0) && (watched.terminateWatch(System.in.read()) || shouldTerminate) (System.in.available > 0) && (watched.terminateWatch(System.in.read()) || shouldTerminate)
val sources = watched.watchSources(s) val log = s.log
val service = s get ContinuousWatchService getOrElse watched.watchService() val logger = new EventMonitor.Logger {
val watchState = s get ContinuousState getOrElse WatchState.empty(service, sources) override def debug(msg: => Any): Unit = log.debug(msg.toString)
}
if (watchState.count > 0) s get ContinuousEventMonitor match {
printIfDefined(watched watchingMessage watchState) case None =>
// This is the first iteration, so run the task and create a new EventMonitor
val (triggered, newWatchState) = (ClearOnFailure :: next :: FailureWall :: repeat :: s)
try { .put(
val (triggered, newWatchState) = ContinuousEventMonitor,
SourceModificationWatch.watch(watched.pollInterval, watchState)(shouldTerminate) EventMonitor(
(triggered, newWatchState) WatchState.empty(watched.watchService(), watched.watchSources(s)),
} catch { watched.pollInterval,
case e: Exception => watched.antiEntropy,
s.log.error( shouldTerminate,
"Error occurred obtaining files to watch. Terminating continuous execution..." logger
)
) )
s.handleError(e) case Some(eventMonitor) =>
(false, watchState) printIfDefined(watched watchingMessage eventMonitor.state)
} val triggered = try eventMonitor.awaitEvent()
catch {
if (triggered) { case e: Exception =>
printIfDefined(watched triggeredMessage newWatchState) log.error(
(ClearOnFailure :: next :: FailureWall :: repeat :: s) "Error occurred obtaining files to watch. Terminating continuous execution..."
.put(ContinuousState, newWatchState) )
.put(ContinuousWatchService, service) s.handleError(e)
} else { false
while (System.in.available() > 0) System.in.read() }
service.close() if (triggered) {
s.remove(ContinuousState).remove(ContinuousWatchService) printIfDefined(watched triggeredMessage eventMonitor.state)
ClearOnFailure :: next :: FailureWall :: repeat :: s
} else {
while (System.in.available() > 0) System.in.read()
eventMonitor.close()
s.remove(ContinuousEventMonitor)
}
} }
} }
val ContinuousEventMonitor =
AttributeKey[EventMonitor](
"watch event monitor",
"Internal: maintains watch state and monitor threads."
)
@deprecated("Superseded by ContinuousEventMonitor", "1.1.5")
val ContinuousState = val ContinuousState =
AttributeKey[WatchState]("watch state", "Internal: tracks state for continuous execution.") AttributeKey[WatchState]("watch state", "Internal: tracks state for continuous execution.")
@deprecated("Superseded by ContinuousEventMonitor", "1.1.5")
val ContinuousWatchService = val ContinuousWatchService =
AttributeKey[WatchService]( AttributeKey[WatchService](
"watch service", "watch service",

View File

@ -259,6 +259,7 @@ object Defaults extends BuildCommon {
concurrentRestrictions := defaultRestrictions.value, concurrentRestrictions := defaultRestrictions.value,
parallelExecution :== true, parallelExecution :== true,
pollInterval :== new FiniteDuration(500, TimeUnit.MILLISECONDS), pollInterval :== new FiniteDuration(500, TimeUnit.MILLISECONDS),
watchAntiEntropy :== new FiniteDuration(40, TimeUnit.MILLISECONDS),
watchService :== { () => watchService :== { () =>
Watched.createWatchService() Watched.createWatchService()
}, },
@ -352,7 +353,18 @@ object Defaults extends BuildCommon {
val baseDir = baseDirectory.value val baseDir = baseDirectory.value
val bases = unmanagedSourceDirectories.value val bases = unmanagedSourceDirectories.value
val include = (includeFilter in unmanagedSources).value val include = (includeFilter in unmanagedSources).value
val exclude = (excludeFilter in unmanagedSources).value val exclude = (excludeFilter in unmanagedSources).value match {
case e =>
(managedSources in ThisScope).value match {
case l if l.nonEmpty =>
e || new FileFilter {
private val files = l.toSet
override def accept(pathname: File): Boolean = files.contains(pathname)
override def toString = s"ManagedSourcesFilter($files)"
}
case _ => e
}
}
val baseSources = val baseSources =
if (sourcesInBase.value) Seq(new Source(baseDir, include, exclude, recursive = false)) if (sourcesInBase.value) Seq(new Source(baseDir, include, exclude, recursive = false))
else Nil else Nil
@ -364,7 +376,7 @@ object Defaults extends BuildCommon {
sourceDirectories := Classpaths sourceDirectories := Classpaths
.concatSettings(unmanagedSourceDirectories, managedSourceDirectories) .concatSettings(unmanagedSourceDirectories, managedSourceDirectories)
.value, .value,
sources := Classpaths.concat(unmanagedSources, managedSources).value sources := Classpaths.concatDistinct(unmanagedSources, managedSources).value
) )
lazy val resourceConfigPaths = Seq( lazy val resourceConfigPaths = Seq(
resourceDirectory := sourceDirectory.value / "resources", resourceDirectory := sourceDirectory.value / "resources",
@ -593,13 +605,15 @@ object Defaults extends BuildCommon {
Def.setting { Def.setting {
val getService = watchService.value val getService = watchService.value
val interval = pollInterval.value val interval = pollInterval.value
val _antiEntropy = watchAntiEntropy.value
val base = thisProjectRef.value val base = thisProjectRef.value
val msg = watchingMessage.value val msg = watchingMessage.value
val trigMsg = triggeredMessage.value val trigMsg = triggeredMessage.value
new Watched { new Watched {
val scoped = watchTransitiveSources in base val scoped = watchTransitiveSources in base
val key = scoped.scopedKey val key = scoped.scopedKey
override def pollInterval = interval override def antiEntropy: FiniteDuration = _antiEntropy
override def pollInterval: FiniteDuration = interval
override def watchingMessage(s: WatchState) = msg(s) override def watchingMessage(s: WatchState) = msg(s)
override def triggeredMessage(s: WatchState) = trigMsg(s) override def triggeredMessage(s: WatchState) = trigMsg(s)
override def watchService() = getService() override def watchService() = getService()
@ -3052,10 +3066,21 @@ object Classpaths {
excl: FileFilter excl: FileFilter
): Classpath = ): Classpath =
(base * (filter -- excl) +++ (base / config.name).descendantsExcept(filter, excl)).classpath (base * (filter -- excl) +++ (base / config.name).descendantsExcept(filter, excl)).classpath
@deprecated(
"The method only works for Scala 2, use the overloaded version to support both Scala 2 and Scala 3",
"1.1.5"
)
def autoPlugins(report: UpdateReport, internalPluginClasspath: Seq[File]): Seq[String] =
autoPlugins(report, internalPluginClasspath, isDotty = false)
def autoPlugins(report: UpdateReport, internalPluginClasspath: Seq[File]): Seq[String] = { def autoPlugins(
report: UpdateReport,
internalPluginClasspath: Seq[File],
isDotty: Boolean
): Seq[String] = {
val pluginClasspath = report.matching(configurationFilter(CompilerPlugin.name)) ++ internalPluginClasspath val pluginClasspath = report.matching(configurationFilter(CompilerPlugin.name)) ++ internalPluginClasspath
val plugins = sbt.internal.inc.classpath.ClasspathUtilities.compilerPlugins(pluginClasspath) val plugins =
sbt.internal.inc.classpath.ClasspathUtilities.compilerPlugins(pluginClasspath, isDotty)
plugins.map("-Xplugin:" + _.getAbsolutePath).toSeq plugins.map("-Xplugin:" + _.getAbsolutePath).toSeq
} }
@ -3077,7 +3102,11 @@ object Classpaths {
lazy val compilerPluginConfig = Seq( lazy val compilerPluginConfig = Seq(
scalacOptions := { scalacOptions := {
val options = scalacOptions.value val options = scalacOptions.value
val newPlugins = autoPlugins(update.value, internalCompilerPluginClasspath.value.files) val newPlugins = autoPlugins(
update.value,
internalCompilerPluginClasspath.value.files,
ScalaInstance.isDotty(scalaVersion.value)
)
val existing = options.toSet val existing = options.toSet
if (autoCompilerPlugins.value) options ++ newPlugins.filterNot(existing) else options if (autoCompilerPlugins.value) options ++ newPlugins.filterNot(existing) else options
} }

View File

@ -143,6 +143,7 @@ object Keys {
val analysis = AttributeKey[CompileAnalysis]("analysis", "Analysis of compilation, including dependencies and generated outputs.", DSetting) val analysis = AttributeKey[CompileAnalysis]("analysis", "Analysis of compilation, including dependencies and generated outputs.", DSetting)
val watch = SettingKey(BasicKeys.watch) val watch = SettingKey(BasicKeys.watch)
val suppressSbtShellNotification = settingKey[Boolean]("""True to suppress the "Executing in batch mode.." message.""").withRank(CSetting) val suppressSbtShellNotification = settingKey[Boolean]("""True to suppress the "Executing in batch mode.." message.""").withRank(CSetting)
val watchAntiEntropy = settingKey[FiniteDuration]("Duration for which the watch EventMonitor will ignore events for a file after that file has triggered a build.").withRank(BMinusSetting)
val pollInterval = settingKey[FiniteDuration]("Interval between checks for modified sources by the continuous execution command.").withRank(BMinusSetting) val pollInterval = settingKey[FiniteDuration]("Interval between checks for modified sources by the continuous execution command.").withRank(BMinusSetting)
val watchService = settingKey[() => WatchService]("Service to use to monitor file system changes.").withRank(BMinusSetting) val watchService = settingKey[() => WatchService]("Service to use to monitor file system changes.").withRank(BMinusSetting)
val watchSources = taskKey[Seq[Watched.WatchSource]]("Defines the sources in this project for continuous execution to watch for changes.").withRank(BMinusSetting) val watchSources = taskKey[Seq[Watched.WatchSource]]("Defines the sources in this project for continuous execution to watch for changes.").withRank(BMinusSetting)

View File

@ -328,8 +328,14 @@ object BuiltinCommands {
'v'.id.+.map(_.size + 1) | 'v'.id.+.map(_.size + 1) |
("V" ^^^ Int.MaxValue) ("V" ^^^ Int.MaxValue)
)) ))
def taskDetail(keys: Seq[AttributeKey[_]], firstOnly: Boolean): Seq[(String, String)] =
sortByLabel(withDescription(keys)) flatMap { t =>
taskStrings(t, firstOnly)
}
def taskDetail(keys: Seq[AttributeKey[_]]): Seq[(String, String)] = def taskDetail(keys: Seq[AttributeKey[_]]): Seq[(String, String)] =
sortByLabel(withDescription(keys)) flatMap taskStrings taskDetail(keys, false)
def allTaskAndSettingKeys(s: State): Seq[AttributeKey[_]] = { def allTaskAndSettingKeys(s: State): Seq[AttributeKey[_]] = {
val extracted = Project.extract(s) val extracted = Project.extract(s)
@ -367,16 +373,19 @@ object BuiltinCommands {
filter: Seq[AttributeKey[_]] => Seq[AttributeKey[_]], filter: Seq[AttributeKey[_]] => Seq[AttributeKey[_]],
arg: Option[String] arg: Option[String]
): String = { ): String = {
val commandAndDescription = taskDetail(filter(allTaskAndSettingKeys(s))) val commandAndDescription = taskDetail(filter(allTaskAndSettingKeys(s)), true)
arg match { arg match {
case Some(selected) => detail(selected, commandAndDescription.toMap) case Some(selected) => detail(selected, commandAndDescription.toMap)
case None => aligned(" ", " ", commandAndDescription) mkString ("\n", "\n", "") case None => aligned(" ", " ", commandAndDescription) mkString ("\n", "\n", "")
} }
} }
def taskStrings(key: AttributeKey[_]): Option[(String, String)] = key.description map { d => def taskStrings(key: AttributeKey[_], firstOnly: Boolean): Option[(String, String)] =
(key.label, d) key.description map { d =>
} if (firstOnly) (key.label, d.split("\r?\n")(0)) else (key.label, d)
}
def taskStrings(key: AttributeKey[_]): Option[(String, String)] = taskStrings(key, false)
def defaults = Command.command(DefaultsCommand) { s => def defaults = Command.command(DefaultsCommand) { s =>
s.copy(definedCommands = DefaultCommands) s.copy(definedCommands = DefaultCommands)

View File

@ -151,7 +151,9 @@ private[sbt] object SbtParser {
reporter.reset() reporter.reset()
val wrapperFile = new BatchSourceFile(reporterId, code) val wrapperFile = new BatchSourceFile(reporterId, code)
val unit = new CompilationUnit(wrapperFile) val unit = new CompilationUnit(wrapperFile)
val parser = new syntaxAnalyzer.UnitParser(unit) val parser = SbtParser.synchronized { // see https://github.com/sbt/sbt/issues/4148
new syntaxAnalyzer.UnitParser(unit)
}
val parsedTrees = SbtParser.synchronized { // see https://github.com/scala/bug/issues/10605 val parsedTrees = SbtParser.synchronized { // see https://github.com/scala/bug/issues/10605
parser.templateStats() parser.templateStats()
} }

View File

@ -0,0 +1,9 @@
[@liufengyun]: https://github.com/liufengyun
[4073]: https://github.com/sbt/sbt/issues/4073
[4084]: https://github.com/sbt/sbt/pull/4084
### Improvements
- Detect dotty plugins which have descriptor file named `plugin.properties` instead of `scalac-plugin.xml`. [#4073][4073]/[#4084][4084] by [@liufengyun][@liufengyun]

View File

@ -8,10 +8,10 @@ object Dependencies {
val baseScalaVersion = scala212 val baseScalaVersion = scala212
// sbt modules // sbt modules
private val ioVersion = "1.1.6" private val ioVersion = "1.1.10"
private val utilVersion = "1.1.3" private val utilVersion = "1.1.3"
private val lmVersion = "1.1.4" private val lmVersion = "1.1.5"
private val zincVersion = "1.1.5" private val zincVersion = "1.1.7"
private val sbtIO = "org.scala-sbt" %% "io" % ioVersion private val sbtIO = "org.scala-sbt" %% "io" % ioVersion

View File

@ -1,2 +1,3 @@
> -error > -error
> early(error) > early(error)
> --error

View File

@ -0,0 +1,16 @@
// hardcode dottyVersion to make test deterministic
lazy val dottyVersion = "0.8.0-bin-20180424-e77604d-NIGHTLY"
lazy val plugin = (project in file("plugin"))
.settings(
name := "dividezero",
version := "0.0.1",
organization := "ch.epfl.lamp",
scalaVersion := dottyVersion,
)
lazy val app = (project in file("."))
.settings(
scalaVersion := dottyVersion,
libraryDependencies += compilerPlugin("ch.epfl.lamp" %% "dividezero" % "0.0.1"),
)

View File

@ -0,0 +1,40 @@
package dividezero
import dotty.tools.dotc._
import core._
import Contexts.Context
import plugins._
import Phases.Phase
import ast.tpd
import transform.MegaPhase.MiniPhase
import Decorators._
import Symbols.Symbol
import Constants.Constant
import transform.{LinkAll, Pickler}
class DivideZero extends PluginPhase with StandardPlugin {
val name: String = "divideZero"
override val description: String = "divide zero check"
val phaseName = name
override val runsAfter = Set(Pickler.name)
override val runsBefore = Set(LinkAll.name)
override def init(options: List[String]): List[PluginPhase] = this :: Nil
private def isNumericDivide(sym: Symbol)(implicit ctx: Context): Boolean = {
def test(tpe: String): Boolean =
(sym.owner eq ctx.requiredClass(tpe.toTermName)) && sym.name.show == "/"
test("scala.Int") || test("scala.Long") || test("scala.Short") || test("scala.Float") || test("scala.Double")
}
override def transformApply(tree: tpd.Apply)(implicit ctx: Context): tpd.Tree = tree match {
case tpd.Apply(fun, tpd.Literal(Constants.Constant(v)) :: Nil) if isNumericDivide(fun.symbol) && v == 0 =>
ctx.warning("divide by zero", tree.pos)
tpd.Literal(Constant(0))
case _ =>
tree
}
}

View File

@ -0,0 +1 @@
pluginClass=dividezero.DivideZero

View File

@ -0,0 +1 @@
addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.2.0")

View File

@ -0,0 +1,13 @@
package hello
object Hello {
def main(args: Array[String]): Unit = {
val dotty: Int | String = "dotty"
val y = 5 / 0 // error
100 + 6 / 0 // error
6L / 0L // error
val z = 7 / 0.0 // error
println(s"Hello $dotty!")
}
}

View File

@ -0,0 +1,2 @@
> plugin/publishLocal
> app/run

View File

@ -0,0 +1,17 @@
import java.nio.file.Files
lazy val watchLoopTest = taskKey[Unit]("Check that managed sources are filtered")
sourceGenerators in Compile += Def.task {
val path = baseDirectory.value.toPath.resolve("src/main/scala/Foo.scala")
Files.write(path, "object Foo".getBytes).toFile :: Nil
}
watchLoopTest := {
val watched = watchSources.value
val managedSource = (managedSources in Compile).value.head
assert(!SourceWrapper.accept(watched, managedSource))
assert((sources in Compile).value.foldLeft((true, Set.empty[File])) {
case ((res, set), f) => (res && !set.contains(f), set + f)
}._1)
}

View File

@ -0,0 +1,6 @@
package sbt
object SourceWrapper {
def accept(sources: Seq[sbt.internal.io.Source], file: File): Boolean =
sources.exists(_.accept(file.toPath))
}

View File

@ -0,0 +1 @@
object Bar

View File

@ -0,0 +1 @@
object Foo

View File

@ -0,0 +1 @@
> watchLoopTest

View File

@ -167,6 +167,7 @@ final class ScriptedTests(
case "actions/external-doc" => LauncherBased // sbt/Package$ case "actions/external-doc" => LauncherBased // sbt/Package$
case "actions/input-task" => LauncherBased // sbt/Package$ case "actions/input-task" => LauncherBased // sbt/Package$
case "actions/input-task-dyn" => LauncherBased // sbt/Package$ case "actions/input-task-dyn" => LauncherBased // sbt/Package$
case "compiler-project/dotty-compiler-plugin" => LauncherBased // sbt/Package$
case "compiler-project/run-test" => LauncherBased // sbt/Package$ case "compiler-project/run-test" => LauncherBased // sbt/Package$
case "compiler-project/src-dep-plugin" => LauncherBased // sbt/Package$ case "compiler-project/src-dep-plugin" => LauncherBased // sbt/Package$
case "dependency-management/artifact" => LauncherBased // tbd case "dependency-management/artifact" => LauncherBased // tbd