3
3
4
4
use jsonschema:: JSONSchema ;
5
5
use serde_json:: Value ;
6
- use std:: { collections:: HashMap , env} ;
6
+ use std:: { collections:: HashMap , env, process :: Stdio } ;
7
7
use crate :: { configure:: { config_doc:: ExecutionKind , { config_result:: ResourceGetResult , parameters, Configurator } } , util:: parse_input_to_json} ;
8
8
use crate :: dscerror:: DscError ;
9
9
use super :: { dscresource:: get_diff, invoke_result:: { ExportResult , GetResult , ResolveResult , SetResult , TestResult , ValidateResult , ResourceGetResponse , ResourceSetResponse , ResourceTestResponse , get_in_desired_state} , resource_manifest:: { ArgKind , InputKind , Kind , ResourceManifest , ReturnKind , SchemaKind } } ;
10
10
use tracing:: { error, warn, info, debug, trace} ;
11
- use tokio:: process:: Command ;
12
- use std:: process:: Stdio ;
13
- use tokio:: io:: { BufReader , AsyncBufReadExt , AsyncWriteExt } ;
11
+ use tokio:: { io:: { AsyncBufReadExt , AsyncWriteExt , BufReader } , process:: Command } ;
14
12
15
13
pub const EXIT_PROCESS_TERMINATED : i32 = 0x102 ;
16
14
@@ -556,6 +554,21 @@ pub fn invoke_resolve(resource: &ResourceManifest, cwd: &str, input: &str) -> Re
556
554
Ok ( result)
557
555
}
558
556
557
+ /// Asynchronously invoke a command and return the exit code, stdout, and stderr.
558
+ ///
559
+ /// # Arguments
560
+ ///
561
+ /// * `executable` - The command to execute
562
+ /// * `args` - Optional arguments to pass to the command
563
+ /// * `input` - Optional input to pass to the command
564
+ /// * `cwd` - Optional working directory to execute the command in
565
+ /// * `env` - Optional environment variable mappings to add or update
566
+ /// * `exit_codes` - Optional descriptions of exit codes
567
+ ///
568
+ /// # Errors
569
+ ///
570
+ /// Error is returned if the command fails to execute or stdin/stdout/stderr cannot be opened.
571
+ ///
559
572
async fn run_process_async ( executable : & str , args : Option < Vec < String > > , input : Option < & str > , cwd : Option < & str > , env : Option < HashMap < String , String > > , exit_codes : & Option < HashMap < i32 , String > > ) -> Result < ( i32 , String , String ) , DscError > {
560
573
561
574
let mut command = Command :: new ( executable) ;
@@ -597,19 +610,20 @@ async fn run_process_async(executable: &str, args: Option<Vec<String>>, input: O
597
610
drop ( stdin) ;
598
611
}
599
612
600
- let child_id: u32 = match child. id ( ) {
601
- Some ( id) => id,
602
- None => {
603
- return Err ( DscError :: CommandOperation ( "Can't get child process id" . to_string ( ) , executable. to_string ( ) ) ) ;
604
- }
613
+ let Some ( child_id) = child. id ( ) else {
614
+ return Err ( DscError :: CommandOperation ( "Can't get child process id" . to_string ( ) , executable. to_string ( ) ) ) ;
605
615
} ;
606
616
607
617
let child_task = tokio:: spawn ( async move {
608
618
child. wait ( ) . await
609
619
} ) ;
610
620
621
+ // use somewhat large initial buffer to avoid early string reallocations;
622
+ // the value is based on list result of largest of built-in adapters - WMI adapter ~500KB
623
+ const INITIAL_BUFFER_CAPACITY : usize = 1024 * 1024 ;
624
+
611
625
let stdout_task = tokio:: spawn ( async move {
612
- let mut stdout_result = String :: with_capacity ( 1024 * 1024 ) ;
626
+ let mut stdout_result = String :: with_capacity ( INITIAL_BUFFER_CAPACITY ) ;
613
627
while let Ok ( Some ( line) ) = stdout_reader. next_line ( ) . await {
614
628
stdout_result. push_str ( & line) ;
615
629
stdout_result. push ( '\n' ) ;
@@ -618,7 +632,7 @@ async fn run_process_async(executable: &str, args: Option<Vec<String>>, input: O
618
632
} ) ;
619
633
620
634
let stderr_task = tokio:: spawn ( async move {
621
- let mut filtered_stderr = String :: with_capacity ( 1024 * 1024 ) ;
635
+ let mut filtered_stderr = String :: with_capacity ( INITIAL_BUFFER_CAPACITY ) ;
622
636
while let Ok ( Some ( stderr_line) ) = stderr_reader. next_line ( ) . await {
623
637
let filtered_stderr_line = log_stderr_line ( & child_id, & stderr_line) ;
624
638
if !filtered_stderr_line. is_empty ( ) {
@@ -660,10 +674,13 @@ async fn run_process_async(executable: &str, args: Option<Vec<String>>, input: O
660
674
/// * `args` - Optional arguments to pass to the command
661
675
/// * `input` - Optional input to pass to the command
662
676
/// * `cwd` - Optional working directory to execute the command in
663
- ///
677
+ /// * `env` - Optional environment variable mappings to add or update
678
+ /// * `exit_codes` - Optional descriptions of exit codes
679
+ ///
664
680
/// # Errors
665
681
///
666
682
/// Error is returned if the command fails to execute or stdin/stdout/stderr cannot be opened.
683
+ ///
667
684
/// # Panics
668
685
///
669
686
/// Will panic if tokio runtime can't be created.
0 commit comments