mirror of https://github.com/sbt/sbt.git
session manipulation commands
save, clear, list, and remove session settings
This commit is contained in:
parent
14990b5127
commit
c9a6d2f6b0
|
|
@ -62,8 +62,11 @@ SetCommand + """ <setting-expression>
|
|||
|
||||
This command does not rebuild the build definitions, plugins, or configurations.
|
||||
It does not automatically persist the setting.
|
||||
This is done by running 'save-settings'.
|
||||
This is done by running 'settings save' or 'settings save-all'.
|
||||
"""
|
||||
|
||||
def SessionCommand = "session"
|
||||
def sessionBrief = (SessionCommand + " ...", "Manipulates session settings. For details, run 'help " + SessionCommand + "'..")
|
||||
|
||||
/** The command name to terminate the program.*/
|
||||
val TerminateAction: String = Exit
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class xMain extends xsbti.AppMain
|
|||
object Commands
|
||||
{
|
||||
def DefaultCommands: Seq[Command] = Seq(ignore, help, reload, read, history, continuous, exit, loadCommands, loadProject, compile, discover,
|
||||
projects, project, setOnFailure, ifLast, multi, shell, set, get, eval, alias, append, nop, act)
|
||||
projects, project, setOnFailure, ifLast, multi, shell, set, get, eval, alias, append, nop, sessionCommand, act)
|
||||
|
||||
def nop = Command.custom(s => success(() => s), Nil)
|
||||
def ignore = Command.command(FailureWall)(identity)
|
||||
|
|
@ -221,15 +221,20 @@ object Commands
|
|||
log.info("ans: " + result.tpe + " = " + result.value.toString)
|
||||
s
|
||||
}
|
||||
def sessionCommand = Command(SessionCommand, sessionBrief, SessionSettings.Help)(SessionSettings.command)
|
||||
def reapply(newSession: SessionSettings, structure: Load.BuildStructure, s: State): State =
|
||||
{
|
||||
logger(s).info("Reapplying settings...")
|
||||
val newStructure = Load.reapply(newSession.mergeSettings, structure)
|
||||
setProject(newSession, newStructure, s)
|
||||
}
|
||||
def set = Command.single(SetCommand, setBrief, setDetailed) { (s, arg) =>
|
||||
val extracted = Project extract s
|
||||
import extracted._
|
||||
val setting = EvaluateConfigurations.evaluateSetting(session.currentEval(), "<set>", imports(extracted), arg, 0)
|
||||
val append = Load.transformSettings(Load.projectScope(curi, cid), curi, rootProject, setting :: Nil)
|
||||
val newSession = session.appendSettings( append map (a => (a, arg)))
|
||||
logger(s).info("Reapplying settings...")
|
||||
val newStructure = Load.reapply(newSession.mergeSettings, structure)
|
||||
setProject(newSession, newStructure, s)
|
||||
reapply(newSession, structure, s)
|
||||
}
|
||||
def get = Command.single(GetCommand, getBrief, getDetailed) { (s, arg) =>
|
||||
val extracted = Project extract s
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ final case class SessionSettings(currentBuild: URI, currentProject: Map[URI, Str
|
|||
def appendSettings(s: Seq[SessionSetting]): SessionSettings = copy(append = modify(append, _ ++ s))
|
||||
def prependSettings(s: Seq[SessionSetting]): SessionSettings = copy(prepend = modify(prepend, s ++ _))
|
||||
def mergeSettings: Seq[Setting[_]] = merge(prepend) ++ original ++ merge(append)
|
||||
def clearExtraSettings: SessionSettings = copy(prepend = Map.empty, append = Map.empty)
|
||||
|
||||
private[this] def merge(map: SessionMap): Seq[Setting[_]] = map.values.toSeq.flatten[SessionSetting].map(_._1)
|
||||
private[this] def modify(map: SessionMap, onSeq: Endo[Seq[SessionSetting]]): SessionMap =
|
||||
|
|
@ -129,6 +130,131 @@ object SessionSettings
|
|||
{
|
||||
type SessionSetting = (Setting[_], String)
|
||||
type SessionMap = Map[(URI, String), Seq[SessionSetting]]
|
||||
|
||||
def reapply(session: SessionSettings, s: State): State =
|
||||
Commands.reapply(session, Project.structure(s), s)
|
||||
|
||||
def clearSettings(s: State): State =
|
||||
withSettings(s)(session => reapply(session.copy(append = session.append - session.current), s))
|
||||
def clearAllSettings(s: State): State =
|
||||
withSettings(s)(session => reapply(session.clearExtraSettings, s))
|
||||
|
||||
def withSettings(s: State)(f: SessionSettings => State): State =
|
||||
{
|
||||
val extracted = Project extract s
|
||||
import extracted._
|
||||
if(session.prepend.isEmpty && session.append.isEmpty)
|
||||
{
|
||||
logger(s).info("No session settings defined.")
|
||||
s
|
||||
}
|
||||
else
|
||||
f(session)
|
||||
}
|
||||
|
||||
def removeRanges[T](in: Seq[T], ranges: Seq[(Int,Int)]): Seq[T] =
|
||||
{
|
||||
val asSet = (Set.empty[Int] /: ranges) { case (s, (hi,lo)) => s ++ (hi to lo) }
|
||||
in.zipWithIndex.flatMap { case (t, index) => if(asSet(index+1)) Nil else t :: Nil }
|
||||
}
|
||||
def removeSettings(s: State, ranges: Seq[(Int,Int)]): State =
|
||||
withSettings(s) { session =>
|
||||
val current = session.current
|
||||
val newAppend = session.append.updated(current, removeRanges(session.append.getOrElse(current, Nil), ranges))
|
||||
reapply(session.copy( append = newAppend ), s)
|
||||
}
|
||||
def saveAllSettings(s: State): State = saveSomeSettings(s)((_,_) => true)
|
||||
def saveSettings(s: State): State =
|
||||
{
|
||||
val (curi,cid) = Project.session(s).current
|
||||
saveSomeSettings(s)( (uri,id) => uri == curi && id == cid)
|
||||
}
|
||||
def saveSomeSettings(s: State)(include: (URI,String) => Boolean): State =
|
||||
withSettings(s){session =>
|
||||
for( ((uri,id), settings) <- session.append if !settings.isEmpty && include(uri,id) )
|
||||
writeSettings(ProjectRef(uri, id), settings, Project.structure(s))
|
||||
reapply(session.copy(original = session.mergeSettings, append = Map.empty, prepend = Map.empty), s)
|
||||
}
|
||||
def writeSettings(pref: ProjectRef, settings: Seq[SessionSetting], structure: Load.BuildStructure)
|
||||
{
|
||||
val project = Project.getProject(pref, structure).getOrElse(error("Invalid project reference " + pref))
|
||||
val appendTo: File = BuildPaths.configurationSources(project.base).headOption.getOrElse(new File(project.base, "build.sbt"))
|
||||
val sbtAppend = settingStrings(settings).flatMap("" :: _ :: Nil)
|
||||
IO.writeLines(appendTo, sbtAppend, append = true)
|
||||
}
|
||||
def printAllSettings(s: State): State =
|
||||
withSettings(s){ session =>
|
||||
for( ((uri,id), settings) <- session.append if !settings.isEmpty) {
|
||||
println("In " + Project.display(ProjectRef(uri,id)))
|
||||
printSettings(settings)
|
||||
}
|
||||
s
|
||||
}
|
||||
def printSettings(s: State): State =
|
||||
withSettings(s){ session =>
|
||||
printSettings(session.append.getOrElse(session.current, Nil))
|
||||
s
|
||||
}
|
||||
def printSettings(settings: Seq[SessionSetting]): Unit =
|
||||
for((stringRep, index) <- settingStrings(settings).zipWithIndex)
|
||||
println(" " + (index+1) + ". " + stringRep)
|
||||
|
||||
def settingStrings(s: Seq[SessionSetting]): Seq[String] = s.map(_._2)
|
||||
|
||||
def Help = """session <command>
|
||||
|
||||
Manipulates session settings, which are temporary settings that do not persist past the current sbt execution (that is, the current session).
|
||||
Valid commands are:
|
||||
|
||||
clear, clear-all
|
||||
Removes temporary settings added using 'set' and re-evaluates all settings.
|
||||
For 'clear', only the settings defined for the current project are cleared.
|
||||
For 'clear-all', all settings in all projects are cleared.
|
||||
|
||||
list, list-all
|
||||
Prints a numbered list of session settings defined.
|
||||
The numbers may be used to remove individual settings or ranges of settings using 'remove'.
|
||||
For 'list', only the settings for the current project are printed.
|
||||
For 'list-all', all settings in all projets are printed.
|
||||
|
||||
remove <range-spec>
|
||||
<range-spec> is a comma-separated list of individual numbers or ranges of numbers.
|
||||
For example, 'remove 1,3,5-7'.
|
||||
The temporary settings at the given indices for the current project are removed and all settings are re-evaluated.
|
||||
Use the 'list' command to see a numbered list of settings for the current project.
|
||||
|
||||
save, save-all
|
||||
Makes the session settings permanent by writing them to a '.sbt' configuration file.
|
||||
For 'save', only the current project's settings are saved (the settings for other projects are left alone).
|
||||
For 'save-all', the session settings are saved for all projects.
|
||||
The session settings defined for a project are appended to the first '.sbt' configuration file in that project.
|
||||
If no '.sbt' configuration file exists, the settings are written to 'build.sbt' in the project's base directory."""
|
||||
|
||||
sealed trait SessionCommand
|
||||
final class Print(val all: Boolean) extends SessionCommand
|
||||
final class Clear(val all: Boolean) extends SessionCommand
|
||||
final class Save(val all: Boolean) extends SessionCommand
|
||||
final class Remove(val ranges: Seq[(Int,Int)]) extends SessionCommand
|
||||
|
||||
import complete._
|
||||
import DefaultParsers._
|
||||
|
||||
lazy val parser =
|
||||
token(Space) ~>
|
||||
(token("list-all" ^^^ new Print(true)) | token("list" ^^^ new Print(false)) | token("clear" ^^^ new Clear(false)) |
|
||||
token("save-all" ^^^ new Save(true)) | token("save" ^^^ new Save(false)) | token("clear-all" ^^^ new Clear(true)) |
|
||||
remove)
|
||||
|
||||
lazy val remove = token("remove") ~> token(Space) ~> natSelect.map(ranges => new Remove(ranges))
|
||||
def natSelect = rep1sep(token(range, "<range>"), ',')
|
||||
def range: Parser[(Int,Int)] = (NatBasic ~ ('-' ~> NatBasic).?).map { case lo ~ hi => (lo, hi getOrElse lo)}
|
||||
|
||||
def command(s: State) = Command.applyEffect(parser){
|
||||
case p: Print => if(p.all) printAllSettings(s) else printSettings(s)
|
||||
case v: Save => if(v.all) saveAllSettings(s) else saveSettings(s)
|
||||
case c: Clear => if(c.all) clearAllSettings(s) else clearSettings(s)
|
||||
case r: Remove => removeSettings(s,r.ranges)
|
||||
}
|
||||
}
|
||||
|
||||
trait ProjectConstructors
|
||||
|
|
|
|||
|
|
@ -39,9 +39,13 @@ trait Parsers
|
|||
|
||||
lazy val Port = token(IntBasic, "<port>")
|
||||
lazy val IntBasic = mapOrFail( '-'.? ~ Digit.+ )( Function.tupled(toInt) )
|
||||
lazy val NatBasic = mapOrFail( Digit.+ )( _.mkString.toInt )
|
||||
private[this] def toInt(neg: Option[Char], digits: Seq[Char]): Int =
|
||||
(neg.toSeq ++ digits).mkString.toInt
|
||||
|
||||
def rep1sep[T](rep: Parser[T], sep: Parser[_]): Parser[Seq[T]] =
|
||||
(rep ~ (sep ~> rep).*).map { case (x ~ xs) => x +: xs }
|
||||
|
||||
def mapOrFail[S,T](p: Parser[S])(f: S => T): Parser[T] =
|
||||
p flatMap { s => try { success(f(s)) } catch { case e: Exception => failure(e.toString) } }
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue