mirror of https://github.com/sbt/sbt.git
Jetty 7 support working
This commit is contained in:
parent
aaea9c3407
commit
31822b2e17
|
|
@ -0,0 +1,2 @@
|
||||||
|
LazyJettyRun6.scala
|
||||||
|
LazyJettyRun7.scala
|
||||||
|
|
@ -36,7 +36,7 @@ class JettyRunner(configuration: JettyConfiguration) extends ExitHook
|
||||||
val jettyParentLoader = configuration match { case d: DefaultJettyConfiguration => d.parentLoader; case _ => ClassLoader.getSystemClassLoader }
|
val jettyParentLoader = configuration match { case d: DefaultJettyConfiguration => d.parentLoader; case _ => ClassLoader.getSystemClassLoader }
|
||||||
val jettyLoader: ClassLoader = new java.net.URLClassLoader(classpathURLs.toArray, jettyParentLoader)
|
val jettyLoader: ClassLoader = new java.net.URLClassLoader(classpathURLs.toArray, jettyParentLoader)
|
||||||
|
|
||||||
val jettyFilter = (name: String) => name.startsWith("org.mortbay.")
|
val jettyFilter = (name: String) => name.startsWith("org.mortbay.") || name.startsWith("org.eclipse.jetty.")
|
||||||
val notJettyFilter = (name: String) => !jettyFilter(name)
|
val notJettyFilter = (name: String) => !jettyFilter(name)
|
||||||
|
|
||||||
val dual = new xsbt.DualLoader(baseLoader, notJettyFilter, x => true, jettyLoader, jettyFilter, x => false)
|
val dual = new xsbt.DualLoader(baseLoader, notJettyFilter, x => true, jettyLoader, jettyFilter, x => false)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import java.net.URL
|
||||||
|
|
||||||
/* This class starts Jetty.
|
/* This class starts Jetty.
|
||||||
* NOTE: DO NOT actively use this class. You will see NoClassDefFoundErrors if you fail
|
* NOTE: DO NOT actively use this class. You will see NoClassDefFoundErrors if you fail
|
||||||
* to do so.Only use its name in JettyRun for reflective loading. This allows using
|
* to do so. Only use its name in JettyRun for reflective loading. This allows using
|
||||||
* the Jetty libraries provided on the project classpath instead of requiring them to be
|
* the Jetty libraries provided on the project classpath instead of requiring them to be
|
||||||
* available on sbt's classpath at startup.
|
* available on sbt's classpath at startup.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,137 +0,0 @@
|
||||||
package sbt.jetty
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/* This class starts Jetty.
|
|
||||||
* NOTE: DO NOT actively use this class. You will see NoClassDefFoundErrors if you fail
|
|
||||||
* to do so.Only use its name in JettyRun for reflective loading. This allows using
|
|
||||||
* the Jetty libraries provided on the project classpath instead of requiring them to be
|
|
||||||
* available on sbt's classpath at startup.
|
|
||||||
*/
|
|
||||||
private object LazyJettyRun6 extends JettyRun
|
|
||||||
{
|
|
||||||
|
|
||||||
import org.mortbay.jetty.{Handler, Server}
|
|
||||||
import org.mortbay.jetty.nio.SelectChannelConnector
|
|
||||||
import org.mortbay.jetty.webapp.{WebAppClassLoader, WebAppContext}
|
|
||||||
import org.mortbay.log.{Log, Logger => JLogger}
|
|
||||||
import org.mortbay.util.Scanner
|
|
||||||
import org.mortbay.xml.XmlConfiguration
|
|
||||||
|
|
||||||
import java.lang.ref.{Reference, WeakReference}
|
|
||||||
|
|
||||||
val DefaultMaxIdleTime = 30000
|
|
||||||
|
|
||||||
def apply(configuration: JettyConfiguration, jettyLoader: ClassLoader): Stoppable =
|
|
||||||
{
|
|
||||||
val oldLog = Log.getLog
|
|
||||||
Log.setLog(new JettyLogger(configuration.log))
|
|
||||||
val server = new Server
|
|
||||||
|
|
||||||
def configureScanner(listener: Scanner.BulkListener, scanDirectories: Seq[File], scanInterval: Int) =
|
|
||||||
{
|
|
||||||
if(scanDirectories.isEmpty)
|
|
||||||
None
|
|
||||||
else
|
|
||||||
{
|
|
||||||
configuration.log.debug("Scanning for changes to: " + scanDirectories.mkString(", "))
|
|
||||||
val scanner = new Scanner
|
|
||||||
val list = new java.util.ArrayList[File]
|
|
||||||
scanDirectories.foreach(x => list.add(x))
|
|
||||||
scanner.setScanDirs(list)
|
|
||||||
scanner.setRecursive(true)
|
|
||||||
scanner.setScanInterval(scanInterval)
|
|
||||||
scanner.setReportExistingFilesOnStartup(false)
|
|
||||||
scanner.addListener(listener)
|
|
||||||
scanner.start()
|
|
||||||
Some(new WeakReference(scanner))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val (listener, scanner) =
|
|
||||||
configuration match
|
|
||||||
{
|
|
||||||
case c: DefaultJettyConfiguration =>
|
|
||||||
import c._
|
|
||||||
configureDefaultConnector(server, port)
|
|
||||||
def classpathURLs = classpath.get.map(_.asURL).toSeq
|
|
||||||
val webapp = new WebAppContext(war.absolutePath, contextPath)
|
|
||||||
|
|
||||||
def createLoader =
|
|
||||||
{
|
|
||||||
class SbtWebAppLoader extends WebAppClassLoader(jettyLoader, webapp) { override def addURL(u: URL) = super.addURL(u) };
|
|
||||||
val loader = new SbtWebAppLoader
|
|
||||||
classpathURLs.foreach(loader.addURL)
|
|
||||||
loader
|
|
||||||
}
|
|
||||||
def setLoader() = webapp.setClassLoader(createLoader)
|
|
||||||
|
|
||||||
setLoader()
|
|
||||||
server.setHandler(webapp)
|
|
||||||
|
|
||||||
val listener = new Scanner.BulkListener with Reload {
|
|
||||||
def reloadApp() = reload(server, setLoader(), log)
|
|
||||||
def filesChanged(files: java.util.List[_]) { reloadApp() }
|
|
||||||
}
|
|
||||||
(Some(listener), configureScanner(listener, c.scanDirectories, c.scanInterval))
|
|
||||||
case c: CustomJettyConfiguration =>
|
|
||||||
for(x <- c.jettyConfigurationXML)
|
|
||||||
(new XmlConfiguration(x.toString)).configure(server)
|
|
||||||
for(file <- c.jettyConfigurationFiles)
|
|
||||||
(new XmlConfiguration(file.toURI.toURL)).configure(server)
|
|
||||||
(None, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
server.start()
|
|
||||||
new StopServer(new WeakReference(server), listener.map(new WeakReference(_)), scanner, oldLog)
|
|
||||||
}
|
|
||||||
catch { case e => server.stop(); throw e }
|
|
||||||
}
|
|
||||||
private def configureDefaultConnector(server: Server, port: Int)
|
|
||||||
{
|
|
||||||
val defaultConnector = new SelectChannelConnector
|
|
||||||
defaultConnector.setPort(port)
|
|
||||||
defaultConnector.setMaxIdleTime(DefaultMaxIdleTime)
|
|
||||||
server.addConnector(defaultConnector)
|
|
||||||
}
|
|
||||||
trait Reload { def reloadApp(): Unit }
|
|
||||||
private class StopServer(serverReference: Reference[Server], reloadReference: Option[Reference[Reload]], scannerReferenceOpt: Option[Reference[Scanner]], oldLog: JLogger) extends Stoppable
|
|
||||||
{
|
|
||||||
def reload(): Unit = on(reloadReference)(_.reloadApp())
|
|
||||||
private def on[T](refOpt: Option[Reference[T]])(f: T => Unit): Unit = refOpt.foreach(ref => onReferenced(ref.get)(f))
|
|
||||||
private def onReferenced[T](t: T)(f: T => Unit): Unit = if(t == null) () else f(t)
|
|
||||||
def stop()
|
|
||||||
{
|
|
||||||
onReferenced(serverReference.get)(_.stop())
|
|
||||||
on(scannerReferenceOpt)(_.stop())
|
|
||||||
Log.setLog(oldLog)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private def reload(server: Server, reconfigure: => Unit, log: Logger)
|
|
||||||
{
|
|
||||||
log.info("Reloading web application...")
|
|
||||||
val handlers = wrapNull(server.getHandlers, server.getHandler)
|
|
||||||
log.debug("Stopping handlers: " + handlers.mkString(", "))
|
|
||||||
handlers.foreach(_.stop)
|
|
||||||
log.debug("Reconfiguring...")
|
|
||||||
reconfigure
|
|
||||||
log.debug("Restarting handlers: " + handlers.mkString(", "))
|
|
||||||
handlers.foreach(_.start)
|
|
||||||
log.info("Reload complete.")
|
|
||||||
}
|
|
||||||
private def wrapNull(a: Array[Handler], b: Handler) =
|
|
||||||
(a, b) match
|
|
||||||
{
|
|
||||||
case (null, null) => Nil
|
|
||||||
case (null, notB) => notB :: Nil
|
|
||||||
case (notA, null) => notA.toList
|
|
||||||
case (notA, notB) => notB :: notA.toList
|
|
||||||
}
|
|
||||||
private class JettyLogger(delegate: Logger) extends JettyLoggerBase(delegate) with JLogger
|
|
||||||
{
|
|
||||||
def getLogger(name: String) = this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,137 +0,0 @@
|
||||||
package sbt.jetty
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/* This class starts Jetty.
|
|
||||||
* NOTE: DO NOT actively use this class. You will see NoClassDefFoundErrors if you fail
|
|
||||||
* to do so.Only use its name in JettyRun for reflective loading. This allows using
|
|
||||||
* the Jetty libraries provided on the project classpath instead of requiring them to be
|
|
||||||
* available on sbt's classpath at startup.
|
|
||||||
*/
|
|
||||||
private object LazyJettyRun7 extends JettyRun
|
|
||||||
{
|
|
||||||
|
|
||||||
import org.eclipse.jetty.server.{Server, Handler}
|
|
||||||
import org.eclipse.jetty.server.nio.SelectChannelConnector
|
|
||||||
import org.eclipse.jetty.webapp.{WebAppClassLoader, WebAppContext}
|
|
||||||
import org.eclipse.jetty.util.log.{Log, Logger => JLogger}
|
|
||||||
import org.eclipse.jetty.util.Scanner
|
|
||||||
import org.eclipse.jetty.xml.XmlConfiguration
|
|
||||||
|
|
||||||
import java.lang.ref.{Reference, WeakReference}
|
|
||||||
|
|
||||||
val DefaultMaxIdleTime = 30000
|
|
||||||
|
|
||||||
def apply(configuration: JettyConfiguration, jettyLoader: ClassLoader): Stoppable =
|
|
||||||
{
|
|
||||||
val oldLog = Log.getLog
|
|
||||||
Log.setLog(new JettyLogger(configuration.log))
|
|
||||||
val server = new Server
|
|
||||||
|
|
||||||
def configureScanner(listener: Scanner.BulkListener, scanDirectories: Seq[File], scanInterval: Int) =
|
|
||||||
{
|
|
||||||
if(scanDirectories.isEmpty)
|
|
||||||
None
|
|
||||||
else
|
|
||||||
{
|
|
||||||
configuration.log.debug("Scanning for changes to: " + scanDirectories.mkString(", "))
|
|
||||||
val scanner = new Scanner
|
|
||||||
val list = new java.util.ArrayList[File]
|
|
||||||
scanDirectories.foreach(x => list.add(x))
|
|
||||||
scanner.setScanDirs(list)
|
|
||||||
scanner.setRecursive(true)
|
|
||||||
scanner.setScanInterval(scanInterval)
|
|
||||||
scanner.setReportExistingFilesOnStartup(false)
|
|
||||||
scanner.addListener(listener)
|
|
||||||
scanner.start()
|
|
||||||
Some(new WeakReference(scanner))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val (listener, scanner) =
|
|
||||||
configuration match
|
|
||||||
{
|
|
||||||
case c: DefaultJettyConfiguration =>
|
|
||||||
import c._
|
|
||||||
configureDefaultConnector(server, port)
|
|
||||||
def classpathURLs = classpath.get.map(_.asURL).toSeq
|
|
||||||
val webapp = new WebAppContext(war.absolutePath, contextPath)
|
|
||||||
|
|
||||||
def createLoader =
|
|
||||||
{
|
|
||||||
class SbtWebAppLoader extends WebAppClassLoader(jettyLoader, webapp) { override def addURL(u: URL) = super.addURL(u) };
|
|
||||||
val loader = new SbtWebAppLoader
|
|
||||||
classpathURLs.foreach(loader.addURL)
|
|
||||||
loader
|
|
||||||
}
|
|
||||||
def setLoader() = webapp.setClassLoader(createLoader)
|
|
||||||
|
|
||||||
setLoader()
|
|
||||||
server.setHandler(webapp)
|
|
||||||
|
|
||||||
val listener = new Scanner.BulkListener with Reload {
|
|
||||||
def reloadApp() = reload(server, setLoader(), log)
|
|
||||||
def filesChanged(files: java.util.List[_]) { reloadApp() }
|
|
||||||
}
|
|
||||||
(Some(listener), configureScanner(listener, c.scanDirectories, c.scanInterval))
|
|
||||||
case c: CustomJettyConfiguration =>
|
|
||||||
for(x <- c.jettyConfigurationXML)
|
|
||||||
(new XmlConfiguration(x.toString)).configure(server)
|
|
||||||
for(file <- c.jettyConfigurationFiles)
|
|
||||||
(new XmlConfiguration(file.toURI.toURL)).configure(server)
|
|
||||||
(None, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
server.start()
|
|
||||||
new StopServer(new WeakReference(server), listener.map(new WeakReference(_)), scanner, oldLog)
|
|
||||||
}
|
|
||||||
catch { case e => server.stop(); throw e }
|
|
||||||
}
|
|
||||||
private def configureDefaultConnector(server: Server, port: Int)
|
|
||||||
{
|
|
||||||
val defaultConnector = new SelectChannelConnector
|
|
||||||
defaultConnector.setPort(port)
|
|
||||||
defaultConnector.setMaxIdleTime(DefaultMaxIdleTime)
|
|
||||||
server.addConnector(defaultConnector)
|
|
||||||
}
|
|
||||||
trait Reload { def reloadApp(): Unit }
|
|
||||||
private class StopServer(serverReference: Reference[Server], reloadReference: Option[Reference[Reload]], scannerReferenceOpt: Option[Reference[Scanner]], oldLog: JLogger) extends Stoppable
|
|
||||||
{
|
|
||||||
def reload(): Unit = on(reloadReference)(_.reloadApp())
|
|
||||||
private def on[T](refOpt: Option[Reference[T]])(f: T => Unit): Unit = refOpt.foreach(ref => onReferenced(ref.get)(f))
|
|
||||||
private def onReferenced[T](t: T)(f: T => Unit): Unit = if(t == null) () else f(t)
|
|
||||||
def stop()
|
|
||||||
{
|
|
||||||
onReferenced(serverReference.get)(_.stop())
|
|
||||||
on(scannerReferenceOpt)(_.stop())
|
|
||||||
Log.setLog(oldLog)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private def reload(server: Server, reconfigure: => Unit, log: Logger)
|
|
||||||
{
|
|
||||||
log.info("Reloading web application...")
|
|
||||||
val handlers = wrapNull(server.getHandlers, server.getHandler)
|
|
||||||
log.debug("Stopping handlers: " + handlers.mkString(", "))
|
|
||||||
handlers.foreach(_.stop)
|
|
||||||
log.debug("Reconfiguring...")
|
|
||||||
reconfigure
|
|
||||||
log.debug("Restarting handlers: " + handlers.mkString(", "))
|
|
||||||
handlers.foreach(_.start)
|
|
||||||
log.info("Reload complete.")
|
|
||||||
}
|
|
||||||
private def wrapNull(a: Array[Handler], b: Handler) =
|
|
||||||
(a, b) match
|
|
||||||
{
|
|
||||||
case (null, null) => Nil
|
|
||||||
case (null, notB) => notB :: Nil
|
|
||||||
case (notA, null) => notA.toList
|
|
||||||
case (notA, notB) => notB :: notA.toList
|
|
||||||
}
|
|
||||||
private class JettyLogger(delegate: Logger) extends JettyLoggerBase(delegate) with JLogger
|
|
||||||
{
|
|
||||||
def getLogger(name: String) = this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,5 +2,5 @@ import sbt._
|
||||||
|
|
||||||
class TestProject(info: ProjectInfo) extends DefaultProject(info)
|
class TestProject(info: ProjectInfo) extends DefaultProject(info)
|
||||||
{
|
{
|
||||||
val specs = "org.scala-tools.testing" %% "specs" % "1.6.1"
|
val specs = "org.scala-tools.testing" %% "specs" % "1.6.1" intransitive()
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
> ++2.8.0.Beta1-RC7
|
#> ++2.8.0.Beta1-RC7
|
||||||
|
> ++2.7.7
|
||||||
> update
|
> update
|
||||||
|
|
||||||
> clean
|
> clean
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,14 @@ import sbt._
|
||||||
|
|
||||||
class WebappBuild(info: ProjectInfo) extends DefaultWebProject(info) {
|
class WebappBuild(info: ProjectInfo) extends DefaultWebProject(info) {
|
||||||
|
|
||||||
val servlet_api = "org.mortbay.jetty" % "servlet-api-2.5" % "6.1.14" % "provided->default"
|
override def libraryDependencies = if("jetty7".asFile.exists) jetty7Dependencies else jetty6Dependencies
|
||||||
val jetty_servlet = "org.mortbay.jetty" % "jetty" % "6.1.14" % "test->default"
|
def jetty6Dependencies =
|
||||||
|
Set("org.mortbay.jetty" % "servlet-api-2.5" % "6.1.14" % "provided->default",
|
||||||
|
"org.mortbay.jetty" % "jetty" % "6.1.14" % "test->default")
|
||||||
|
def jetty7Dependencies =
|
||||||
|
Set("javax.servlet" % "servlet-api" % "2.5" % "provided",
|
||||||
|
"org.eclipse.jetty" % "jetty-server" % "7.0.1.v20091125" % "test",
|
||||||
|
"org.eclipse.jetty" % "jetty-webapp" % "7.0.1.v20091125" % "test")
|
||||||
|
|
||||||
def indexURL = new java.net.URL("http://localhost:8080")
|
def indexURL = new java.net.URL("http://localhost:8080")
|
||||||
def indexFile = new java.io.File("index.html")
|
def indexFile = new java.io.File("index.html")
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,26 @@
|
||||||
> ++2.8.0.Beta1-RC6
|
> ++2.8.0.Beta1
|
||||||
|
|
||||||
|
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
|
||||||
> update
|
> update
|
||||||
> jetty-run
|
> jetty-run
|
||||||
$ pause
|
|
||||||
> check-page "Hello, Scala!"
|
> check-page "Hello, Scala!"
|
||||||
|
|
||||||
$ copy-file changes/MyServlet.scala src/main/scala/test/MyServlet.scala
|
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
|
||||||
|
|
||||||
|
> prepare-webapp
|
||||||
|
> jetty-reload
|
||||||
|
> check-page "Hello, Scala 2!"
|
||||||
|
|
||||||
|
> jetty-stop
|
||||||
|
-> check-page "Hello World 2!"
|
||||||
|
|
||||||
|
$ touch jetty7
|
||||||
|
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
|
||||||
|
> update
|
||||||
|
> jetty-run
|
||||||
|
> check-page "Hello, Scala!"
|
||||||
|
|
||||||
|
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
|
||||||
|
|
||||||
> prepare-webapp
|
> prepare-webapp
|
||||||
> jetty-reload
|
> jetty-reload
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,14 @@ import sbt._
|
||||||
|
|
||||||
class WebappBuild(info: ProjectInfo) extends DefaultWebProject(info) {
|
class WebappBuild(info: ProjectInfo) extends DefaultWebProject(info) {
|
||||||
|
|
||||||
val servlet_api = "org.mortbay.jetty" % "servlet-api-2.5" % "6.1.14" % "provided->default"
|
override def libraryDependencies = if("jetty7".asFile.exists) jetty7Dependencies else jetty6Dependencies
|
||||||
val jetty_servlet = "org.mortbay.jetty" % "jetty" % "6.1.14" % "test->default"
|
def jetty6Dependencies =
|
||||||
|
Set("org.mortbay.jetty" % "servlet-api-2.5" % "6.1.14" % "provided->default",
|
||||||
|
"org.mortbay.jetty" % "jetty" % "6.1.14" % "test->default")
|
||||||
|
def jetty7Dependencies =
|
||||||
|
Set("javax.servlet" % "servlet-api" % "2.5" % "provided",
|
||||||
|
"org.eclipse.jetty" % "jetty-server" % "7.0.1.v20091125" % "test",
|
||||||
|
"org.eclipse.jetty" % "jetty-webapp" % "7.0.1.v20091125" % "test")
|
||||||
|
|
||||||
def indexURL = new java.net.URL("http://localhost:8080")
|
def indexURL = new java.net.URL("http://localhost:8080")
|
||||||
def indexFile = new java.io.File("index.html")
|
def indexFile = new java.io.File("index.html")
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"http://java.sun.com/dtd/web-app_2_3.dtd" >
|
"http://java.sun.com/dtd/web-app_2_3.dtd" >
|
||||||
|
|
||||||
<web-app>
|
<web-app>
|
||||||
<display-name>Archetype Created Web Application</display-name>
|
<display-name>Test Web Application</display-name>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<servlet-name>Home</servlet-name>
|
<servlet-name>Home</servlet-name>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,28 @@
|
||||||
> ++2.8.0.Beta1-RC6
|
> ++2.8.0.Beta1
|
||||||
|
|
||||||
|
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
|
||||||
> update
|
> update
|
||||||
> jetty-run
|
> jetty-run
|
||||||
> check-page "Hello, Scala!"
|
> check-page "Hello, Scala!"
|
||||||
|
|
||||||
$ copy-file changes/MyServlet.scala src/main/scala/test/MyServlet.scala
|
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
|
||||||
|
|
||||||
|
> prepare-webapp
|
||||||
|
> jetty-reload
|
||||||
|
> check-page "Hello, Scala 2!"
|
||||||
|
|
||||||
|
> jetty-stop
|
||||||
|
-> check-page "Hello World 2!"
|
||||||
|
|
||||||
|
# test that it works with Jetty 7 support
|
||||||
|
$ touch jetty7
|
||||||
|
|
||||||
|
$ copy-file changes/MyServlet1.scala src/main/scala/test/MyServlet.scala
|
||||||
|
> update
|
||||||
|
> jetty-run
|
||||||
|
> check-page "Hello, Scala!"
|
||||||
|
|
||||||
|
$ copy-file changes/MyServlet2.scala src/main/scala/test/MyServlet.scala
|
||||||
|
|
||||||
> prepare-webapp
|
> prepare-webapp
|
||||||
> jetty-reload
|
> jetty-reload
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue