/** * $Id$ * $Date$ * */ package org.xmlsh.core; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.xmlsh.sh.core.SourceLocation; import org.xmlsh.sh.shell.Module; import org.xmlsh.sh.shell.Shell; import org.xmlsh.util.PortCopier; import org.xmlsh.util.StreamCopier; import org.xmlsh.util.Util; public class ExternalCommand implements ICommand { private static Logger mLogger = LogManager.getLogger( ExternalCommand.class ); private File mCommandFile; // command path private SourceLocation mLocation ; public ExternalCommand( File cmd , SourceLocation location ) { mCommandFile = cmd; mLocation = location ; } public int run(Shell shell, String cmd, List<XValue> args) throws Exception { File curdir = shell.getCurdir() ; mLogger.debug("Run external command: " + mCommandFile.getPath() + " in directory: " + curdir.getPath() ); ArrayList<XValue> cmdlist = new ArrayList<XValue>(); cmdlist.add( new XValue(mCommandFile.getPath())); cmdlist.addAll( Util.expandSequences(args)); Process proc = null ; synchronized ( this.getClass() ){ ProcessBuilder builder = new ProcessBuilder(); builder.command( Util.toStringList(cmdlist)); builder.directory( curdir ); setEnvironment(shell, builder ); proc = builder.start(); if( proc == null ) return -1; } // Start copiers for stdout, stderr StreamCopier outCopier = new StreamCopier( proc.getInputStream() , shell.getEnv().getStdout().asOutputStream(shell.getSerializeOpts()),true); StreamCopier errCopier = new StreamCopier( proc.getErrorStream() , shell.getEnv().getStderr().asOutputStream(shell.getSerializeOpts()),true); PortCopier inCopier = null; if( shell.getEnv().isStdinRedirected() ) inCopier = new PortCopier( shell.getEnv().getStdin() , proc.getOutputStream() , shell.getSerializeOpts() , true ); else proc.getOutputStream().close(); errCopier.start(); if( inCopier != null ) inCopier.start(); // outCopier.start(); outCopier.run(); // In place // Close input just in case we have a broken pipe outCopier.closeIn(); int ret = proc.waitFor(); // Kill off the input copier // inCopier.interrupt(); if( inCopier != null ) inCopier.join(); outCopier.join(); errCopier.join(); return ret ; } /* * Set the environment for a subprocess by the following * * 1) If a variable does not exist in the shell then delete it * 2) For any "EXPORT" variables which are atomic Update any existing variables with new content from the shell * 3) Add any unset "EXPORT" atomic variables * 4) PATH and XPATH are re-set by re-serializing the sequence using the path seperator * and the native directory seperator */ private void setEnvironment(Shell shell, ProcessBuilder builder) { XEnvironment xenv = shell.getEnv(); Map<String,String> env = builder.environment(); if( env == null ) return ; // 1) delete any env vars not in the shell // Use Iterator so we can call remove Iterator<Entry<String,String>> iter = env.entrySet().iterator(); while( iter.hasNext() ){ Entry<String,String> e = iter.next(); String name = e.getKey(); // Remove PATH and XPATH as well as non-defined names if( Util.isPath(name) || ! xenv.isDefined(name) ) iter.remove(); } /* * 2) For any "EXPORT" variables Update any existing variables with new content from the shell * 3) Add any unset "EXPORT" variables of type string */ for( String name : xenv.getVarNames() ){ if( !Util.isPath(name) ){ XVariable var = xenv.getVar(name); if( var.isExport() && var.getValue() != null && var.getValue().isAtomic() ) env.put(name , var.getValue().toString() ); } } // Special case for PATH and XPATH XVariable vpath = xenv.getVar("PATH"); if( vpath != null && vpath.isExport() ){ Path p = new Path( vpath.getValue() ); String ps = p.toOSString(); env.put("PATH", ps); } XVariable vxpath = xenv.getVar("XPATH"); if( vxpath != null && vxpath.isExport() ){ Path p = new Path( vxpath.getValue() ); String ps = p.toOSString(); env.put("XPATH", ps); } } /* (non-Javadoc) * @see org.xmlsh.core.ICommand#getType() */ public CommandType getType() { return CommandType.CMD_TYPE_EXTERNAL; } public File getFile() { return mCommandFile ; } public Module getModule() { // TODO Auto-generated method stub return null; } /* (non-Javadoc) * @see org.xmlsh.core.ICommand#close() */ @Override public void close() { // TODO Auto-generated method stub } @Override public SourceLocation getLocation() { return mLocation ; } @Override public void setLocation(SourceLocation loc) { mLocation = loc ; } } // // //Copyright (C) 2008-2014 David A. Lee. // //The contents of this file are subject to the "Simplified BSD License" (the "License"); //you may not use this file except in compliance with the License. You may obtain a copy of the //License at http://www.opensource.org/licenses/bsd-license.php // //Software distributed under the License is distributed on an "AS IS" basis, //WITHOUT WARRANTY OF ANY KIND, either express or implied. //See the License for the specific language governing rights and limitations under the License. // //The Original Code is: all this file. // //The Initial Developer of the Original Code is David A. Lee // //Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // //Contributor(s): none. //