clippy pedantic fix + get rid of a few unwraps
All checks were successful
Build and test / docs (push) Successful in 7m1s
Build and test / check-license (push) Successful in 57s
Build and test / check (push) Successful in 2m46s
Build and test / build (push) Successful in 3m12s
Build and test / test (push) Successful in 3m25s

This commit is contained in:
2025-12-23 13:40:46 +09:00
parent c866400b4a
commit 4c3677d6d3
51 changed files with 596 additions and 545 deletions

View File

@@ -39,13 +39,13 @@ pub fn erroneous_server_response(
) -> anyhow::Result<()> {
match response {
Some(Ok(Response::Error(e))) => {
anyhow::bail!("Server returned error: {}", e);
anyhow::bail!("Server returned error: {e}");
}
Some(Err(e)) => {
anyhow::bail!(e);
}
Some(response) => {
anyhow::bail!("Unexpected response from server: {:?}", response);
anyhow::bail!("Unexpected response from server: {response:?}");
}
None => {
anyhow::bail!("No response from server");
@@ -72,7 +72,7 @@ async fn print_authorization_owner_hint(
eprintln!(
"Note: You are allowed to manage databases and users with the following prefixes:\n{}",
response.into_iter().map(|p| format!(" - {}", p)).join("\n")
response.into_iter().map(|p| format!(" - {p}")).join("\n")
);
Ok(())

View File

@@ -14,7 +14,7 @@ use tokio_stream::StreamExt;
#[derive(Parser, Debug, Clone)]
pub struct CheckAuthArgs {
/// The MySQL database(s) or user(s) to check authorization for
/// The `MySQL` database(s) or user(s) to check authorization for
#[arg(num_args = 1.., value_name = "NAME")]
name: Vec<String>,
@@ -63,7 +63,7 @@ pub async fn check_authorization(
print_check_authorization_output_status(&result);
}
if result.values().any(|res| res.is_err()) {
if result.values().any(std::result::Result::is_err) {
std::process::exit(1);
}

View File

@@ -18,7 +18,7 @@ use crate::{
#[derive(Parser, Debug, Clone)]
pub struct CreateDbArgs {
/// The MySQL database(s) to create
/// The `MySQL` database(s) to create
#[arg(num_args = 1.., value_name = "DB_NAME")]
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(prefix_completer)))]
name: Vec<MySQLDatabase>,
@@ -36,7 +36,7 @@ pub async fn create_databases(
anyhow::bail!("No database names provided");
}
let message = Request::CreateDatabases(args.name.to_owned());
let message = Request::CreateDatabases(args.name.clone());
server_connection.send(message).await?;
let result = match server_connection.next().await {
@@ -57,13 +57,13 @@ pub async fn create_databases(
))
)
}) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
}
server_connection.send(Request::Exit).await?;
if result.values().any(|res| res.is_err()) {
if result.values().any(std::result::Result::is_err) {
std::process::exit(1);
}

View File

@@ -22,7 +22,7 @@ use crate::{
#[derive(Parser, Debug, Clone)]
pub struct CreateUserArgs {
/// The MySQL user(s) to create
/// The `MySQL` user(s) to create
#[arg(num_args = 1.., value_name = "USER_NAME")]
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(prefix_completer)))]
username: Vec<MySQLUser>,
@@ -46,7 +46,7 @@ pub async fn create_users(
anyhow::bail!("No usernames provided");
}
let message = Request::CreateUsers(args.username.to_owned());
let message = Request::CreateUsers(args.username.clone());
if let Err(err) = server_connection.send(message).await {
server_connection.close().await.ok();
anyhow::bail!(anyhow::Error::from(err).context("Failed to communicate with server"));
@@ -70,20 +70,19 @@ pub async fn create_users(
))
)
}) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
let successfully_created_users = result
.iter()
.filter_map(|(username, result)| result.as_ref().ok().map(|_| username))
.filter_map(|(username, result)| result.as_ref().ok().map(|()| username))
.collect::<Vec<_>>();
for username in successfully_created_users {
if !args.no_password
&& Confirm::new()
.with_prompt(format!(
"Do you want to set a password for user '{}'?",
username
"Do you want to set a password for user '{username}'?"
))
.default(false)
.interact()?
@@ -98,7 +97,7 @@ pub async fn create_users(
match server_connection.next().await {
Some(Ok(Response::SetUserPassword(result))) => {
print_set_password_output_status(&result, username)
print_set_password_output_status(&result, username);
}
response => return erroneous_server_response(response),
}
@@ -110,7 +109,7 @@ pub async fn create_users(
server_connection.send(Request::Exit).await?;
if result.values().any(|res| res.is_err()) {
if result.values().any(std::result::Result::is_err) {
std::process::exit(1);
}

View File

@@ -19,7 +19,7 @@ use crate::{
#[derive(Parser, Debug, Clone)]
pub struct DropDbArgs {
/// The MySQL database(s) to drop
/// The `MySQL` database(s) to drop
#[arg(num_args = 1.., value_name = "DB_NAME")]
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(mysql_database_completer)))]
name: Vec<MySQLDatabase>,
@@ -47,7 +47,7 @@ pub async fn drop_databases(
"Are you sure you want to drop the databases?\n\n{}\n\nThis action cannot be undone",
args.name
.iter()
.map(|d| format!("- {}", d))
.map(|d| format!("- {d}"))
.collect::<Vec<_>>()
.join("\n")
))
@@ -62,7 +62,7 @@ pub async fn drop_databases(
}
}
let message = Request::DropDatabases(args.name.to_owned());
let message = Request::DropDatabases(args.name.clone());
server_connection.send(message).await?;
let result = match server_connection.next().await {
@@ -83,13 +83,13 @@ pub async fn drop_databases(
))
)
}) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
};
}
server_connection.send(Request::Exit).await?;
if result.values().any(|res| res.is_err()) {
if result.values().any(std::result::Result::is_err) {
std::process::exit(1);
}

View File

@@ -19,7 +19,7 @@ use crate::{
#[derive(Parser, Debug, Clone)]
pub struct DropUserArgs {
/// The MySQL user(s) to drop
/// The `MySQL` user(s) to drop
#[arg(num_args = 1.., value_name = "USER_NAME")]
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(mysql_user_completer)))]
username: Vec<MySQLUser>,
@@ -47,7 +47,7 @@ pub async fn drop_users(
"Are you sure you want to drop the users?\n\n{}\n\nThis action cannot be undone",
args.username
.iter()
.map(|d| format!("- {}", d))
.map(|d| format!("- {d}"))
.collect::<Vec<_>>()
.join("\n")
))
@@ -61,7 +61,7 @@ pub async fn drop_users(
}
}
let message = Request::DropUsers(args.username.to_owned());
let message = Request::DropUsers(args.username.clone());
if let Err(err) = server_connection.send(message).await {
server_connection.close().await.ok();
@@ -86,13 +86,13 @@ pub async fn drop_users(
))
)
}) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
}
server_connection.send(Request::Exit).await?;
if result.values().any(|res| res.is_err()) {
if result.values().any(std::result::Result::is_err) {
std::process::exit(1);
}

View File

@@ -67,7 +67,7 @@ pub struct EditPrivsArgs {
#[derive(Args, Debug, Clone)]
pub struct SinglePrivilegeEditArgs {
/// The MySQL database to edit privileges for
/// The `MySQL` database to edit privileges for
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(mysql_database_completer)))]
#[arg(
value_name = "DB_NAME",
@@ -76,7 +76,7 @@ pub struct SinglePrivilegeEditArgs {
)]
pub db_name: Option<MySQLDatabase>,
/// The MySQL database to edit privileges for
/// The `MySQL` database to edit privileges for
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(mysql_user_completer)))]
#[arg(value_name = "USER_NAME")]
pub user_name: Option<MySQLUser>,
@@ -212,13 +212,13 @@ pub async fn edit_database_privileges(
response => return erroneous_server_response(response),
};
let diffs: BTreeSet<DatabasePrivilegesDiff> = if !privs.is_empty() {
let privileges_to_change = parse_privilege_tables(&privs)?;
create_or_modify_privilege_rows(&existing_privilege_rows, &privileges_to_change)?
} else {
let diffs: BTreeSet<DatabasePrivilegesDiff> = if privs.is_empty() {
let privileges_to_change =
edit_privileges_with_editor(&existing_privilege_rows, use_database.as_ref())?;
diff_privileges(&existing_privilege_rows, &privileges_to_change)
} else {
let privileges_to_change = parse_privilege_tables(&privs)?;
create_or_modify_privilege_rows(&existing_privilege_rows, &privileges_to_change)?
};
let database_existence_map = databases_exist(&mut server_connection, &diffs).await?;
@@ -306,12 +306,12 @@ pub async fn edit_database_privileges(
))
)
}) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
server_connection.send(Request::Exit).await?;
if result.values().any(|res| res.is_err()) {
if result.values().any(std::result::Result::is_err) {
std::process::exit(1);
}
@@ -328,8 +328,7 @@ fn parse_privilege_tables(
priv_edit_entry
.as_database_privileges_diff()
.context(format!(
"Failed parsing database privileges: `{}`",
priv_edit_entry
"Failed parsing database privileges: `{priv_edit_entry}`"
))
})
.collect::<anyhow::Result<BTreeSet<DatabasePrivilegeRowDiff>>>()
@@ -352,7 +351,7 @@ fn edit_privileges_with_editor(
match result {
None => Ok(privilege_data.to_vec()),
Some(result) => parse_privilege_data_from_editor_content(result)
Some(result) => parse_privilege_data_from_editor_content(&result)
.context("Could not parse privilege data from editor"),
}
}

View File

@@ -18,7 +18,7 @@ use crate::{
#[derive(Parser, Debug, Clone)]
pub struct LockUserArgs {
/// The MySQL user(s) to loc
/// The `MySQL` user(s) to loc
#[arg(num_args = 1.., value_name = "USER_NAME")]
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(mysql_user_completer)))]
username: Vec<MySQLUser>,
@@ -36,7 +36,7 @@ pub async fn lock_users(
anyhow::bail!("No usernames provided");
}
let message = Request::LockUsers(args.username.to_owned());
let message = Request::LockUsers(args.username.clone());
if let Err(err) = server_connection.send(message).await {
server_connection.close().await.ok();
@@ -61,13 +61,13 @@ pub async fn lock_users(
))
)
}) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
}
server_connection.send(Request::Exit).await?;
if result.values().any(|res| res.is_err()) {
if result.values().any(std::result::Result::is_err) {
std::process::exit(1);
}

View File

@@ -21,7 +21,7 @@ use crate::{
#[derive(Parser, Debug, Clone)]
pub struct PasswdUserArgs {
/// The MySQL user whose password is to be changed
/// The `MySQL` user whose password is to be changed
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(mysql_user_completer)))]
#[arg(value_name = "USER_NAME")]
username: MySQLUser,
@@ -41,9 +41,9 @@ pub struct PasswdUserArgs {
pub fn read_password_from_stdin_with_double_check(username: &MySQLUser) -> anyhow::Result<String> {
Password::new()
.with_prompt(format!("New MySQL password for user '{}'", username))
.with_prompt(format!("New MySQL password for user '{username}'"))
.with_confirmation(
format!("Retype new MySQL password for user '{}'", username),
format!("Retype new MySQL password for user '{username}'"),
"Passwords do not match",
)
.interact()
@@ -55,7 +55,7 @@ pub async fn passwd_user(
mut server_connection: ClientToServerMessageStream,
) -> anyhow::Result<()> {
// TODO: create a "user" exists check" command
let message = Request::ListUsers(Some(vec![args.username.to_owned()]));
let message = Request::ListUsers(Some(vec![args.username.clone()]));
if let Err(err) = server_connection.send(message).await {
server_connection.close().await.ok();
anyhow::bail!(err);
@@ -91,7 +91,7 @@ pub async fn passwd_user(
read_password_from_stdin_with_double_check(&args.username)?
};
let message = Request::PasswdUser((args.username.to_owned(), password));
let message = Request::PasswdUser((args.username.clone(), password));
if let Err(err) = server_connection.send(message).await {
server_connection.close().await.ok();
@@ -111,7 +111,7 @@ pub async fn passwd_user(
ValidationError::AuthorizationError(_)
))
) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
server_connection.send(Request::Exit).await?;

View File

@@ -18,7 +18,7 @@ use crate::{
#[derive(Parser, Debug, Clone)]
pub struct ShowDbArgs {
/// The MySQL database(s) to show
/// The `MySQL` database(s) to show
#[arg(num_args = 0.., value_name = "DB_NAME")]
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(mysql_database_completer)))]
name: Vec<MySQLDatabase>,
@@ -39,7 +39,7 @@ pub async fn show_databases(
let message = if args.name.is_empty() {
Request::ListDatabases(None)
} else {
Request::ListDatabases(Some(args.name.to_owned()))
Request::ListDatabases(Some(args.name.clone()))
};
server_connection.send(message).await?;
@@ -74,13 +74,13 @@ pub async fn show_databases(
))
)
}) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
}
server_connection.send(Request::Exit).await?;
if databases.values().any(|res| res.is_err()) {
if databases.values().any(std::result::Result::is_err) {
std::process::exit(1);
}

View File

@@ -19,7 +19,7 @@ use crate::{
#[derive(Parser, Debug, Clone)]
pub struct ShowPrivsArgs {
/// The MySQL database(s) to show privileges for
/// The `MySQL` database(s) to show privileges for
#[arg(num_args = 0.., value_name = "DB_NAME")]
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(mysql_database_completer)))]
name: Vec<MySQLDatabase>,
@@ -42,7 +42,7 @@ pub async fn show_database_privileges(
let message = if args.name.is_empty() {
Request::ListPrivileges(None)
} else {
Request::ListPrivileges(Some(args.name.to_owned()))
Request::ListPrivileges(Some(args.name.clone()))
};
server_connection.send(message).await?;
@@ -78,13 +78,13 @@ pub async fn show_database_privileges(
))
)
}) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
}
server_connection.send(Request::Exit).await?;
if privilege_data.values().any(|res| res.is_err()) {
if privilege_data.values().any(std::result::Result::is_err) {
std::process::exit(1);
}

View File

@@ -18,7 +18,7 @@ use crate::{
#[derive(Parser, Debug, Clone)]
pub struct ShowUserArgs {
/// The MySQL user(s) to show
/// The `MySQL` user(s) to show
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(mysql_user_completer)))]
#[arg(num_args = 0.., value_name = "USER_NAME")]
username: Vec<MySQLUser>,
@@ -35,7 +35,7 @@ pub async fn show_users(
let message = if args.username.is_empty() {
Request::ListUsers(None)
} else {
Request::ListUsers(Some(args.username.to_owned()))
Request::ListUsers(Some(args.username.clone()))
};
if let Err(err) = server_connection.send(message).await {
@@ -73,13 +73,13 @@ pub async fn show_users(
))
)
}) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
}
server_connection.send(Request::Exit).await?;
if users.values().any(|result| result.is_err()) {
if users.values().any(std::result::Result::is_err) {
std::process::exit(1);
}

View File

@@ -18,7 +18,7 @@ use crate::{
#[derive(Parser, Debug, Clone)]
pub struct UnlockUserArgs {
/// The MySQL user(s) to unlock
/// The `MySQL` user(s) to unlock
#[cfg_attr(not(feature = "suid-sgid-mode"), arg(add = ArgValueCompleter::new(mysql_user_completer)))]
#[arg(num_args = 1.., value_name = "USER_NAME")]
username: Vec<MySQLUser>,
@@ -36,7 +36,7 @@ pub async fn unlock_users(
anyhow::bail!("No usernames provided");
}
let message = Request::UnlockUsers(args.username.to_owned());
let message = Request::UnlockUsers(args.username.clone());
if let Err(err) = server_connection.send(message).await {
server_connection.close().await.ok();
@@ -61,13 +61,13 @@ pub async fn unlock_users(
))
)
}) {
print_authorization_owner_hint(&mut server_connection).await?
print_authorization_owner_hint(&mut server_connection).await?;
}
}
server_connection.send(Request::Exit).await?;
if result.values().any(|result| result.is_err()) {
if result.values().any(std::result::Result::is_err) {
std::process::exit(1);
}

View File

@@ -1,11 +1,13 @@
use crate::core::types::{MySQLDatabase, MySQLUser};
#[inline]
#[must_use]
pub fn trim_db_name_to_32_chars(db_name: &MySQLDatabase) -> MySQLDatabase {
db_name.chars().take(32).collect::<String>().into()
}
#[inline]
#[must_use]
pub fn trim_user_name_to_32_chars(user_name: &MySQLUser) -> MySQLUser {
user_name.chars().take(32).collect::<String>().into()
}

View File

@@ -6,7 +6,7 @@ use crate::core::{
types::DbOrUser,
};
pub fn name_validation_error_to_error_message(db_or_user: DbOrUser) -> String {
pub fn name_validation_error_to_error_message(db_or_user: &DbOrUser) -> String {
let argv0 = std::env::args().next().unwrap_or_else(|| match db_or_user {
DbOrUser::Database(_) => "mysql-dbadm".to_string(),
DbOrUser::User(_) => "mysql-useradm".to_string(),
@@ -23,7 +23,7 @@ pub fn name_validation_error_to_error_message(db_or_user: DbOrUser) -> String {
)
}
pub fn authorization_error_message(db_or_user: DbOrUser) -> String {
pub fn authorization_error_message(db_or_user: &DbOrUser) -> String {
format!(
"You are not in charge of mysql-{}: '{}'. Skipping.",
db_or_user.lowercased_noun(),
@@ -31,7 +31,7 @@ pub fn authorization_error_message(db_or_user: DbOrUser) -> String {
)
}
pub fn handle_create_user_error(error: CreateUserError, name: &str) {
pub fn handle_create_user_error(error: &CreateUserError, name: &str) {
let argv0 = std::env::args()
.next()
.unwrap_or_else(|| "mysql-useradm".to_string());
@@ -39,22 +39,22 @@ pub fn handle_create_user_error(error: CreateUserError, name: &str) {
CreateUserError::ValidationError(ValidationError::NameValidationError(_)) => {
eprintln!(
"{}",
name_validation_error_to_error_message(DbOrUser::User(name.into()))
name_validation_error_to_error_message(&DbOrUser::User(name.into()))
);
}
CreateUserError::ValidationError(ValidationError::AuthorizationError(_)) => {
eprintln!(
"{}",
authorization_error_message(DbOrUser::User(name.into()))
authorization_error_message(&DbOrUser::User(name.into()))
);
}
CreateUserError::MySqlError(_) | CreateUserError::UserAlreadyExists => {
eprintln!("{}: Failed to create user '{}'.", argv0, name);
eprintln!("{argv0}: Failed to create user '{name}'.");
}
}
}
pub fn handle_drop_user_error(error: DropUserError, name: &str) {
pub fn handle_drop_user_error(error: &DropUserError, name: &str) {
let argv0 = std::env::args()
.next()
.unwrap_or_else(|| "mysql-useradm".to_string());
@@ -62,22 +62,22 @@ pub fn handle_drop_user_error(error: DropUserError, name: &str) {
DropUserError::ValidationError(ValidationError::NameValidationError(_)) => {
eprintln!(
"{}",
name_validation_error_to_error_message(DbOrUser::User(name.into()))
name_validation_error_to_error_message(&DbOrUser::User(name.into()))
);
}
DropUserError::ValidationError(ValidationError::AuthorizationError(_)) => {
eprintln!(
"{}",
authorization_error_message(DbOrUser::User(name.into()))
authorization_error_message(&DbOrUser::User(name.into()))
);
}
DropUserError::MySqlError(_) | DropUserError::UserDoesNotExist => {
eprintln!("{}: Failed to delete user '{}'.", argv0, name);
eprintln!("{argv0}: Failed to delete user '{name}'.");
}
}
}
pub fn handle_list_users_error(error: ListUsersError, name: &str) {
pub fn handle_list_users_error(error: &ListUsersError, name: &str) {
let argv0 = std::env::args()
.next()
.unwrap_or_else(|| "mysql-useradm".to_string());
@@ -85,30 +85,27 @@ pub fn handle_list_users_error(error: ListUsersError, name: &str) {
ListUsersError::ValidationError(ValidationError::NameValidationError(_)) => {
eprintln!(
"{}",
name_validation_error_to_error_message(DbOrUser::User(name.into()))
name_validation_error_to_error_message(&DbOrUser::User(name.into()))
);
}
ListUsersError::ValidationError(ValidationError::AuthorizationError(_)) => {
eprintln!(
"{}",
authorization_error_message(DbOrUser::User(name.into()))
authorization_error_message(&DbOrUser::User(name.into()))
);
}
ListUsersError::UserDoesNotExist => {
eprintln!(
"{}: User '{}' does not exist. You must create it first.",
argv0, name,
);
eprintln!("{argv0}: User '{name}' does not exist. You must create it first.",);
}
ListUsersError::MySqlError(_) => {
eprintln!("{}: Failed to look up password for user '{}'", argv0, name);
eprintln!("{argv0}: Failed to look up password for user '{name}'");
}
}
}
// ----------------------------------------------------------------------------
pub fn handle_create_database_error(error: CreateDatabaseError, name: &str) {
pub fn handle_create_database_error(error: &CreateDatabaseError, name: &str) {
let argv0 = std::env::args()
.next()
.unwrap_or_else(|| "mysql-dbadm".to_string());
@@ -116,26 +113,26 @@ pub fn handle_create_database_error(error: CreateDatabaseError, name: &str) {
CreateDatabaseError::ValidationError(ValidationError::NameValidationError(_)) => {
eprintln!(
"{}",
name_validation_error_to_error_message(DbOrUser::Database(name.into()))
name_validation_error_to_error_message(&DbOrUser::Database(name.into()))
);
}
CreateDatabaseError::ValidationError(ValidationError::AuthorizationError(_)) => {
eprintln!(
"{}",
authorization_error_message(DbOrUser::Database(name.into()))
authorization_error_message(&DbOrUser::Database(name.into()))
);
}
CreateDatabaseError::MySqlError(_) => {
eprintln!("{}: Cannot create database '{}'.", argv0, name);
eprintln!("{argv0}: Cannot create database '{name}'.");
}
CreateDatabaseError::DatabaseAlreadyExists => {
eprintln!("{}: Database '{}' already exists.", argv0, name);
eprintln!("{argv0}: Database '{name}' already exists.");
}
}
}
pub fn handle_drop_database_error(error: DropDatabaseError, name: &str) {
pub fn handle_drop_database_error(error: &DropDatabaseError, name: &str) {
let argv0 = std::env::args()
.next()
.unwrap_or_else(|| "mysql-dbadm".to_string());
@@ -143,44 +140,41 @@ pub fn handle_drop_database_error(error: DropDatabaseError, name: &str) {
DropDatabaseError::ValidationError(ValidationError::NameValidationError(_)) => {
eprintln!(
"{}",
name_validation_error_to_error_message(DbOrUser::Database(name.into()))
name_validation_error_to_error_message(&DbOrUser::Database(name.into()))
);
}
DropDatabaseError::ValidationError(ValidationError::AuthorizationError(_)) => {
eprintln!(
"{}",
authorization_error_message(DbOrUser::Database(name.into()))
authorization_error_message(&DbOrUser::Database(name.into()))
);
}
DropDatabaseError::MySqlError(_) => {
eprintln!("{}: Cannot drop database '{}'.", argv0, name);
eprintln!("{argv0}: Cannot drop database '{name}'.");
}
DropDatabaseError::DatabaseDoesNotExist => {
eprintln!("{}: Database '{}' doesn't exist.", argv0, name);
eprintln!("{argv0}: Database '{name}' doesn't exist.");
}
}
}
pub fn format_show_database_error_message(error: ListPrivilegesError, name: &str) -> String {
pub fn format_show_database_error_message(error: &ListPrivilegesError, name: &str) -> String {
let argv0 = std::env::args()
.next()
.unwrap_or_else(|| "mysql-dbadm".to_string());
match error {
ListPrivilegesError::ValidationError(ValidationError::NameValidationError(_)) => {
name_validation_error_to_error_message(DbOrUser::Database(name.into()))
name_validation_error_to_error_message(&DbOrUser::Database(name.into()))
}
ListPrivilegesError::ValidationError(ValidationError::AuthorizationError(_)) => {
authorization_error_message(DbOrUser::Database(name.into()))
authorization_error_message(&DbOrUser::Database(name.into()))
}
ListPrivilegesError::MySqlError(err) => {
format!(
"{}: Failed to look up privileges for database '{}': {}",
argv0, name, err
)
format!("{argv0}: Failed to look up privileges for database '{name}': {err}")
}
ListPrivilegesError::DatabaseDoesNotExist => {
format!("{}: Database '{}' doesn't exist.", argv0, name)
format!("{argv0}: Database '{name}' doesn't exist.")
}
}
}

View File

@@ -1,5 +1,6 @@
use clap::{Parser, Subcommand};
use clap_complete::ArgValueCompleter;
use clap_verbosity_flag::Verbosity;
use futures_util::{SinkExt, StreamExt};
use std::os::unix::net::UnixStream as StdUnixStream;
use std::path::PathBuf;
@@ -28,7 +29,7 @@ use crate::{
},
};
const HELP_DB_PERM: &str = r#"
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)
@@ -49,7 +50,7 @@ The Y/N-values corresponds to the following mysql privileges:
Temp - Enables use of CREATE TEMPORARY TABLE
Lock - Enables use of LOCK TABLE
References - Enables use of REFERENCES
"#;
";
/// Create, drop or edit permissions for the DATABASE(s),
/// as determined by the COMMAND.
@@ -156,25 +157,22 @@ pub fn main() -> anyhow::Result<()> {
let args: Args = Args::parse();
if args.help_editperm {
println!("{}", HELP_DB_PERM);
println!("{HELP_DB_PERM}");
return Ok(());
}
let server_connection = bootstrap_server_connection_and_drop_privileges(
args.server_socket_path,
args.config,
Default::default(),
Verbosity::default(),
)?;
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 Some(command) = args.command else {
println!(
"Try `{} --help' for more information.",
std::env::args().next().unwrap_or("mysql-dbadm".to_string())
);
return Ok(());
};
tokio_run_command(command, server_connection)?;
@@ -194,11 +192,11 @@ fn tokio_run_command(command: Command, server_connection: StdUnixStream) -> anyh
while let Some(Ok(message)) = message_stream.next().await {
match message {
Response::Error(err) => {
anyhow::bail!("{}", err);
anyhow::bail!("{err}");
}
Response::Ready => break,
message => {
eprintln!("Unexpected message from server: {:?}", message);
eprintln!("Unexpected message from server: {message:?}");
}
}
}
@@ -245,8 +243,8 @@ async fn create_databases(
for (name, result) in result {
match result {
Ok(()) => println!("Database {} created.", name),
Err(err) => handle_create_database_error(err, &name),
Ok(()) => println!("Database {name} created."),
Err(err) => handle_create_database_error(&err, &name),
}
}
@@ -271,8 +269,8 @@ async fn drop_databases(
for (name, result) in result {
match result {
Ok(()) => println!("Database {} dropped.", name),
Err(err) => handle_drop_database_error(err, &name),
Ok(()) => println!("Database {name} dropped."),
Err(err) => handle_drop_database_error(&err, &name),
}
}
@@ -312,24 +310,21 @@ async fn show_databases(
let results: Vec<Result<(MySQLDatabase, Vec<DatabasePrivilegeRow>), String>> = match response {
Some(Ok(Response::ListPrivileges(result))) => result
.into_iter()
.map(
|(name, rows)| match rows.map(|rows| (name.to_owned(), rows)) {
Ok(rows) => Ok(rows),
Err(ListPrivilegesError::DatabaseDoesNotExist) => Ok((name, vec![])),
Err(err) => Err(format_show_database_error_message(err, &name)),
},
)
.map(|(name, rows)| match rows.map(|rows| (name.clone(), rows)) {
Ok(rows) => Ok(rows),
Err(ListPrivilegesError::DatabaseDoesNotExist) => Ok((name, vec![])),
Err(err) => Err(format_show_database_error_message(&err, &name)),
})
.collect(),
response => return erroneous_server_response(response),
};
results.into_iter().try_for_each(|result| match result {
Ok((name, rows)) => print_db_privs(&name, rows),
Err(err) => {
eprintln!("{}", err);
Ok(())
for result in results {
match result {
Ok((name, rows)) => print_db_privs(&name, rows),
Err(err) => eprintln!("{err}"),
}
})?;
}
Ok(())
}
@@ -339,7 +334,7 @@ fn yn(value: bool) -> &'static str {
if value { "Y" } else { "N" }
}
fn print_db_privs(name: &str, rows: Vec<DatabasePrivilegeRow>) -> anyhow::Result<()> {
fn print_db_privs(name: &str, rows: Vec<DatabasePrivilegeRow>) {
println!(
concat!(
"Database '{}':\n",
@@ -369,6 +364,4 @@ fn print_db_privs(name: &str, rows: Vec<DatabasePrivilegeRow>) -> anyhow::Result
);
}
}
Ok(())
}

View File

@@ -75,7 +75,7 @@ pub enum Command {
/// delete the USER(s).
Delete(DeleteArgs),
/// change the MySQL password for the USER(s).
/// change the `MySQL` password for the USER(s).
Passwd(PasswdArgs),
/// give information about the USERS(s), or, if
@@ -119,17 +119,14 @@ pub struct ShowArgs {
pub fn main() -> anyhow::Result<()> {
let args: Args = Args::parse();
let command = match args.command {
Some(command) => command,
None => {
println!(
"Try `{} --help' for more information.",
std::env::args()
.next()
.unwrap_or("mysql-useradm".to_string())
);
return Ok(());
}
let Some(command) = args.command else {
println!(
"Try `{} --help' for more information.",
std::env::args()
.next()
.unwrap_or("mysql-useradm".to_string())
);
return Ok(());
};
let server_connection = bootstrap_server_connection_and_drop_privileges(
@@ -155,11 +152,11 @@ fn tokio_run_command(command: Command, server_connection: StdUnixStream) -> anyh
while let Some(Ok(message)) = message_stream.next().await {
match message {
Response::Error(err) => {
anyhow::bail!("{}", err);
anyhow::bail!("{err}");
}
Response::Ready => break,
message => {
eprintln!("Unexpected message from server: {:?}", message);
eprintln!("Unexpected message from server: {message:?}");
}
}
}
@@ -191,8 +188,8 @@ async fn create_user(
for (name, result) in result {
match result {
Ok(()) => println!("User '{}' created.", name),
Err(err) => handle_create_user_error(err, &name),
Ok(()) => println!("User '{name}' created."),
Err(err) => handle_create_user_error(&err, &name),
}
}
@@ -217,8 +214,8 @@ async fn drop_users(
for (name, result) in result {
match result {
Ok(()) => println!("User '{}' deleted.", name),
Err(err) => handle_drop_user_error(err, &name),
Ok(()) => println!("User '{name}' deleted."),
Err(err) => handle_drop_user_error(&err, &name),
}
}
@@ -248,7 +245,7 @@ async fn passwd_users(
.filter_map(|(name, result)| match result {
Ok(user) => Some(user),
Err(err) => {
handle_list_users_error(err, &name);
handle_list_users_error(&err, &name);
None
}
})
@@ -256,7 +253,7 @@ async fn passwd_users(
for user in users {
let password = read_password_from_stdin_with_double_check(&user.user)?;
let message = Request::PasswdUser((user.user.to_owned(), password));
let message = Request::PasswdUser((user.user.clone(), password));
server_connection.send(message).await?;
match server_connection.next().await {
Some(Ok(Response::SetUserPassword(result))) => match result {
@@ -292,7 +289,7 @@ async fn show_users(
Some(Ok(Response::ListAllUsers(result))) => match result {
Ok(users) => users,
Err(err) => {
eprintln!("Failed to list users: {:?}", err);
eprintln!("Failed to list users: {err:?}");
return Ok(());
}
},
@@ -301,7 +298,7 @@ async fn show_users(
.filter_map(|(name, result)| match result {
Ok(user) => Some(user),
Err(err) => {
handle_list_users_error(err, &name);
handle_list_users_error(&err, &name);
None
}
})