Skip to content

Commit

Permalink
Merge pull request #614 from anmenaga/issue_592
Browse files Browse the repository at this point in the history
Support writing progress as JSON
  • Loading branch information
SteveL-MSFT authored Jan 31, 2025
2 parents ea93e04 + cbc0d54 commit 481f758
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 62 deletions.
1 change: 1 addition & 0 deletions dsc/locales/en-us.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ _version = 1
about = "Apply configuration or invoke specific DSC resources"
traceFormat = "Trace format to use"
traceLevel = "Trace level to use"
progressFormat = "Progress format to use"
completer = "Generate a shell completion script"
configAbout = "Apply a configuration document"
parameters = "Parameters to pass to the configuration as JSON or YAML"
Expand Down
3 changes: 3 additions & 0 deletions dsc/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use clap::{Parser, Subcommand, ValueEnum};
use clap_complete::Shell;
use dsc_lib::dscresources::command_resource::TraceLevel;
use dsc_lib::util::ProgressFormat;
use rust_i18n::t;
use serde::Deserialize;

Expand Down Expand Up @@ -33,6 +34,8 @@ pub struct Args {
pub trace_level: Option<TraceLevel>,
#[clap(short = 't', long, help = t!("args.traceFormat").to_string(), value_enum)]
pub trace_format: Option<TraceFormat>,
#[clap(short = 'p', long, help = t!("args.progressFormat").to_string(), value_enum)]
pub progress_format: Option<ProgressFormat>,
}

#[derive(Debug, PartialEq, Eq, Subcommand)]
Expand Down
9 changes: 6 additions & 3 deletions dsc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use rust_i18n::{i18n, t};
use std::{io, process::exit};
use sysinfo::{Process, RefreshKind, System, get_current_pid, ProcessRefreshKind};
use tracing::{error, info, warn, debug};
use dsc_lib::util::ProgressFormat;

#[cfg(debug_assertions)]
use crossterm::event;
Expand Down Expand Up @@ -40,6 +41,8 @@ fn main() {

debug!("{}: {}", t!("main.usingDscVersion"), env!("CARGO_PKG_VERSION"));

let progress_format = args.progress_format.unwrap_or( ProgressFormat::Default );

match args.subcommand {
SubCommand::Completer { shell } => {
info!("{} {:?}", t!("main.generatingCompleter"), shell);
Expand All @@ -50,19 +53,19 @@ fn main() {
if let Some(file_name) = parameters_file {
info!("{}: {file_name}", t!("main.readingParametersFile"));
match std::fs::read_to_string(&file_name) {
Ok(parameters) => subcommand::config(&subcommand, &Some(parameters), system_root.as_ref(), &as_group, &as_include),
Ok(parameters) => subcommand::config(&subcommand, &Some(parameters), system_root.as_ref(), &as_group, &as_include, progress_format),
Err(err) => {
error!("{} '{file_name}': {err}", t!("main.failedToReadParametersFile"));
exit(util::EXIT_INVALID_INPUT);
}
}
}
else {
subcommand::config(&subcommand, &parameters, system_root.as_ref(), &as_group, &as_include);
subcommand::config(&subcommand, &parameters, system_root.as_ref(), &as_group, &as_include, progress_format);
}
},
SubCommand::Resource { subcommand } => {
subcommand::resource(&subcommand);
subcommand::resource(&subcommand, progress_format);
},
SubCommand::Schema { dsc_type , output_format } => {
let schema = util::get_schema(dsc_type);
Expand Down
31 changes: 17 additions & 14 deletions dsc/src/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use dsc_lib::{
},
dscresources::dscresource::{Capability, ImplementedAs, Invoke},
dscresources::resource_manifest::{import_manifest, ResourceManifest},
util::ProgressFormat,
};
use rust_i18n::t;
use std::{
Expand Down Expand Up @@ -251,7 +252,7 @@ fn initialize_config_root(path: Option<&String>) -> Option<String> {
}

#[allow(clippy::too_many_lines)]
pub fn config(subcommand: &ConfigSubCommand, parameters: &Option<String>, mounted_path: Option<&String>, as_group: &bool, as_include: &bool) {
pub fn config(subcommand: &ConfigSubCommand, parameters: &Option<String>, mounted_path: Option<&String>, as_group: &bool, as_include: &bool, progress_format: ProgressFormat) {
let (new_parameters, json_string) = match subcommand {
ConfigSubCommand::Get { input, file, .. } |
ConfigSubCommand::Set { input, file, .. } |
Expand Down Expand Up @@ -295,6 +296,8 @@ pub fn config(subcommand: &ConfigSubCommand, parameters: &Option<String>, mounte
}
};

configurator.set_progress_format(progress_format);

if let ConfigSubCommand::Set { what_if , .. } = subcommand {
if *what_if {
configurator.context.execution_type = ExecutionKind::WhatIf;
Expand Down Expand Up @@ -382,7 +385,7 @@ pub fn config(subcommand: &ConfigSubCommand, parameters: &Option<String>, mounte
}
}
} else {
match validate_config(configurator.get_config()) {
match validate_config(configurator.get_config(), progress_format) {
Ok(()) => {
// valid, so do nothing
},
Expand Down Expand Up @@ -450,7 +453,7 @@ pub fn config(subcommand: &ConfigSubCommand, parameters: &Option<String>, mounte
/// # Errors
///
/// * `DscError` - The error that occurred.
pub fn validate_config(config: &Configuration) -> Result<(), DscError> {
pub fn validate_config(config: &Configuration, progress_format: ProgressFormat) -> Result<(), DscError> {
// first validate against the config schema
debug!("{}", t!("subcommand.validatingConfiguration"));
let schema = serde_json::to_value(get_schema(DscType::Configuration))?;
Expand All @@ -476,7 +479,7 @@ pub fn validate_config(config: &Configuration) -> Result<(), DscError> {

resource_types.push(type_name.to_lowercase().to_string());
}
dsc.find_resources(&resource_types);
dsc.find_resources(&resource_types, progress_format);

for resource_block in resources {
let Some(type_name) = resource_block["type"].as_str() else {
Expand Down Expand Up @@ -527,7 +530,7 @@ pub fn validate_config(config: &Configuration) -> Result<(), DscError> {
}

#[allow(clippy::too_many_lines)]
pub fn resource(subcommand: &ResourceSubCommand) {
pub fn resource(subcommand: &ResourceSubCommand, progress_format: ProgressFormat) {
let mut dsc = match DscManager::new() {
Ok(dsc) => dsc,
Err(err) => {
Expand All @@ -538,43 +541,43 @@ pub fn resource(subcommand: &ResourceSubCommand) {

match subcommand {
ResourceSubCommand::List { resource_name, adapter_name, description, tags, output_format } => {
list_resources(&mut dsc, resource_name.as_ref(), adapter_name.as_ref(), description.as_ref(), tags.as_ref(), output_format.as_ref());
list_resources(&mut dsc, resource_name.as_ref(), adapter_name.as_ref(), description.as_ref(), tags.as_ref(), output_format.as_ref(), progress_format);
},
ResourceSubCommand::Schema { resource , output_format } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[resource.to_string()], progress_format);
resource_command::schema(&dsc, resource, output_format.as_ref());
},
ResourceSubCommand::Export { resource, output_format } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[resource.to_string()], progress_format);
resource_command::export(&mut dsc, resource, output_format.as_ref());
},
ResourceSubCommand::Get { resource, input, file: path, all, output_format } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[resource.to_string()], progress_format);
if *all { resource_command::get_all(&dsc, resource, output_format.as_ref()); }
else {
let parsed_input = get_input(input.as_ref(), path.as_ref());
resource_command::get(&dsc, resource, parsed_input, output_format.as_ref());
}
},
ResourceSubCommand::Set { resource, input, file: path, output_format } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[resource.to_string()], progress_format);
let parsed_input = get_input(input.as_ref(), path.as_ref());
resource_command::set(&dsc, resource, parsed_input, output_format.as_ref());
},
ResourceSubCommand::Test { resource, input, file: path, output_format } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[resource.to_string()], progress_format);
let parsed_input = get_input(input.as_ref(), path.as_ref());
resource_command::test(&dsc, resource, parsed_input, output_format.as_ref());
},
ResourceSubCommand::Delete { resource, input, file: path } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[resource.to_string()], progress_format);
let parsed_input = get_input(input.as_ref(), path.as_ref());
resource_command::delete(&dsc, resource, parsed_input);
},
}
}

fn list_resources(dsc: &mut DscManager, resource_name: Option<&String>, adapter_name: Option<&String>, description: Option<&String>, tags: Option<&Vec<String>>, format: Option<&OutputFormat>) {
fn list_resources(dsc: &mut DscManager, resource_name: Option<&String>, adapter_name: Option<&String>, description: Option<&String>, tags: Option<&Vec<String>>, format: Option<&OutputFormat>, progress_format: ProgressFormat) {
let mut write_table = false;
let mut table = Table::new(&[
t!("subcommand.tableHeader_type").to_string().as_ref(),
Expand All @@ -588,7 +591,7 @@ fn list_resources(dsc: &mut DscManager, resource_name: Option<&String>, adapter_
// write as table if format is not specified and interactive
write_table = true;
}
for resource in dsc.list_available_resources(resource_name.unwrap_or(&String::from("*")), adapter_name.unwrap_or(&String::new())) {
for resource in dsc.list_available_resources(resource_name.unwrap_or(&String::from("*")), adapter_name.unwrap_or(&String::new()), progress_format) {
let mut capabilities = "--------".to_string();
let capability_types = [
(Capability::Get, "g"),
Expand Down
23 changes: 23 additions & 0 deletions dsc/tests/dsc_config_get.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,29 @@ Describe 'dsc config get tests' {
$LASTEXITCODE | Should -Be 0
}

It 'json progress for config subcommand' {
$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json
resources:
- name: Echo
type: Microsoft.DSC.Debug/Echo
properties:
output: hello
"@
$config_yaml | dsc --progress-format json config get -f - 2> $TestDrive/ErrorStream.txt
$LASTEXITCODE | Should -Be 0
$lines = Get-Content $TestDrive/ErrorStream.txt
$ProgressMessagesFound = $False
foreach ($line in $lines) {
$jp = $line | ConvertFrom-Json
if ($jp.activity) { # if line is a progress message
$jp.percent_complete | Should -BeIn (0..100)
$ProgressMessagesFound = $True
}
}
$ProgressMessagesFound | Should -BeTrue
}

It 'contentVersion is ignored' {
$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json
Expand Down
15 changes: 15 additions & 0 deletions dsc/tests/dsc_resource_list.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ Describe 'Tests for listing resources' {
}
}

It 'json progress for resource subcommand' {
dsc -t json -p json resource list -a '*' 2> $TestDrive/ErrorStream.txt
$LASTEXITCODE | Should -Be 0
$lines = Get-Content $TestDrive/ErrorStream.txt
$ProgressMessagesFound = $False
foreach ($line in $lines) {
$jp = $line | ConvertFrom-Json
if ($jp.activity) { # if line is a progress message
$jp.percent_complete | Should -BeIn (0..100)
$ProgressMessagesFound = $True
}
}
$ProgressMessagesFound | Should -BeTrue
}

It 'Capabilities are returned' {
$resource = dsc resource list Microsoft/OSInfo | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0
Expand Down
Loading

0 comments on commit 481f758

Please sign in to comment.