diff --git a/Cargo.lock b/Cargo.lock
index 5be10f14..ae385fe6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -269,6 +269,33 @@ dependencies = [
"libloading",
]
+[[package]]
+name = "clap"
+version = "3.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
+dependencies = [
+ "bitflags",
+ "clap_derive",
+ "indexmap",
+ "lazy_static",
+ "os_str_bytes",
+ "textwrap",
+]
+
+[[package]]
+name = "clap_derive"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153"
+dependencies = [
+ "heck 0.4.0",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "color_quant"
version = "1.1.0"
@@ -281,6 +308,7 @@ version = "0.2.0"
dependencies = [
"base64 0.13.0",
"bytes",
+ "clap",
"crossbeam",
"directories",
"heed",
@@ -630,7 +658,7 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595"
dependencies = [
- "heck",
+ "heck 0.3.3",
"proc-macro2",
"quote",
"syn",
@@ -902,6 +930,12 @@ dependencies = [
"unicode-segmentation",
]
+[[package]]
+name = "heck"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
+
[[package]]
name = "heed"
version = "0.10.6"
@@ -1570,6 +1604,15 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "os_str_bytes"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "page_size"
version = "0.4.2"
@@ -1728,6 +1771,30 @@ dependencies = [
"toml",
]
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
@@ -2863,6 +2930,12 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "textwrap"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
+
[[package]]
name = "thiserror"
version = "1.0.30"
diff --git a/Cargo.toml b/Cargo.toml
index 9a2d2fdb..3f8677d6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -86,8 +86,7 @@ thread_local = "1.1.3"
hmac = "0.11.0"
sha-1 = "0.9.8"
# used for conduit's CLI and admin room command parsing
-structopt = { version = "0.3.25", default-features = false }
-pulldown-cmark = "0.9.1"
+clap = { version = "3.0.10", default-features = false, features = ["std", "derive"] }
[features]
default = ["conduit_bin", "backend_sqlite", "backend_rocksdb"]
diff --git a/src/database/admin.rs b/src/database/admin.rs
index 362ef294..59b8acdf 100644
--- a/src/database/admin.rs
+++ b/src/database/admin.rs
@@ -5,6 +5,7 @@ use crate::{
pdu::PduBuilder,
server_server, Database, PduEvent,
};
+use clap::Parser;
use regex::Regex;
use rocket::{
futures::{channel::mpsc, stream::StreamExt},
@@ -15,7 +16,6 @@ use ruma::{
EventId, RoomId, RoomVersionId, UserId,
};
use serde_json::value::to_raw_value;
-use structopt::StructOpt;
use tokio::sync::{MutexGuard, RwLock, RwLockReadGuard};
use tracing::warn;
@@ -155,7 +155,7 @@ pub fn parse_admin_command(db: &Database, command_line: &str, body: Vec<&str>) -
Some(command) => *command,
None => {
let markdown_message = "No command given. Use `help` for a list of commands.";
- let html_message = markdown_to_html(&markdown_message);
+ let html_message = "No command given. Use help
for a list of commands.";
return AdminCommand::SendMessage(RoomMessageEventContent::text_html(
markdown_message,
@@ -164,10 +164,17 @@ pub fn parse_admin_command(db: &Database, command_line: &str, body: Vec<&str>) -
}
};
+ // Replace `help command` with `command --help`
+ // Clap has a help subcommand, but it omits the long help description.
+ if argv[0] == "help" {
+ argv.remove(0);
+ argv.push("--help");
+ }
+
// Backwards compatibility with `register_appservice`-style commands
let command_with_dashes;
- if command_line.contains("_") {
- command_with_dashes = command_name.replace("_", "-");
+ if argv[0].contains("_") {
+ command_with_dashes = argv[0].replace("_", "-");
argv[0] = &command_with_dashes;
}
@@ -179,7 +186,11 @@ pub fn parse_admin_command(db: &Database, command_line: &str, body: Vec<&str>) -
```\n{}\n```",
command_name, error,
);
- let html_message = markdown_to_html(&markdown_message);
+ let html_message = format!(
+ "Encountered an error while handling the {}
command:\n\
+
\n{}\n", + command_name, error, + ); AdminCommand::SendMessage(RoomMessageEventContent::text_html( markdown_message, @@ -189,9 +200,10 @@ pub fn parse_admin_command(db: &Database, command_line: &str, body: Vec<&str>) - } } -#[derive(StructOpt)] +#[derive(Parser)] +#[clap(name = "@conduit:example.com", version = env!("CARGO_PKG_VERSION"))] enum AdminCommands { - #[structopt(verbatim_doc_comment)] + #[clap(verbatim_doc_comment)] /// Register an appservice using its registration YAML /// /// This command needs a YAML generated by an appservice (such as a bridge), @@ -200,25 +212,25 @@ enum AdminCommands { /// Registering a new bridge using the ID of an existing bridge will replace /// the old one. /// - /// Example: - /// ```` - /// @conduit:example.com: register-appservice - /// ``` - /// yaml content here - /// ``` - /// ```` + /// [add-yaml-block-to-usage] RegisterAppservice, /// Unregister an appservice using its ID - /// + /// /// You can find the ID using the `list-appservices` command. - UnregisterAppservice { appservice_identifier: String }, + UnregisterAppservice { + /// The appservice to unregister + appservice_identifier: String, + }, /// List all the currently registered appservices ListAppservices, /// Get the auth_chain of a PDU - GetAuthChain { event_id: Box
-V, --version
: Prints version information
// (?m) enables multi-line mode for ^ and $
- let re = Regex::new("(?m)^ ([a-z-]+) +(.*)$").expect("Regex compilation should not fail");
- let text = re.replace_all(&text, " `$1`: $2");
+ let re = Regex::new("(?m)^ (([a-zA-Z_&;-]+(, )?)+) +(.*)$")
+ .expect("Regex compilation should not fail");
+ let text = re.replace_all(&text, "$1
: $4");
- // Add * to list items
- let re = Regex::new("(?m)^ (.*)$").expect("Regex compilation should not fail");
- let text = re.replace_all(&text, "* $1");
+ // // Enclose examples in code blocks
+ // // (?ms) enables multi-line mode and dot-matches-all
+ // let re =
+ // Regex::new("(?ms)^Example:\n(.*?)\nUSAGE:$").expect("Regex compilation should not fail");
+ // let text = re.replace_all(&text, "EXAMPLE:\n$1\nUSAGE:"); - // Turn section names to headings - let re = Regex::new("(?m)^([A-Z-]+):$").expect("Regex compilation should not fail"); - let text = re.replace_all(&text, "#### $1"); + let has_yaml_block_marker = text.contains("\n[add-yaml-block-to-usage]\n"); + let text = text.replace("\n[add-yaml-block-to-usage]\n", ""); + + // Add HTML line-breaks + let text = text.replace("\n", "
$1
$1\n```\nyaml content here\n```", + ) + }; text.to_string() } - -// Convert markdown to HTML using the CommonMark flavor -fn markdown_to_html(text: &str) -> String { - // CommonMark's spec allows HTML tags; however, CLI required arguments look - // very much like tags so escape them. - let text = text.replace("<", "<").replace(">", ">"); - - let mut html_output = String::new(); - - let parser = pulldown_cmark::Parser::new(&text); - pulldown_cmark::html::push_html(&mut html_output, parser); - - html_output -}