/* ************************************************************************ # # DivConq # # http://divconq.com/ # # Copyright: # Copyright 2014 eTimeline, LLC. All rights reserved. # # License: # See the license.txt file in the project's top-level directory for details. # # Authors: # * Andy White # ************************************************************************ */ package divconq.script.inst.ext; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import divconq.lang.op.OperationContext; import divconq.script.ExecuteState; import divconq.script.Instruction; import divconq.script.StackEntry; import divconq.struct.ScalarStruct; import divconq.struct.Struct; import divconq.struct.scalar.IntegerStruct; import divconq.util.StringUtil; import divconq.xml.XElement; public class ShellProcess extends Instruction { static public final Pattern logpattern = Pattern.compile("^(\\d\\d\\d)\\s.+$"); @Override public void run(final StackEntry stack) { List<XElement> params = this.source.selectAll("Param"); List<String> oparams = new ArrayList<String>(); String cmd = stack.stringFromSource("Command"); if (cmd.endsWith(".bat")) { oparams.add("cmd.exe"); oparams.add("/c"); } oparams.add(cmd); for (int i = 0; i < params.size(); i++) { String v = stack.stringFromElement(params.get(i), "Value"); if (StringUtil.isEmpty(v)) { OperationContext.get().error("Missing value for parameter: " + (i + 1)); // TODO error code and set last stack.setState(ExecuteState.Done); // done is fine, the script should decide what to do with the rrror stack.resume(); } // TODO test this //if (stack.boolFromElement(params.get(i), "Quote", false)) v = "\"" + v.replace("\"", "\"\"") + "\""; // TODO could be ^ instead?? oparams.add(v); } final ProcessBuilder pb = new ProcessBuilder(oparams); pb.redirectErrorStream(true); pb.directory(new File(stack.stringFromSource("WorkingFolder"))); // must keep in same thread so we obey the rules of the pool we are running in try { Process proc = pb.start(); BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream())); String line = null; while ((line = input.readLine()) != null) { line = line.trim(); // TODO configure if empty lines should be removed if (StringUtil.isEmpty(line)) continue; Matcher m = ShellProcess.logpattern.matcher(line); int code = 0; if (m.matches()) { code = Integer.parseInt(m.group(1)); line = line.substring(4); } if (code < 300) OperationContext.get().info(0, line); else if (code < 500) OperationContext.get().warn(0, line); else OperationContext.get().error(400000 + code, line); // TODO configure error start code } input.close(); long ecode = (long) proc.exitValue(); if (ecode >= 500) ecode += 400000; // TODO fix stack.setLastCode(ecode); Struct var = stack.refFromSource("Target"); if (var instanceof ScalarStruct) ((ScalarStruct) var).adaptValue(ecode); String handle = stack.stringFromSource("Handle"); if (handle != null) stack.addVariable(handle, new IntegerStruct(ecode)); } catch (IOException x) { OperationContext.get().error("Shell IO Error " + x); } stack.setState(ExecuteState.Done); stack.resume(); } @Override public void cancel(StackEntry stack) { // TODO see if we can do something about this } }