浏览代码

ZOOKEEPER-1853: zkCli.sh can't issue a CREATE command containing
spaces in the data (Ryan Lamore via rgs)

git-svn-id: https://svn.apache.org/repos/asf/zookeeper/trunk@1713303 13f79535-47bb-0310-9956-ffa450edef68

Raúl Gutiérrez Segalés 9 年之前
父节点
当前提交
df7e637a4d

+ 3 - 0
.gitignore

@@ -1,9 +1,12 @@
 .classpath
 .eclipse/
+.idea/
 .project
 .revision/
 .settings/
 build/
+out/
+*.iml
 src/c/core.*
 src/c/TEST-*.txt
 src/c/*.la

+ 3 - 0
CHANGES.txt

@@ -205,6 +205,9 @@ BUGFIXES:
   ZOOKEEPER-2227: stmk four-letter word fails execution at server while reading
   trace mask argument (Chris Nauroth via rgs)
 
+  ZOOKEEPER-1853: zkCli.sh can't issue a CREATE command containing spaces in
+  the data (Ryan Lamore via rgs)
+
 IMPROVEMENTS:
   ZOOKEEPER-1660 Documentation for Dynamic Reconfiguration (Reed Wanderman-Milne via shralex)  
 

+ 18 - 9
src/java/main/org/apache/zookeeper/ZooKeeperMain.java

@@ -39,6 +39,9 @@ import org.slf4j.LoggerFactory;
 import org.apache.zookeeper.ZooDefs.Ids;
 import org.apache.zookeeper.data.Stat;
 import java.util.StringTokenizer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 import org.apache.commons.cli.ParseException;
 import org.apache.zookeeper.cli.AddAuthCommand;
 import org.apache.zookeeper.cli.CliCommand;
@@ -145,6 +148,8 @@ public class ZooKeeperMain {
         private Map<String,String> options = new HashMap<String,String>();
         private List<String> cmdArgs = null;
         private String command = null;
+        public static final Pattern ARGS_PATTERN = Pattern.compile("\\s*([^\"\']\\S*|\"[^\"]*\"|'[^']*')\\s*");
+        public static final Pattern QUOTED_PATTERN = Pattern.compile("^([\'\"])(.*)(\\1)$");
 
         public MyCommandOptions() {
           options.put("server", "localhost:2181");
@@ -216,18 +221,22 @@ public class ZooKeeperMain {
          * @return true if parsing succeeded.
          */
         public boolean parseCommand( String cmdstring ) {
-            StringTokenizer cmdTokens = new StringTokenizer(cmdstring, " ");          
-            String[] args = new String[cmdTokens.countTokens()];
-            int tokenIndex = 0;
-            while (cmdTokens.hasMoreTokens()) {
-                args[tokenIndex] = cmdTokens.nextToken();
-                tokenIndex++;
+            Matcher matcher = ARGS_PATTERN.matcher(cmdstring);
+
+            List args = new LinkedList();
+            while (matcher.find()) {
+                String value = matcher.group(1);
+                if (QUOTED_PATTERN.matcher(value).matches()) {
+                    // Strip off the surrounding quotes
+                    value = value.substring(1, value.length() - 1);
+                }
+                args.add(value);
             }
-            if (args.length == 0){
+            if (args.isEmpty()){
                 return false;
             }
-            command = args[0];
-            cmdArgs = Arrays.asList(args);
+            command = (String)args.get(0);
+            cmdArgs = args;
             return true;
         }
     }

+ 55 - 0
src/java/test/org/apache/zookeeper/ZooKeeperTest.java

@@ -164,6 +164,61 @@ public class ZooKeeperTest extends ClientBase {
         Assert.assertEquals("/ is not taken as second argument", zkMain.cl.getCmdArgument(1), "/");
     }
 
+    @Test
+    public void testParseWithQuotes() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        for (String quoteChar : new String[] {"'", "\""}) {
+            String cmdstring = String.format("create /node %1$squoted data%1$s", quoteChar);
+            zkMain.cl.parseCommand(cmdstring);
+            Assert.assertEquals("quotes combine arguments", zkMain.cl.getNumArguments(), 3);
+            Assert.assertEquals("create is not taken as first argument", zkMain.cl.getCmdArgument(0), "create");
+            Assert.assertEquals("/node is not taken as second argument", zkMain.cl.getCmdArgument(1), "/node");
+            Assert.assertEquals("quoted data is not taken as third argument", zkMain.cl.getCmdArgument(2), "quoted data");
+        }
+    }
+
+    @Test
+    public void testParseWithMixedQuotes() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        for (String[] quoteChars : new String[][] {{"'", "\""}, {"\"", "'"}}) {
+            String outerQuotes = quoteChars[0];
+            String innerQuotes = quoteChars[1];
+            String cmdstring = String.format("create /node %1$s%2$squoted data%2$s%1$s", outerQuotes, innerQuotes);
+            zkMain.cl.parseCommand(cmdstring);
+            Assert.assertEquals("quotes combine arguments", zkMain.cl.getNumArguments(), 3);
+            Assert.assertEquals("create is not taken as first argument", zkMain.cl.getCmdArgument(0), "create");
+            Assert.assertEquals("/node is not taken as second argument", zkMain.cl.getCmdArgument(1), "/node");
+            Assert.assertEquals("quoted data is not taken as third argument", zkMain.cl.getCmdArgument(2), innerQuotes + "quoted data" + innerQuotes);
+        }
+    }
+
+    @Test
+    public void testParseWithEmptyQuotes() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmdstring = "create /node ''";
+        zkMain.cl.parseCommand(cmdstring);
+        Assert.assertEquals("empty quotes should produce arguments", zkMain.cl.getNumArguments(), 3);
+        Assert.assertEquals("create is not taken as first argument", zkMain.cl.getCmdArgument(0), "create");
+        Assert.assertEquals("/node is not taken as second argument", zkMain.cl.getCmdArgument(1), "/node");
+        Assert.assertEquals("empty string is not taken as third argument", zkMain.cl.getCmdArgument(2), "");
+    }
+
+    @Test
+    public void testParseWithMultipleQuotes() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmdstring = "create /node '' ''";
+        zkMain.cl.parseCommand(cmdstring);
+        Assert.assertEquals("expected 5 arguments", zkMain.cl.getNumArguments(), 4);
+        Assert.assertEquals("create is not taken as first argument", zkMain.cl.getCmdArgument(0), "create");
+        Assert.assertEquals("/node is not taken as second argument", zkMain.cl.getCmdArgument(1), "/node");
+        Assert.assertEquals("empty string is not taken as third argument", zkMain.cl.getCmdArgument(2), "");
+        Assert.assertEquals("empty string is not taken as fourth argument", zkMain.cl.getCmdArgument(3), "");
+    }
+
     @Test
     public void testInvalidCommand() throws Exception {
         final ZooKeeper zk = createClient();