4545
4646import hudson .AbortException ;
4747import io .fabric8 .kubernetes .api .model .Container ;
48+ import org .apache .commons .io .output .NullOutputStream ;
4849import org .apache .commons .io .output .TeeOutputStream ;
4950import org .csanchez .jenkins .plugins .kubernetes .ContainerTemplate ;
5051import org .csanchez .jenkins .plugins .kubernetes .KubernetesSlave ;
@@ -344,6 +345,7 @@ private Proc doLaunch(boolean quiet, String[] cmdEnvs, OutputStream outputForCal
344345
345346 // Only output to stdout at the beginning for diagnostics.
346347 ByteArrayOutputStream stdout = new ByteArrayOutputStream ();
348+ // Wrap stdout so that we can toggle it off.
347349 ToggleOutputStream toggleStdout = new ToggleOutputStream (stdout );
348350
349351 // Do not send this command to the output when in quiet mode
@@ -355,14 +357,27 @@ private Proc doLaunch(boolean quiet, String[] cmdEnvs, OutputStream outputForCal
355357 stream = new TeeOutputStream (toggleStdout , printStream );
356358 }
357359
360+ ByteArrayOutputStream dryRunCaller = null ;;
361+ ToggleOutputStream toggleDryRunCaller = null ;
362+ ToggleOutputStream toggleOutputForCaller = null ;
358363 // Send to proc caller as well if they sent one
359364 if (outputForCaller != null && !outputForCaller .equals (printStream )) {
360- stream = new TeeOutputStream (outputForCaller , stream );
365+ if (launcher .isUnix ()) {
366+ stream = new TeeOutputStream (outputForCaller , stream );
367+ } else {
368+ // Prepare to capture output for later.
369+ dryRunCaller = new ByteArrayOutputStream ();
370+ toggleDryRunCaller = new ToggleOutputStream (dryRunCaller );
371+ // Initially disable the output for the caller, to prevent it from getting unwanted output such as prompt
372+ toggleOutputForCaller = new ToggleOutputStream (outputForCaller , true );
373+ stream = new TeeOutputStream (toggleOutputForCaller , stream );
374+ stream = new TeeOutputStream (toggleDryRunCaller , stream );
375+ }
361376 }
362377 ByteArrayOutputStream error = new ByteArrayOutputStream ();
363378
364- String sh = shell != null ? shell : launcher .isUnix () ? "sh" : "cmd" ;
365- String msg = "Executing " + sh + " script inside container " + containerName + " of pod " + getPodName ();
379+ String [] sh = shell != null ? new String []{ shell } : launcher .isUnix () ? new String [] { "sh" } : new String [] { "cmd" , "/Q" } ;
380+ String msg = "Executing " + String . join ( " " , sh ) + " script inside container " + containerName + " of pod " + getPodName ();
366381 LOGGER .log (Level .FINEST , msg );
367382 printStream .println (msg );
368383
@@ -453,6 +468,10 @@ public void onClose(int i, String s) {
453468 toggleStdout .disable ();
454469 OutputStream stdin = watch .getInput ();
455470 PrintStream in = new PrintStream (stdin , true , StandardCharsets .UTF_8 .name ());
471+ if (!launcher .isUnix ()) {
472+ in .print ("@echo off" );
473+ in .print (newLine (true ));
474+ }
456475 if (pwd != null ) {
457476 // We need to get into the project workspace.
458477 // The workspace is not known in advance, so we have to execute a cd command.
@@ -485,7 +504,31 @@ public void onClose(int i, String s) {
485504 LOGGER .log (Level .FINEST , "Launching with env vars: {0}" , envVars .toString ());
486505
487506 setupEnvironmentVariable (envVars , in , !launcher .isUnix ());
488-
507+ if (!launcher .isUnix () && toggleOutputForCaller != null ) {
508+ // Windows welcome message should not be sent to the caller as it is a side-effect of calling the wrapping cmd.exe
509+ // Microsoft Windows [Version 10.0.17763.2686]
510+ // (c) 2018 Microsoft Corporation. All rights reserved.
511+ //
512+ // C:\>
513+ stream .flush ();
514+ long beginning = System .currentTimeMillis ();
515+ // watch for the prompt character
516+ while (!dryRunCaller .toString (StandardCharsets .UTF_8 .name ()).contains (">" )) {
517+ Thread .sleep (100 );
518+ }
519+ LOGGER .log (Level .FINEST , "Windows prompt printed after " + (System .currentTimeMillis () - beginning ) + " ms" );
520+ }
521+ // We don't need to capture output anymore
522+ if (toggleDryRunCaller != null ) {
523+ toggleDryRunCaller .disable ();
524+ }
525+ // Clear any captured bytes
526+ if (dryRunCaller != null ) {
527+ dryRunCaller .reset ();
528+ }
529+ if (toggleOutputForCaller != null ) {
530+ toggleOutputForCaller .enable ();
531+ }
489532 doExec (in , !launcher .isUnix (), printStream , masks , commands );
490533
491534 LOGGER .log (Level .INFO , "Created process inside pod: [" + getPodName () + "], container: ["
@@ -554,7 +597,12 @@ public void close() throws IOException {
554597 private static class ToggleOutputStream extends FilterOutputStream {
555598 private boolean disabled ;
556599 public ToggleOutputStream (OutputStream out ) {
600+ this (out , false );
601+ }
602+
603+ public ToggleOutputStream (OutputStream out , boolean disabled ) {
557604 super (out );
605+ this .disabled = disabled ;
558606 }
559607
560608 public void disable () {
@@ -571,6 +619,20 @@ public void write(int b) throws IOException {
571619 out .write (b );
572620 }
573621 }
622+
623+ @ Override
624+ public void write (byte [] b ) throws IOException {
625+ if (!disabled ) {
626+ out .write (b );
627+ }
628+ }
629+
630+ @ Override
631+ public void write (byte [] b , int off , int len ) throws IOException {
632+ if (!disabled ) {
633+ out .write (b , off , len );
634+ }
635+ }
574636 }
575637
576638 /**
@@ -625,17 +687,19 @@ private static void doExec(PrintStream in, boolean windows, PrintStream out, boo
625687 // Mask sensitive output
626688 MaskOutputStream maskedOutput = new MaskOutputStream (teeOutput , masks );
627689 // Tee everything together
628- PrintStream tee = null ;
690+ PrintStream tee ;
629691 try {
630692 String encoding = StandardCharsets .UTF_8 .name ();
631693 tee = new PrintStream (new TeeOutputStream (in , maskedOutput ), false , encoding );
632694 // To output things that shouldn't be considered for masking
633695 PrintStream unmasked = new PrintStream (teeOutput , false , encoding );
634696 unmasked .print ("Executing command: " );
635697 for (String statement : statements ) {
636- tee .append ("\" " )
637- .append (statement )
638- .append ("\" " );
698+ if (windows ) {
699+ tee .append (statement ).append (" " );
700+ } else {
701+ tee .append ("\" " ).append (statement ).append ("\" " );
702+ }
639703 }
640704 tee .print (newLine (windows ));
641705 LOGGER .log (Level .FINEST , loggingOutput .toString (encoding ) + "[" + TimeUnit .NANOSECONDS .toMicros (System .nanoTime () - start ) + " μs." + "]" );
@@ -644,7 +708,7 @@ private static void doExec(PrintStream in, boolean windows, PrintStream out, boo
644708 tee .print (newLine (windows ));
645709 tee .flush ();
646710 } catch (UnsupportedEncodingException e ) {
647- e . printStackTrace ( );
711+ LOGGER . log ( Level . SEVERE , "Failed to execute command because of unsupported encoding" , e );
648712 }
649713 }
650714
0 commit comments