create compatibility layer for mysql-admutils commands

This commit was merged in pull request #32.
This commit is contained in:
2024-08-05 22:37:23 +02:00
parent c473a4823e
commit 4353689a03
14 changed files with 688 additions and 79 deletions

View File

@@ -0,0 +1,220 @@
use clap::Parser;
use sqlx::MySqlConnection;
use crate::{
cli::{
database_command,
mysql_admutils_compatibility::common::{filter_db_or_user_names, DbOrUser},
},
core::{
config::{get_config, mysql_connection_from_config, GlobalConfigArgs},
database_operations::{self, yn},
},
};
const HELP_DB_PERM: &str = r#"
Edit permissions for the DATABASE(s). Running this command will
spawn the editor stored in the $EDITOR environment variable.
(pico will be used if the variable is unset)
The file should contain one line per user, starting with the
username and followed by ten Y/N-values seperated by whitespace.
Lines starting with # are ignored.
The Y/N-values corresponds to the following mysql privileges:
Select - Enables use of SELECT
Insert - Enables use of INSERT
Update - Enables use of UPDATE
Delete - Enables use of DELETE
Create - Enables use of CREATE TABLE
Drop - Enables use of DROP TABLE
Alter - Enables use of ALTER TABLE
Index - Enables use of CREATE INDEX and DROP INDEX
Temp - Enables use of CREATE TEMPORARY TABLE
Lock - Enables use of LOCK TABLE
References - Enables use of REFERENCES
"#;
#[derive(Parser)]
pub struct Args {
#[command(subcommand)]
pub command: Option<Command>,
#[command(flatten)]
config_overrides: GlobalConfigArgs,
/// Print help for the 'editperm' subcommand.
#[arg(long, global = true)]
pub help_editperm: bool,
}
/// Create, drop or edit permissions for the DATABASE(s),
/// as determined by the COMMAND.
///
/// This is a compatibility layer for the mysql-dbadm command.
/// Please consider using the newer mysqladm command instead.
#[derive(Parser)]
#[command(
version,
about,
disable_help_subcommand = true,
verbatim_doc_comment,
)]
pub enum Command {
/// create the DATABASE(s).
Create(CreateArgs),
/// delete the DATABASE(s).
Drop(DatabaseDropArgs),
/// give information about the DATABASE(s), or, if
/// none are given, all the ones you own.
Show(DatabaseShowArgs),
// TODO: make this output more verbatim_doc_comment-like,
// without messing up the indentation.
/// change permissions for the DATABASE(s). Your
/// favorite editor will be started, allowing you
/// to make changes to the permission table.
/// Run 'mysql-dbadm --help-editperm' for more
/// information.
EditPerm(EditPermArgs),
}
#[derive(Parser)]
pub struct CreateArgs {
/// The name of the DATABASE(s) to create.
#[arg(num_args = 1..)]
name: Vec<String>,
}
#[derive(Parser)]
pub struct DatabaseDropArgs {
/// The name of the DATABASE(s) to drop.
#[arg(num_args = 1..)]
name: Vec<String>,
}
#[derive(Parser)]
pub struct DatabaseShowArgs {
/// The name of the DATABASE(s) to show.
#[arg(num_args = 0..)]
name: Vec<String>,
}
#[derive(Parser)]
pub struct EditPermArgs {
/// The name of the DATABASE to edit permissions for.
pub database: String,
}
pub async fn main() -> anyhow::Result<()> {
let args: Args = Args::parse();
if args.help_editperm {
println!("{}", HELP_DB_PERM);
return Ok(());
}
let command = match args.command {
Some(command) => command,
None => {
println!(
"Try `{} --help' for more information.",
std::env::args().next().unwrap_or("mysql-dbadm".to_string())
);
return Ok(());
}
};
let config = get_config(args.config_overrides)?;
let mut connection = mysql_connection_from_config(config).await?;
match command {
Command::Create(args) => {
let filtered_names = filter_db_or_user_names(args.name, DbOrUser::Database)?;
for name in filtered_names {
database_operations::create_database(&name, &mut connection).await?;
println!("Database {} created.", name);
}
}
Command::Drop(args) => {
let filtered_names = filter_db_or_user_names(args.name, DbOrUser::Database)?;
for name in filtered_names {
database_operations::drop_database(&name, &mut connection).await?;
println!("Database {} dropped.", name);
}
}
Command::Show(args) => {
let names = if args.name.is_empty() {
database_operations::get_database_list(&mut connection).await?
} else {
filter_db_or_user_names(args.name, DbOrUser::Database)?
};
for name in names {
show_db(&name, &mut connection).await?;
}
}
Command::EditPerm(args) => {
// TODO: This does not accurately replicate the behavior of the old implementation.
// Hopefully, not many people rely on this in an automated fashion, as it
// is made to be interactive in nature. However, we should still try to
// replicate the old behavior as closely as possible.
let edit_permissions_args = database_command::DatabaseEditPermArgs {
name: Some(args.database),
perm: vec![],
json: false,
editor: None,
yes: false,
};
database_command::edit_permissions(edit_permissions_args, &mut connection).await?;
}
}
Ok(())
}
async fn show_db(name: &str, conn: &mut MySqlConnection) -> anyhow::Result<()> {
// NOTE: mysql-dbadm show has a quirk where valid database names
// for non-existent databases will report with no users.
// This function should *not* check for db existence, only
// validate the names.
let permissions = database_operations::get_database_privileges(name, conn)
.await
.unwrap_or(vec![]);
println!(
concat!(
"Database '{}':\n",
"# User Select Insert Update Delete Create Drop Alter Index Temp Lock References\n",
"# ---------------- ------ ------ ------ ------ ------ ---- ----- ----- ---- ---- ----------"
),
name,
);
if permissions.is_empty() {
println!("# (no permissions currently granted to any users)");
} else {
for permission in permissions {
println!(
" {:<16} {:<7} {:<7} {:<7} {:<7} {:<7} {:<7} {:<7} {:<7} {:<7} {:<7} {}",
permission.user,
yn(permission.select_priv),
yn(permission.insert_priv),
yn(permission.update_priv),
yn(permission.delete_priv),
yn(permission.create_priv),
yn(permission.drop_priv),
yn(permission.alter_priv),
yn(permission.index_priv),
yn(permission.create_tmp_table_priv),
yn(permission.lock_tables_priv),
yn(permission.references_priv)
);
}
}
Ok(())
}