Don't use last modified time of directories in doc

I noticed that sbt does a _lot_ of no-op docs in the sbt project.
Through some debugging, I determined that this was because the target
directory last modified time of some of the dependent projects would
change between runs. I'm not really sure why that was happening but
instead of computing the last modified time of the directory, we should
be checking the last modified time of the directory contents.

After this change a no-op `doc` in the sbt project returns in less than
one second on my mac. Before, it was more like 25-60 seconds (the upper
bound is one runs `doc` because `sbtRoot/doc` takes about a minute).
This commit is contained in:
Ethan Atkins 2020-01-12 12:06:39 -08:00
parent 27531c5d29
commit c5f0ee0e59
2 changed files with 25 additions and 4 deletions

View File

@ -56,10 +56,9 @@ object RawCompileLike {
type Inputs =
FilesInfo[HashFileInfo] :+: FilesInfo[ModifiedFileInfo] :+: Seq[File] :+: File :+:
Seq[String] :+: Int :+: HNil
val inputs
: Inputs = hash(sources.toSet ++ optionFiles(options, fileInputOpts)) :+: lastModified(
classpath.toSet
) :+: classpath :+: outputDirectory :+: options :+: maxErrors :+: HNil
val inputs: Inputs = hash(sources.toSet ++ optionFiles(options, fileInputOpts)) :+:
FilesInfo(classpath.toSet.map(lastModified.fileOrDirectoryMax)) :+: classpath :+:
outputDirectory :+: options :+: maxErrors :+: HNil
val cachedComp = inputChanged(cacheStoreFactory make "inputs") { (inChanged, in: Inputs) =>
inputChanged(cacheStoreFactory make "output") {
(outChanged, outputs: FilesInfo[PlainFileInfo]) =>

View File

@ -13,6 +13,8 @@ import scala.util.control.NonFatal
import sbt.io.{ Hash, IO }
import sjsonnew.{ Builder, DeserializationException, JsonFormat, Unbuilder, deserializationError }
import CacheImplicits.{ arrayFormat => _, _ }
import sbt.nio.file._
import sbt.nio.file.syntax._
sealed trait FileInfo { def file: File }
sealed trait HashFileInfo extends FileInfo {
@ -209,6 +211,26 @@ object FileInfo {
FileModified(file.getAbsoluteFile, IO.getModifiedTimeOrZero(file))
def apply(file: File, lastModified: Long): ModifiedFileInfo =
FileModified(file.getAbsoluteFile, lastModified)
/**
* Returns an instance of [[FileModified]] where, for any directory, the maximum last
* modified time taken from its contents is used rather than the last modified time of the
* directory itself. The specific motivation was to prevent the doc task from re-running when
* the modified time changed for a directory classpath but none of the classfiles had changed.
*
* @param file the file or directory
* @return the [[FileModified]]
*/
private[sbt] def fileOrDirectoryMax(file: File): ModifiedFileInfo = {
val maxLastModified =
if (file.isDirectory) FileTreeView.default.list(file.toGlob / **).foldLeft(0L) {
case (max, (path, attributes)) =>
val lm = if (!attributes.isDirectory) IO.getModifiedTimeOrZero(path.toFile) else 0L
if (lm > max) lm else max
}
else IO.getModifiedTimeOrZero(file)
FileModified(file, maxLastModified)
}
}
object exists extends Style {