From 7554d8c61e8f0b38625d7e5e1624446bb4c997fc Mon Sep 17 00:00:00 2001 From: SomeRandomDeveloper Date: Mon, 26 Jan 2026 01:52:46 +0100 Subject: [PATCH 1/2] feat(rs): basic WIP farm module remove unused fix again fix refactor and fix --- rs/src/main.rs | 4 +++ rs/src/modules/db.rs | 10 +++++- rs/src/modules/farm.rs | 69 +++++++++++++++++++++++++++++++++++++++++ rs/src/modules/mod.rs | 1 + rs/src/modules/reset.rs | 28 +++++++++++++---- 5 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 rs/src/modules/farm.rs diff --git a/rs/src/main.rs b/rs/src/main.rs index e4bb621..aab1ad6 100644 --- a/rs/src/main.rs +++ b/rs/src/main.rs @@ -16,6 +16,7 @@ use crate::modules::sql::SqlArgs; use crate::types::RepoOrigin; use anyhow::bail; use clap::{CommandFactory, Parser, Subcommand}; +use crate::modules::farm::FarmArgs; use crate::modules::watch::WatchArgs; mod config; @@ -47,6 +48,8 @@ pub enum Modules { Db(DbArgs), /// Stops containers Down(ContainerActionArgs), + /// Allows managing a wiki farm + Farm(FarmArgs), /// Prints info about the environment Info, /// Runs a linter @@ -107,6 +110,7 @@ impl Modules { Modules::Composer(args) => modules::composer::execute(config.unwrap(), args), Modules::Db(args) => modules::db::execute(config.unwrap(), args), Modules::Down(args) => modules::container_action::down(config.unwrap(), args), + Modules::Farm(args) => modules::farm::execute(config.unwrap(), args), Modules::Info => modules::info::execute(config.unwrap()), Modules::Lint(args) => modules::lint::execute(config.unwrap(), args, true), Modules::ListRepoRemotes => modules::list_repo_remotes::execute(config.unwrap()), diff --git a/rs/src/modules/db.rs b/rs/src/modules/db.rs index b887192..d1792fc 100644 --- a/rs/src/modules/db.rs +++ b/rs/src/modules/db.rs @@ -154,13 +154,21 @@ pub fn delete_all_dumps(config: &MWUtilConfig) -> anyhow::Result<()> { } pub fn drop_mw_database(config: &MWUtilConfig) -> anyhow::Result<()> { + let db = &config.mw_database.clone().ok_or_else(|| anyhow!("MW database not set!"))?; + drop_database( + config, + db + ) +} + +pub fn drop_database(config: &MWUtilConfig, db: &str) -> anyhow::Result<()> { let status = run_sql_query( config, DbCommandUser::Root, Some(DbCommandDatabase::None), format!( "DROP DATABASE IF EXISTS `{}`;", - config.mw_database.clone().ok_or_else(|| anyhow!("MW database not set!"))? + db ).as_str(), ).context("Failed to drop database")?; if !status.success() { diff --git a/rs/src/modules/farm.rs b/rs/src/modules/farm.rs new file mode 100644 index 0000000..5459052 --- /dev/null +++ b/rs/src/modules/farm.rs @@ -0,0 +1,69 @@ +use anyhow::{anyhow, bail, Context}; +use clap::{Args, Subcommand}; +use crate::config::MWUtilConfig; +use crate::exec::{run_sql_query, DbCommandDatabase, DbCommandUser}; +use crate::modules::reset; + +#[derive(Args)] +pub struct FarmArgs { + #[command(subcommand)] + command: FarmCommand, +} + +#[derive(Subcommand)] +pub enum FarmCommand { + /// Install a new wiki + Install(InstallArgs), +} + +#[derive(Args)] +pub struct InstallArgs { + /// The DB name of the wiki that should be installed + db_name: String, +} + +pub fn execute(config: &MWUtilConfig, farm_args: FarmArgs) -> anyhow::Result<()> { + match farm_args.command { + FarmCommand::Install(args) => install_wiki(config, args), + } +} + +fn install_wiki(config: &MWUtilConfig, args: InstallArgs) -> anyhow::Result<()> { + if !args.db_name.ends_with("wiki") { + // TODO maybe we want to allow other suffixes? + bail!("The DB name must end with 'wiki'!"); + } + + let status = run_sql_query( + config, + DbCommandUser::Root, + Some(DbCommandDatabase::None), + format!( + "CREATE DATABASE IF NOT EXISTS `{}`;", + args.db_name, + ).as_str() + ).context("Failed to create database")?; + if !status.success() { + bail!("Failed to create database! Exit code: {:?}", status.code()); + } + + let status = run_sql_query( + config, + DbCommandUser::Root, + Some(DbCommandDatabase::None), + format!( + "GRANT ALL PRIVILEGES ON `{}`.* TO {};", + args.db_name, + config.db_user.clone().ok_or_else(|| anyhow!("DB User not set!"))? + ).as_str() + ).context("Failed to grant privileges")?; + if !status.success() { + bail!("Failed to grant privileges! Exit code: {:?}", status.code()); + } + + println!("Created database."); + + reset::reset_database(config, &args.db_name, true)?; + + Ok(()) +} \ No newline at end of file diff --git a/rs/src/modules/mod.rs b/rs/src/modules/mod.rs index 837f23a..57702d0 100644 --- a/rs/src/modules/mod.rs +++ b/rs/src/modules/mod.rs @@ -15,3 +15,4 @@ pub(crate) mod reset; pub(crate) mod container_action; pub(crate) mod setup_repo; pub(crate) mod watch; +pub(crate) mod farm; diff --git a/rs/src/modules/reset.rs b/rs/src/modules/reset.rs index d21862d..3f7a64d 100644 --- a/rs/src/modules/reset.rs +++ b/rs/src/modules/reset.rs @@ -39,7 +39,7 @@ pub fn execute(config: &MWUtilConfig, args: ResetArgs) -> anyhow::Result<()> { } if actions.contains(&ResetActions::Database) { spinner.next("Resetting database"); - reset_database(config)?; + reset_default_database(config)?; } if actions.contains(&ResetActions::OpenSearch) { spinner.next("Resetting OpenSearch"); @@ -72,15 +72,25 @@ pub fn reset_uploads(config: &MWUtilConfig) -> anyhow::Result<()> { Ok(()) } -pub fn reset_database(config: &MWUtilConfig) -> anyhow::Result<()> { - db::drop_mw_database(config)?; +pub fn reset_default_database(config: &MWUtilConfig) -> anyhow::Result<()> { + reset_database( + config, + &config.mw_database.clone().ok_or_else(|| anyhow!("MW database not set!"))?, + false + ) +} + +pub fn reset_database(config: &MWUtilConfig, db: &str, new: bool) -> anyhow::Result<()> { + if !new { + db::drop_database(config, db)?; + } let local_settings = config.core_dir.join("LocalSettings.php"); let local_settings_tmp = config.core_dir.join("LocalSettings.temp.php"); fs::rename(&local_settings, &local_settings_tmp)?; let install_args = vec![ - format!("--dbname={}", config.mw_database.clone().ok_or_else(|| anyhow!("MW Database not set!"))?), + format!("--dbname={}", db), format!("--dbuser={}", config.db_user.clone().ok_or_else(|| anyhow!("DB User not set!"))?), format!("--dbpass={}", config.db_password.clone().ok_or_else(|| anyhow!("DB Password not set!"))?), format!("--dbserver={}", config.db_type.clone().get_container_name()), @@ -101,8 +111,14 @@ pub fn reset_database(config: &MWUtilConfig) -> anyhow::Result<()> { result?; - Modules::Update.run(config)?; - Modules::Recreate(Default::default()).run(config)?; + Modules::Run(RunArgs { + script: "update".into(), + extra_args: vec!["--wiki".into(), db.into(), "--quick".into()], + }).run(config)?; + + if !new { + Modules::Recreate(Default::default()).run(config)?; + } Ok(()) } From c116a8b1a7504778ae690b13bc6301a93f1b2489 Mon Sep 17 00:00:00 2001 From: SomeRandomDeveloper Date: Wed, 11 Mar 2026 01:29:44 +0100 Subject: [PATCH 2/2] docs: add installation instructions --- rs/README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/rs/README.md b/rs/README.md index 314ccfd..48fc1a6 100644 --- a/rs/README.md +++ b/rs/README.md @@ -1,4 +1,19 @@ # mwutil-rs -This is a rewrite of mwutil in rust. It aims to heavily improve the performance and stability of the tool, and will -replace the python version at some point. +This is a rewrite of mwutil in rust. It aims to heavily improve the performance and stability of the tool and replaces +the python version. + +## Installation + +0. Set up cargo (no, not the MediaWiki extension) if you haven't yet +1. Clone this repository +2. `cd rs` +3. `cargo install --path . --profile release` + +Try running `mwutil` in a new shell. + + +If the command wasn't found, maybe you didn't add Cargo to the PATH? +```shell +export PATH="$PATH:$HOME/.cargo/bin" +```