ソースを参照

etcdctl: fix quoted string handling in txn and watch

Fixes #6315
Anthony Romano 9 年 前
コミット
b1740f5fe4
2 ファイル変更47 行追加44 行削除
  1. 17 2
      etcdctl/ctlv3/command/util.go
  2. 30 42
      etcdctl/ctlv3/command/watch_command.go

+ 17 - 2
etcdctl/ctlv3/command/util.go

@@ -48,8 +48,23 @@ func addHexPrefix(s string) string {
 }
 }
 
 
 func argify(s string) []string {
 func argify(s string) []string {
-	r := regexp.MustCompile("'.+'|\".+\"|\\S+")
-	return r.FindAllString(s, -1)
+	r := regexp.MustCompile(`"(?:[^"\\]|\\.)*"|'[^']*'|[^'"\s]\S*[^'"\s]?`)
+	args := r.FindAllString(s, -1)
+	for i := range args {
+		if len(args[i]) == 0 {
+			continue
+		}
+		if args[i][0] == '\'' {
+			// 'single-quoted string'
+			args[i] = args[i][1 : len(args)-1]
+		} else if args[i][0] == '"' {
+			// "double quoted string"
+			if _, err := fmt.Sscanf(args[i], "%q", &args[i]); err != nil {
+				ExitWithError(ExitInvalidInput, err)
+			}
+		}
+	}
+	return args
 }
 }
 
 
 func commandCtx(cmd *cobra.Command) (context.Context, context.CancelFunc) {
 func commandCtx(cmd *cobra.Command) (context.Context, context.CancelFunc) {

+ 30 - 42
etcdctl/ctlv3/command/watch_command.go

@@ -54,34 +54,18 @@ func watchCommandFunc(cmd *cobra.Command, args []string) {
 		watchInteractiveFunc(cmd, args)
 		watchInteractiveFunc(cmd, args)
 		return
 		return
 	}
 	}
-	if len(args) < 1 || len(args) > 2 {
-		ExitWithError(ExitBadArgs, fmt.Errorf("watch in non-interactive mode requires one or two arguments as key or prefix, with range end"))
-	}
-
-	opts := []clientv3.OpOption{clientv3.WithRev(watchRev)}
-	key := args[0]
-	if len(args) == 2 {
-		if watchPrefix {
-			ExitWithError(ExitBadArgs, fmt.Errorf("`range_end` and `--prefix` cannot be set at the same time, choose one"))
-		}
-		opts = append(opts, clientv3.WithRange(args[1]))
-	}
 
 
-	if watchPrefix {
-		opts = append(opts, clientv3.WithPrefix())
-	}
-	if watchPrevKey {
-		opts = append(opts, clientv3.WithPrevKV())
+	c := mustClientFromCmd(cmd)
+	wc, err := getWatchChan(c, args)
+	if err != nil {
+		ExitWithError(ExitBadArgs, err)
 	}
 	}
 
 
-	c := mustClientFromCmd(cmd)
-	wc := c.Watch(context.TODO(), key, opts...)
 	printWatchCh(wc)
 	printWatchCh(wc)
-	err := c.Close()
-	if err == nil {
-		ExitWithError(ExitInterrupted, fmt.Errorf("watch is canceled by the server"))
+	if err = c.Close(); err != nil {
+		ExitWithError(ExitBadConnection, err)
 	}
 	}
-	ExitWithError(ExitBadConnection, err)
+	ExitWithError(ExitInterrupted, fmt.Errorf("watch is canceled by the server"))
 }
 }
 
 
 func watchInteractiveFunc(cmd *cobra.Command, args []string) {
 func watchInteractiveFunc(cmd *cobra.Command, args []string) {
@@ -113,30 +97,34 @@ func watchInteractiveFunc(cmd *cobra.Command, args []string) {
 			fmt.Fprintf(os.Stderr, "Invalid command %s (%v)\n", l, err)
 			fmt.Fprintf(os.Stderr, "Invalid command %s (%v)\n", l, err)
 			continue
 			continue
 		}
 		}
-		moreargs := flagset.Args()
-		if len(moreargs) < 1 || len(moreargs) > 2 {
-			fmt.Fprintf(os.Stderr, "Invalid command %s (Too few or many arguments)\n", l)
-			continue
-		}
-		var key string
-		_, err = fmt.Sscanf(moreargs[0], "%q", &key)
+		ch, err := getWatchChan(c, flagset.Args())
 		if err != nil {
 		if err != nil {
-			key = moreargs[0]
-		}
-		opts := []clientv3.OpOption{clientv3.WithRev(watchRev)}
-		if len(moreargs) == 2 {
-			if watchPrefix {
-				fmt.Fprintf(os.Stderr, "`range_end` and `--prefix` cannot be set at the same time, choose one\n")
-				continue
-			}
-			opts = append(opts, clientv3.WithRange(moreargs[1]))
+			fmt.Fprintf(os.Stderr, "Invalid command %s (%v)\n", l, err)
+			continue
 		}
 		}
+		go printWatchCh(ch)
+	}
+}
+
+func getWatchChan(c *clientv3.Client, args []string) (clientv3.WatchChan, error) {
+	if len(args) < 1 || len(args) > 2 {
+		return nil, fmt.Errorf("bad number of arguments")
+	}
+	key := args[0]
+	opts := []clientv3.OpOption{clientv3.WithRev(watchRev)}
+	if len(args) == 2 {
 		if watchPrefix {
 		if watchPrefix {
-			opts = append(opts, clientv3.WithPrefix())
+			return nil, fmt.Errorf("`range_end` and `--prefix` are mutually exclusive")
 		}
 		}
-		ch := c.Watch(context.TODO(), key, opts...)
-		go printWatchCh(ch)
+		opts = append(opts, clientv3.WithRange(args[1]))
+	}
+	if watchPrefix {
+		opts = append(opts, clientv3.WithPrefix())
+	}
+	if watchPrevKey {
+		opts = append(opts, clientv3.WithPrevKV())
 	}
 	}
+	return c.Watch(context.TODO(), key, opts...), nil
 }
 }
 
 
 func printWatchCh(ch clientv3.WatchChan) {
 func printWatchCh(ch clientv3.WatchChan) {