Skip to content
This repository has been archived by the owner on Dec 21, 2024. It is now read-only.

feat(sidekick): add backend gen command #273

Merged
merged 1 commit into from
Aug 2, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 70 additions & 38 deletions cli/src/commands/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, io::Write, path::PathBuf};
use std::{collections::HashMap, io::Write, path::PathBuf, str::FromStr};

use clap::Parser;
use cli_core::rivet_api::{apis, models};
@@ -131,13 +131,38 @@ pub struct OpenGbCommandOpts {
pub cwd: PathBuf,
}

pub async fn run_opengb_command(opts: OpenGbCommandOpts) -> GlobalResult<std::process::ExitStatus> {
let run_native = std::env::var("_RIVET_NATIVE_OPENGB")
.ok()
.map_or(false, |x| &x == "1");
#[derive(PartialEq)]
pub enum OpenGbTarget {
Native,
Docker,
}

impl Default for OpenGbTarget {
fn default() -> Self {
Self::Docker
}
}
impl FromStr for OpenGbTarget {
type Err = GlobalError;

fn from_str(s: &str) -> GlobalResult<Self> {
match s {
"native" => Ok(Self::Native),
"docker" => Ok(Self::Docker),
_ => bail!("unknown opengb target: {s}"),
}
}
}

pub fn build_opengb_command(opts: OpenGbCommandOpts) -> GlobalResult<Command> {
let opengb_target = if let Ok(x) = std::env::var("RIVET_OPENGB_TARGET") {
OpenGbTarget::from_str(&x)?
} else {
OpenGbTarget::default()
};

// Check OpenGB installed
if run_native {
if opengb_target == OpenGbTarget::Native {
ensure!(
which::which("opengb").is_ok(),
"OpenGB is not installed. Install it from {}.",
@@ -146,39 +171,46 @@ pub async fn run_opengb_command(opts: OpenGbCommandOpts) -> GlobalResult<std::pr
}

// Build command
if run_native {
let mut cmd = Command::new("opengb");
cmd.envs(opts.env);
cmd.current_dir(opts.cwd);
cmd.args(&opts.args);
Ok(cmd.status().await?)
} else {
let image_tag = std::env::var("_RIVET_OPENGB_IMAGE")
.ok()
.unwrap_or_else(|| DEFAULT_OPENGB_DOCKER_TAG.to_string());

// Build env file
let mut env_file = NamedTempFile::new().expect("Failed to create temp file");
for (k, v) in std::env::vars() {
writeln!(env_file, "{k}={v}")?;
}
if std::env::var("DATABASE_URL").is_err() {
writeln!(env_file, "DATABASE_URL=postgres://postgres:[email protected]:5432/postgres?sslmode=disable")?;
match opengb_target {
OpenGbTarget::Native => {
let mut cmd = Command::new("opengb");
cmd.envs(opts.env);
cmd.current_dir(opts.cwd);
cmd.args(&opts.args);
Ok(cmd)
}
for (k, v) in opts.env {
writeln!(env_file, "{k}={v}")?;
OpenGbTarget::Docker => {
let image_tag = std::env::var("RIVET_OPENGB_DOCKER_IMAGE")
.ok()
.unwrap_or_else(|| DEFAULT_OPENGB_DOCKER_TAG.to_string());

// Build env file
let mut env_file = NamedTempFile::new().expect("Failed to create temp file");
for (k, v) in std::env::vars() {
writeln!(env_file, "{k}={v}")?;
}
if std::env::var("DATABASE_URL").is_err() {
writeln!(env_file, "DATABASE_URL=postgres://postgres:[email protected]:5432/postgres?sslmode=disable")?;
}
for (k, v) in opts.env {
writeln!(env_file, "{k}={v}")?;
}

let mut cmd = Command::new("docker");
cmd.arg("run").arg("-it");
cmd.arg("--init");
cmd.arg("--env-file").arg(env_file.path());
cmd.arg("--add-host=host.docker.internal:host-gateway");
cmd.arg("--publish=6420:6420");
cmd.arg(format!("--volume={}:/backend", opts.cwd.display()));
cmd.arg("--workdir=/backend");
cmd.arg(image_tag);
cmd.args(&opts.args);
Ok(cmd)
}

let mut cmd = Command::new("docker");
cmd.arg("run").arg("-it");
cmd.arg("--init");
cmd.arg("--env-file").arg(env_file.path());
cmd.arg("--add-host=host.docker.internal:host-gateway");
cmd.arg("--publish=6420:6420");
cmd.arg(format!("--volume={}:/backend", opts.cwd.display()));
cmd.arg("--workdir=/backend");
cmd.arg(image_tag);
cmd.args(&opts.args);
Ok(cmd.status().await?)
}
}

pub async fn run_opengb_command(opts: OpenGbCommandOpts) -> GlobalResult<std::process::ExitStatus> {
Ok(build_opengb_command(opts)?.status().await?)
}
64 changes: 64 additions & 0 deletions cli/src/commands/sidekick/backend_gen_sdk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use clap::Parser;
use global_error::prelude::*;
use serde::Serialize;
use std::collections::HashMap;

use crate::commands::backend;

use super::SideKickHandler;

#[derive(Parser)]
pub struct Opts {
#[clap(long)]
output_path: String,
#[clap(long)]
unity: bool,
#[clap(long)]
godot: bool,
}

#[derive(Serialize)]
pub struct Output {
pub exit_code: i32,
pub stdout: String,
pub stderr: String,
}

impl SideKickHandler for Output {}

impl Opts {
pub async fn execute(&self) -> GlobalResult<Output> {
// Run command
let target = if self.unity {
"unity"
} else if self.godot {
"godot"
} else {
bail!("no target selected")
};
let args = vec![
"sdk".into(),
"generate".into(),
"--output".into(),
self.output_path.clone(),
target.into(),
];
let mut env = HashMap::new();
env.insert("OPENGB_TERM_COLOR".into(), "never".into());
let opengb_output = backend::build_opengb_command(backend::OpenGbCommandOpts {
args,
env,
cwd: std::env::current_dir()?,
})?
.output()
.await?;

let output = Output {
exit_code: opengb_output.status.code().unwrap_or(1),
stdout: String::from_utf8(opengb_output.stdout)?,
stderr: String::from_utf8(opengb_output.stderr)?,
};

Ok(output)
}
}
4 changes: 4 additions & 0 deletions cli/src/commands/sidekick/mod.rs
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ use crate::util::{
struct_fmt::{self, Format},
};

pub mod backend_gen_sdk;
pub mod deploy;
pub mod generate_config;
pub mod get_bootstrap_data;
@@ -61,6 +62,7 @@ pub enum SubCommand {
GetNamespaceDevelopmentToken(get_namespace_dev_token::Opts),
/// Generate config
GenerateConfig(generate_config::Opts),
BackendGenerateSdk(backend_gen_sdk::Opts),
/// Unlink current game
Unlink(unlink::Opts),
}
@@ -97,6 +99,7 @@ impl SubCommand {
SubCommand::CheckLoginState => serialize_output(self.validate_token(&token)),
SubCommand::GetCliVersion(opts) => serialize_output(opts.execute().await),
SubCommand::GenerateConfig(opts) => serialize_output(opts.execute().await),
SubCommand::BackendGenerateSdk(opts) => serialize_output(opts.execute().await),
_ => {
// If the command is anything else, we need to check if a token
// has already been provided. If not, we need to print an error
@@ -148,6 +151,7 @@ impl SubCommand {
| SubCommand::CheckLoginState
| SubCommand::WaitForLogin(_)
| SubCommand::GenerateConfig(_)
| SubCommand::BackendGenerateSdk(_)
| SubCommand::GetCliVersion(_) => {
unreachable!("This command should be handled before this")
}
Loading