From: Wolfgang Bumiller Date: Fri, 17 Mar 2023 14:44:45 +0000 (+0100) Subject: router: OneOfSchema support X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=ae7454b05e3a585c88deb1c69afeacfa1ef99724;p=proxmox.git router: OneOfSchema support Signed-off-by: Wolfgang Bumiller Reviewed-by: Lukas Wagner --- diff --git a/proxmox-router/src/cli/text_table.rs b/proxmox-router/src/cli/text_table.rs index 9bc7210e..ea50b04b 100644 --- a/proxmox-router/src/cli/text_table.rs +++ b/proxmox-router/src/cli/text_table.rs @@ -1,11 +1,11 @@ use std::io::Write; -use anyhow::{bail, Error}; +use anyhow::{bail, format_err, Error}; use serde_json::Value; use unicode_width::UnicodeWidthStr; use proxmox_lang::c_str; -use proxmox_schema::{ObjectSchemaType, Schema, SchemaPropertyEntry}; +use proxmox_schema::{ObjectSchemaType, OneOfSchema, Schema, SchemaPropertyEntry}; /// allows to configure the default output fromat using environment vars pub const ENV_VAR_PROXMOX_OUTPUT_FORMAT: &str = "PROXMOX_OUTPUT_FORMAT"; @@ -66,10 +66,9 @@ fn data_to_text(data: &Value, schema: &Schema) -> Result { } match schema { - Schema::Null => { - // makes no sense to display Null columns - bail!("internal error"); - } + // When printing a table of OneOf values, different variants have different properties, and + // nonexistent properties will be null. + Schema::Null => Ok(String::new()), Schema::Boolean(_) => match data.as_bool() { Some(value) => Ok(String::from(if value { "1" } else { "0" })), None => bail!("got unexpected data (expected bool)."), @@ -89,6 +88,7 @@ fn data_to_text(data: &Value, schema: &Schema) -> Result { Schema::Object(_) => Ok(data.to_string()), Schema::Array(_) => Ok(data.to_string()), Schema::AllOf(_) => Ok(data.to_string()), + Schema::OneOf(_) => Ok(data.to_string()), } } @@ -620,6 +620,16 @@ fn format_object( .collect() }; + format_object_with_properties(output, data, schema, options, properties_to_print) +} + +fn format_object_with_properties( + output: W, + data: &Value, + schema: &dyn ObjectSchemaType, + options: &TableFormatOptions, + properties_to_print: Vec, +) -> Result<(), Error> { let row_count = properties_to_print.len(); if row_count == 0 { return Ok(()); @@ -723,6 +733,25 @@ fn format_object( render_table(output, &tabledata, &column_names, options) } +fn format_one_of( + output: W, + data: &Value, + schema: &OneOfSchema, + options: &TableFormatOptions, +) -> Result<(), Error> { + let properties_to_print = if options.column_config.is_empty() { + extract_one_of_variant_properties(data, schema)? + } else { + options + .column_config + .iter() + .map(|v| v.name.clone()) + .collect() + }; + + format_object_with_properties(output, data, schema, options, properties_to_print) +} + fn extract_properties_to_print(properties: I) -> Vec where I: Iterator, @@ -743,6 +772,21 @@ where result } +fn extract_one_of_variant_properties( + value: &Value, + schema: &OneOfSchema, +) -> Result, Error> { + let variant_name = value[schema.type_property()] + .as_str() + .ok_or_else(|| format_err!("missing '{}' property", schema.type_property()))?; + let variant_schema = schema + .lookup_variant(variant_name) + .ok_or_else(|| format_err!("invalid variant '{variant_name}'"))?; + Ok(extract_properties_to_print( + variant_schema.unwrap_object_schema().properties(), + )) +} + /// Format data using TableFormatOptions pub fn value_to_text( output: W, @@ -768,8 +812,8 @@ pub fn value_to_text( Schema::String(_string_schema) => { unimplemented!(); } - Schema::Object(object_schema) => { - format_object(output, data, object_schema, options)?; + Schema::Object(schema) => { + format_object(output, data, schema, options)?; } Schema::Array(array_schema) => { let list = match data.as_array_mut() { @@ -781,19 +825,25 @@ pub fn value_to_text( } match array_schema.items { - Schema::Object(object_schema) => { - format_table(output, list, object_schema, options)?; + Schema::Object(schema) => { + format_table(output, list, schema, options)?; + } + Schema::AllOf(schema) => { + format_table(output, list, schema, options)?; } - Schema::AllOf(all_of_schema) => { - format_table(output, list, all_of_schema, options)?; + Schema::OneOf(schema) => { + format_table(output, list, schema, options)?; } _ => { unimplemented!(); } } } - Schema::AllOf(all_of_schema) => { - format_object(output, data, all_of_schema, options)?; + Schema::AllOf(schema) => { + format_object(output, data, schema, options)?; + } + Schema::OneOf(schema) => { + format_one_of(output, data, schema, options)?; } } Ok(())