Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ param(
[ValidateSet('current','aarch64-pc-windows-msvc','x86_64-pc-windows-msvc','aarch64-apple-darwin','x86_64-apple-darwin','aarch64-unknown-linux-gnu','aarch64-unknown-linux-musl','x86_64-unknown-linux-gnu','x86_64-unknown-linux-musl')]
$architecture = 'current',
[switch]$Clippy,
[switch]$FmtFix,
[switch]$SkipBuild,
[ValidateSet('msix','msix-private','msixbundle','tgz','zip')]
$packageType,
Expand Down Expand Up @@ -252,6 +253,19 @@ if ($null -ne $packageType) {
if ($LASTEXITCODE -ne 0) {
throw "Failed to install clippy"
}

Write-Verbose -Verbose "Installing rustfmt..."
if ($UseCFS) {
cargo install rustfmt --config .cargo/config.toml
} else {
if ($architecture -ne 'current') {
write-verbose -verbose "Installing rustfmt for $architecture"
rustup component add rustfmt --target $architecture
} else {
write-verbose -verbose "Installing rustfmt for current architecture"
rustup component add rustfmt
}
}
}

## Test if Node is installed
Expand Down Expand Up @@ -433,6 +447,22 @@ if (!$SkipBuild) {
Write-Verbose -Verbose "Running clippy with pedantic for $project"
cargo clippy @flags --% -- -Dwarnings -Dclippy::pedantic
}

if ($LASTEXITCODE -ne 0) {
throw "Clippy failed for $project"
}

if ($FmtFix) {
Write-Verbose -Verbose "Running rustfmt for $project"
cargo fmt --all
}
else {
Write-Verbose -Verbose "Running rustfmt check for $project"
cargo fmt --all -- --check
}
if ($LASTEXITCODE -ne 0) {
throw "Rustfmt failed for $project"
}
}
else {
if ($UpdateLockFile) {
Expand Down
34 changes: 27 additions & 7 deletions dsc/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ pub enum ConfigSubCommand {
file: Option<String>,
#[clap(short = 'o', long, help = t!("args.outputFormat").to_string())]
output_format: Option<OutputFormat>,
}
},
}

#[derive(Debug, PartialEq, Eq, Subcommand)]
Expand Down Expand Up @@ -226,7 +226,11 @@ pub enum ResourceSubCommand {
#[clap(short = 'o', long, help = t!("args.outputFormat").to_string())]
output_format: Option<GetOutputFormat>,
},
#[clap(name = "set", about = "Invoke the set operation to a resource", arg_required_else_help = true)]
#[clap(
name = "set",
about = "Invoke the set operation to a resource",
arg_required_else_help = true
)]
Set {
#[clap(short, long, help = t!("args.resource").to_string())]
resource: String,
Expand All @@ -239,7 +243,11 @@ pub enum ResourceSubCommand {
#[clap(short = 'o', long, help = t!("args.outputFormat").to_string())]
output_format: Option<OutputFormat>,
},
#[clap(name = "test", about = "Invoke the test operation to a resource", arg_required_else_help = true)]
#[clap(
name = "test",
about = "Invoke the test operation to a resource",
arg_required_else_help = true
)]
Test {
#[clap(short, long, help = t!("args.resource").to_string())]
resource: String,
Expand All @@ -252,7 +260,11 @@ pub enum ResourceSubCommand {
#[clap(short = 'o', long, help = t!("args.outputFormat").to_string())]
output_format: Option<OutputFormat>,
},
#[clap(name = "delete", about = "Invoke the delete operation to a resource", arg_required_else_help = true)]
#[clap(
name = "delete",
about = "Invoke the delete operation to a resource",
arg_required_else_help = true
)]
Delete {
#[clap(short, long, help = t!("args.resource").to_string())]
resource: String,
Expand All @@ -263,7 +275,11 @@ pub enum ResourceSubCommand {
#[clap(short = 'f', long, help = t!("args.file").to_string(), conflicts_with = "input")]
file: Option<String>,
},
#[clap(name = "schema", about = "Get the JSON schema for a resource", arg_required_else_help = true)]
#[clap(
name = "schema",
about = "Get the JSON schema for a resource",
arg_required_else_help = true
)]
Schema {
#[clap(short, long, help = t!("args.resource").to_string())]
resource: String,
Expand All @@ -272,7 +288,11 @@ pub enum ResourceSubCommand {
#[clap(short = 'o', long, help = t!("args.outputFormat").to_string())]
output_format: Option<OutputFormat>,
},
#[clap(name = "export", about = "Retrieve all resource instances", arg_required_else_help = true)]
#[clap(
name = "export",
about = "Retrieve all resource instances",
arg_required_else_help = true
)]
Export {
#[clap(short, long, help = t!("args.resource").to_string())]
resource: String,
Expand Down Expand Up @@ -304,5 +324,5 @@ pub enum SchemaType {
ExtensionManifest,
ExtensionDiscoverResult,
FunctionDefinition,
RestartRequired
RestartRequired,
}
122 changes: 90 additions & 32 deletions dsc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
use args::{Args, SubCommand};
use clap::{CommandFactory, Parser};
use clap_complete::generate;
use dsc_lib::progress::ProgressFormat;
use mcp::start_mcp_server;
use rust_i18n::{i18n, t};
use std::{io, io::Read, process::exit};
use sysinfo::{Process, RefreshKind, System, get_current_pid, ProcessRefreshKind};
use tracing::{error, info, warn, debug};
use dsc_lib::progress::ProgressFormat;
use sysinfo::{get_current_pid, Process, ProcessRefreshKind, RefreshKind, System};
use tracing::{debug, error, info, warn};

use crate::util::EXIT_INVALID_INPUT;

Expand All @@ -28,6 +28,7 @@ pub mod util;

i18n!("locales", fallback = "en-us");

#[allow(clippy::too_many_lines)]
fn main() {
#[cfg(debug_assertions)]
check_debug();
Expand All @@ -45,58 +46,88 @@ fn main() {

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

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

match args.subcommand {
SubCommand::Completer { shell } => {
info!("{} {:?}", t!("main.generatingCompleter"), shell);
let mut cmd = Args::command();
generate(shell, &mut cmd, "dsc", &mut io::stdout());
},
SubCommand::Config { subcommand, parameters, parameters_file, system_root, as_group, as_assert, as_include } => {
}
SubCommand::Config {
subcommand,
parameters,
parameters_file,
system_root,
as_group,
as_assert,
as_include,
} => {
if let Some(file_name) = parameters_file {
if file_name == "-" {
info!("{}", t!("main.readingParametersFromStdin"));
let mut stdin = Vec::<u8>::new();
let parameters = match io::stdin().read_to_end(&mut stdin) {
Ok(_) => {
match String::from_utf8(stdin) {
Ok(input) => {
input
},
Err(err) => {
error!("{}: {err}", t!("util.invalidUtf8"));
exit(EXIT_INVALID_INPUT);
}
Ok(_) => match String::from_utf8(stdin) {
Ok(input) => input,
Err(err) => {
error!("{}: {err}", t!("util.invalidUtf8"));
exit(EXIT_INVALID_INPUT);
}
},
Err(err) => {
error!("{}: {err}", t!("util.failedToReadStdin"));
exit(EXIT_INVALID_INPUT);
}
};
subcommand::config(&subcommand, &Some(parameters), true, system_root.as_ref(), &as_group, &as_assert, &as_include, progress_format);
subcommand::config(
&subcommand,
&Some(parameters),
true,
system_root.as_ref(),
&as_group,
&as_assert,
&as_include,
progress_format,
);
return;
}
info!("{}: {file_name}", t!("main.readingParametersFile"));
match std::fs::read_to_string(&file_name) {
Ok(parameters) => subcommand::config(&subcommand, &Some(parameters), false, system_root.as_ref(), &as_group, &as_assert, &as_include, progress_format),
Ok(parameters) => subcommand::config(
&subcommand,
&Some(parameters),
false,
system_root.as_ref(),
&as_group,
&as_assert,
&as_include,
progress_format,
),
Err(err) => {
error!("{} '{file_name}': {err}", t!("main.failedReadingParametersFile"));
exit(util::EXIT_INVALID_INPUT);
}
}
} else {
subcommand::config(
&subcommand,
&parameters,
false,
system_root.as_ref(),
&as_group,
&as_assert,
&as_include,
progress_format,
);
}
else {
subcommand::config(&subcommand, &parameters, false, system_root.as_ref(), &as_group, &as_assert, &as_include, progress_format);
}
},
}
SubCommand::Extension { subcommand } => {
subcommand::extension(&subcommand, progress_format);
},
}
SubCommand::Function { subcommand } => {
subcommand::function(&subcommand);
},
}
SubCommand::Mcp => {
if let Err(err) = start_mcp_server() {
error!("{}", t!("main.failedToStartMcpServer", error = err));
Expand All @@ -106,8 +137,11 @@ fn main() {
}
SubCommand::Resource { subcommand } => {
subcommand::resource(&subcommand, progress_format);
},
SubCommand::Schema { dsc_type , output_format } => {
}
SubCommand::Schema {
dsc_type,
output_format,
} => {
let schema = util::get_schema(dsc_type);
let json = match serde_json::to_string(&schema) {
Ok(json) => json,
Expand All @@ -117,7 +151,7 @@ fn main() {
}
};
util::write_object(&json, output_format.as_ref(), false);
},
}
}

exit(util::EXIT_SUCCESS);
Expand All @@ -144,21 +178,43 @@ fn ctrlc_handler() {
}

fn terminate_subprocesses(sys: &System, process: &Process) {
info!("{}: {:?} {}", t!("main.terminatingSubprocess"), process.name(), process.pid());
for subprocess in sys.processes().values().filter(|p| p.parent().is_some_and(|parent| parent == process.pid())) {
info!(
"{}: {:?} {}",
t!("main.terminatingSubprocess"),
process.name(),
process.pid()
);
for subprocess in sys
.processes()
.values()
.filter(|p| p.parent().is_some_and(|parent| parent == process.pid()))
{
terminate_subprocesses(sys, subprocess);
}

info!("{}: {:?} {}", t!("main.terminatingProcess"), process.name(), process.pid());
info!(
"{}: {:?} {}",
t!("main.terminatingProcess"),
process.name(),
process.pid()
);
if !process.kill() {
error!("{}: {:?} {}", t!("main.failedTerminatingProcess"), process.name(), process.pid());
error!(
"{}: {:?} {}",
t!("main.failedTerminatingProcess"),
process.name(),
process.pid()
);
}
}

#[cfg(debug_assertions)]
fn check_debug() {
if env::var("DEBUG_DSC").is_ok() {
eprintln!("attach debugger to pid {} and press a key to continue", std::process::id());
eprintln!(
"attach debugger to pid {} and press a key to continue",
std::process::id()
);
loop {
let event = match event::read() {
Ok(event) => event,
Expand Down Expand Up @@ -200,7 +256,9 @@ fn check_store() {
};

// MS Store runs app using `sihost.exe`
if parent_process.name().eq_ignore_ascii_case("sihost.exe") || parent_process.name().eq_ignore_ascii_case("explorer.exe") {
if parent_process.name().eq_ignore_ascii_case("sihost.exe")
|| parent_process.name().eq_ignore_ascii_case("explorer.exe")
{
eprintln!("{}", t!("main.storeMessage"));
// wait for keypress
let _ = io::stdin().read(&mut [0u8]).unwrap();
Expand Down
Loading
Loading