feat: finish django cli and add aliases

Implemented basic wanted functionality for django subcommands.

Added single or two letter aliases for all subsubcommands.
This commit is contained in:
Matej Janezic 2023-05-23 22:49:18 +02:00
parent 907740fc5a
commit 286e16e7ce
Signed by: janezicmatej
GPG Key ID: 4298E230ED37B2C0
8 changed files with 112 additions and 19 deletions

View File

@ -2,28 +2,38 @@ use std::path::PathBuf;
use clap::Parser; use clap::Parser;
// TODO: (matej) dsu template command
#[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,
#[arg(value_enum)] #[arg(value_enum)]
command: String, name: String,
}, },
/// 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.
Migrate, #[clap(alias("mg"))]
Migrate {
#[arg(value_enum)]
rest: Vec<String>,
},
/// Run Django's manage.py shell. /// Run Django's manage.py shell.
#[clap(alias("s"))]
Shell, Shell,
} }

View File

@ -3,5 +3,6 @@ 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,
} }

View File

@ -4,23 +4,30 @@ 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,
} }

View File

@ -5,12 +5,14 @@ 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,

View File

@ -5,11 +5,15 @@ mod scripts;
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use std::env;
fn main() -> Result<()> { fn main() -> Result<()> {
// always load dotenv on start // always load dotenv on start
dotenvy::dotenv().ok(); dotenvy::dotenv().ok();
// TODO: (matej) some prints about project
// eg: DJANGO_SETTINGS_MODULE for django projects, used docker-compose, etc.
let args = cli::Ahab::parse(); let args = cli::Ahab::parse();
match args.command { match args.command {
@ -26,12 +30,10 @@ fn main() -> Result<()> {
cli::DockerCompose::Up => scripts::docker_compose::up(), cli::DockerCompose::Up => scripts::docker_compose::up(),
}, },
cli::Commands::Dj { command } => match command { cli::Commands::Dj { command } => match command {
cli::Django::MakeCommand { app, command } => { cli::Django::MakeCommand { app, name } => scripts::django::make_command(&app, &name),
scripts::django::make_command(&app, &command)
}
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 => scripts::django::migrate(), cli::Django::Migrate { rest } => scripts::django::migrate(&rest),
cli::Django::Shell => scripts::django::shell(), cli::Django::Shell => scripts::django::shell(),
}, },
cli::Commands::Pg { command } => match command { cli::Commands::Pg { command } => match command {

View File

@ -1,20 +1,73 @@
use anyhow::Result; use crate::scripts::{create_file, safe_create_file};
use std::path::PathBuf;
pub fn make_command(app: &PathBuf, command: &str) -> Result<()> { use super::DockerCommand;
println!("{app:?} and {command:?}"); use anyhow::{anyhow, Result};
todo!() use std::env;
use std::fs::create_dir;
use std::path::{Path, PathBuf};
fn get_django_settings_module() -> Result<String> {
Ok(env::var("DJANGO_SETTINGS_MODULE")?)
} }
pub fn make_command(app: &PathBuf, name: &str) -> Result<()> {
let app_name = app.to_string_lossy();
let app_dir = Path::new(&app);
let not_app_exists = !app_dir.is_dir();
if not_app_exists {
return Err(anyhow!("directory {app_name} does not exist"));
}
println!("found app {app_name}");
let management_dir = app_dir.join("management");
let not_management_exists = !management_dir.exists();
if not_management_exists {
create_dir(&management_dir)?;
create_file(management_dir.join("__init__.py"))?;
println!("created module {app_name}.management")
};
let commands_dir = management_dir.join("commands");
let not_commands_exists = !commands_dir.exists();
if not_commands_exists {
create_dir(&commands_dir)?;
create_file(commands_dir.join("__init__.py"))?;
println!("created module {app_name}.management.commands")
};
safe_create_file(commands_dir.join(name))?;
println!("created command {app_name}.management.commands.{name}");
Ok(())
}
pub fn makemigrations() -> Result<()> { pub fn makemigrations() -> Result<()> {
todo!() let dsm = get_django_settings_module()?;
let command = format!("manage makemigrations --settings={dsm}");
DockerCommand::docker_compose().args(&command).spawn_wait()
} }
pub fn manage(command: &[String]) -> Result<()> {
println!("{command:?}"); pub fn manage(rest: &[String]) -> Result<()> {
todo!() let dsm = get_django_settings_module()?;
let joined = rest.join(" ");
let command = format!("manage {joined} --settings={dsm}");
DockerCommand::docker_compose().args(&command).spawn_wait()
} }
pub fn migrate() -> Result<()> {
todo!() pub fn migrate(rest: &[String]) -> Result<()> {
let dsm = get_django_settings_module()?;
let joined = rest.join(" ");
let command = format!("manage migrate {joined} --settings={dsm}");
DockerCommand::docker_compose().args(&command).spawn_wait()
} }
pub fn shell() -> Result<()> { pub fn shell() -> Result<()> {
todo!() let dsm = get_django_settings_module()?;
let command = format!("manage shell --settings={dsm}");
DockerCommand::docker_compose().args(&command).spawn_wait()
} }

View File

@ -3,6 +3,11 @@ use anyhow::Result;
pub fn stop_all() -> Result<()> { pub fn stop_all() -> Result<()> {
let running_containers = DockerCommand::docker().args("ps -q").stdout()?; let running_containers = DockerCommand::docker().args("ps -q").stdout()?;
if running_containers.is_empty() {
return Ok(());
}
DockerCommand::docker() DockerCommand::docker()
.args(&format!("stop {running_containers}")) .args(&format!("stop {running_containers}"))
.spawn_wait() .spawn_wait()

View File

@ -3,7 +3,12 @@ pub mod docker;
pub mod docker_compose; pub mod docker_compose;
pub mod postgres; pub mod postgres;
use std::{ffi::OsStr, process::Command}; use std::{
ffi::OsStr,
fs::{File, OpenOptions},
path::PathBuf,
process::Command,
};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
@ -43,3 +48,11 @@ impl DockerCommand {
Ok(()) 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)
}