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

Commit

Permalink
feat(sidekick): add backend gen command (#273)
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanFlurry committed Aug 1, 2024
1 parent 5fc1c89 commit 2f1358e
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 38 deletions.
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};
Expand Down Expand Up @@ -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 {}.",
Expand All @@ -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
Expand Up @@ -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;
Expand Down Expand Up @@ -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),
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -148,6 +151,7 @@ impl SubCommand {
| SubCommand::CheckLoginState
| SubCommand::WaitForLogin(_)
| SubCommand::GenerateConfig(_)
| SubCommand::BackendGenerateSdk(_)
| SubCommand::GetCliVersion(_) => {
unreachable!("This command should be handled before this")
}
Expand Down

0 comments on commit 2f1358e

Please sign in to comment.