src/bin/dump-backup-api.rs: helper to generate backup API docs

This commit is contained in:
Dietmar Maurer 2019-06-04 13:12:42 +02:00
parent 5e0f305142
commit 22e5aa1d3e
2 changed files with 172 additions and 0 deletions

View File

@ -1,4 +1,8 @@
use failure::*;
use std::io::Write;
use crate::api_schema::*; use crate::api_schema::*;
use crate::api_schema::router::*;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum ParameterDisplayStyle { pub enum ParameterDisplayStyle {
@ -134,3 +138,158 @@ pub fn get_property_description(
text text
} }
} }
fn dump_api_parameters(param: &ObjectSchema) -> String {
let mut res = wrap_text("", "", param.description, 80);
let properties = &param.properties;
let mut prop_names: Vec<&str> = properties.keys().map(|v| *v).collect();
prop_names.sort();
let mut required_list: Vec<String> = vec![];
let mut optional_list: Vec<String> = vec![];
for prop in prop_names {
let (optional, schema) = properties.get(prop).unwrap();
let param_descr = get_property_description(
prop, &schema, ParameterDisplayStyle::Config, DocumentationFormat::ReST);
if *optional {
optional_list.push(param_descr);
} else {
required_list.push(param_descr);
}
}
if required_list.len() > 0 {
res.push_str("\n*Required properties:*\n\n");
for text in required_list {
res.push_str(&text);
res.push('\n');
}
}
if optional_list.len() > 0 {
res.push_str("\n*Optional properties:*\n\n");
for text in optional_list {
res.push_str(&text);
res.push('\n');
}
}
res
}
fn dump_api_return_schema(schema: &Schema) -> String {
let mut res = String::from("*Returns*: ");
let type_text = get_schema_type_text(schema, ParameterDisplayStyle::Config);
res.push_str(&format!("**{}**\n\n", type_text));
match schema {
Schema::Null => {
return res;
}
Schema::Boolean(schema) => {
let description = wrap_text("", "", schema.description, 80);
res.push_str(&description);
}
Schema::Integer(schema) => {
let description = wrap_text("", "", schema.description, 80);
res.push_str(&description);
}
Schema::String(schema) => {
let description = wrap_text("", "", schema.description, 80);
res.push_str(&description);
}
Schema::Array(schema) => {
let description = wrap_text("", "", schema.description, 80);
res.push_str(&description);
}
Schema::Object(obj_schema) => {
res.push_str(&dump_api_parameters(obj_schema));
}
}
res.push('\n');
res
}
fn dump_method_definition(method: &str, path: &str, def: &MethodDefinition) -> Option<String> {
match def {
MethodDefinition::None => return None,
MethodDefinition::Simple(simple_method) => {
let param_descr = dump_api_parameters(&simple_method.parameters);
let return_descr = dump_api_return_schema(&simple_method.returns);
let res = format!("**{} {}**\n\n{}\n\n{}", method, path, param_descr, return_descr);
return Some(res);
}
MethodDefinition::Async(async_method) => {
let method = if method == "POST" { "UPLOAD" } else { method };
let method = if method == "GET" { "DOWNLOAD" } else { method };
let param_descr = dump_api_parameters(&async_method.parameters);
let return_descr = dump_api_return_schema(&async_method.returns);
let res = format!("**{} {}**\n\n{}\n\n{}", method, path, param_descr, return_descr);
return Some(res);
}
}
}
pub fn dump_api(output: &mut dyn Write, router: &Router, path: &str, mut pos: usize) -> Result<(), Error> {
let mut cond_print = |x| -> Result<_, Error> {
if let Some(text) = x {
if pos > 0 {
writeln!(output, "-----\n")?;
}
writeln!(output, "{}", text)?;
pos += 1;
}
Ok(())
};
cond_print(dump_method_definition("GET", path, &router.get))?;
cond_print(dump_method_definition("POST", path, &router.post))?;
cond_print(dump_method_definition("PUT", path, &router.put))?;
cond_print(dump_method_definition("DELETE", path, &router.delete))?;
match &router.subroute {
SubRoute::None => return Ok(()),
SubRoute::MatchAll { router, param_name } => {
let sub_path = if path == "." {
format!("<{}>", param_name)
} else {
format!("{}/<{}>", path, param_name)
};
dump_api(output, router, &sub_path, pos)?;
}
SubRoute::Hash(map) => {
let mut keys: Vec<&String> = map.keys().collect();
keys.sort_unstable_by(|a, b| a.cmp(b));
for key in keys {
let sub_router = &map[key];
let sub_path = if path == "." { key.to_owned() } else { format!("{}/{}", path, key) };
dump_api(output, sub_router, &sub_path, pos)?;
}
}
}
Ok(())
}

View File

@ -0,0 +1,13 @@
use failure::*;
use proxmox_backup::api2;
use proxmox_backup::api_schema::format::*;
fn main() -> Result<(), Error> {
let api = api2::admin::datastore::backup::backup_api();
dump_api(&mut std::io::stdout(), &api, ".", 0)?;
Ok(())
}