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 import scala.concurrent.ExecutionContext
sealed trait AquaPath sealed trait AquaPath {
def getPath[F[_]: Async](): F[Path]
}
// Path for package relative files // 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 // 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 // All info to run any aqua function
case class RunInfo( case class RunInfo(
common: GeneralOptions, common: GeneralOptions,
func: CliFunc, func: CliFunc,
input: AquaPath, input: Option[AquaPath],
imports: List[Path] = Nil, imports: List[Path] = Nil,
argumentGetters: Map[String, VarJson] = Map.empty, argumentGetters: Map[String, VarJson] = Map.empty,
services: List[Service] = Nil, services: List[Service] = Nil,
@ -50,15 +63,9 @@ class SubCommandBuilder[F[_]: Async](
riF.flatMap { riF.flatMap {
case Validated.Valid(ri) => case Validated.Valid(ri) =>
LogFormatter.initLogger(Some(ri.common.logLevel.compiler)) LogFormatter.initLogger(Some(ri.common.logLevel.compiler))
(ri.input match { RunCommand.execRun(
case PackagePath(p) => PlatformOpts.getPackagePath(p) ri
case RelativePath(p) => p.pure[F] )
}).flatMap { path =>
RunCommand.execRun(
ri,
path
)
}
case i @ Validated.Invalid(_) => case i @ Validated.Invalid(_) =>
i.pure[F] i.pure[F]
} }
@ -103,7 +110,7 @@ object SubCommandBuilder {
name, name,
header, header,
GeneralOptions.opt.map { c => 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.data.{Chain, NonEmptyList, Validated, ValidatedNec}
import cats.effect.IO import cats.effect.IO
import cats.effect.kernel.{Async, Clock} import cats.effect.kernel.{Async, Clock}
import cats.syntax.applicative.*
import cats.syntax.flatMap.* import cats.syntax.flatMap.*
import cats.syntax.functor.* import cats.syntax.functor.*
import cats.syntax.monad.* import cats.syntax.monad.*
@ -27,11 +28,12 @@ import cats.syntax.traverse.*
import fs2.io.file.{Files, Path} import fs2.io.file.{Files, Path}
import scribe.Logging import scribe.Logging
import scala.concurrent.duration.Duration
import scala.scalajs.js import scala.scalajs.js
// Function compiler // Function compiler
class FuncCompiler[F[_]: Files: AquaIO: Async]( class FuncCompiler[F[_]: Files: AquaIO: Async](
input: Path, input: Option[AquaPath],
imports: List[Path], imports: List[Path],
transformConfig: TransformConfig, transformConfig: TransformConfig,
withRunImport: Boolean = false withRunImport: Boolean = false
@ -46,9 +48,7 @@ class FuncCompiler[F[_]: Files: AquaIO: Async](
.fold( .fold(
contexts contexts
.collectFirstSome(_.allFuncs.get(func.name)) .collectFirstSome(_.allFuncs.get(func.name))
)(ab => )(ab => contexts.collectFirstSome(_.abilities.get(ab).flatMap(_.allFuncs.get(func.name))))
contexts.collectFirstSome(_.abilities.get(ab).flatMap(_.allFuncs.get(func.name)))
)
.map(validNec) .map(validNec)
.getOrElse( .getOrElse(
Validated.invalidNec[String, FuncArrow]( 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 // Compile and get only one function
def compile( def compile(
func: CliFunc, func: CliFunc,
jsonServices: List[JsonService] jsonServices: List[JsonService],
withBuiltins: Boolean = false
): F[ValidatedNec[String, (FuncArrow, List[Service])]] = { ): F[ValidatedNec[String, (FuncArrow, List[Service])]] = {
for { for {
prelude <- Prelude.init[F](withRunImport) prelude <- Prelude.init[F](withRunImport)
sources = new AquaFileSources[F](input, prelude.importPaths ++ imports) // compile builtins and add it to context
// compile only context to wrap and call function later builtinsV <-
compileResult <- Clock[F].timed( if (withBuiltins) compileBuiltins()
CompilerAPI else validNec[String, Chain[AquaContext]](Chain.empty).pure[F]
.compileToContext[F, AquaFileError, FileModuleId, FileSpan.F]( compileResult <- input.map { ap =>
sources, // compile only context to wrap and call function later
SpanParser.parser, Clock[F].timed(ap.getPath().flatMap(p => compileToContext(p, prelude.importPaths ++ imports)))
AquaCompilerConf(transformConfig.constantsList) }.getOrElse((Duration.Zero, validNec[String, Chain[AquaContext]](Chain.empty)).pure[F])
)
.map(_.leftMap(_.map(_.show)))
)
(compileTime, contextV) = compileResult (compileTime, contextV) = compileResult
} yield { } yield {
logger.debug(s"Compile time: ${compileTime.toMillis}ms") 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( RunInfo(
common, common,
CliFunc(UploadFuncName, LiteralRaw.quote(path) :: Nil), CliFunc(UploadFuncName, LiteralRaw.quote(path) :: Nil),
PackagePath(IpfsAqua) Option(PackagePath(IpfsAqua))
) )
} }
) )

View File

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

View File

@ -77,7 +77,7 @@ object RemoteInfoOpts {
ListInterfacesFuncName, ListInterfacesFuncName,
Nil Nil
), ),
PackagePath(NetworkAqua) Option(PackagePath(NetworkAqua))
) )
else else
RunInfo( RunInfo(
@ -86,7 +86,7 @@ object RemoteInfoOpts {
ListInterfacesByPeerFuncName, ListInterfacesByPeerFuncName,
peer.map(LiteralRaw.quote).getOrElse(ValueRaw.InitPeerId) :: Nil peer.map(LiteralRaw.quote).getOrElse(ValueRaw.InitPeerId) :: Nil
), ),
PackagePath(NetworkAqua) Option(PackagePath(NetworkAqua))
) )
} }
) )
@ -99,7 +99,7 @@ object RemoteInfoOpts {
RunInfo( RunInfo(
common, common,
CliFunc(GetInterfaceFuncName, LiteralRaw.quote(serviceId) :: Nil), CliFunc(GetInterfaceFuncName, LiteralRaw.quote(serviceId) :: Nil),
PackagePath(NetworkAqua) Option(PackagePath(NetworkAqua))
) )
} }
) )
@ -112,7 +112,7 @@ object RemoteInfoOpts {
RunInfo( RunInfo(
common, common,
CliFunc(GetModuleInterfaceFuncName, LiteralRaw.quote(serviceId) :: Nil), 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]( def run[F[_]: Files: AquaIO: Async](
func: CliFunc, func: CliFunc,
input: Path, input: Option[AquaPath],
imports: List[Path], imports: List[Path],
runConfig: RunConfig, runConfig: RunConfig,
transformConfig: TransformConfig transformConfig: TransformConfig
@ -72,7 +72,7 @@ object RunCommand extends Logging {
val funcCompiler = new FuncCompiler[F](input, imports, transformConfig, withRunImport = true) val funcCompiler = new FuncCompiler[F](input, imports, transformConfig, withRunImport = true)
for { for {
funcArrowV <- funcCompiler.compile(func, runConfig.jsonServices) funcArrowV <- funcCompiler.compile(func, runConfig.jsonServices, true)
callResult <- Clock[F].timed { callResult <- Clock[F].timed {
funcArrowV match { funcArrowV match {
case Validated.Valid((funcCallable, jsonServices)) => case Validated.Valid((funcCallable, jsonServices)) =>
@ -112,7 +112,6 @@ object RunCommand extends Logging {
*/ */
def execRun[F[_]: Async]( def execRun[F[_]: Async](
runInfo: RunInfo, runInfo: RunInfo,
inputPath: Path
): F[ValidatedNec[String, Unit]] = { ): F[ValidatedNec[String, Unit]] = {
val common = runInfo.common val common = runInfo.common
LogFormatter.initLogger(Some(common.logLevel.compiler)) LogFormatter.initLogger(Some(common.logLevel.compiler))
@ -121,7 +120,7 @@ object RunCommand extends Logging {
RunCommand RunCommand
.run[F]( .run[F](
runInfo.func, runInfo.func,
inputPath, runInfo.input,
runInfo.imports, runInfo.imports,
RunConfig(common, runInfo.argumentGetters, runInfo.services ++ builtinServices, runInfo.jsonServices, runInfo.pluginsPaths), RunConfig(common, runInfo.argumentGetters, runInfo.services ++ builtinServices, runInfo.jsonServices, runInfo.pluginsPaths),
transformConfig(common.on, common.constants, common.flags.noXor, common.flags.noRelay) 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] 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], AppOpts.importOpts[F],
ArgOpts.funcWithArgsOpt[F], ArgOpts.funcWithArgsOpt[F],
AppOpts.wrapWithOption(JsonService.jsonServiceOpt), AppOpts.wrapWithOption(JsonService.jsonServiceOpt),
AppOpts.wrapWithOption(Plugin.opt) AppOpts.wrapWithOption(Plugin.opt)
).mapN { case (inputF, importF, funcWithArgsF, jsonServiceOp, pluginsOp) => ).mapN { case (inputF, importF, funcWithArgsF, jsonServiceOp, pluginsOp) =>
for { 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 importV <- importF
funcWithArgsV <- funcWithArgsF funcWithArgsV <- funcWithArgsF
jsonServiceV <- jsonServiceOp jsonServiceV <- jsonServiceOp
@ -93,7 +96,7 @@ object RunOpts extends Logging {
RunInfo( RunInfo(
common, common,
funcWithArgs.func, funcWithArgs.func,
RelativePath(input), input,
imps, imps,
funcWithArgs.getters, funcWithArgs.getters,
Nil, Nil,

View File

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