diff --git a/.mill-version b/.mill-version index ecd2d5d92b..1ee43fc53c 100644 --- a/.mill-version +++ b/.mill-version @@ -1,2 +1 @@ -0.11.6 - +0.11.8 diff --git a/build.sc b/build.sc index c836fcbdf8..397e947135 100644 --- a/build.sc +++ b/build.sc @@ -28,13 +28,13 @@ import $file.example.websockets3.build import $file.example.websockets4.build import $file.ci.upload import $ivy.`de.tototec::de.tobiasroeser.mill.vcs.version::0.4.0` -import $ivy.`com.github.lolgab::mill-mima::0.0.23` +import $ivy.`com.github.lolgab::mill-mima::0.1.0` import de.tobiasroeser.mill.vcs.version.VcsVersion -val scala213 = "2.13.10" -val scala212 = "2.12.17" -val scala3 = "3.2.2" -val scalaJS = "1.13.0" +val scala213 = "2.13.14" +val scala212 = "2.12.19" +val scala3 = "3.3.3" +val scalaJS = "1.16.0" val communityBuildDottyVersion = sys.props.get("dottyVersion").toList val scalaVersions = List(scala212, scala213, scala3) ++ communityBuildDottyVersion @@ -59,20 +59,20 @@ trait CaskModule extends CrossScalaModule with PublishModule{ trait CaskMainModule extends CaskModule { def ivyDeps = T{ Agg( - ivy"io.undertow:undertow-core:2.3.10.Final", - ivy"com.lihaoyi::upickle:3.0.0" + ivy"io.undertow:undertow-core:2.3.13.Final", + ivy"com.lihaoyi::upickle:3.3.1" ) ++ Agg.when(!isScala3)(ivy"org.scala-lang:scala-reflect:$crossScalaVersion") } - def compileIvyDeps = Agg.when(!isScala3)(ivy"com.lihaoyi:::acyclic:0.3.6") + def compileIvyDeps = Agg.when(!isScala3)(ivy"com.lihaoyi:::acyclic:0.3.12") def scalacOptions = Agg.when(!isScala3)("-P:acyclic:force").toSeq - def scalacPluginIvyDeps = Agg.when(!isScala3)(ivy"com.lihaoyi:::acyclic:0.3.6") + def scalacPluginIvyDeps = Agg.when(!isScala3)(ivy"com.lihaoyi:::acyclic:0.3.12") object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0" + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.2" ) } def moduleDeps = Seq(cask.util.jvm(crossScalaVersion)) @@ -82,9 +82,9 @@ object cask extends Cross[CaskMainModule](scalaVersions) { object util extends Module { trait UtilModule extends CaskModule with PlatformScalaModule{ def ivyDeps = Agg( - ivy"com.lihaoyi::sourcecode:0.3.0", - ivy"com.lihaoyi::pprint:0.8.1", - ivy"com.lihaoyi::geny:1.0.0" + ivy"com.lihaoyi::sourcecode:0.4.1", + ivy"com.lihaoyi::pprint:0.9.0", + ivy"com.lihaoyi::geny:1.1.0" ) } @@ -92,7 +92,7 @@ object cask extends Cross[CaskMainModule](scalaVersions) { trait UtilJvmModule extends UtilModule { def ivyDeps = super.ivyDeps() ++ Agg( ivy"com.lihaoyi::castor::0.3.0", - ivy"org.java-websocket:Java-WebSocket:1.5.3" + ivy"org.java-websocket:Java-WebSocket:1.5.6" ) } @@ -101,7 +101,7 @@ object cask extends Cross[CaskMainModule](scalaVersions) { def scalaJSVersion = scalaJS def ivyDeps = super.ivyDeps() ++ Agg( ivy"com.lihaoyi::castor::0.3.0", - ivy"org.scala-js::scalajs-dom::2.4.0" + ivy"org.scala-js::scalajs-dom::2.8.0" ) } } @@ -168,7 +168,7 @@ object example extends Module{ object todoDb extends Cross[TodoDbModule](scala213) // uses quill, can't enable for Dotty yet trait TwirlModule extends millbuild.example.twirl.build.AppModule with LocalModule - object twirl extends Cross[TwirlModule](scalaVersions) +// object twirl extends Cross[TwirlModule](scalaVersions) trait VariableRoutesModule extends millbuild.example.variableRoutes.build.AppModule with LocalModule object variableRoutes extends Cross[VariableRoutesModule](scalaVersions) @@ -230,7 +230,7 @@ def uploadToGithub() = T.command{ millbuild.example.todo.build.millSourcePath, millbuild.example.todoApi.build.millSourcePath, millbuild.example.todoDb.build.millSourcePath, - millbuild.example.twirl.build.millSourcePath, +// millbuild.example.twirl.build.millSourcePath, millbuild.example.variableRoutes.build.millSourcePath, millbuild.example.queryParams.build.millSourcePath, millbuild.example.websockets.build.millSourcePath, diff --git a/cask/src-2/cask/main/Routes.scala b/cask/src-2/cask/main/Routes.scala index 18aff11a74..f4b00a24ac 100644 --- a/cask/src-2/cask/main/Routes.scala +++ b/cask/src-2/cask/main/Routes.scala @@ -7,8 +7,8 @@ import language.experimental.macros trait Routes{ def decorators = Seq.empty[cask.router.Decorator[_, _, _]] - private[this] var metadata0: RoutesEndpointsMetadata[this.type] = null - def caskMetadata = + private[this] var metadata0: RoutesEndpointsMetadata[this.type] = _ + def caskMetadata: RoutesEndpointsMetadata[Routes.this.type] = if (metadata0 != null) metadata0 else throw new Exception("Routes not yet initialized") diff --git a/cask/src-3/cask/main/Routes.scala b/cask/src-3/cask/main/Routes.scala index dec32d257b..e81b895a57 100644 --- a/cask/src-3/cask/main/Routes.scala +++ b/cask/src-3/cask/main/Routes.scala @@ -7,8 +7,8 @@ import language.experimental.macros trait Routes{ def decorators = Seq.empty[cask.router.Decorator[_, _, _]] - private[this] var metadata0: RoutesEndpointsMetadata[this.type] = null - def caskMetadata = + private[this] var metadata0: RoutesEndpointsMetadata[this.type] = _ + def caskMetadata: RoutesEndpointsMetadata[Routes.this.type] = if (metadata0 != null) metadata0 else throw new Exception("Routes not yet initialized") diff --git a/cask/src/cask/internal/ThreadBlockingHandler.scala b/cask/src/cask/internal/ThreadBlockingHandler.scala new file mode 100644 index 0000000000..0b1b55ece5 --- /dev/null +++ b/cask/src/cask/internal/ThreadBlockingHandler.scala @@ -0,0 +1,16 @@ +package cask.internal + +import io.undertow.server.{HttpHandler, HttpServerExchange} + +import java.util.concurrent.Executor + +final class ThreadBlockingHandler(executor: Executor, + handler: HttpHandler) + extends HttpHandler { + require(executor != null, "executor should not be null") + + override def handleRequest(exchange: HttpServerExchange): Unit = { + exchange.startBlocking() + exchange.dispatch(executor, handler) + } +} \ No newline at end of file diff --git a/cask/src/cask/internal/Util.scala b/cask/src/cask/internal/Util.scala index 87e2a15623..1511591610 100644 --- a/cask/src/cask/internal/Util.scala +++ b/cask/src/cask/internal/Util.scala @@ -1,24 +1,94 @@ package cask.internal import java.io.{InputStream, PrintWriter, StringWriter} - import scala.collection.generic.CanBuildFrom import scala.collection.mutable import java.io.OutputStream - +import java.lang.invoke.{MethodHandles, MethodType} +import java.util.concurrent.{Executor, ExecutorService, ThreadFactory} import scala.annotation.switch import scala.concurrent.{ExecutionContext, Future, Promise} +import scala.util.Try +import scala.util.control.NonFatal object Util { + private val lookup = MethodHandles.lookup + + import cask.util.Logger.Console.globalLogger + + /** + * Create a virtual thread executor with the given executor as the scheduler. + * */ + def createVirtualThreadExecutor(executor: Executor): Option[Executor] = { + (for { + factory <- Try(createVirtualThreadFactory("cask-handler-executor", executor)) + executor <- Try(createNewThreadPerTaskExecutor(factory)) + } yield executor).toOption + } + + def createNewThreadPerTaskExecutor(threadFactory: ThreadFactory): ExecutorService = { + try { + val executorsClazz = ClassLoader.getSystemClassLoader.loadClass("java.util.concurrent.Executors") + val newThreadPerTaskExecutorMethod = lookup.findStatic( + executorsClazz, + "newThreadPerTaskExecutor", + MethodType.methodType(classOf[ExecutorService], classOf[ThreadFactory])) + newThreadPerTaskExecutorMethod.invoke(threadFactory) + .asInstanceOf[ExecutorService] + } catch { + case NonFatal(e) => + globalLogger.exception(e) + throw new UnsupportedOperationException("Failed to create newThreadPerTaskExecutor.", e) + } + } + + /** + * Create a virtual thread factory with a executor, the executor will be used as the scheduler of + * virtual thread. + * + * The executor should run task on platform threads. + * + * returns null if not supported. + */ + def createVirtualThreadFactory(prefix: String, + executor: Executor): ThreadFactory = + try { + val builderClass = ClassLoader.getSystemClassLoader.loadClass("java.lang.Thread$Builder") + val ofVirtualClass = ClassLoader.getSystemClassLoader.loadClass("java.lang.Thread$Builder$OfVirtual") + val ofVirtualMethod = lookup.findStatic(classOf[Thread], "ofVirtual", MethodType.methodType(ofVirtualClass)) + var builder = ofVirtualMethod.invoke() + if (executor != null) { + val clazz = builder.getClass + val privateLookup = MethodHandles.privateLookupIn( + clazz, + lookup + ) + val schedulerFieldSetter = privateLookup + .findSetter(clazz, "scheduler", classOf[Executor]) + schedulerFieldSetter.invoke(builder, executor) + } + val nameMethod = lookup.findVirtual(ofVirtualClass, "name", + MethodType.methodType(ofVirtualClass, classOf[String], classOf[Long])) + val factoryMethod = lookup.findVirtual(builderClass, "factory", MethodType.methodType(classOf[ThreadFactory])) + builder = nameMethod.invoke(builder, prefix + "-virtual-thread-", 0L) + factoryMethod.invoke(builder).asInstanceOf[ThreadFactory] + } catch { + case NonFatal(e) => + globalLogger.exception(e) + //--add-opens java.base/java.lang=ALL-UNNAMED + throw new UnsupportedOperationException("Failed to create virtual thread factory", e) + } + def firstFutureOf[T](futures: Seq[Future[T]])(implicit ec: ExecutionContext) = { val p = Promise[T] futures.foreach(_.foreach(p.trySuccess)) p.future } + /** - * Convert a string to a C&P-able literal. Basically - * copied verbatim from the uPickle source code. - */ + * Convert a string to a C&P-able literal. Basically + * copied verbatim from the uPickle source code. + */ def literalize(s: IndexedSeq[Char], unicode: Boolean = true) = { val sb = new StringBuilder sb.append('"') @@ -47,8 +117,8 @@ object Util { def transferTo(in: InputStream, out: OutputStream) = { val buffer = new Array[Byte](8192) - while ({ - in.read(buffer) match{ + while ( { + in.read(buffer) match { case -1 => false case n => out.write(buffer, 0, n) @@ -56,20 +126,21 @@ object Util { } }) () } + def pluralize(s: String, n: Int) = { if (n == 1) s else s + "s" } /** - * Splits a string into path segments; automatically removes all - * leading/trailing slashes, and ignores empty path segments. - * - * Written imperatively for performance since it's used all over the place. - */ + * Splits a string into path segments; automatically removes all + * leading/trailing slashes, and ignores empty path segments. + * + * Written imperatively for performance since it's used all over the place. + */ def splitPath(p: String): collection.IndexedSeq[String] = { val pLength = p.length var i = 0 - while(i < pLength && p(i) == '/') i += 1 + while (i < pLength && p(i) == '/') i += 1 var segmentStart = i val out = mutable.ArrayBuffer.empty[String] @@ -81,7 +152,7 @@ object Util { segmentStart = i + 1 } - while(i < pLength){ + while (i < pLength) { if (p(i) == '/') complete() i += 1 } @@ -96,6 +167,7 @@ object Util { pw.flush() trace.toString } + def softWrap(s: String, leftOffset: Int, maxWidth: Int) = { val oneLine = s.linesIterator.mkString(" ").split(' ') @@ -103,13 +175,13 @@ object Util { val output = new StringBuilder(oneLine.head) var currentLineWidth = oneLine.head.length - for(chunk <- oneLine.tail){ + for (chunk <- oneLine.tail) { val addedWidth = currentLineWidth + chunk.length + 1 - if (addedWidth > maxWidth){ + if (addedWidth > maxWidth) { output.append("\n" + indent) output.append(chunk) currentLineWidth = chunk.length - } else{ + } else { currentLineWidth = addedWidth output.append(' ') output.append(chunk) @@ -117,12 +189,13 @@ object Util { } output.mkString } + def sequenceEither[A, B, M[X] <: TraversableOnce[X]](in: M[Either[A, B]])( implicit cbf: CanBuildFrom[M[Either[A, B]], B, M[B]]): Either[A, M[B]] = { in.foldLeft[Either[A, mutable.Builder[B, M[B]]]](Right(cbf(in))) { - case (acc, el) => - for (a <- acc; e <- el) yield a += e - } + case (acc, el) => + for (a <- acc; e <- el) yield a += e + } .map(_.result()) } } diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala index b789604058..a8a0b81ddc 100644 --- a/cask/src/cask/main/Main.scala +++ b/cask/src/cask/main/Main.scala @@ -2,65 +2,94 @@ package cask.main import cask.endpoints.{WebsocketResult, WsHandler} import cask.model._ -import cask.internal.{DispatchTrie, Util} -import cask.main -import cask.router.{Decorator, EndpointMetadata, EntryPoint, RawDecorator, Result} +import cask.internal.{DispatchTrie, ThreadBlockingHandler, Util} +import Response.Raw +import cask.router.{Decorator, EndpointMetadata, EntryPoint, Result} import cask.util.Logger import io.undertow.Undertow import io.undertow.server.{HttpHandler, HttpServerExchange} import io.undertow.server.handlers.BlockingHandler import io.undertow.util.HttpString +import java.util.concurrent.Executor +import scala.annotation.nowarn import scala.concurrent.ExecutionContext +import scala.util.control.NonFatal /** - * A combination of [[cask.Main]] and [[cask.Routes]], ideal for small - * one-file web applications. - */ -class MainRoutes extends Main with Routes{ - def allRoutes = Seq(this) + * A combination of [[cask.Main]] and [[cask.Routes]], ideal for small + * one-file web applications. + */ +class MainRoutes extends Main with Routes { + def allRoutes: Seq[Routes] = Seq(this) } /** - * Defines the main entrypoint and configuration of the Cask web application. - * - * You can pass in an arbitrary number of [[cask.Routes]] objects for it to - * serve, and override various properties on [[Main]] in order to configure - * application-wide properties. - */ -abstract class Main{ + * Defines the main entrypoint and configuration of the Cask web application. + * + * You can pass in an arbitrary number of [[cask.Routes]] objects for it to + * serve, and override various properties on [[Main]] in order to configure + * application-wide properties. + * + * By default,the [[Routes]] running inside a worker threads, and can run with + * `Virtual Threads` if the runtime supports it and the property `cask.virtualThread.enabled` is set to `true`. + */ +abstract class Main { def mainDecorators: Seq[Decorator[_, _, _]] = Nil + def allRoutes: Seq[Routes] + def port: Int = 8080 + def host: String = "localhost" + def verbose = false + def debugMode: Boolean = true - def createExecutionContext = castor.Context.Simple.executionContext + def createExecutionContext: ExecutionContext = castor.Context.Simple.executionContext + def createActorContext = new castor.Context.Simple(executionContext, log.exception) - val executionContext = createExecutionContext + val executionContext: ExecutionContext = createExecutionContext implicit val actorContext: castor.Context = createActorContext implicit def log: cask.util.Logger = new cask.util.Logger.Console() - def dispatchTrie = Main.prepareDispatchTrie(allRoutes) + def dispatchTrie: DispatchTrie[Map[String, (Routes, EndpointMetadata[_])]] = Main.prepareDispatchTrie(allRoutes) + + protected def handlerExecutor(): Executor = { + null + } + + private def screenExecutor(executor: Executor): Executor = { + if (executor eq null) executor + else if (System.getProperty("cask.virtualThread.enabled", "true").toBoolean) { + Util.createVirtualThreadExecutor(executor).getOrElse(executor) + } else executor + } + + def defaultHandler: HttpHandler = { + val mainHandler = new Main.DefaultHandler(dispatchTrie, mainDecorators, debugMode, handleNotFound, handleMethodNotAllowed, handleEndpointError) + val executor = screenExecutor(handlerExecutor()) + if (handlerExecutor ne null) { + new ThreadBlockingHandler(executor, mainHandler) + } else new BlockingHandler(mainHandler) + } - def defaultHandler = new BlockingHandler( - new Main.DefaultHandler(dispatchTrie, mainDecorators, debugMode, handleNotFound, handleMethodNotAllowed, handleEndpointError) - ) + def handler(): HttpHandler = defaultHandler - def handleNotFound() = Main.defaultHandleNotFound() + def handleNotFound(): Raw = Main.defaultHandleNotFound() - def handleMethodNotAllowed() = Main.defaultHandleMethodNotAllowed() + def handleMethodNotAllowed(): Raw = Main.defaultHandleMethodNotAllowed() def handleEndpointError(routes: Routes, metadata: EndpointMetadata[_], - e: cask.router.Result.Error) = { + e: cask.router.Result.Error): Response[String] = { Main.defaultHandleError(routes, metadata, e, debugMode) } - def main(args: Array[String]): Unit = { + def main(@nowarn args: Array[String]): Unit = { if (!verbose) Main.silenceJboss() val server = Undertow.builder .addHttpListener(port, host) @@ -71,10 +100,10 @@ abstract class Main{ } -object Main{ +object Main { class DefaultHandler(dispatchTrie: DispatchTrie[Map[String, (Routes, EndpointMetadata[_])]], mainDecorators: Seq[Decorator[_, _, _]], - debugMode: Boolean, + @nowarn debugMode: Boolean, handleNotFound: () => Response.Raw, handleMethodNotAllowed: () => Response.Raw, handleError: (Routes, EndpointMetadata[_], Result.Error) => Response.Raw) @@ -85,7 +114,7 @@ object Main{ Tuple2( "websocket", (r: Any) => - r.asInstanceOf[WebsocketResult] match{ + r.asInstanceOf[WebsocketResult] match { case l: WsHandler => io.undertow.Handlers.websocket(l).handleRequest(exchange) case l: WebsocketResult.Listener => @@ -129,8 +158,9 @@ object Main{ } } } - }catch{case e: Throwable => - e.printStackTrace() + } catch { + case NonFatal(e) => + log.exception(e) } } @@ -158,25 +188,25 @@ object Main{ val methodMap = methods.toMap[String, (Routes, EndpointMetadata[_])] val subpath = metadata.endpoint.subpath || - metadata.entryPoint.argSignatures.exists(_.exists(_.reads.remainingPathSegments)) + metadata.entryPoint.argSignatures.exists(_.exists(_.reads.remainingPathSegments)) (segments, methodMap, subpath) } val dispatchInputs = flattenedRoutes.groupBy(_._1).map { case (segments, values) => - val methodMap = values.map(_._2).flatten - val hasSubpath = values.map(_._3).contains(true) - (segments, methodMap, hasSubpath) + val methodMap = values.flatMap(_._2) + val hasSubPath = values.exists(_._3) + (segments, methodMap, hasSubPath) }.toSeq DispatchTrie.construct(0, dispatchInputs)(_.map(_._1)).map(_.toMap) } - def writeResponse(exchange: HttpServerExchange, response: Response.Raw) = { - response.data.headers.foreach{case (k, v) => + def writeResponse(exchange: HttpServerExchange, response: Response.Raw): Unit = { + response.data.headers.foreach { case (k, v) => exchange.getResponseHeaders.put(new HttpString(k), v) } - response.headers.foreach{case (k, v) => + response.headers.foreach { case (k, v) => exchange.getResponseHeaders.put(new HttpString(k), v) } response.cookies.foreach(c => exchange.setResponseCookie(Cookie.toUndertow(c))) @@ -185,12 +215,16 @@ object Main{ val output = exchange.getOutputStream response.data.write(new java.io.OutputStream { def write(b: Int): Unit = output.write(b) + override def write(b: Array[Byte]): Unit = output.write(b) + override def write(b: Array[Byte], off: Int, len: Int): Unit = output.write(b, off, len) - override def close() = { + + override def close(): Unit = { if (!exchange.isComplete) output.close() } - override def flush() = { + + override def flush(): Unit = { if (!exchange.isComplete) output.flush() } }) @@ -200,7 +234,7 @@ object Main{ metadata: EndpointMetadata[_], e: Result.Error, debugMode: Boolean) - (implicit log: Logger) = { + (implicit log: Logger): Response[String] = { e match { case e: Result.Error.Exception => log.exception(e.t) case _ => // do nothing diff --git a/example/compress/app/src/Compress.scala b/example/compress/app/src/Compress.scala index 9c57494ad2..eb95e17101 100644 --- a/example/compress/app/src/Compress.scala +++ b/example/compress/app/src/Compress.scala @@ -1,9 +1,14 @@ package app -object Compress extends cask.MainRoutes{ + +import cask.internal.{ThreadBlockingHandler, Util} + +import java.util.concurrent.{Executor, Executors} + +object Compress extends cask.MainRoutes { @cask.decorators.compress @cask.get("/") - def hello() = { + def hello(): String = { "Hello World! Hello World! Hello World!" } diff --git a/example/compress/build.sc b/example/compress/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/compress/build.sc +++ b/example/compress/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/compress2/build.sc b/example/compress2/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/compress2/build.sc +++ b/example/compress2/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/compress3/build.sc b/example/compress3/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/compress3/build.sc +++ b/example/compress3/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/cookies/build.sc b/example/cookies/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/cookies/build.sc +++ b/example/cookies/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/decorated/build.sc b/example/decorated/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/decorated/build.sc +++ b/example/decorated/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/decorated2/build.sc b/example/decorated2/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/decorated2/build.sc +++ b/example/decorated2/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/endpoints/build.sc b/example/endpoints/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/endpoints/build.sc +++ b/example/endpoints/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/formJsonPost/build.sc b/example/formJsonPost/build.sc index b9c65484bc..83352910bc 100644 --- a/example/formJsonPost/build.sc +++ b/example/formJsonPost/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0" + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3" ) } } diff --git a/example/httpMethods/build.sc b/example/httpMethods/build.sc index edb70116ba..e5687594c4 100644 --- a/example/httpMethods/build.sc +++ b/example/httpMethods/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) def forkArgs = Seq("--add-opens=java.base/java.net=ALL-UNNAMED") } diff --git a/example/minimalApplication/build.sc b/example/minimalApplication/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/minimalApplication/build.sc +++ b/example/minimalApplication/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/minimalApplication2/build.sc b/example/minimalApplication2/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/minimalApplication2/build.sc +++ b/example/minimalApplication2/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/queryParams/build.sc b/example/queryParams/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/queryParams/build.sc +++ b/example/queryParams/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/redirectAbort/build.sc b/example/redirectAbort/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/redirectAbort/build.sc +++ b/example/redirectAbort/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/scalatags/build.sc b/example/scalatags/build.sc index 21cce09e08..b4771ac507 100644 --- a/example/scalatags/build.sc +++ b/example/scalatags/build.sc @@ -9,8 +9,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/staticFiles/build.sc b/example/staticFiles/build.sc index 3f9c2f941b..389e51d4e2 100644 --- a/example/staticFiles/build.sc +++ b/example/staticFiles/build.sc @@ -8,8 +8,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) def forkWorkingDir = build.millSourcePath diff --git a/example/staticFiles2/build.sc b/example/staticFiles2/build.sc index 3f9c2f941b..389e51d4e2 100644 --- a/example/staticFiles2/build.sc +++ b/example/staticFiles2/build.sc @@ -8,8 +8,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) def forkWorkingDir = build.millSourcePath diff --git a/example/todo/build.sc b/example/todo/build.sc index 19d2486230..c026c2517e 100644 --- a/example/todo/build.sc +++ b/example/todo/build.sc @@ -12,8 +12,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/todoApi/build.sc b/example/todoApi/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/todoApi/build.sc +++ b/example/todoApi/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/todoDb/build.sc b/example/todoDb/build.sc index 893b424be9..56a10ed222 100644 --- a/example/todoDb/build.sc +++ b/example/todoDb/build.sc @@ -10,8 +10,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/twirl/build.sc b/example/twirl/build.sc index 06a078c294..210e3e0204 100644 --- a/example/twirl/build.sc +++ b/example/twirl/build.sc @@ -15,8 +15,8 @@ trait AppModule extends CrossScalaModule with mill.twirllib.TwirlModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/variableRoutes/build.sc b/example/variableRoutes/build.sc index 75de91ef2f..ecf4564d24 100644 --- a/example/variableRoutes/build.sc +++ b/example/variableRoutes/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ) } } diff --git a/example/websockets/build.sc b/example/websockets/build.sc index 7681359512..7b4a29457c 100644 --- a/example/websockets/build.sc +++ b/example/websockets/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ivy"org.asynchttpclient:async-http-client:2.12.3" ) } diff --git a/example/websockets2/build.sc b/example/websockets2/build.sc index 7681359512..7b4a29457c 100644 --- a/example/websockets2/build.sc +++ b/example/websockets2/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ivy"org.asynchttpclient:async-http-client:2.12.3" ) } diff --git a/example/websockets3/build.sc b/example/websockets3/build.sc index 7681359512..7b4a29457c 100644 --- a/example/websockets3/build.sc +++ b/example/websockets3/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ivy"org.asynchttpclient:async-http-client:2.12.3" ) } diff --git a/example/websockets4/build.sc b/example/websockets4/build.sc index 7681359512..7b4a29457c 100644 --- a/example/websockets4/build.sc +++ b/example/websockets4/build.sc @@ -7,8 +7,8 @@ trait AppModule extends CrossScalaModule{ object test extends ScalaTests with TestModule.Utest{ def ivyDeps = Agg( - ivy"com.lihaoyi::utest::0.8.1", - ivy"com.lihaoyi::requests::0.8.0", + ivy"com.lihaoyi::utest::0.8.3", + ivy"com.lihaoyi::requests::0.8.3", ivy"org.asynchttpclient:async-http-client:2.12.3" ) }