mirror of https://github.com/sbt/sbt.git
Add support for polling some directories
It is not always possible to monitor a directory using OS file system events. For example, inotify does not work with nfs. To work around this, I add support for a hybrid FileTreeViewConfig that caches a portion of the file system and monitors it with os file system notification, but that polls a subset of the directories. When we query the view using list or listEntries, we will actually query the file system for the polling directories while we will read from the cache for the remainder. When we are not in a continuous build (~ *), there is no polling of the pollingDirectories but the cache will continue to update the regular directories in the background. When we are in a continuous build, we use a PollingWatchService to poll the pollingDirectories and continue to use the regular repository callbacks for the other directories. I suspect that #4179 may be resolved by adding the directories for which monitoring is not working to the pollingDirectories task.
This commit is contained in:
parent
2b2b84f589
commit
b155ffb77b
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
package sbt
|
||||
import sbt.Watched.WatchSource
|
||||
import sbt.internal.io.{ WatchServiceBackedObservable, WatchState }
|
||||
import sbt.internal.io.{ HybridPollingFileTreeRepository, WatchServiceBackedObservable, WatchState }
|
||||
import sbt.io._
|
||||
import FileTreeDataView.{ Observable, Observer }
|
||||
import sbt.util.Logger
|
||||
|
|
@ -109,4 +109,64 @@ object FileTreeViewConfig {
|
|||
FileEventMonitor.antiEntropy(copied, antiEntropy, msg => logger.debug(msg.toString))
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Provides a default [[FileTreeViewConfig]]. When the pollingSources argument is empty, it
|
||||
* returns the same config as [[sbt.FileTreeViewConfig.default(antiEntropy:scala\.concurrent\.duration\.FiniteDuration)*]].
|
||||
* Otherwise, it returns the same config as [[polling]].
|
||||
* @param antiEntropy the duration of the period after a path triggers a build for which it is
|
||||
* quarantined from triggering another build
|
||||
* @param pollingInterval the frequency with which the sbt.io.FileEventMonitor polls the file
|
||||
* system for the paths included in pollingSources
|
||||
* @param pollingSources the sources that will not be cached in the sbt.io.FileTreeRepository and that
|
||||
* will be periodically polled for changes during continuous builds.
|
||||
* @return
|
||||
*/
|
||||
def default(
|
||||
antiEntropy: FiniteDuration,
|
||||
pollingInterval: FiniteDuration,
|
||||
pollingSources: Seq[WatchSource]
|
||||
): FileTreeViewConfig = {
|
||||
if (pollingSources.isEmpty) default(antiEntropy)
|
||||
else polling(antiEntropy, pollingInterval, pollingSources)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a polling [[FileTreeViewConfig]]. Unlike the view returned by newDataView in
|
||||
* [[sbt.FileTreeViewConfig.default(antiEntropy:scala\.concurrent\.duration\.FiniteDuration)*]],
|
||||
* the view returned by newDataView will not cache any portion of the file system tree that is is
|
||||
* covered by the pollingSources parameter. The monitor that is generated by newMonitor, will
|
||||
* poll these directories for changes rather than relying on file system events from the
|
||||
* operating system. Any paths that are registered with the view that are not included in the
|
||||
* pollingSources will be cached and monitored using file system events from the operating system
|
||||
* in the same way that they are in the default view.
|
||||
*
|
||||
* @param antiEntropy the duration of the period after a path triggers a build for which it is
|
||||
* quarantined from triggering another build
|
||||
* @param pollingInterval the frequency with which the FileEventMonitor polls the file system
|
||||
* for the paths included in pollingSources
|
||||
* @param pollingSources the sources that will not be cached in the sbt.io.FileTreeRepository and that
|
||||
* will be periodically polled for changes during continuous builds.
|
||||
* @return a [[FileTreeViewConfig]] instance.
|
||||
*/
|
||||
def polling(
|
||||
antiEntropy: FiniteDuration,
|
||||
pollingInterval: FiniteDuration,
|
||||
pollingSources: Seq[WatchSource],
|
||||
): FileTreeViewConfig = FileTreeViewConfig(
|
||||
() => FileTreeRepository.hybrid(StampedFile.converter, pollingSources: _*),
|
||||
(
|
||||
repository: HybridPollingFileTreeRepository[StampedFile],
|
||||
sources: Seq[WatchSource],
|
||||
logger: Logger
|
||||
) => {
|
||||
repository.register(sources)
|
||||
FileEventMonitor
|
||||
.antiEntropy(
|
||||
repository.toPollingObservable(pollingInterval, sources, NullWatchLogger),
|
||||
antiEntropy,
|
||||
msg => logger.debug(msg.toString)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@ object Defaults extends BuildCommon {
|
|||
extraLoggers :== { _ =>
|
||||
Nil
|
||||
},
|
||||
pollingDirectories :== Nil,
|
||||
watchSources :== Nil,
|
||||
watchProjectSources :== Nil,
|
||||
skip :== false,
|
||||
|
|
@ -271,7 +272,8 @@ object Defaults extends BuildCommon {
|
|||
None
|
||||
},
|
||||
watchStartMessage := Watched.defaultStartWatch,
|
||||
fileTreeViewConfig := FileTreeViewConfig.default(watchAntiEntropy.value),
|
||||
fileTreeViewConfig := FileTreeViewConfig
|
||||
.default(watchAntiEntropy.value, pollInterval.value, pollingDirectories.value),
|
||||
fileTreeView := state.value
|
||||
.get(BasicKeys.globalFileTreeView)
|
||||
.getOrElse(FileTreeView.DEFAULT.asDataView(StampedFile.converter)),
|
||||
|
|
@ -655,7 +657,8 @@ object Defaults extends BuildCommon {
|
|||
},
|
||||
watchStartMessage := Watched.projectOnWatchMessage(thisProjectRef.value.project),
|
||||
watch := watchSetting.value,
|
||||
fileTreeViewConfig := FileTreeViewConfig.default(watchAntiEntropy.value)
|
||||
fileTreeViewConfig := FileTreeViewConfig
|
||||
.default(watchAntiEntropy.value, pollInterval.value, pollingDirectories.value)
|
||||
)
|
||||
|
||||
def generate(generators: SettingKey[Seq[Task[Seq[File]]]]): Initialize[Task[Seq[File]]] =
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ object Keys {
|
|||
val suppressSbtShellNotification = settingKey[Boolean]("""True to suppress the "Executing in batch mode.." message.""").withRank(CSetting)
|
||||
val fileTreeView = taskKey[FileTreeDataView[StampedFile]]("A view of the file system")
|
||||
val pollInterval = settingKey[FiniteDuration]("Interval between checks for modified sources by the continuous execution command.").withRank(BMinusSetting)
|
||||
val pollingDirectories = settingKey[Seq[Watched.WatchSource]]("Directories that cannot be cached and must always be rescanned. Typically these will be NFS mounted or something similar.").withRank(DSetting)
|
||||
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 watchConfig = taskKey[WatchConfig]("The configuration for continuous execution.").withRank(BMinusSetting)
|
||||
val watchLogger = taskKey[Logger]("A logger that reports watch events.").withRank(DSetting)
|
||||
|
|
|
|||
Loading…
Reference in New Issue