/******************************************************************************* * Copyright (c) 2014 Elphel, Inc. * This file is a part of VDT plug-in. * VDT plug-in is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VDT plug-in is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Additional permission under GNU GPL version 3 section 7: * If you modify this Program, or any covered work, by linking or combining it * with Eclipse or Eclipse plugins (or a modified version of those libraries), * containing parts covered by the terms of EPL/CPL, the licensors of this * Program grant you additional permission to convey the resulting work. * {Corresponding Source for a non-source form of such a combination shall * include the source code for the parts of Eclipse or Eclipse plugins used * as well as that of the covered work.} *******************************************************************************/ package com.elphel.vdt.core.launching; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IStreamsProxy2; import com.elphel.vdt.core.tools.contexts.BuildParamsItem; import com.elphel.vdt.veditor.VerilogPlugin; import com.elphel.vdt.veditor.preference.PreferenceStrings; public class VDTConsolePlayback{ private final VDTRunnerConfiguration runConfig; public VDTConsolePlayback (VDTRunnerConfiguration runConfig){ this.runConfig=runConfig; } private int getParserIndex( String parserName){ if (parserName==null) return -1; BuildParamsItem[] buildParamsItems = runConfig.getArgumentsItemsArray(); // uses already calculated if (buildParamsItems==null) return -1; for (int i=0;i<buildParamsItems.length;i++){ if (parserName.equals(buildParamsItems[i].getNameAsParser())) return i; } return -1; } public boolean runConsole(String consolePrefix , ILaunch launch , IProgressMonitor monitor ) throws CoreException{ final boolean debugPrint=VerilogPlugin.getPreferenceBoolean(PreferenceStrings.DEBUG_LAUNCHING); VDTProgramRunner programRunner = runConfig.getProgramRunner(); int numItem=runConfig.getPrevBuildStep(); // current is already icremented // TODO: process - null- normal run, "" - playback latest log, or timestamp - play selected log file(s) String playBackStamp=runConfig.getPlayBackStamp(); if (playBackStamp==null){ System.out.println("Wrong, it is not playback as playBackStamp==null "); return false; } BuildParamsItem buildParamsItem = runConfig.getArgumentsItemsArray()[numItem]; // uses already calculated // try to send String[] arguments = runConfig.getToolArguments(); if (arguments == null) arguments=new String[0]; if (debugPrint) { if (arguments!=null){ for (int i=0;i<arguments.length;i++){ System.out.println("Console line "+i+" = \""+arguments[i]+"\""); } } } // See if any parsers are configured int stderrParserIndex=getParserIndex(buildParamsItem.getStderr()); int stdoutParserIndex=getParserIndex(buildParamsItem.getStdout()); BuildParamsItem stderrParser=(stderrParserIndex>=0)?runConfig.getArgumentsItemsArray()[stderrParserIndex]:null; BuildParamsItem stdoutParser=(stdoutParserIndex>=0)?runConfig.getArgumentsItemsArray()[stdoutParserIndex]:null; if (debugPrint) { System.out.println("Using parser for stderr: "+((stderrParser!=null)?stderrParser.getNameAsParser():"none")); // actually may be the same as stdout System.out.println("Using parser for stdout: "+((stdoutParser!=null)?stdoutParser.getNameAsParser():"none")); } if ((stderrParser==null) && (stdoutParser==null)){ return false; // no parsers, no playback } // Open logfiles for reading (if available) boolean twoFiles=(stdoutParser!=null) && (stderrParser!=null); ToolLogFile toolLogFile=new ToolLogFile ( false, runConfig.getLogDir(), runConfig.getToolName(), buildParamsItem.getLogName(), null, // extension - use default (stdoutParser!=null), //boolean useOut, (stderrParser!=null), //boolean useErr, playBackStamp);//String buildStamp FileReader outLogReader=toolLogFile.getOutReader(); FileReader errLogReader=toolLogFile.getErrReader(); if ((outLogReader==null) && (errLogReader==null)){ if (debugPrint) { System.out.println( "No logs available in "+runConfig.getLogDir()+ " for tool "+runConfig.getToolName()+ ((buildParamsItem.getLogName()!=null)?(" ("+buildParamsItem.getLogName()+")"):"")+ ((playBackStamp.length()>0)?(" timestamp: "+playBackStamp):"")); } return false; // no parsers, no playback } if (twoFiles){ if (outLogReader==null) stdoutParser=null; // no log available if (errLogReader==null) stderrParser=null; // no log available } final String outLogName=toolLogFile.getOutLogName(); final String errLogName=toolLogFile.getErrLogName(); VDTRunner runner = VDTLaunchUtil.getRunner(); String msg="Playing back log file from "+runConfig.getLogDir()+ " for tool "+runConfig.getToolName()+ ((buildParamsItem.getLogName()!=null)?(" ("+buildParamsItem.getLogName()+")"):"")+ ((playBackStamp.length()>0)?(" timestamp: "+playBackStamp):""); runner.log(msg, null, null, false, true); // Appears in the console of the target Eclipse (may be immediately erased) if (debugPrint) runner.log(msg, null, null, false, false); // Appears in the console of the parent Eclipse IProcess processErr=null; IProcess processOut=null; IStreamsProxy2 stdoutStreamProxy=null; IStreamsProxy2 stderrStreamProxy=null; if (stdoutParser!=null){ List<String> toolArgumentsStdout = new ArrayList<String>(); List<String> stdoutArguments=stdoutParser.getParamsAsList(); if (stdoutArguments != null) toolArgumentsStdout.addAll(stdoutArguments); // overwriting runConfig, but this is done sequentially, so OK runConfig.setToolArguments((String[])toolArgumentsStdout.toArray(new String[toolArgumentsStdout.size()])); processOut=programRunner.run(runConfig, "replay log "+outLogName, launch, null, //monitor stdoutParserIndex); stdoutStreamProxy= (IStreamsProxy2) processOut.getStreamsProxy(); } if (stderrParser!=null){ List<String> toolArgumentsStderr = new ArrayList<String>(); List<String> stderrArguments=stderrParser.getParamsAsList(); if (stderrArguments != null) toolArgumentsStderr.addAll(stderrArguments); // overwriting runConfig, but this is done sequentially, so OK runConfig.setToolArguments((String[])toolArgumentsStderr.toArray(new String[toolArgumentsStderr.size()])); processErr=programRunner.run(runConfig, "replay err log "+errLogName, launch, null, //monitor); stderrParserIndex); stderrStreamProxy= (IStreamsProxy2) processErr.getStreamsProxy(); //TODO: Add error parsers } IStreamsProxy2 sendErrorsToStreamProxy=(stderrStreamProxy!=null)?stderrStreamProxy:stdoutStreamProxy; final IStreamsProxy2 fSendErrorsToStreamProxy=sendErrorsToStreamProxy; final IStreamsProxy2 fSendOutputToStreamProxy= stdoutStreamProxy; BufferedReader outBufReader=null; BufferedReader errBufReader=null; try { outBufReader=((outLogReader!=null) && (fSendOutputToStreamProxy!=null))? (new BufferedReader(outLogReader)):null; errBufReader=((errLogReader!=null) && (fSendErrorsToStreamProxy!=null))? (new BufferedReader(errLogReader)):null; } catch (Exception e) { System.out.println ("Failed to create BufferedReader"); } // Read logs should be fast, not sure how much will be buffered in IStreamsProxy2, so sending logs // one after another in the same thread if (errBufReader!=null){ int dbgBytes=0; String line; try { while ((line = errBufReader.readLine()) != null){ fSendErrorsToStreamProxy.write(line+"\n"); dbgBytes+=line.length()+1; //if(debugPrint) System.out.println ("err->>"+line); } } catch (IOException e) { System.out.println ("Failed to replay "+errLogName+" to error parser"); } finally { try { errBufReader.close(); if(debugPrint) System.out.println ("err->>CLOSED, got "+dbgBytes+" bytes"); } catch (IOException e) { System.out.println ("Failed to close "+errLogName+" BufferedReader"); } } } if (outBufReader!=null){ int dbgBytes=0; String line; try { while ((line = outBufReader.readLine()) != null){ fSendOutputToStreamProxy.write(line+"\n"); dbgBytes+=line.length()+1; // if(debugPrint) System.out.println ("out->>"+line); } } catch (IOException e) { System.out.println ("Failed to replay "+outLogName+" to output parser"); } finally { try { outBufReader.close(); if(debugPrint) System.out.println ("out->>CLOSED, got "+dbgBytes+" bytes"); // bytes OK, always the same } catch (IOException e) { System.out.println ("Failed to close "+outLogName+" BufferedReader"); } } } if (stdoutStreamProxy!=null) try { // Checked that all is sent through write() method, by end of data is often lost when calling closeInputStream() too soon AFTER // Less visible when the source is doing something, more - here, when it is just a play back if(debugPrint) System.out.println("mitigating possible closeInputStream() bug - sleeping "+VDTLaunchUtil.CLOSE_INPUT_STREAM_DELAY+" ms"); Thread.sleep(VDTLaunchUtil.CLOSE_INPUT_STREAM_DELAY); stdoutStreamProxy.closeInputStream(); // System.out.println ("closed output stream proxy"); } catch (IOException e){ System.out.println ("Failed to close output stream proxy"); } catch (InterruptedException e) { } // next uses stderrStreamProxy, not fSendErrorsToStreamProxy as it can be the same as fSendOutputToStreamProxy if (stderrStreamProxy!=null) try { if(debugPrint) System.out.println("mitigating possible closeInputStream() bug - sleeping "+VDTLaunchUtil.CLOSE_INPUT_STREAM_DELAY+" ms"); Thread.sleep(VDTLaunchUtil.CLOSE_INPUT_STREAM_DELAY); stderrStreamProxy.closeInputStream(); System.out.println ("closed error stream proxy"); // ??? } catch (IOException e){ System.out.println ("Failed to close error stream proxy"); } catch (InterruptedException e) { e.printStackTrace(); } return true; } } // class VDTConsolePlayback