Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
7bf76d3ff2
|
|||
|
316b37cd05
|
|||
|
e3306c494d
|
|||
|
5d45eccfef
|
|||
|
251826c048
|
|||
|
63b4b60f9a
|
|||
|
55d4ae3f6f
|
|||
|
de5e6b4d10
|
|||
|
61e7556997
|
|||
|
a9a5e401dc
|
|||
|
423badfe07
|
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -4,10 +4,11 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahab"
|
name = "ahab"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
"clap_complete",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -102,6 +103,15 @@ dependencies = [
|
|||||||
"strsim",
|
"strsim",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_complete"
|
||||||
|
version = "4.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a04ddfaacc3bc9e6ea67d024575fafc2a813027cf374b8f24f7bc233c6b6be12"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.3.0"
|
version = "4.3.0"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "ahab"
|
name = "ahab"
|
||||||
description = "docker cli wrapper"
|
description = "docker cli wrapper"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Matej Janežič <janezic.mj@gmail.com>"]
|
authors = ["Matej Janežič <janezic.mj@gmail.com>"]
|
||||||
@@ -12,5 +12,6 @@ repository = "https://github.com/janezicmatej/ahab.git"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.3.0", features = ["derive"] }
|
clap = { version = "4.3.0", features = ["derive"] }
|
||||||
|
clap_complete = "4.3.0"
|
||||||
anyhow = "1.0.71"
|
anyhow = "1.0.71"
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use super::{Django, Docker, DockerCompose, Postgres};
|
use super::{Django, Docker, DockerCompose, Postgres};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
use clap_complete::Shell;
|
||||||
|
|
||||||
/// A program for interacting with various dockerized applications.
|
/// A program for interacting with various dockerized applications.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@@ -11,26 +12,32 @@ pub struct Ahab {
|
|||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum Commands {
|
pub enum Commands {
|
||||||
|
/// Generate completion files
|
||||||
|
Completion {
|
||||||
|
#[arg(value_enum)]
|
||||||
|
shell: Shell,
|
||||||
|
},
|
||||||
|
|
||||||
/// Docker related subcommands
|
/// Docker related subcommands
|
||||||
D {
|
Docker {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Docker,
|
command: Docker,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Docker compose related subcommands
|
/// Docker compose related subcommands
|
||||||
Dc {
|
Compose {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: DockerCompose,
|
command: DockerCompose,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Docker compose related subcommands
|
/// Django related subcommands
|
||||||
Dj {
|
Django {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Django,
|
command: Django,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Postgres related subcommands
|
/// Postgres related subcommands
|
||||||
Pg {
|
Postgres {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Postgres,
|
command: Postgres,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use clap::Parser;
|
|||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub enum Django {
|
pub enum Django {
|
||||||
/// Prepare empty management command 'command' in app 'app'.
|
/// Prepare empty management command 'command' in app 'app'.
|
||||||
#[clap(alias("mc"))]
|
|
||||||
MakeCommand {
|
MakeCommand {
|
||||||
#[arg(value_enum)]
|
#[arg(value_enum)]
|
||||||
app: PathBuf,
|
app: PathBuf,
|
||||||
@@ -16,24 +15,23 @@ pub enum Django {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/// Run Django's manage.py makemigrations.
|
/// Run Django's manage.py makemigrations.
|
||||||
#[clap(alias("mm"))]
|
|
||||||
Makemigrations,
|
Makemigrations,
|
||||||
|
|
||||||
/// Pass arguments to Django's manage.py.
|
/// Pass arguments to Django's manage.py.
|
||||||
#[clap(alias("m"))]
|
|
||||||
Manage {
|
Manage {
|
||||||
#[arg(value_enum)]
|
#[arg(value_enum)]
|
||||||
rest: Vec<String>,
|
rest: Vec<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Run Django's manage.py migrate.
|
/// Run Django's manage.py migrate.
|
||||||
#[clap(alias("mg"))]
|
|
||||||
Migrate {
|
Migrate {
|
||||||
#[arg(value_enum)]
|
#[arg(value_enum)]
|
||||||
rest: Vec<String>,
|
rest: Vec<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Run Django's manage.py shell.
|
/// Run Django's manage.py shell.
|
||||||
#[clap(alias("s"))]
|
|
||||||
Shell,
|
Shell,
|
||||||
|
|
||||||
|
/// Run Django's manage.py test.
|
||||||
|
Test,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,5 @@ use clap::Parser;
|
|||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub enum Docker {
|
pub enum Docker {
|
||||||
/// Stop all containers via `docker stop $(docker ps -q)`
|
/// Stop all containers via `docker stop $(docker ps -q)`
|
||||||
#[clap(alias("sa"))]
|
|
||||||
StopAll,
|
StopAll,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,30 +6,23 @@ use clap::Subcommand;
|
|||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
pub enum DockerCompose {
|
pub enum DockerCompose {
|
||||||
/// Build containers.
|
/// Build containers.
|
||||||
#[clap(alias("b"))]
|
|
||||||
Build,
|
Build,
|
||||||
|
|
||||||
/// Down containers.
|
/// Down containers.
|
||||||
#[clap(alias("d"))]
|
|
||||||
Down,
|
Down,
|
||||||
|
|
||||||
/// Stop, build and start containers.
|
/// Stop, build and start containers.
|
||||||
#[clap(alias("rb"))]
|
|
||||||
Rebuild,
|
Rebuild,
|
||||||
|
|
||||||
/// Stop and start containers.
|
/// Stop and start containers.
|
||||||
#[clap(alias("rs"))]
|
|
||||||
Restart,
|
Restart,
|
||||||
|
|
||||||
/// Start containers.
|
/// Start containers.
|
||||||
#[clap(alias("st"))]
|
|
||||||
Start,
|
Start,
|
||||||
|
|
||||||
/// Stop containers.
|
/// Stop containers.
|
||||||
#[clap(alias("s"))]
|
|
||||||
Stop,
|
Stop,
|
||||||
|
|
||||||
/// Up containers.
|
/// Up containers.
|
||||||
#[clap(alias("u"))]
|
|
||||||
Up,
|
Up,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,12 @@ use clap::Subcommand;
|
|||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
pub enum Postgres {
|
pub enum Postgres {
|
||||||
/// Import dump via pg_restore
|
/// Import dump via pg_restore
|
||||||
#[clap(alias("i"))]
|
|
||||||
Import {
|
Import {
|
||||||
#[arg(value_enum)]
|
#[arg(value_enum)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Dump via pg_dump with format=c
|
/// Dump via pg_dump with format=c
|
||||||
#[clap(alias("d"))]
|
|
||||||
Dump {
|
Dump {
|
||||||
#[arg(value_enum)]
|
#[arg(value_enum)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
|||||||
82
src/command_builder.rs
Normal file
82
src/command_builder.rs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use std::{
|
||||||
|
collections::VecDeque,
|
||||||
|
ffi::OsStr,
|
||||||
|
fmt::Display,
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
path::PathBuf,
|
||||||
|
process::{Command, Stdio},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::debug_println;
|
||||||
|
|
||||||
|
pub struct Args(Vec<String>);
|
||||||
|
|
||||||
|
impl From<&str> for Args {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
Self(Vec::from_iter(value.split_whitespace().map(String::from)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&String> for Args {
|
||||||
|
fn from(value: &String) -> Self {
|
||||||
|
Self(Vec::from_iter(value.split_whitespace().map(String::from)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct CommandBuilder {
|
||||||
|
args: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for CommandBuilder {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(&self.args.join(" "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandBuilder {
|
||||||
|
pub fn new(args: &str) -> Self {
|
||||||
|
Self::default().args("docker")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn docker() -> Self {
|
||||||
|
Self::default().args("docker")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn docker_compose() -> Self {
|
||||||
|
Self::default().args("docker compose -f docker/local/docker-compose.yaml")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn args<T>(mut self, args: T) -> Self
|
||||||
|
where
|
||||||
|
Args: From<T>,
|
||||||
|
{
|
||||||
|
self.args.extend(Args::from(args).0);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(self) -> Result<Command> {
|
||||||
|
debug_println!("\nran {self}\n");
|
||||||
|
|
||||||
|
let (first, rest) = self.args.split_first().context("empty args")?;
|
||||||
|
let mut command = Command::new(first);
|
||||||
|
command.args(rest);
|
||||||
|
|
||||||
|
Ok(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exec_get_stdout(mut self) -> Result<String> {
|
||||||
|
Ok(String::from_utf8(self.build()?.output()?.stdout)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exec(mut self) -> Result<()> {
|
||||||
|
self.build()?.spawn()?.wait()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exec_redirect_stdout(mut self, stdio: Stdio) -> Result<()> {
|
||||||
|
self.build()?.stdout(stdio).spawn()?.wait()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/lib.rs
Normal file
24
src/lib.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod cli;
|
||||||
|
pub mod command_builder;
|
||||||
|
pub mod scripts;
|
||||||
|
|
||||||
|
// NOTE: stolen from https://docs.rs/debug_print/latest/debug_print/
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug_println {
|
||||||
|
($($arg:tt)*) => (if ::std::cfg!(debug_assertions) { ::std::println!($($arg)*); })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn safe_create_file(path: PathBuf) -> Result<File, std::io::Error> {
|
||||||
|
OpenOptions::new().write(true).create_new(true).open(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_file(path: PathBuf) -> Result<File, std::io::Error> {
|
||||||
|
OpenOptions::new().write(true).create(true).open(path)
|
||||||
|
}
|
||||||
26
src/main.rs
26
src/main.rs
@@ -1,11 +1,7 @@
|
|||||||
#![allow(unused)]
|
use ahab::{cli, scripts};
|
||||||
|
|
||||||
mod cli;
|
|
||||||
mod scripts;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::{CommandFactory, Parser};
|
||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// always load dotenv on start
|
// always load dotenv on start
|
||||||
@@ -17,10 +13,19 @@ fn main() -> Result<()> {
|
|||||||
let args = cli::Ahab::parse();
|
let args = cli::Ahab::parse();
|
||||||
|
|
||||||
match args.command {
|
match args.command {
|
||||||
cli::Commands::D { command } => match command {
|
cli::Commands::Completion { shell } => {
|
||||||
|
clap_complete::generate(
|
||||||
|
shell,
|
||||||
|
&mut cli::Ahab::command(),
|
||||||
|
"ahab",
|
||||||
|
&mut std::io::stdout(),
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
cli::Commands::Docker { command } => match command {
|
||||||
cli::Docker::StopAll => scripts::docker::stop_all(),
|
cli::Docker::StopAll => scripts::docker::stop_all(),
|
||||||
},
|
},
|
||||||
cli::Commands::Dc { command } => match command {
|
cli::Commands::Compose { command } => match command {
|
||||||
cli::DockerCompose::Build => scripts::docker_compose::build(),
|
cli::DockerCompose::Build => scripts::docker_compose::build(),
|
||||||
cli::DockerCompose::Down => scripts::docker_compose::down(),
|
cli::DockerCompose::Down => scripts::docker_compose::down(),
|
||||||
cli::DockerCompose::Rebuild => scripts::docker_compose::rebuild(),
|
cli::DockerCompose::Rebuild => scripts::docker_compose::rebuild(),
|
||||||
@@ -29,14 +34,15 @@ fn main() -> Result<()> {
|
|||||||
cli::DockerCompose::Stop => scripts::docker_compose::stop(),
|
cli::DockerCompose::Stop => scripts::docker_compose::stop(),
|
||||||
cli::DockerCompose::Up => scripts::docker_compose::up(),
|
cli::DockerCompose::Up => scripts::docker_compose::up(),
|
||||||
},
|
},
|
||||||
cli::Commands::Dj { command } => match command {
|
cli::Commands::Django { command } => match command {
|
||||||
cli::Django::MakeCommand { app, name } => scripts::django::make_command(&app, &name),
|
cli::Django::MakeCommand { app, name } => scripts::django::make_command(&app, &name),
|
||||||
cli::Django::Makemigrations => scripts::django::makemigrations(),
|
cli::Django::Makemigrations => scripts::django::makemigrations(),
|
||||||
cli::Django::Manage { rest } => scripts::django::manage(&rest),
|
cli::Django::Manage { rest } => scripts::django::manage(&rest),
|
||||||
cli::Django::Migrate { rest } => scripts::django::migrate(&rest),
|
cli::Django::Migrate { rest } => scripts::django::migrate(&rest),
|
||||||
cli::Django::Shell => scripts::django::shell(),
|
cli::Django::Shell => scripts::django::shell(),
|
||||||
|
cli::Django::Test => scripts::django::test(),
|
||||||
},
|
},
|
||||||
cli::Commands::Pg { command } => match command {
|
cli::Commands::Postgres { command } => match command {
|
||||||
cli::Postgres::Import { path } => scripts::postgres::import(&path),
|
cli::Postgres::Import { path } => scripts::postgres::import(&path),
|
||||||
cli::Postgres::Dump { path } => scripts::postgres::dump(&path),
|
cli::Postgres::Dump { path } => scripts::postgres::dump(&path),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,15 +1,28 @@
|
|||||||
use crate::scripts::{create_file, safe_create_file};
|
|
||||||
|
|
||||||
use super::DockerCommand;
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::create_dir;
|
use std::fs::create_dir;
|
||||||
|
use std::io::Write;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
|
use crate::command_builder::CommandBuilder;
|
||||||
|
use crate::{create_file, safe_create_file};
|
||||||
|
|
||||||
fn get_django_settings_module() -> Result<String> {
|
fn get_django_settings_module() -> Result<String> {
|
||||||
Ok(env::var("DJANGO_SETTINGS_MODULE")?)
|
let dsm = env::var("DJANGO_SETTINGS_MODULE")?;
|
||||||
|
println!("USING: {dsm}");
|
||||||
|
|
||||||
|
Ok(dsm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEBUG_TEMPLATE: &str = r#"from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
pass
|
||||||
|
|
||||||
|
"#;
|
||||||
|
|
||||||
pub fn make_command(app: &PathBuf, name: &str) -> Result<()> {
|
pub fn make_command(app: &PathBuf, name: &str) -> Result<()> {
|
||||||
let app_name = app.to_string_lossy();
|
let app_name = app.to_string_lossy();
|
||||||
let app_dir = Path::new(&app);
|
let app_dir = Path::new(&app);
|
||||||
@@ -41,33 +54,36 @@ pub fn make_command(app: &PathBuf, name: &str) -> Result<()> {
|
|||||||
println!("created module {app_name}.management.commands")
|
println!("created module {app_name}.management.commands")
|
||||||
};
|
};
|
||||||
|
|
||||||
safe_create_file(commands_dir.join(name))?;
|
let mut file = safe_create_file(commands_dir.join(format!("{name}.py")))?;
|
||||||
|
file.write_all(DEBUG_TEMPLATE.as_bytes())?;
|
||||||
|
|
||||||
println!("created command {app_name}.management.commands.{name}");
|
println!("created command {app_name}.management.commands.{name}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn makemigrations() -> Result<()> {
|
|
||||||
let dsm = get_django_settings_module()?;
|
|
||||||
let command = format!("manage makemigrations --settings={dsm}");
|
|
||||||
DockerCommand::docker_compose().args(&command).spawn_wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn manage(rest: &[String]) -> Result<()> {
|
pub fn manage(rest: &[String]) -> Result<()> {
|
||||||
let dsm = get_django_settings_module()?;
|
let dsm = get_django_settings_module()?;
|
||||||
let joined = rest.join(" ");
|
let joined = rest.join(" ");
|
||||||
let command = format!("manage {joined} --settings={dsm}");
|
let command = format!("exec appserver python manage.py {joined} --settings={dsm}");
|
||||||
DockerCommand::docker_compose().args(&command).spawn_wait()
|
CommandBuilder::docker_compose().args(&command).exec()
|
||||||
|
}
|
||||||
|
|
||||||
|
// shortcuts
|
||||||
|
pub fn makemigrations() -> Result<()> {
|
||||||
|
manage(&["makemigrations".to_string()])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn migrate(rest: &[String]) -> Result<()> {
|
pub fn migrate(rest: &[String]) -> Result<()> {
|
||||||
let dsm = get_django_settings_module()?;
|
let mut full_rest = vec!["migrate".to_string()];
|
||||||
let joined = rest.join(" ");
|
full_rest.extend_from_slice(rest);
|
||||||
let command = format!("manage migrate {joined} --settings={dsm}");
|
|
||||||
DockerCommand::docker_compose().args(&command).spawn_wait()
|
manage(&full_rest)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shell() -> Result<()> {
|
pub fn shell() -> Result<()> {
|
||||||
let dsm = get_django_settings_module()?;
|
manage(&["shell".to_string()])
|
||||||
let command = format!("manage shell --settings={dsm}");
|
}
|
||||||
DockerCommand::docker_compose().args(&command).spawn_wait()
|
|
||||||
|
pub fn test() -> Result<()> {
|
||||||
|
manage(&["test".to_string()])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
use super::DockerCommand;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::command_builder::CommandBuilder;
|
||||||
|
|
||||||
pub fn stop_all() -> Result<()> {
|
pub fn stop_all() -> Result<()> {
|
||||||
let running_containers = DockerCommand::docker().args("ps -q").stdout()?;
|
let running_containers = CommandBuilder::docker().args("ps -q").exec_get_stdout()?;
|
||||||
|
|
||||||
if running_containers.is_empty() {
|
if running_containers.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
DockerCommand::docker()
|
CommandBuilder::docker()
|
||||||
.args(&format!("stop {running_containers}"))
|
.args(&format!("stop {running_containers}"))
|
||||||
.spawn_wait()
|
.exec()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
use super::DockerCommand;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::command_builder::CommandBuilder;
|
||||||
|
|
||||||
// simple commands
|
// simple commands
|
||||||
pub fn build() -> Result<()> {
|
pub fn build() -> Result<()> {
|
||||||
DockerCommand::docker_compose().args("build").spawn_wait()
|
CommandBuilder::docker_compose().args("build").exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn down() -> Result<()> {
|
pub fn down() -> Result<()> {
|
||||||
DockerCommand::docker_compose().args("down").spawn_wait()
|
CommandBuilder::docker_compose().args("down").exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start containers via `docker compose start`. Optionally pass containers to be started.
|
/// Start containers via `docker compose start`. Optionally pass containers to be started.
|
||||||
@@ -18,25 +19,25 @@ pub fn down() -> Result<()> {
|
|||||||
/// `docker compose --env-file ./.env -f docker/local/docker-compose.yaml up start`
|
/// `docker compose --env-file ./.env -f docker/local/docker-compose.yaml up start`
|
||||||
pub fn start(containers: Option<&str>) -> Result<()> {
|
pub fn start(containers: Option<&str>) -> Result<()> {
|
||||||
let args = format!("start {}", containers.unwrap_or(""));
|
let args = format!("start {}", containers.unwrap_or(""));
|
||||||
DockerCommand::docker_compose().args("start").spawn_wait()
|
CommandBuilder::docker_compose().args("start").exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop() -> Result<()> {
|
pub fn stop() -> Result<()> {
|
||||||
DockerCommand::docker_compose().args("stop").spawn_wait()
|
CommandBuilder::docker_compose().args("stop").exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn up() -> Result<()> {
|
pub fn up() -> Result<()> {
|
||||||
DockerCommand::docker_compose().args("up -d").spawn_wait()
|
CommandBuilder::docker_compose().args("up -d").exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
// shortcuts
|
// shortcuts
|
||||||
pub fn rebuild() -> Result<()> {
|
pub fn rebuild() -> Result<()> {
|
||||||
stop()?;
|
stop()?;
|
||||||
build()?;
|
build()?;
|
||||||
start(None)
|
up()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn restart() -> Result<()> {
|
pub fn restart() -> Result<()> {
|
||||||
stop()?;
|
stop()?;
|
||||||
start(None)
|
up()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,63 +2,3 @@ pub mod django;
|
|||||||
pub mod docker;
|
pub mod docker;
|
||||||
pub mod docker_compose;
|
pub mod docker_compose;
|
||||||
pub mod postgres;
|
pub mod postgres;
|
||||||
|
|
||||||
use std::{
|
|
||||||
ffi::OsStr,
|
|
||||||
fs::{File, OpenOptions},
|
|
||||||
path::PathBuf,
|
|
||||||
process::{Command, Stdio},
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
|
||||||
|
|
||||||
struct DockerCommand {
|
|
||||||
command: Command,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DockerCommand {
|
|
||||||
fn new<T>(program: T) -> Self
|
|
||||||
where
|
|
||||||
T: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
DockerCommand {
|
|
||||||
command: Command::new(program),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn docker() -> Self {
|
|
||||||
Self::new("docker")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn docker_compose() -> Self {
|
|
||||||
Self::new("docker").args("compose -f docker/local/docker-compose.yaml")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn args(mut self, args: &str) -> Self {
|
|
||||||
self.command.args(args.split_whitespace());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stdout(mut self) -> Result<String> {
|
|
||||||
Ok(String::from_utf8(self.command.output()?.stdout)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spawn_wait(mut self) -> Result<()> {
|
|
||||||
self.command.spawn()?.wait()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_stdout(mut self, stdio: Stdio) -> Result<()> {
|
|
||||||
self.command.stdout(stdio);
|
|
||||||
self.spawn_wait()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn safe_create_file(path: PathBuf) -> Result<File, std::io::Error> {
|
|
||||||
OpenOptions::new().write(true).create_new(true).open(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_file(path: PathBuf) -> Result<File, std::io::Error> {
|
|
||||||
OpenOptions::new().write(true).create(true).open(path)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,25 +1,31 @@
|
|||||||
use super::{docker_compose, DockerCommand};
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Stdio,
|
process::Stdio,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::docker_compose;
|
||||||
|
use crate::command_builder::CommandBuilder;
|
||||||
|
|
||||||
fn get_containers() -> Result<[String; 2]> {
|
fn get_containers() -> Result<[String; 2]> {
|
||||||
// get db container
|
// get db container
|
||||||
// FIX: we assume we are running db in service named "postgresbd"
|
// FIX: we assume we are running db in service named "postgresbd"
|
||||||
let db_container = DockerCommand::docker_compose()
|
let db_container = CommandBuilder::docker_compose()
|
||||||
.args("ps -q postgresdb")
|
.args("ps -q postgresdb")
|
||||||
.stdout()?
|
.exec_get_stdout()?
|
||||||
.trim()
|
.trim()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
|
let no_result = db_container.is_empty();
|
||||||
|
if no_result {
|
||||||
|
return Err(anyhow!("no container"));
|
||||||
|
}
|
||||||
|
|
||||||
// get all containers and filter out db container
|
// get all containers and filter out db container
|
||||||
let app_containers = DockerCommand::docker_compose()
|
let app_containers = CommandBuilder::docker_compose()
|
||||||
.args("ps -q")
|
.args("ps -q")
|
||||||
.stdout()?
|
.exec_get_stdout()?
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.filter(|x| x != &db_container)
|
.filter(|x| x != &db_container)
|
||||||
.collect::<Vec<&str>>()
|
.collect::<Vec<&str>>()
|
||||||
@@ -46,7 +52,7 @@ pub fn import(file: &Path) -> Result<()> {
|
|||||||
format!("exec {db_container} pg_restore -U db --dbname=db /tmp/dbdump"),
|
format!("exec {db_container} pg_restore -U db --dbname=db /tmp/dbdump"),
|
||||||
];
|
];
|
||||||
for command in commands {
|
for command in commands {
|
||||||
DockerCommand::docker().args(&command).spawn_wait()?;
|
CommandBuilder::docker().args(&command).exec()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("restarting containers");
|
println!("restarting containers");
|
||||||
@@ -65,9 +71,9 @@ pub fn dump(file: &PathBuf) -> Result<()> {
|
|||||||
let stdout = Stdio::from(file);
|
let stdout = Stdio::from(file);
|
||||||
|
|
||||||
let command = format!("exec {db_container} pg_dump -U db --format=c db");
|
let command = format!("exec {db_container} pg_dump -U db --format=c db");
|
||||||
DockerCommand::docker()
|
CommandBuilder::docker()
|
||||||
.args(&command)
|
.args(&command)
|
||||||
.write_stdout(stdout)?;
|
.exec_redirect_stdout(stdout)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user