mirror of https://github.com/sbt/sbt.git
Add parser for file size
At the suggestion of @eed3si9n, instead of specifying the file cache size in bytes, we now specify it in a formatted string. For example, instead of specifying 128 megabytes in bytes (134217728), we can specify it with the string "128M".
This commit is contained in:
parent
cad89d17a9
commit
0172d118af
|
|
@ -219,6 +219,12 @@ trait Parsers {
|
|||
(DQuoteChar ~> (NotDQuoteBackslashClass | EscapeSequence).+.string <~ DQuoteChar |
|
||||
(DQuoteChar ~ DQuoteChar) ^^^ "")
|
||||
|
||||
/**
|
||||
* Parses a size unit string. For example, `128K` parsers to `128L * 1024`, and `1.25g` parses
|
||||
* to `1024L * 1024 * 1024 * 5 / 4`.
|
||||
*/
|
||||
lazy val Size: Parser[Long] = SizeParser.value
|
||||
|
||||
/**
|
||||
* Parses a brace enclosed string and, if each opening brace is matched with a closing brace,
|
||||
* it returns the entire string including the braces.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt.internal.util.complete
|
||||
|
||||
import sbt.internal.util.complete.DefaultParsers._
|
||||
|
||||
private[sbt] object SizeParser {
|
||||
def apply(s: String): Option[Long] = Parser.parse(s, value).toOption
|
||||
private sealed trait SizeUnit
|
||||
private case object Bytes extends SizeUnit
|
||||
private case object KiloBytes extends SizeUnit
|
||||
private case object MegaBytes extends SizeUnit
|
||||
private case object GigaBytes extends SizeUnit
|
||||
private def parseDouble(s: String): Parser[Either[Double, Long]] =
|
||||
try Parser.success(Left(java.lang.Double.valueOf(s)))
|
||||
catch { case _: NumberFormatException => Parser.failure(s"Couldn't parse $s as double.") }
|
||||
private def parseLong(s: String): Parser[Either[Double, Long]] =
|
||||
try Parser.success(Right(java.lang.Long.valueOf(s)))
|
||||
catch { case _: NumberFormatException => Parser.failure(s"Couldn't parse $s as double.") }
|
||||
private[this] val digit = charClass(_.isDigit, "digit")
|
||||
private[this] val numberParser: Parser[Either[Double, Long]] =
|
||||
(digit.+ ~ ('.'.examples() ~> digit.+).?).flatMap {
|
||||
case (leading, Some(decimalPart)) =>
|
||||
parseDouble(s"${leading.mkString}.${decimalPart.mkString}")
|
||||
case (leading, _) => parseLong(leading.mkString)
|
||||
}
|
||||
private[this] val unitParser: Parser[SizeUnit] =
|
||||
token("b" | "B" | "g" | "G" | "k" | "K" | "m" | "M").map {
|
||||
case "b" | "B" => Bytes
|
||||
case "g" | "G" => GigaBytes
|
||||
case "k" | "K" => KiloBytes
|
||||
case "m" | "M" => MegaBytes
|
||||
}
|
||||
private[this] def multiply(left: Either[Double, Long], right: Long): Long = left match {
|
||||
case Left(d) => (d * right).toLong
|
||||
case Right(l) => l * right
|
||||
}
|
||||
private[sbt] val value: Parser[Long] =
|
||||
((numberParser <~ SpaceClass
|
||||
.examples(" ", "b", "B", "g", "G", "k", "K", "m", "M")
|
||||
.*) ~ unitParser.?)
|
||||
.map {
|
||||
case (number, unit) =>
|
||||
unit match {
|
||||
case None | Some(Bytes) => multiply(number, right = 1)
|
||||
case Some(KiloBytes) => multiply(number, right = 1024)
|
||||
case Some(MegaBytes) => multiply(number, right = 1024 * 1024)
|
||||
case Some(GigaBytes) => multiply(number, right = 1024 * 1024 * 1024)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt.internal.util.complete
|
||||
|
||||
import org.scalatest.FlatSpec
|
||||
|
||||
class SizeParserSpec extends FlatSpec {
|
||||
"SizeParser" should "handle raw bytes" in {
|
||||
assert(Parser.parse(str = "123456", SizeParser.value) == Right(123456L))
|
||||
}
|
||||
it should "handle bytes" in {
|
||||
assert(Parser.parse(str = "123456b", SizeParser.value) == Right(123456L))
|
||||
assert(Parser.parse(str = "123456B", SizeParser.value) == Right(123456L))
|
||||
assert(Parser.parse(str = "123456 b", SizeParser.value) == Right(123456L))
|
||||
assert(Parser.parse(str = "123456 B", SizeParser.value) == Right(123456L))
|
||||
}
|
||||
it should "handle kilobytes" in {
|
||||
assert(Parser.parse(str = "123456k", SizeParser.value) == Right(123456L * 1024))
|
||||
assert(Parser.parse(str = "123456K", SizeParser.value) == Right(123456L * 1024))
|
||||
assert(Parser.parse(str = "123456 K", SizeParser.value) == Right(123456L * 1024))
|
||||
assert(Parser.parse(str = "123456 K", SizeParser.value) == Right(123456L * 1024))
|
||||
}
|
||||
it should "handle megabytes" in {
|
||||
assert(Parser.parse(str = "123456m", SizeParser.value) == Right(123456L * 1024 * 1024))
|
||||
assert(Parser.parse(str = "123456M", SizeParser.value) == Right(123456L * 1024 * 1024))
|
||||
assert(Parser.parse(str = "123456 M", SizeParser.value) == Right(123456L * 1024 * 1024))
|
||||
assert(Parser.parse(str = "123456 M", SizeParser.value) == Right(123456L * 1024 * 1024))
|
||||
}
|
||||
it should "handle gigabytes" in {
|
||||
assert(Parser.parse(str = "123456g", SizeParser.value) == Right(123456L * 1024 * 1024 * 1024))
|
||||
assert(Parser.parse(str = "123456G", SizeParser.value) == Right(123456L * 1024 * 1024 * 1024))
|
||||
assert(Parser.parse(str = "123456 G", SizeParser.value) == Right(123456L * 1024 * 1024 * 1024))
|
||||
assert(Parser.parse(str = "123456 G", SizeParser.value) == Right(123456L * 1024 * 1024 * 1024))
|
||||
}
|
||||
it should "handle doubles" in {
|
||||
assert(Parser.parse(str = "1.25g", SizeParser.value) == Right(5L * 1024 * 1024 * 1024 / 4))
|
||||
assert(Parser.parse(str = "1.25 g", SizeParser.value) == Right(5L * 1024 * 1024 * 1024 / 4))
|
||||
assert(Parser.parse(str = "1.25 g", SizeParser.value) == Right(5L * 1024 * 1024 * 1024 / 4))
|
||||
assert(Parser.parse(str = "1.25 G", SizeParser.value) == Right(5L * 1024 * 1024 * 1024 / 4))
|
||||
}
|
||||
private val expectedCompletions = Set("", "b", "B", "g", "G", "k", "K", "m", "M", " ")
|
||||
it should "have completions for long" in {
|
||||
val completions = Parser.completions(SizeParser.value, "123", level = 0).get.map(_.display)
|
||||
assert(completions == expectedCompletions)
|
||||
}
|
||||
it should "have completions for long with spaces" in {
|
||||
val completions = Parser.completions(SizeParser.value, "123", level = 0).get.map(_.display)
|
||||
assert(completions == expectedCompletions)
|
||||
}
|
||||
it should "have completions for double " in {
|
||||
val completions = Parser.completions(SizeParser.value, "1.25", level = 0).get.map(_.display)
|
||||
assert(completions == expectedCompletions)
|
||||
}
|
||||
it should "have completions for double with spaces" in {
|
||||
val completions = Parser.completions(SizeParser.value, "1.25 ", level = 0).get.map(_.display)
|
||||
assert(completions == expectedCompletions + "")
|
||||
}
|
||||
}
|
||||
|
|
@ -258,6 +258,7 @@ object Defaults extends BuildCommon {
|
|||
checkBuildSources / Continuous.dynamicInputs := None,
|
||||
checkBuildSources / fileInputs := CheckBuildSources.buildSourceFileInputs.value,
|
||||
checkBuildSources := CheckBuildSources.needReloadImpl.value,
|
||||
fileCacheSize := "128M",
|
||||
trapExit :== true,
|
||||
connectInput :== false,
|
||||
cancelable :== true,
|
||||
|
|
|
|||
|
|
@ -489,7 +489,7 @@ object Keys {
|
|||
val globalPluginUpdate = taskKey[UpdateReport]("A hook to get the UpdateReport of the global plugin.").withRank(DTask)
|
||||
private[sbt] val taskCancelStrategy = settingKey[State => TaskCancellationStrategy]("Experimental task cancellation handler.").withRank(DTask)
|
||||
private[sbt] val cacheStoreFactory = AttributeKey[CacheStoreFactoryFactory]("cache-store-factory")
|
||||
val fileCacheSize = settingKey[Long]("The approximate maximum size in bytes of the cache used to store previous task results.")
|
||||
val fileCacheSize = settingKey[String]("The approximate maximum size in bytes of the cache used to store previous task results. For example, it could be set to \"256M\" to make the maximum size 256 megabytes.")
|
||||
|
||||
// Experimental in sbt 0.13.2 to enable grabbing semantic compile failures.
|
||||
private[sbt] val compilerReporter = taskKey[xsbti.Reporter]("Experimental hook to listen (or send) compilation failure messages.").withRank(DTask)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import sbt.internal._
|
|||
import sbt.internal.inc.ScalaInstance
|
||||
import sbt.internal.util.Types.{ const, idFun }
|
||||
import sbt.internal.util._
|
||||
import sbt.internal.util.complete.Parser
|
||||
import sbt.internal.util.complete.{ SizeParser, Parser }
|
||||
import sbt.io._
|
||||
import sbt.io.syntax._
|
||||
import sbt.util.{ Level, Logger, Show }
|
||||
|
|
@ -848,7 +848,11 @@ object BuiltinCommands {
|
|||
}
|
||||
|
||||
private val addCacheStoreFactoryFactory: State => State = (s: State) => {
|
||||
val size = Project.extract(s).getOpt(Keys.fileCacheSize).getOrElse(SysProp.fileCacheSize)
|
||||
val size = Project
|
||||
.extract(s)
|
||||
.getOpt(Keys.fileCacheSize)
|
||||
.flatMap(SizeParser(_))
|
||||
.getOrElse(SysProp.fileCacheSize)
|
||||
s.get(Keys.cacheStoreFactory).foreach(_.close())
|
||||
s.put(Keys.cacheStoreFactory, InMemoryCacheStore.factory(size))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@ package sbt
|
|||
package internal
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
import scala.util.control.NonFatal
|
||||
import sbt.internal.util.ConsoleAppender
|
||||
import sbt.internal.util.complete.SizeParser
|
||||
|
||||
// See also BuildPaths.scala
|
||||
// See also LineReader.scala
|
||||
|
|
@ -84,7 +86,8 @@ object SysProp {
|
|||
|
||||
def closeClassLoaders: Boolean = getOrTrue("sbt.classloader.close")
|
||||
|
||||
def fileCacheSize: Long = long("sbt.file.cache.size", 128 * 1024 * 1024)
|
||||
def fileCacheSize: Long =
|
||||
SizeParser(System.getProperty("sbt.file.cache.size", "128M")).getOrElse(128 * 1024 * 1024)
|
||||
def supershell: Boolean = color && getOrTrue("sbt.supershell")
|
||||
|
||||
def supershellSleep: Long = long("sbt.supershell.sleep", 100L)
|
||||
|
|
|
|||
Loading…
Reference in New Issue