Make sure we capture the output of evaluation if there’s no explicit result
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1736025 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/jline/src/test/java/org/apache/felix/gogo/jline/AbstractParserTest.java b/gogo/jline/src/test/java/org/apache/felix/gogo/jline/AbstractParserTest.java
new file mode 100644
index 0000000..0b04ab3
--- /dev/null
+++ b/gogo/jline/src/test/java/org/apache/felix/gogo/jline/AbstractParserTest.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.gogo.jline;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import junit.framework.TestCase;
+import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
+
+public abstract class AbstractParserTest extends TestCase {
+
+ private ThreadIOImpl threadIO;
+ private InputStream sin;
+ private PrintStream sout;
+ private PrintStream serr;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ sin = new NoCloseInputStream(System.in);
+ sout = new NoClosePrintStream(System.out);
+ serr = new NoClosePrintStream(System.err);
+ threadIO = new ThreadIOImpl();
+ threadIO.start();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ threadIO.stop();
+ super.tearDown();
+ }
+
+ public class Context extends org.apache.felix.gogo.jline.Context {
+ public Context() {
+ super(AbstractParserTest.this.threadIO, sin, sout, serr);
+ }
+ }
+
+ private static class NoCloseInputStream extends FilterInputStream {
+ public NoCloseInputStream(InputStream in) {
+ super(in);
+ }
+ @Override
+ public void close() throws IOException {
+ }
+ }
+
+ private static class NoClosePrintStream extends PrintStream {
+ public NoClosePrintStream(OutputStream out) {
+ super(out);
+ }
+ @Override
+ public void close() {
+ }
+ }
+
+}
diff --git a/gogo/jline/src/test/java/org/apache/felix/gogo/jline/Context.java b/gogo/jline/src/test/java/org/apache/felix/gogo/jline/Context.java
new file mode 100644
index 0000000..5e7a859
--- /dev/null
+++ b/gogo/jline/src/test/java/org/apache/felix/gogo/jline/Context.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.gogo.jline;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.nio.file.Path;
+
+import org.apache.felix.gogo.runtime.CommandProcessorImpl;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.threadio.ThreadIO;
+
+public class Context extends CommandProcessorImpl
+{
+ public static final String EMPTY = "";
+
+ private final CommandSession session;
+
+ public Context(ThreadIO threadio, InputStream in, PrintStream out, PrintStream err)
+ {
+ super(threadio);
+ Shell shell = new Shell(new MyContext(), this);
+ addCommand("gogo", this, "addCommand");
+ addCommand("gogo", this, "removeCommand");
+ addCommand("gogo", this, "eval");
+ register(this, new Builtin(), Builtin.functions);
+ register(this, new Procedural(), Procedural.functions);
+ register(this, new Posix(this), Posix.functions);
+ register(this, shell, Shell.functions);
+ session = createSession(in, out, err);
+ }
+
+ static void register(CommandProcessorImpl processor, Object target, String[] functions) {
+ for (String function : functions) {
+ processor.addCommand("gogo", target, function);
+ }
+ }
+
+ private static class MyContext implements Shell.Context {
+
+ public String getProperty(String name) {
+ return System.getProperty(name);
+ }
+
+ public void exit() throws Exception {
+ System.exit(0);
+ }
+ }
+
+ public Object execute(CharSequence source) throws Exception
+ {
+ Object result = new Exception();
+ try
+ {
+ return result = session.execute(source);
+ }
+ finally
+ {
+ System.err.println("execute<" + source + "> = ("
+ + (null == result ? "Null" : result.getClass().getSimpleName()) + ")("
+ + result + ")\n");
+ }
+ }
+
+ public void addCommand(String function, Object target)
+ {
+ addCommand("test", target, function);
+ }
+
+ public Object set(String name, Object value)
+ {
+ return session.put(name, value);
+ }
+
+ public Object get(String name)
+ {
+ return session.get(name);
+ }
+
+ public void currentDir(Path path) {
+ session.currentDir(path);
+ }
+
+ public Path currentDir() {
+ return session.currentDir();
+ }
+}
diff --git a/gogo/jline/src/test/java/org/apache/felix/gogo/jline/ShellTest.java b/gogo/jline/src/test/java/org/apache/felix/gogo/jline/ShellTest.java
new file mode 100644
index 0000000..b3e7738
--- /dev/null
+++ b/gogo/jline/src/test/java/org/apache/felix/gogo/jline/ShellTest.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.gogo.jline;
+
+import org.junit.Test;
+
+public class ShellTest extends AbstractParserTest {
+
+
+ @Test
+ public void test() throws Exception {
+ Context context = new Context();
+ context.execute("a = \"foo\"");
+ assertEquals("foo", context.get("a"));
+ context.execute("a = $(echo bar)");
+ assertEquals("bar", context.get("a"));
+ }
+
+}
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Closure.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Closure.java
index 0025f11..304485c 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Closure.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Closure.java
@@ -18,6 +18,7 @@
*/
package org.apache.felix.gogo.runtime;
+import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
@@ -144,11 +145,16 @@
// implements Function interface
public Object execute(CommandSession x, List<Object> values) throws Exception
{
+ return execute(x, values, null);
+ }
+
+ public Object execute(CommandSession x, List<Object> values, Channel capturingOutput) throws Exception
+ {
try
{
location.remove();
session.put(LOCATION, null);
- return execute(values);
+ return execute(values, capturingOutput);
}
catch (Exception e)
{
@@ -157,7 +163,7 @@
}
@SuppressWarnings("unchecked")
- private Object execute(List<Object> values) throws Exception
+ private Object execute(List<Object> values, Channel capturingOutput) throws Exception
{
if (null != values)
{
@@ -213,6 +219,9 @@
streams = new Channel[10];
System.arraycopy(session.channels, 0, streams, 0, 3);
}
+ if (capturingOutput != null) {
+ streams[1] = capturingOutput;
+ }
List<Pipe> pipes = new ArrayList<>();
if (executable instanceof Pipeline) {
@@ -317,8 +326,19 @@
}
else if (t instanceof Sequence)
{
- return new Closure(session, this, ((Sequence) t).program())
- .execute(session, parms);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Channel out = Channels.newChannel(baos);
+ Object result = new Closure(session, this, ((Sequence) t).program())
+ .execute(session, parms, out);
+ if (result != null) {
+ return result;
+ } else {
+ String s = baos.toString();
+ while (s.charAt(s.length() - 1) == '\n') {
+ s = s.substring(0, s.length() - 1);
+ }
+ return s;
+ }
}
else if (t instanceof Array)
{
@@ -342,7 +362,7 @@
}
else if (executable instanceof Sequence)
{
- return new Closure(session, this, ((Sequence) executable).program()).execute(new ArrayList<>());
+ return new Closure(session, this, ((Sequence) executable).program()).execute(new ArrayList<>(), null);
}
else
{