diff --git a/main-command/src/main/scala/sbt/BasicKeys.scala b/main-command/src/main/scala/sbt/BasicKeys.scala index ca77d1d73..d42a1d381 100644 --- a/main-command/src/main/scala/sbt/BasicKeys.scala +++ b/main-command/src/main/scala/sbt/BasicKeys.scala @@ -8,6 +8,7 @@ object BasicKeys { val historyPath = AttributeKey[Option[File]]("history", "The location where command line history is persisted.", 40) val shellPrompt = AttributeKey[State => String]("shell-prompt", "The function that constructs the command prompt from the current build state.", 10000) val watch = AttributeKey[Watched]("watch", "Continuous execution configuration.", 1000) + val serverPort = AttributeKey[Int]("server-port", "The port number used by server command.", 10000) private[sbt] val interactive = AttributeKey[Boolean]("interactive", "True if commands are currently being entered from an interactive environment.", 10) private[sbt] val classLoaderCache = AttributeKey[ClassLoaderCache]("class-loader-cache", "Caches class loaders based on the classpath entries and last modified times.", 10) private[sbt] val OnFailureStack = AttributeKey[List[Option[String]]]("on-failure-stack", "Stack that remembers on-failure handlers.", 10) diff --git a/main/command/src/main/scala/sbt/internal/NetworkChannel.scala b/main/command/src/main/scala/sbt/internal/NetworkChannel.scala index 3d44a7b6a..701a4ecdb 100644 --- a/main/command/src/main/scala/sbt/internal/NetworkChannel.scala +++ b/main/command/src/main/scala/sbt/internal/NetworkChannel.scala @@ -2,12 +2,18 @@ package sbt package internal import sbt.internal.server._ +import BasicKeys._ private[sbt] final class NetworkChannel(exchange: CommandExchange) extends CommandChannel(exchange) { private var server: Option[ServerInstance] = None def runOrResume(status: CommandStatus): Unit = { + val s = status.state + val port = (s get serverPort) match { + case Some(x) => x + case None => 5001 + } def onCommand(command: internal.server.Command): Unit = { command match { case Execution(cmd) => exchange.append(CommandRequest(CommandSource.Network, cmd)) @@ -16,7 +22,7 @@ private[sbt] final class NetworkChannel(exchange: CommandExchange) extends Comma server match { case Some(x) => // do nothing case _ => - server = Some(Server.start("127.0.0.1", 12700, onCommand)) + server = Some(Server.start("127.0.0.1", port, onCommand)) } } diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index ed54a98be..049bdbcfa 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -41,7 +41,7 @@ import sbt.util.InterfaceUtil.{ f1, o2m } import sbt.internal.util.Types._ import sbt.internal.io.WatchState -import sbt.io.{ AllPassFilter, FileFilter, GlobFilter, HiddenFileFilter, IO, NameFilter, NothingFilter, Path, PathFinder, SimpleFileFilter, DirectoryFilter } +import sbt.io.{ AllPassFilter, FileFilter, GlobFilter, HiddenFileFilter, IO, NameFilter, NothingFilter, Path, PathFinder, SimpleFileFilter, DirectoryFilter, Hash } import Path._ import sbt.io.syntax._ @@ -200,7 +200,8 @@ object Defaults extends BuildCommon { fork :== false, initialize :== {}, forcegc :== sys.props.get("sbt.task.forcegc").map(java.lang.Boolean.parseBoolean).getOrElse(GCUtil.defaultForceGarbageCollection), - minForcegcInterval :== GCUtil.defaultMinForcegcInterval + minForcegcInterval :== GCUtil.defaultMinForcegcInterval, + serverPort := 5000 + (Hash.toHex(Hash(appConfiguration.value.baseDirectory.toString)).## % 1000) )) def defaultTestTasks(key: Scoped): Seq[Setting[_]] = inTask(key)(Seq( tags := Seq(Tags.Test -> 1), diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index ee21d78b8..33ac5f3f2 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -114,6 +114,7 @@ object Keys { // Command keys val historyPath = SettingKey(BasicKeys.historyPath) val shellPrompt = SettingKey(BasicKeys.shellPrompt) + val serverPort = SettingKey(BasicKeys.serverPort) val analysis = AttributeKey[CompileAnalysis]("analysis", "Analysis of compilation, including dependencies and generated outputs.", DSetting) val watch = SettingKey(BasicKeys.watch) val pollInterval = SettingKey[Int]("poll-interval", "Interval between checks for modified sources by the continuous execution command.", BMinusSetting) diff --git a/main/src/main/scala/sbt/Project.scala b/main/src/main/scala/sbt/Project.scala index dce3233e5..7ddcc6c82 100755 --- a/main/src/main/scala/sbt/Project.scala +++ b/main/src/main/scala/sbt/Project.scala @@ -6,9 +6,8 @@ package sbt import java.io.File import java.net.URI import java.util.Locale -import Project._ -import Keys.{ stateBuildStructure, commands, configuration, historyPath, projectCommand, sessionSettings, - shellPrompt, watch } +import Project.{ Initialize => _, Setting => _, _ } +import Keys.{ appConfiguration, stateBuildStructure, commands, configuration, historyPath, projectCommand, sessionSettings, shellPrompt, serverPort, thisProject, thisProjectRef, watch } import Scope.{ GlobalScope, ThisScope } import Def.{ Flattened, Initialize, ScopedKey, Setting } import sbt.internal.{ Load, BuildStructure, LoadedBuild, LoadedBuildUnit, SettingGraph, SettingCompletions, AddSettings, SessionSettings } @@ -417,9 +416,11 @@ object Project extends ProjectExtra { val history = get(historyPath) flatMap idFun val prompt = get(shellPrompt) val watched = get(watch) + val port: Option[Int] = get(serverPort) val commandDefs = allCommands.distinct.flatten[Command].map(_ tag (projectCommand, true)) val newDefinedCommands = commandDefs ++ BasicCommands.removeTagged(s.definedCommands, projectCommand) - val newAttrs = setCond(Watched.Configuration, watched, s.attributes).put(historyPath.key, history) + val newAttrs0 = setCond(Watched.Configuration, watched, s.attributes).put(historyPath.key, history) + val newAttrs = setCond(serverPort.key, port, newAttrs0) s.copy(attributes = setCond(shellPrompt.key, prompt, newAttrs), definedCommands = newDefinedCommands) } def setCond[T](key: AttributeKey[T], vopt: Option[T], attributes: AttributeMap): AttributeMap =