Browse code

CommandUtil C# API tweaks (#30453)

* changed RunCommand result from Tuple to CommandResult for easier future extensibility
* moved Win32 Dictionary->multi-null-string environment munging into C#
(cherry picked from commit 0e70057f561875c40d3d5285fd5f0dfcbe8087e6)

Matt Davis authored on 2017/09/16 15:09:15
Showing 1 changed files
... ...
@@ -3,6 +3,7 @@
3 3
 
4 4
 $process_util = @"
5 5
 using System;
6
+using System.Collections;
6 7
 using System.IO;
7 8
 using System.Linq;
8 9
 using System.Runtime.InteropServices;
... ...
@@ -210,7 +211,14 @@ namespace Ansible
210 210
             return sbOut.ToString();
211 211
         }
212 212
 
213
-        public static Tuple<string, string, uint> RunCommand(string lpApplicationName, string lpCommandLine, string lpCurrentDirectory, string stdinInput, string environmentBlock)
213
+        public class CommandResult
214
+        {
215
+            public string StandardOut { get; internal set; }
216
+            public string StandardError { get; internal set; }
217
+            public uint ExitCode { get; internal set; }
218
+        }
219
+
220
+        public static CommandResult RunCommand(string lpApplicationName, string lpCommandLine, string lpCurrentDirectory, string stdinInput, IDictionary environment)
214 221
         {
215 222
             UInt32 startup_flags = CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | EXTENDED_STARTUPINFO_PRESENT;
216 223
             STARTUPINFOEX si = new STARTUPINFOEX();
... ...
@@ -277,11 +285,21 @@ namespace Ansible
277 277
             // string here, we need to convert it
278 278
             if (lpCurrentDirectory == "")
279 279
                 lpCurrentDirectory = null;
280
-            
280
+
281
+            StringBuilder environmentString = null;
282
+
283
+            if(environment != null && environment.Count > 0)
284
+            {
285
+                environmentString = new StringBuilder();
286
+                foreach (DictionaryEntry kv in environment)
287
+                    environmentString.AppendFormat("{0}={1}\0", kv.Key, kv.Value);
288
+                environmentString.Append('\0');
289
+            }
290
+
281 291
             // Create the environment block if set
282 292
             IntPtr lpEnvironment = IntPtr.Zero;
283
-            if (environmentBlock != "")
284
-                lpEnvironment = Marshal.StringToHGlobalUni(environmentBlock);
293
+            if (environmentString != null)
294
+                lpEnvironment = Marshal.StringToHGlobalUni(environmentString.ToString());
285 295
 
286 296
             // Create new process and run
287 297
             StringBuilder argument_string = new StringBuilder(lpCommandLine);
... ...
@@ -316,7 +334,12 @@ namespace Ansible
316 316
             GetProcessOutput(stdout, stderr, out stdout_str, out stderr_str);
317 317
             uint rc = GetProcessExitCode(pi.hProcess);
318 318
 
319
-            return Tuple.Create(stdout_str, stderr_str, rc);
319
+            return new CommandResult
320
+            {
321
+                StandardOut = stdout_str,
322
+                StandardError = stderr_str,
323
+                ExitCode = rc
324
+            };
320 325
         }
321 326
 
322 327
         private static void GetProcessOutput(StreamReader stdoutStream, StreamReader stderrStream, out string stdout, out string stderr)
... ...
@@ -361,7 +384,7 @@ Function Load-CommandUtils {
361 361
     #   [Ansible.CommandUtil]::RunCommand(string lpApplicationName, string lpCommandLine, string lpCurrentDirectory, string stdinInput, string environmentBlock)
362 362
     #
363 363
     # there are also numerous P/Invoke methods that can be called if you are feeling adventurous
364
-    Add-Type -TypeDefinition $process_util -IgnoreWarnings
364
+    Add-Type -TypeDefinition $process_util -IgnoreWarnings -Debug:$false
365 365
 }
366 366
 
367 367
 Function Get-ExecutablePath($executable, $directory) {
... ...
@@ -412,29 +435,14 @@ Function Run-Command {
412 412
     $arguments = [Ansible.CommandUtil]::ParseCommandLine($command)
413 413
     $executable = Get-ExecutablePath -executable $arguments[0] -directory $working_directory
414 414
 
415
-    # set the extra environment variables
416
-    $environment_string = $null
417
-    if ($environment.Count -gt 0) {
418
-        $environment_string = ""
419
-    }
420
-    foreach ($environment_entry in $environment.GetEnumerator()){
421
-        $environment_key = $environment_entry.Name
422
-        $environment_value = $environment_entry.Value
423
-        $environment_string += "$environment_key=$environment_value`0"
424
-    }
425
-    if ($environment_string) {
426
-        $environment_string += "`0"
427
-    }
428
-
429 415
     # run the command and get the results
430
-    $command_result = [Ansible.CommandUtil]::RunCommand($executable, $command, $working_directory, $stdin, $environment_string)
416
+    $command_result = [Ansible.CommandUtil]::RunCommand($executable, $command, $working_directory, $stdin, $environment)
431 417
 
432
-    # RunCommand returns a tuple, we will convert to a hashtable
433 418
     return ,@{
434 419
         executable = $executable
435
-        stdout = $command_result.Item1
436
-        stderr = $command_result.Item2
437
-        rc = $command_result.Item3
420
+        stdout = $command_result.StandardOut
421
+        stderr = $command_result.StandardError
422
+        rc = $command_result.ExitCode
438 423
     }
439 424
 }
440 425