1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
use tokio::io::AsyncWriteExt;
use ya_runtime_api::server::proto::{output::Type, request::RunProcess, Output};

use crate::cli::{Command, CommandCli};
use crate::env::{DefaultEnv, Env};
use crate::runtime::{Context, Runtime, RuntimeMode};
use crate::server::Server;

/// Starts the runtime
pub async fn run<R: Runtime + 'static>() -> anyhow::Result<()> {
    run_with::<R, _>(DefaultEnv::default()).await
}

/// Starts the runtime using a custom environment configuration provider
pub async fn run_with<R: Runtime + 'static, E: Env>(env: E) -> anyhow::Result<()> {
    let mut runtime = R::default();
    let mut ctx = Context::<R>::try_with(env)?;

    match ctx.cli.command() {
        Command::Deploy { .. } => {
            let deployment = match runtime.deploy(&mut ctx).await? {
                Some(deployment) => deployment,
                None => {
                    crate::serialize::json::json!({
                        "startMode": match R::MODE {
                            RuntimeMode::Server => "blocking",
                            RuntimeMode::Command => "empty",
                        },
                        "valid": {"Ok": ""},
                        "vols": []
                    })
                }
            };
            output(deployment).await?;
        }
        Command::Start { .. } => match R::MODE {
            RuntimeMode::Command => {
                if let Some(started) = runtime.start(&mut ctx).await? {
                    output(started).await?;
                }
            }
            RuntimeMode::Server => {
                ya_runtime_api::server::run_async(|emitter| async move {
                    let start = {
                        ctx.set_emitter(emitter);
                        runtime.start(&mut ctx)
                    };

                    let mut cmd_ctx = crate::runtime::RunCommandContext {
                        id: ctx.next_pid(),
                        emitter: ctx.emitter.clone(),
                    };

                    if let Some(out) = start.await.expect("Failed to start the runtime") {
                        cmd_ctx.stdout(out.to_string()).await;
                    }

                    Server::new(runtime, ctx)
                })
                .await;
            }
        },
        Command::Run { args } => {
            if args.is_empty() {
                anyhow::bail!("not enough arguments");
            }

            let mut args = args.clone();
            let bin = args.remove(0);
            let capture = Some(Output {
                r#type: Some(Type::AtEnd(40960)),
            });
            let command = RunProcess {
                bin,
                args,
                work_dir: ctx.cli.workdir().unwrap().display().to_string(),
                stdout: capture.clone(),
                stderr: capture,
            };

            let pid = runtime
                .run_command(command, RuntimeMode::Command, &mut ctx)
                .await?;

            output(serde_json::json!(pid)).await?;
        }
        Command::OfferTemplate { .. } => {
            if let Some(template) = runtime.offer(&mut ctx).await? {
                output(template).await?;
            }
        }
        Command::Test { .. } => runtime.test(&mut ctx).await?,
    }

    Ok(())
}

async fn output(json: serde_json::Value) -> anyhow::Result<()> {
    let string = json.to_string();
    let mut stdout = tokio::io::stdout();
    stdout.write_all(string.as_bytes()).await?;
    stdout.flush().await?;
    Ok(())
}