Skip to content

Commit 0f9959e

Browse files
committed
Prepared the error detection in a Ruby script
1 parent d2ef4fa commit 0f9959e

1 file changed

Lines changed: 165 additions & 8 deletions

File tree

RubyScript/src/org/knime/ext/jruby/RubyScriptNodeModel.java

Lines changed: 165 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
import java.net.URL;
1515
import java.util.ArrayList;
1616
import java.util.List;
17+
import java.util.regex.Matcher;
18+
import java.util.regex.Pattern;
19+
1720
import org.eclipse.core.runtime.FileLocator;
1821
import org.eclipse.core.runtime.Path;
1922
import org.eclipse.core.runtime.Platform;
@@ -51,6 +54,7 @@ public class RubyScriptNodeModel extends NodeModel {
5154
public static final String APPEND_COLS = "append_columns";
5255
public static final String COLUMN_NAMES = "new_column_names";
5356
public static final String COLUMN_TYPES = "new_column_types";
57+
5458
protected int numInputs = 0;
5559
protected int numOutputs = 0;
5660

@@ -72,17 +76,43 @@ public class RubyScriptNodeModel extends NodeModel {
7276

7377
private boolean snippetMode;
7478

79+
private class ScriptError {
80+
public int errorLine;
81+
public int errorColumn;
82+
public String errorType;
83+
public String errorText;
84+
public String errorTrace;
85+
public String msg;
86+
87+
public ScriptError() {
88+
clear();
89+
}
90+
91+
public void clear() {
92+
errorLine = -1;
93+
errorColumn = -1;
94+
errorType = "--UnKnown--";
95+
errorText = "--UnKnown--";
96+
errorTrace = "";
97+
msg = "";
98+
}
99+
}
100+
101+
private ScriptError m_script_error;
102+
75103
protected RubyScriptNodeModel(int inNumInputs, int inNumOutputs, boolean snippetMode) {
76104
super(inNumInputs, inNumOutputs);
77105

78106
this.numInputs = inNumInputs;
79107
this.numOutputs = inNumOutputs;
80108
this.snippetMode = snippetMode;
109+
110+
this.m_script_error = new ScriptError();
81111

82112
// define the common imports string
83113
StringBuffer buffer = new StringBuffer();
84114
buffer.append("require PLUGIN_PATH+'/rb/knime.rb'\n");
85-
scriptFirstLineNumber = 2;
115+
scriptFirstLineNumber = 1;
86116

87117
if (this.snippetMode == true ) {
88118
buffer.append("func = ->(row) do \n");
@@ -270,11 +300,30 @@ protected final BufferedDataTable[] execute(final BufferedDataTable[] inData,
270300
container.put("$outColumnTypes", columnTypes);
271301
container.put("$exec", exec);
272302
container.put("PLUGIN_PATH", rubyPluginPath);
273-
274-
EvalUnit unit = container.parse(scriptHeader + script + scriptFooter,
275-
scriptFirstLineNumber);
276-
unit.run();
277-
303+
String script_fn = "node_script.rb";
304+
305+
try {
306+
m_script_error.clear();
307+
container.setScriptFilename(script_fn);
308+
EvalUnit unit = container.parse(scriptHeader + script
309+
+ scriptFooter,
310+
-scriptFirstLineNumber // fix first string number
311+
);
312+
unit.run();
313+
} catch (Exception e) {
314+
Pattern p = Pattern.compile("SystemExit: ([0-9]+)");
315+
Matcher matcher = p.matcher(e.toString());
316+
if (matcher.find()) {
317+
int exitCode = Integer.parseInt(matcher.group(1));
318+
logger.debug("Exit code: " + exitCode);
319+
} else {
320+
findErrorSource(e, script_fn);
321+
logger.error("Script error in line: "
322+
+ m_script_error.errorLine);
323+
}
324+
throw new CanceledExecutionException(e.getMessage());
325+
}
326+
278327
BufferedDataTable[] result = new BufferedDataTable[numOutputs];
279328
for (i = 0; i < numOutputs; i++) {
280329
outContainer[i].close();
@@ -289,6 +338,8 @@ protected final BufferedDataTable[] execute(final BufferedDataTable[] inData,
289338
*/
290339
protected final DataTableSpec[] configure(final DataTableSpec[] inSpecs)
291340
throws InvalidSettingsException {
341+
m_script_error.clear();
342+
292343
appendCols &= numInputs > 0;
293344
// append the property columns to the data table spec
294345
DataTableSpec newSpec = appendCols ? inSpecs[0] : new DataTableSpec();
@@ -344,7 +395,7 @@ protected final DataTableSpec[] configure(final DataTableSpec[] inSpecs)
344395
DataTableSpec[] result = new DataTableSpec[numOutputs];
345396
for (int i = 0; i < numOutputs; i++) {
346397
result[i] = newSpec;
347-
}
398+
}
348399
return result;
349400
}
350401

@@ -420,5 +471,111 @@ public static void setJavaClasspathExtensionPath(String path) {
420471

421472
public static String getJavaClasspathExtensionPath() {
422473
return javaClasspathExtensionsPath;
423-
}
474+
}
475+
476+
private int findErrorSource(Throwable thr, String filename) {
477+
String err = thr.getMessage();
478+
479+
if (err.startsWith("(SyntaxError)")) {
480+
// org.jruby.parser.ParserSyntaxException
481+
// (SyntaxError) script.rb:2: syntax error, unexpected tRCURLY
482+
483+
Pattern pLineS = Pattern.compile("(?<=:)(\\d+):(.*)");
484+
Matcher mLine = pLineS.matcher(err);
485+
if (mLine.find()) {
486+
logger.debug("SyntaxError error line: " + mLine.group(1));
487+
m_script_error.errorText = mLine.group(2) == null ? m_script_error.errorText
488+
: mLine.group(2);
489+
logger.debug("SyntaxError: " + m_script_error.errorText);
490+
m_script_error.errorLine = Integer.parseInt(mLine.group(1));
491+
m_script_error.errorColumn = -1;
492+
m_script_error.errorType = "SyntaxError";
493+
}
494+
} else {
495+
// if (err.startsWith("(NameError)")) {
496+
// org.jruby.embed.EvalFailedException
497+
// (NameError) undefined local variable or method `asdf' for
498+
// main:Object
499+
500+
Pattern type = Pattern.compile("(?<=\\()(\\w*)");
501+
Matcher mLine = type.matcher(err);
502+
if (mLine.find()) {
503+
m_script_error.errorType = mLine.group(1);
504+
}
505+
Throwable cause = thr.getCause();
506+
// cause.printStackTrace();
507+
for (StackTraceElement line : cause.getStackTrace()) {
508+
if (line.getFileName().equals(filename)) {
509+
m_script_error.errorText = cause.getMessage();
510+
m_script_error.errorColumn = -1;
511+
m_script_error.errorLine = line.getLineNumber();
512+
m_script_error.errorText = thr.getMessage();
513+
514+
Pattern knimeType = Pattern
515+
.compile("(?<=org.knime.)(.*)(?=:)");
516+
Matcher mKnimeType = knimeType
517+
.matcher(m_script_error.errorText);
518+
519+
if (mKnimeType.find()) {
520+
m_script_error.errorType = mKnimeType.group(1);
521+
}
522+
523+
m_script_error.errorType = "RuntimeError";
524+
525+
break;
526+
}
527+
}
528+
}
529+
530+
m_script_error.msg = "script";
531+
if (m_script_error.errorLine != -1) {
532+
m_script_error.msg += " stopped with error in line "
533+
+ m_script_error.errorLine;
534+
if (m_script_error.errorColumn != -1) {
535+
m_script_error.msg += " at column "
536+
+ m_script_error.errorColumn;
537+
}
538+
} else {
539+
m_script_error.msg += "] stopped with error at line --unknown--";
540+
}
541+
542+
if (m_script_error.errorType == "RuntimeError") {
543+
logger.error(m_script_error.msg + "\n" + m_script_error.errorType
544+
+ " ( " + m_script_error.errorText + " )");
545+
546+
Throwable cause = thr.getCause();
547+
// cause.printStackTrace();
548+
StackTraceElement[] stack = cause.getStackTrace();
549+
/*
550+
* StringWriter writer = new StringWriter(); PrintWriter out = new
551+
* PrintWriter(writer); cause.printStackTrace(out); errorTrace =
552+
* writer.toString();
553+
*/
554+
StringBuilder builder = new StringBuilder();
555+
for (StackTraceElement line : stack) {
556+
builder.append(line.getLineNumber());
557+
builder.append(":\t");
558+
builder.append(line.getClassName());
559+
builder.append(" ( ");
560+
builder.append(line.getMethodName());
561+
builder.append(" )\t");
562+
builder.append(line.getFileName());
563+
builder.append('\n');
564+
}
565+
566+
m_script_error.errorTrace = builder.toString();
567+
if (m_script_error.errorTrace.length() > 0) {
568+
logger.error("--- Traceback --- error source first\n"
569+
+ "line: class ( method ) file \n"
570+
+ m_script_error.errorTrace
571+
+ "[error] --- Traceback --- end --------------");
572+
}
573+
574+
} else if (m_script_error.errorType != "SyntaxError") {
575+
logger.error(m_script_error.msg);
576+
logger.error("Could not evaluate error source nor reason. Analyze StackTrace!");
577+
logger.error(err);
578+
}
579+
return m_script_error.errorLine;
580+
}
424581
}

0 commit comments

Comments
 (0)