diff --git a/dsc/src/args.rs b/dsc/src/args.rs index 31a3627fd..01b8027b6 100644 --- a/dsc/src/args.rs +++ b/dsc/src/args.rs @@ -15,6 +15,14 @@ pub enum OutputFormat { Yaml, } +#[derive(Debug, Clone, PartialEq, Eq, ValueEnum)] +pub enum ListOutputFormat { + Json, + PrettyJson, + Yaml, + TableNoTruncate, +} + #[derive(Debug, Clone, PartialEq, Eq, ValueEnum, Deserialize)] pub enum TraceFormat { Default, @@ -156,7 +164,7 @@ pub enum ExtensionSubCommand { /// Optional filter to apply to the list of extensions extension_name: Option, #[clap(short = 'o', long, help = t!("args.outputFormat").to_string())] - output_format: Option, + output_format: Option, }, } @@ -174,7 +182,7 @@ pub enum ResourceSubCommand { #[clap(short, long, help = t!("args.tags").to_string())] tags: Option>, #[clap(short = 'o', long, help = t!("args.outputFormat").to_string())] - output_format: Option, + output_format: Option, }, #[clap(name = "get", about = t!("args.resourceGet").to_string(), arg_required_else_help = true)] Get { diff --git a/dsc/src/subcommand.rs b/dsc/src/subcommand.rs index c52a1ed28..f568adaee 100644 --- a/dsc/src/subcommand.rs +++ b/dsc/src/subcommand.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -use crate::args::{ConfigSubCommand, DscType, ExtensionSubCommand, OutputFormat, ResourceSubCommand}; +use crate::args::{ConfigSubCommand, DscType, ExtensionSubCommand, ListOutputFormat, OutputFormat, ResourceSubCommand}; use crate::resolve::{get_contents, Include}; use crate::resource_command::{get_resource, self}; use crate::tablewriter::Table; @@ -611,7 +611,7 @@ pub fn resource(subcommand: &ResourceSubCommand, progress_format: ProgressFormat } } -fn list_extensions(dsc: &mut DscManager, extension_name: Option<&String>, format: Option<&OutputFormat>, progress_format: ProgressFormat) { +fn list_extensions(dsc: &mut DscManager, extension_name: Option<&String>, format: Option<&ListOutputFormat>, progress_format: ProgressFormat) { let mut write_table = false; let mut table = Table::new(&[ t!("subcommand.tableHeader_type").to_string().as_ref(), @@ -654,7 +654,13 @@ fn list_extensions(dsc: &mut DscManager, extension_name: Option<&String>, format exit(EXIT_JSON_ERROR); } }; - write_object(&json, format, include_separator); + let format = match format { + Some(ListOutputFormat::Json) => Some(OutputFormat::Json), + Some(ListOutputFormat::PrettyJson) => Some(OutputFormat::PrettyJson), + Some(ListOutputFormat::Yaml) => Some(OutputFormat::Yaml), + _ => None, + }; + write_object(&json, format.as_ref(), include_separator); include_separator = true; // insert newline separating instances if writing to console if io::stdout().is_terminal() { println!(); } @@ -663,11 +669,12 @@ fn list_extensions(dsc: &mut DscManager, extension_name: Option<&String>, format } if write_table { - table.print(); + let truncate = format != Some(&ListOutputFormat::TableNoTruncate); + table.print(truncate); } } -fn list_resources(dsc: &mut DscManager, resource_name: Option<&String>, adapter_name: Option<&String>, description: Option<&String>, tags: Option<&Vec>, format: Option<&OutputFormat>, progress_format: ProgressFormat) { +fn list_resources(dsc: &mut DscManager, resource_name: Option<&String>, adapter_name: Option<&String>, description: Option<&String>, tags: Option<&Vec>, format: Option<&ListOutputFormat>, progress_format: ProgressFormat) { let mut write_table = false; let mut table = Table::new(&[ t!("subcommand.tableHeader_type").to_string().as_ref(), @@ -677,7 +684,7 @@ fn list_resources(dsc: &mut DscManager, resource_name: Option<&String>, adapter_ t!("subcommand.tableHeader_adapter").to_string().as_ref(), t!("subcommand.tableHeader_description").to_string().as_ref(), ]); - if format.is_none() && io::stdout().is_terminal() { + if format == Some(&ListOutputFormat::TableNoTruncate) || (format.is_none() && io::stdout().is_terminal()) { // write as table if format is not specified and interactive write_table = true; } @@ -759,7 +766,13 @@ fn list_resources(dsc: &mut DscManager, resource_name: Option<&String>, adapter_ exit(EXIT_JSON_ERROR); } }; - write_object(&json, format, include_separator); + let format = match format { + Some(ListOutputFormat::Json) => Some(OutputFormat::Json), + Some(ListOutputFormat::PrettyJson) => Some(OutputFormat::PrettyJson), + Some(ListOutputFormat::Yaml) => Some(OutputFormat::Yaml), + _ => None, + }; + write_object(&json, format.as_ref(), include_separator); include_separator = true; // insert newline separating instances if writing to console if io::stdout().is_terminal() { println!(); } @@ -768,6 +781,7 @@ fn list_resources(dsc: &mut DscManager, resource_name: Option<&String>, adapter_ } if write_table { - table.print(); + let truncate = format != Some(&ListOutputFormat::TableNoTruncate); + table.print(truncate); } } diff --git a/dsc/src/tablewriter.rs b/dsc/src/tablewriter.rs index 46696ea05..a9c6ce662 100644 --- a/dsc/src/tablewriter.rs +++ b/dsc/src/tablewriter.rs @@ -48,8 +48,12 @@ impl Table { } /// Print the table to the console. + /// + /// # Arguments + /// + /// * `truncate` - Whether to truncate the table if it is too wide for the console #[allow(clippy::format_push_string)] - pub fn print(&self) { + pub fn print(&self, truncate: bool) { let (width, _) = size().unwrap_or((80, 25)); // make header bright green println!("\x1b[1;32m"); @@ -62,7 +66,7 @@ impl Table { } } // if header row is too wide, truncate - if header_row.len() > width as usize { + if truncate && header_row.len() > width as usize { header_row.truncate(width as usize); } @@ -80,7 +84,7 @@ impl Table { } // if row is too wide and last character is not a space, truncate and add ellipsis unicode character - if row_str.len() > width as usize { + if truncate && row_str.len() > width as usize { row_str.truncate(width as usize); if !row_str.ends_with(' ') { row_str.pop(); diff --git a/dsc/tests/dsc_extension_discover.tests.ps1 b/dsc/tests/dsc_extension_discover.tests.ps1 index 5428e3b9c..ff5f92044 100644 --- a/dsc/tests/dsc_extension_discover.tests.ps1 +++ b/dsc/tests/dsc_extension_discover.tests.ps1 @@ -90,4 +90,16 @@ Describe 'Discover extension tests' { $env:DSC_RESOURCE_PATH = $null } } + + It 'Table can be not truncated' { + $output = dsc extension list --output-format table-no-truncate + $LASTEXITCODE | Should -Be 0 + $foundWideLine = $false + foreach ($line in $output) { + if ($line.Length -gt [Console]::WindowWidth) { + $foundWideLine = $true + } + } + $foundWideLine | Should -BeTrue + } } diff --git a/dsc/tests/dsc_resource_list.tests.ps1 b/dsc/tests/dsc_resource_list.tests.ps1 index df9be7a4a..db90fdc45 100644 --- a/dsc/tests/dsc_resource_list.tests.ps1 +++ b/dsc/tests/dsc_resource_list.tests.ps1 @@ -88,4 +88,17 @@ Describe 'Tests for listing resources' { $LASTEXITCODE | Should -Be 0 $out | Should -BeLike "*ERROR*Adapter not found: foo`*" } + + It 'Table is not truncated' { + $output = dsc resource list --output-format table-no-truncate + $LASTEXITCODE | Should -Be 0 + $foundWideLine = $false + foreach ($line in $output) { + if ($line.Length -gt [Console]::WindowWidth) { + $foundWideLine = $true + break + } + } + $foundWideLine | Should -BeTrue + } } diff --git a/extensions/test/discover/testDiscover.dsc.extension.json b/extensions/test/discover/testDiscover.dsc.extension.json index 2a8db3809..28de7bd0c 100644 --- a/extensions/test/discover/testDiscover.dsc.extension.json +++ b/extensions/test/discover/testDiscover.dsc.extension.json @@ -2,7 +2,7 @@ "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", "type": "Test/Discover", "version": "0.1.0", - "description": "Test discover resource", + "description": "Test discover resource, this is a really long description to test that the table can be rendered without truncating the description text from this extension.", "discover": { "executable": "pwsh", "args": [