src/bin/dump-backup-api.rs: helper to generate backup API docs
This commit is contained in:
parent
5e0f305142
commit
22e5aa1d3e
@ -1,4 +1,8 @@
|
||||
use failure::*;
|
||||
|
||||
use std::io::Write;
|
||||
use crate::api_schema::*;
|
||||
use crate::api_schema::router::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ParameterDisplayStyle {
|
||||
@ -134,3 +138,158 @@ pub fn get_property_description(
|
||||
text
|
||||
}
|
||||
}
|
||||
|
||||
fn dump_api_parameters(param: &ObjectSchema) -> String {
|
||||
|
||||
let mut res = wrap_text("", "", param.description, 80);
|
||||
|
||||
let properties = ¶m.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(())
|
||||
}
|
||||
|
13
src/bin/dump-backup-api.rs
Normal file
13
src/bin/dump-backup-api.rs
Normal 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(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user