pub mod garage;
pub mod postgres;
use crate::config::ServicesConfig;
use crate::context::WorkspaceContext;
use crate::docker::DockerCompose;
use anyhow::{Context, Result, bail};
use serde_json::{Map, Value};
use std::collections::BTreeMap;
use std::path::Path;
use std::process::Command;
pub trait Service {
fn name(&self) -> &str;
fn post_start(&self, ctx: &WorkspaceContext, compose: &DockerCompose<'_>) -> Result<()>;
}
pub trait ServiceProvider: Sync {
fn name(&self) -> &'static str;
fn init_label(&self) -> &'static str;
fn init_default_selected(&self) -> bool {
true
}
fn reserved_names(&self) -> Vec<&'static str> {
vec![self.name()]
}
fn port_offsets(&self, services: &ServicesConfig) -> Vec<(String, u16)>;
fn prompt_init(
&self,
services: &mut ServicesConfig,
project_name: &str,
non_interactive: bool,
) -> Result<BTreeMap<String, String>>;
fn write_auxiliary_files(&self, _ctx: &WorkspaceContext, _dir: &Path) -> Result<()> {
Ok(())
}
fn contribute_compose(
&self,
ctx: &WorkspaceContext,
services: &mut Map<String, Value>,
volumes: &mut Map<String, Value>,
);
fn contribute_template_vars(&self, ctx: &WorkspaceContext, vars: &mut BTreeMap<String, String>);
fn get_active_service<'a>(&self, ctx: &'a WorkspaceContext) -> Option<Box<dyn Service + 'a>>;
}
pub static BUILTIN_SERVICES: &[&'static dyn ServiceProvider] =
&[&garage::GarageProvider, &postgres::PostgresProvider];
pub fn get_active_services(ctx: &WorkspaceContext) -> Vec<Box<dyn Service + '_>> {
let mut active = Vec::new();
for provider in BUILTIN_SERVICES {
if let Some(service) = provider.get_active_service(ctx) {
active.push(service);
}
}
active
}
pub fn all_reserved_names() -> Vec<&'static str> {
let mut names = vec!["base"];
for provider in BUILTIN_SERVICES {
names.extend(provider.reserved_names());
}
names
}
pub fn run_shell(
ctx: &WorkspaceContext,
command: &str,
env: &BTreeMap<String, String>,
) -> Result<()> {
let status = Command::new("sh")
.arg("-c")
.arg(command)
.current_dir(&ctx.workspace_path)
.envs(env)
.status()
.with_context(|| format!("Failed to run `{command}`"))?;
if !status.success() {
bail!("`{command}` exited with {status}");
}
Ok(())
}