change priority of ; and | to match bash. resolves FELIX-1500.


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@892356 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Closure.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Closure.java
index c205775..8ab4dc1 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Closure.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Closure.java
@@ -18,11 +18,15 @@
  */
 package org.apache.felix.gogo.runtime.shell;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.osgi.service.command.CommandSession;
 import org.osgi.service.command.Function;
 
-import java.util.*;
-
 public class Closure extends Reflective implements Function
 {
     private static final long serialVersionUID = 1L;
@@ -42,65 +46,75 @@
     {
         parms = values;
         Parser parser = new Parser(source);
-        ArrayList<Pipe> pipes = new ArrayList<Pipe>();
         List<List<List<CharSequence>>> program = parser.program();
+        Pipe last = null;
 
-        for (List<List<CharSequence>> statements : program)
+        for (List<List<CharSequence>> pipeline : program)
         {
-            Pipe current = new Pipe(this, statements);
+            ArrayList<Pipe> pipes = new ArrayList<Pipe>();
 
-            if (pipes.isEmpty())
-            {
-		if (current.out == null)
+	    for (List<CharSequence> statement : pipeline)
+	    {
+		Pipe current = new Pipe(this, statement);
+
+		if (pipes.isEmpty())
 		{
-		    current.setIn(session.in);
-		    current.setOut(session.out);
-		    current.setErr(session.err);
+		    if (current.out == null)
+		    {
+			current.setIn(session.in);
+			current.setOut(session.out);
+			current.setErr(session.err);
+		    }
 		}
-            }
-            else
-            {
-                Pipe previous = pipes.get(pipes.size() - 1);
-                previous.connect(current);
-            }
-            pipes.add(current);
-        }
-        if (pipes.size() == 0)
-        {
-            return null;
-        }
+		else
+		{
+		    Pipe previous = pipes.get(pipes.size() - 1);
+		    previous.connect(current);
+		}
+		pipes.add(current);
+	    }
 
-        if (pipes.size() == 1)
-        {
-            pipes.get(0).run();
-        }
-        else
-        {
-            for (Pipe pipe : pipes)
-            {
-                pipe.start();
-            }
-            for (Pipe pipe : pipes)
-            {
-                pipe.join();
-            }
-        }
+	    if (pipes.size() == 1)
+	    {
+		pipes.get(0).run();
+	    }
+	    else if (pipes.size() > 1)
+	    {
+		for (Pipe pipe : pipes)
+		{
+		    pipe.start();
+		}
+		for (Pipe pipe : pipes)
+		{
+		    pipe.join();
+		}
+	    }
 
-        Pipe last = pipes.remove(pipes.size() - 1);
+	    last = pipes.remove(pipes.size() - 1);
 
-        for (Pipe pipe : pipes)
-        {
-            if (pipe.exception != null)
-            {
-                // can't throw exception, as result is defined by last pipe
-                session.err.println("pipe: " + pipe.exception);
-            }
-        }
+	    for (Pipe pipe : pipes)
+	    {
+		if (pipe.exception != null)
+		{
+		    // can't throw exception, as result is defined by last pipe
+		    session.err.println("pipe: " + pipe.exception);
+		    session.put("pipe-exception", pipe.exception);
+		}
+	    }
 
-        if (last.exception != null)
-        {
-            throw last.exception;
-        }
+	    if (last.exception != null)
+	    {
+		Pipe.reset();
+		throw last.exception;
+	    }
+	}
+
+	Pipe.reset();   // reset IO in case sshd uses same thread for new client
+
+	if (last == null)
+	{
+	    return null;
+	}
 
         if (last.result instanceof Object[])
         {
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Parser.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Parser.java
index 60d09ba..930a3ab 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Parser.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Parser.java
@@ -137,11 +137,15 @@
         ws();
         if (!eof())
         {
-            program.add(statements());
-            while (peek() == '|')
+            program.add(pipeline());
+            while (peek() == ';')
             {
                 current++;
-                program.add(statements());
+                List<List<CharSequence>> pipeline = pipeline();
+                if (pipeline.get(0).get(0).length() != 0)
+                {
+                    program.add(pipeline);
+                }
             }
         }
         if (!eof())
@@ -157,19 +161,22 @@
         return text.subSequence(Math.max(0, current - 20), Math.min(text.length(), current + 4));
     }
 
-    public List<List<CharSequence>> statements()
+    public List<List<CharSequence>> pipeline()
     {
         List<List<CharSequence>> statements = new ArrayList<List<CharSequence>>();
         statements.add(statement());
-        while (peek() == ';')
+        while (peek() == '|')
         {
             current++;
-            // derek: BUGFIX: allow trailing ;
             ws();
             if (!eof())
             {
                 statements.add(statement());
             }
+            else
+            {
+                throw new RuntimeException("Eof found after pipe |");
+            }
         }
         return statements;
     }
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Pipe.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Pipe.java
index 5b8dca5..f3608cf 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Pipe.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Pipe.java
@@ -39,18 +39,29 @@
     Closure closure;
     Exception exception;
     Object result;
-    List<List<CharSequence>> statements;
-
-    public Pipe(Closure closure, List<List<CharSequence>> statements)
+    List<CharSequence> statement;
+    
+    public static void reset()
     {
-        super("pipe-" + statements);
+        tIn.set(null);
+        tOut.set(null);
+        tErr.set(null);
+    }
+
+    public Pipe(Closure closure, List<CharSequence> statement)
+    {
+        super("pipe-" + statement);
         this.closure = closure;
-        this.statements = statements;
+        this.statement = statement;
 
         in = tIn.get();
         out = tOut.get();
         err = tErr.get();
     }
+    
+    public String toString() {
+        return "pipe<" + statement + "> out=" + out;
+    }
 
     public void setIn(InputStream in)
     {
@@ -86,13 +97,10 @@
 
         try
         {
-            for (List<CharSequence> statement : statements)
+            result = closure.executeStatement(statement);
+            if (result != null && pout != null)
             {
-                result = closure.executeStatement(statement);
-                if (result != null && pout != null)
-                {
-                    out.println(closure.session.format(result, Converter.INSPECT));
-                }
+                out.println(closure.session.format(result, Converter.INSPECT));
             }
         }
         catch (Exception e)
@@ -119,11 +127,6 @@
             {
                 e.printStackTrace();
             }
-
-            tIn.set(null);
-            tOut.set(null);
-            tErr.set(null);
-
         }
     }
 }
diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/shell/TestParser.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/shell/TestParser.java
index bc521a1..18aa183 100644
--- a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/shell/TestParser.java
+++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/shell/TestParser.java
@@ -113,9 +113,10 @@
         assertEquals("def", c.execute("echo def|grep d.*|capture"));
         assertEquals("def", c.execute("echoout def|grep d.*|capture"));
         assertEquals("def", c.execute("myecho def|grep d.*|capture"));
-        assertEquals("def", c.execute("echo abc; echo def; echo ghi|grep d.*|capture"));
+        assertEquals("def", c.execute("(echoout abc; echoout def; echoout ghi)|grep d.*|capture"));
+        assertEquals("", c.execute("echoout def; echoout ghi | grep d.* | capture"));
         assertEquals("hello world", c.execute("echo hello world|capture"));
-        assertEquals("defghi", c.execute("echo abc; echo def; echo ghi|grep 'def|ghi'|capture"));
+        assertEquals("defghi", c.execute("(echoout abc; echoout def; echoout ghi)|grep 'def|ghi'|capture"));
     }
 
     public void testAssignment() throws Exception
@@ -320,17 +321,17 @@
         List<List<List<CharSequence>>> x = new Parser("abc def|ghi jkl;mno pqr|stu vwx").program();
         assertEquals("abc", x.get(0).get(0).get(0));
         assertEquals("def", x.get(0).get(0).get(1));
-        assertEquals("ghi", x.get(1).get(0).get(0));
-        assertEquals("jkl", x.get(1).get(0).get(1));
-        assertEquals("mno", x.get(1).get(1).get(0));
-        assertEquals("pqr", x.get(1).get(1).get(1));
-        assertEquals("stu", x.get(2).get(0).get(0));
-        assertEquals("vwx", x.get(2).get(0).get(1));
+        assertEquals("ghi", x.get(0).get(1).get(0));
+        assertEquals("jkl", x.get(0).get(1).get(1));
+        assertEquals("mno", x.get(1).get(0).get(0));
+        assertEquals("pqr", x.get(1).get(0).get(1));
+        assertEquals("stu", x.get(1).get(1).get(0));
+        assertEquals("vwx", x.get(1).get(1).get(1));
     }
 
     public void testStatements()
     {
-        List<List<CharSequence>> x = new Parser("abc def;ghi jkl;mno pqr").statements();
+        List<List<CharSequence>> x = new Parser("abc def|ghi jkl|mno pqr").pipeline();
         assertEquals("abc", x.get(0).get(0));
         assertEquals("def", x.get(0).get(1));
         assertEquals("ghi", x.get(1).get(0));