Package org.jboss.forge.addon.shell.command

Source Code of org.jboss.forge.addon.shell.command.RunCommand$UncloseablePrintStream

/**
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Eclipse Public License version 1.0, available at
* http://www.eclipse.org/legal/epl-v10.html
*/

package org.jboss.forge.addon.shell.command;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.inject.Inject;

import org.jboss.aesh.console.Prompt;
import org.jboss.aesh.console.settings.Settings;
import org.jboss.aesh.console.settings.SettingsBuilder;
import org.jboss.aesh.terminal.TerminalSize;
import org.jboss.forge.addon.resource.Resource;
import org.jboss.forge.addon.resource.ResourceFactory;
import org.jboss.forge.addon.resource.util.ResourcePathResolver;
import org.jboss.forge.addon.shell.CommandNotFoundListener;
import org.jboss.forge.addon.shell.Shell;
import org.jboss.forge.addon.shell.ShellFactory;
import org.jboss.forge.addon.shell.aesh.ForgeTerminal;
import org.jboss.forge.addon.shell.spi.Terminal;
import org.jboss.forge.addon.shell.ui.AbstractShellCommand;
import org.jboss.forge.addon.ui.command.AbstractCommandExecutionListener;
import org.jboss.forge.addon.ui.command.CommandExecutionListener;
import org.jboss.forge.addon.ui.command.UICommand;
import org.jboss.forge.addon.ui.context.UIBuilder;
import org.jboss.forge.addon.ui.context.UIContext;
import org.jboss.forge.addon.ui.context.UIExecutionContext;
import org.jboss.forge.addon.ui.context.UIValidationContext;
import org.jboss.forge.addon.ui.hints.InputType;
import org.jboss.forge.addon.ui.input.UIInput;
import org.jboss.forge.addon.ui.input.UIInputMany;
import org.jboss.forge.addon.ui.metadata.UICommandMetadata;
import org.jboss.forge.addon.ui.metadata.WithAttributes;
import org.jboss.forge.addon.ui.output.UIOutput;
import org.jboss.forge.addon.ui.result.Failed;
import org.jboss.forge.addon.ui.result.Result;
import org.jboss.forge.addon.ui.result.Results;
import org.jboss.forge.addon.ui.util.Metadata;
import org.jboss.forge.furnace.exception.ContainerException;
import org.jboss.forge.furnace.spi.ListenerRegistration;
import org.jboss.forge.furnace.util.Assert;
import org.jboss.forge.furnace.util.OperatingSystemUtils;
import org.jboss.forge.furnace.util.Streams;

/**
* Implementation of the "run script" command
*
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*/
public class RunCommand extends AbstractShellCommand
{
   @Inject
   ResourceFactory resourceFactory;

   @Inject
   @WithAttributes(label = "Timeout (seconds)", defaultValue = "500", required = false,
            description = "Set the timeout after which this script should abort if execution has not completed.")
   private UIInput<Integer> timeout;

   @Inject
   @WithAttributes(label = "Arguments", type = InputType.FILE_PICKER, required = false)
   private UIInputMany<String> arguments;

   @Inject
   @WithAttributes(label = "Command", shortName = 'c', required = false)
   private UIInput<String> command;

   @Inject
   private ShellFactory shellFactory;

   @Override
   public UICommandMetadata getMetadata(UIContext context)
   {
      return Metadata.from(super.getMetadata(context), getClass()).name("run")
               .description("Execute/run a forge script file.");
   }

   @Override
   public void initializeUI(UIBuilder builder) throws Exception
   {
      builder.add(timeout).add(arguments).add(command);
   }

   @Override
   public void validate(UIValidationContext validator)
   {
      if (!command.hasValue() && !arguments.hasValue())
      {
         validator.addValidationError(null, "Command or script file must be informed");
      }
   }

   @Override
   public Result execute(UIExecutionContext context) throws Exception
   {
      Result result = Results.fail("Error executing script.");
      UIContext uiContext = context.getUIContext();
      Resource<?> currentResource = (Resource<?>) uiContext.getInitialSelection().get();
      final UIOutput output = uiContext.getProvider().getOutput();
      if (command.hasValue())
      {
         String[] commands = command.getValue().split(" ");
         ProcessBuilder processBuilder = new ProcessBuilder(commands);
         Object currentDir = currentResource.getUnderlyingResourceObject();
         if (currentDir instanceof File)
         {
            processBuilder.directory((File) currentDir);
         }
         final Process process = processBuilder.start();
         ExecutorService executor = Executors.newFixedThreadPool(2);
         // Read std out
         executor.submit(new Runnable()
         {
            @Override
            public void run()
            {
               Streams.write(process.getInputStream(), output.out());
            }
         });
         // Read std err
         executor.submit(new Runnable()
         {
            @Override
            public void run()
            {
               Streams.write(process.getErrorStream(), output.err());
            }
         });
         executor.shutdown();
         int returnCode = process.waitFor();
         if (returnCode == 0)
         {
            result = Results.success();
         }
         else
         {
            result = Results.fail("Error while executing native command. See output for more details");
         }
      }
      else
      {
         Resource<?> selectedResource = currentResource;
         ALL: for (String path : arguments.getValue())
         {
            List<Resource<?>> resources = new ResourcePathResolver(resourceFactory, currentResource, path).resolve();
            for (Resource<?> resource : resources)
            {
               if (resource.exists())
               {
                  final PipedOutputStream stdin = new PipedOutputStream();
                  BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));

                  PrintStream stdout = new UncloseablePrintStream(output.out());
                  PrintStream stderr = new UncloseablePrintStream(output.err());
                 
                  Shell currentShell = (Shell) uiContext.getProvider();
                  final TerminalSize terminalSize = currentShell.getConsole().getShell().getSize();
                  ForgeTerminal terminal = new ForgeTerminal(
                           new Terminal()
                           {

                              @Override
                              public void close() throws IOException
                              {

                              }

                              @Override
                              public void initialize()
                              {

                              }

                              @Override
                              public int getWidth()
                              {
                                 return terminalSize.getWidth();
                              }

                              @Override
                              public int getHeight()
                              {
                                 return terminalSize.getHeight();
                              }
                           });

                  Settings settings = new SettingsBuilder()
                           .inputStream(new PipedInputStream(stdin))
                           .outputStream(stdout)
                           .outputStreamError(stderr)
                           .terminal(terminal)
                           .create();

                  try (Shell scriptShell = shellFactory.createShell(currentResource, settings))
                  {

                     scriptShell.getConsole().setPrompt(new Prompt(""));
                     try (BufferedReader reader = new BufferedReader(new InputStreamReader(
                              resource.getResourceInputStream())))
                     {
                        long startTime = System.currentTimeMillis();
                        while (reader.ready())
                        {
                           try
                           {
                              String line = readLine(reader);
                              if (skipsLine(line))
                              {
                                 // Skip Comments
                                 continue;
                              }
                              Integer timeoutValue = timeout.getValue();
                              result = execute(scriptShell, writer, line, timeoutValue,
                                       TimeUnit.SECONDS, startTime);

                              if (result instanceof Failed)
                              {
                                 break ALL;
                              }
                              else
                              {
                                 selectedResource = scriptShell.getCurrentResource();
                              }
                           }
                           catch (TimeoutException e)
                           {
                              result = Results.fail(path + ": timed out.");
                              break ALL;
                           }
                        }
                     }
                  }
               }
               else
               {
                  result = Results.fail(path + ": not found.");
                  break ALL;
               }
            }
         }
         if (!(result instanceof Failed))
         {
            uiContext.setSelection(selectedResource);
         }
      }
      return result;
   }

   private String readLine(BufferedReader reader) throws IOException
   {
      StringBuilder result = new StringBuilder();
      String line;
      while ((line = reader.readLine()) != null)
      {
         line = line.trim();
         if (line.endsWith("\\"))
         {
            // Read next line
            result.append(line.substring(0, line.lastIndexOf("\\"))).append(' ');
         }
         else
         {
            result.append(line);
            break;
         }
      }
      return result.toString();
   }

   public Result execute(Shell shell, BufferedWriter stdin, String line, int quantity, TimeUnit unit, long startTime)
            throws TimeoutException
   {
      Assert.notNull(line, "Line to execute cannot be null.");
      if (skipsLine(line))
      {
         return Results.success();
      }
      Result result = null;

      if (!line.trim().isEmpty())
      {
         if (!line.endsWith(OperatingSystemUtils.getLineSeparator()))
            line = line + OperatingSystemUtils.getLineSeparator();

         ScriptCommandListener listener = new ScriptCommandListener();
         ListenerRegistration<CommandExecutionListener> listenerRegistration = shell
                  .addCommandExecutionListener(listener);
         ListenerRegistration<CommandNotFoundListener> notFoundRegistration = shell
                  .addCommandNotFoundListener(listener);
         try
         {
            stdin.write(line);
            stdin.flush();
            while (!listener.isExecuted())
            {
               if (System.currentTimeMillis() > (startTime + TimeUnit.MILLISECONDS.convert(quantity, unit)))
               {
                  throw new TimeoutException("Timeout expired waiting for command [" + line + "] to execute.");
               }

               try
               {
                  Thread.sleep(10);
               }
               catch (InterruptedException e)
               {
                  throw new ContainerException("Command [" + line + "] did not respond.", e);
               }
            }
            result = listener.getResult();
         }
         catch (IOException e)
         {
            throw new RuntimeException("Failed to execute command.", e);
         }
         finally
         {
            listenerRegistration.removeListener();
            notFoundRegistration.removeListener();
         }
      }
      return result;
   }

   public class ScriptCommandListener extends AbstractCommandExecutionListener implements CommandNotFoundListener
   {
      Result result;

      @Override
      public void preCommandExecuted(UICommand command, UIExecutionContext context)
      {
      }

      @Override
      public void postCommandExecuted(UICommand command, UIExecutionContext context, Result result)
      {
         synchronized (this)
         {
            this.result = result;
         }
      }

      @Override
      public void postCommandFailure(UICommand command, UIExecutionContext context, Throwable failure)
      {
         synchronized (this)
         {
            this.result = Results.fail("Error encountered during command execution.", failure);
         }
      }

      @Override
      public void onCommandNotFound(String line, UIContext context)
      {
         synchronized (this)
         {
            this.result = Results.fail("Command not found: " + line);
         }
      }

      public boolean isExecuted()
      {
         synchronized (this)
         {
            return result != null;
         }
      }

      public Result getResult()
      {
         synchronized (this)
         {
            return result;
         }
      }

      public void reset()
      {
         synchronized (this)
         {
            result = null;
         }
      }
   }

   private boolean skipsLine(String line)
   {
      return line.startsWith("#") || line.trim().isEmpty();
   }

   private static class UncloseablePrintStream extends PrintStream
   {
      public UncloseablePrintStream(PrintStream stream)
      {
         super(stream, true);
      }

      @Override
      public void close()
      {
         // Uncloseable
      }
   }
}
TOP

Related Classes of org.jboss.forge.addon.shell.command.RunCommand$UncloseablePrintStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.