Run builtin services directly from aqua run (#552)

This commit is contained in:
Dima 2022-08-30 18:45:25 +04:00 committed by GitHub
parent 5bd30c7918
commit 7b61247ade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 85 additions and 51 deletions

View File

@ -20,17 +20,30 @@ import scalajs.js
import scala.concurrent.ExecutionContext
sealed trait AquaPath
sealed trait AquaPath {
def getPath[F[_]: Async](): F[Path]
}
// Path for package relative files
case class PackagePath(path: String) extends AquaPath
case class PackagePath(path: String) extends AquaPath {
def getPath[F[_]: Async](): F[Path] = PlatformOpts.getPackagePath(path)
}
// Path for absolute or call path relative files
case class RelativePath(path: Path) extends AquaPath
case class RelativePath(path: Path) extends AquaPath {
def getPath[F[_]: Async](): F[Path] = path.pure[F]
}
object PackagePath {
// path to a builtin file in aqua package
val builtin: PackagePath = PackagePath("../aqua-lib/builtin.aqua")
}
// All info to run any aqua function
case class RunInfo(
common: GeneralOptions,
func: CliFunc,
input: AquaPath,
input: Option[AquaPath],
imports: List[Path] = Nil,
argumentGetters: Map[String, VarJson] = Map.empty,
services: List[Service] = Nil,
@ -50,15 +63,9 @@ class SubCommandBuilder[F[_]: Async](
riF.flatMap {
case Validated.Valid(ri) =>
LogFormatter.initLogger(Some(ri.common.logLevel.compiler))
(ri.input match {
case PackagePath(p) => PlatformOpts.getPackagePath(p)
case RelativePath(p) => p.pure[F]
}).flatMap { path =>
RunCommand.execRun(
ri,
path
)
}
RunCommand.execRun(
ri
)
case i @ Validated.Invalid(_) =>
i.pure[F]
}
@ -103,7 +110,7 @@ object SubCommandBuilder {
name,
header,
GeneralOptions.opt.map { c =>
RunInfo(c, CliFunc(funcName), path)
RunInfo(c, CliFunc(funcName), Some(path))
}
)

View File

@ -19,6 +19,7 @@ import cats.data.Validated.{invalidNec, validNec}
import cats.data.{Chain, NonEmptyList, Validated, ValidatedNec}
import cats.effect.IO
import cats.effect.kernel.{Async, Clock}
import cats.syntax.applicative.*
import cats.syntax.flatMap.*
import cats.syntax.functor.*
import cats.syntax.monad.*
@ -27,11 +28,12 @@ import cats.syntax.traverse.*
import fs2.io.file.{Files, Path}
import scribe.Logging
import scala.concurrent.duration.Duration
import scala.scalajs.js
// Function compiler
class FuncCompiler[F[_]: Files: AquaIO: Async](
input: Path,
input: Option[AquaPath],
imports: List[Path],
transformConfig: TransformConfig,
withRunImport: Boolean = false
@ -46,9 +48,7 @@ class FuncCompiler[F[_]: Files: AquaIO: Async](
.fold(
contexts
.collectFirstSome(_.allFuncs.get(func.name))
)(ab =>
contexts.collectFirstSome(_.abilities.get(ab).flatMap(_.allFuncs.get(func.name)))
)
)(ab => contexts.collectFirstSome(_.abilities.get(ab).flatMap(_.allFuncs.get(func.name))))
.map(validNec)
.getOrElse(
Validated.invalidNec[String, FuncArrow](
@ -123,28 +123,53 @@ class FuncCompiler[F[_]: Files: AquaIO: Async](
}
}
private def compileToContext(
path: Path,
imports: List[Path],
config: AquaCompilerConf = AquaCompilerConf(transformConfig.constantsList)
) = {
val sources = new AquaFileSources[F](path, imports)
CompilerAPI
.compileToContext[F, AquaFileError, FileModuleId, FileSpan.F](
sources,
SpanParser.parser,
config
)
.map(_.leftMap(_.map(_.show)))
}
private def compileBuiltins() = {
for {
path <- PackagePath.builtin.getPath()
context <- compileToContext(path, Nil)
} yield {
context
}
}
// Compile and get only one function
def compile(
func: CliFunc,
jsonServices: List[JsonService]
jsonServices: List[JsonService],
withBuiltins: Boolean = false
): F[ValidatedNec[String, (FuncArrow, List[Service])]] = {
for {
prelude <- Prelude.init[F](withRunImport)
sources = new AquaFileSources[F](input, prelude.importPaths ++ imports)
// compile only context to wrap and call function later
compileResult <- Clock[F].timed(
CompilerAPI
.compileToContext[F, AquaFileError, FileModuleId, FileSpan.F](
sources,
SpanParser.parser,
AquaCompilerConf(transformConfig.constantsList)
)
.map(_.leftMap(_.map(_.show)))
)
// compile builtins and add it to context
builtinsV <-
if (withBuiltins) compileBuiltins()
else validNec[String, Chain[AquaContext]](Chain.empty).pure[F]
compileResult <- input.map { ap =>
// compile only context to wrap and call function later
Clock[F].timed(ap.getPath().flatMap(p => compileToContext(p, prelude.importPaths ++ imports)))
}.getOrElse((Duration.Zero, validNec[String, Chain[AquaContext]](Chain.empty)).pure[F])
(compileTime, contextV) = compileResult
} yield {
logger.debug(s"Compile time: ${compileTime.toMillis}ms")
contextV.andThen(c => findFunctionAndServices(c, func, jsonServices))
// add builtins to the end of context
contextV.andThen(c => builtinsV.map(bc => c ++ bc)) andThen (c =>
findFunctionAndServices(c, func, jsonServices)
)
}
}
}

View File

@ -60,7 +60,7 @@ object IpfsOpts extends Logging {
RunInfo(
common,
CliFunc(UploadFuncName, LiteralRaw.quote(path) :: Nil),
PackagePath(IpfsAqua)
Option(PackagePath(IpfsAqua))
)
}
)

View File

@ -64,7 +64,7 @@ object DistOpts extends Logging {
RunInfo(
common,
CliFunc(RemoveFuncName, LiteralRaw.quote(srvId) :: Nil),
PackagePath(DistAqua)
Option(PackagePath(DistAqua))
)
}
)
@ -77,7 +77,7 @@ object DistOpts extends Logging {
RunInfo(
common,
CliFunc(CreateServiceFuncName, LiteralRaw.quote(blueprintId) :: Nil),
PackagePath(DistAqua)
Option(PackagePath(DistAqua))
)
}
)
@ -106,7 +106,7 @@ object DistOpts extends Logging {
RunInfo(
common,
CliFunc(AddBlueprintFuncName, addBlueprintRequestVar :: Nil),
PackagePath(DistAqua),
Option(PackagePath(DistAqua)),
Nil,
Map(
addBlueprintRequestVar.name -> VarJson(
@ -151,7 +151,7 @@ object DistOpts extends Logging {
RunInfo(
common,
CliFunc(DeployFuncName, args),
PackagePath(DistAqua),
Option(PackagePath(DistAqua)),
Nil,
// hack: air cannot use undefined fields, fill undefined arrays with nils
Map(srvName -> VarJson(srvArg, c))

View File

@ -77,7 +77,7 @@ object RemoteInfoOpts {
ListInterfacesFuncName,
Nil
),
PackagePath(NetworkAqua)
Option(PackagePath(NetworkAqua))
)
else
RunInfo(
@ -86,7 +86,7 @@ object RemoteInfoOpts {
ListInterfacesByPeerFuncName,
peer.map(LiteralRaw.quote).getOrElse(ValueRaw.InitPeerId) :: Nil
),
PackagePath(NetworkAqua)
Option(PackagePath(NetworkAqua))
)
}
)
@ -99,7 +99,7 @@ object RemoteInfoOpts {
RunInfo(
common,
CliFunc(GetInterfaceFuncName, LiteralRaw.quote(serviceId) :: Nil),
PackagePath(NetworkAqua)
Option(PackagePath(NetworkAqua))
)
}
)
@ -112,7 +112,7 @@ object RemoteInfoOpts {
RunInfo(
common,
CliFunc(GetModuleInterfaceFuncName, LiteralRaw.quote(serviceId) :: Nil),
PackagePath(NetworkAqua)
Option(PackagePath(NetworkAqua))
)
}
)

View File

@ -64,7 +64,7 @@ object RunCommand extends Logging {
*/
def run[F[_]: Files: AquaIO: Async](
func: CliFunc,
input: Path,
input: Option[AquaPath],
imports: List[Path],
runConfig: RunConfig,
transformConfig: TransformConfig
@ -72,7 +72,7 @@ object RunCommand extends Logging {
val funcCompiler = new FuncCompiler[F](input, imports, transformConfig, withRunImport = true)
for {
funcArrowV <- funcCompiler.compile(func, runConfig.jsonServices)
funcArrowV <- funcCompiler.compile(func, runConfig.jsonServices, true)
callResult <- Clock[F].timed {
funcArrowV match {
case Validated.Valid((funcCallable, jsonServices)) =>
@ -112,7 +112,6 @@ object RunCommand extends Logging {
*/
def execRun[F[_]: Async](
runInfo: RunInfo,
inputPath: Path
): F[ValidatedNec[String, Unit]] = {
val common = runInfo.common
LogFormatter.initLogger(Some(common.logLevel.compiler))
@ -121,7 +120,7 @@ object RunCommand extends Logging {
RunCommand
.run[F](
runInfo.func,
inputPath,
runInfo.input,
runInfo.imports,
RunConfig(common, runInfo.argumentGetters, runInfo.services ++ builtinServices, runInfo.jsonServices, runInfo.pluginsPaths),
transformConfig(common.on, common.constants, common.flags.noXor, common.flags.noRelay)

View File

@ -51,16 +51,19 @@ object RunOpts extends Logging {
}
def runOptsCompose[F[_]: Files: Concurrent]
: Opts[F[ValidatedNec[String, (Path, List[Path], FuncWithData, Option[NonEmptyList[JsonService]], List[String])]]] = {
: Opts[F[ValidatedNec[String, (Option[AquaPath], List[Path], FuncWithData, Option[NonEmptyList[JsonService]], List[String])]]] = {
(
AppOpts.inputOpts[F],
AppOpts.wrapWithOption(AppOpts.inputOpts[F]),
AppOpts.importOpts[F],
ArgOpts.funcWithArgsOpt[F],
AppOpts.wrapWithOption(JsonService.jsonServiceOpt),
AppOpts.wrapWithOption(Plugin.opt)
).mapN { case (inputF, importF, funcWithArgsF, jsonServiceOp, pluginsOp) =>
for {
inputV <- inputF
inputV: ValidatedNec[String, Option[AquaPath]] <-
inputF.map(_.map(_.map(p => Option(RelativePath(p))))).getOrElse {
validNec[String, Option[AquaPath]](None).pure[F]
}
importV <- importF
funcWithArgsV <- funcWithArgsF
jsonServiceV <- jsonServiceOp
@ -93,7 +96,7 @@ object RunOpts extends Logging {
RunInfo(
common,
funcWithArgs.func,
RelativePath(input),
input,
imps,
funcWithArgs.getters,
Nil,

View File

@ -120,7 +120,7 @@ object ScriptOpts extends Logging {
val tConfig = TransformConfig(relayVarName = None, wrapWithXor = false)
val funcCompiler =
new FuncCompiler[F](
input,
Option(RelativePath(input)),
imports,
tConfig,
withRunImport = true
@ -173,7 +173,7 @@ object ScriptOpts extends Logging {
RunInfo(
common,
CliFunc(AddFuncName, scriptVar :: intervalArg :: Nil),
PackagePath(ScriptAqua),
Option(PackagePath(ScriptAqua)),
Nil,
Map(
"script" -> VarJson(
@ -227,7 +227,7 @@ object ScriptOpts extends Logging {
RunInfo(
common,
CliFunc(RemoveFuncName, LiteralRaw.quote(scriptId) :: Nil),
PackagePath(ScriptAqua)
Option(PackagePath(ScriptAqua))
)
}
)