func parseWatchArgs(osArgs, commandArgs []string, envKey, envRange string, interactive bool) (watchArgs []string, execArgs []string, err error) {
	rawArgs := make([]string, len(osArgs))
	copy(rawArgs, osArgs)
	watchArgs = make([]string, len(commandArgs))
	copy(watchArgs, commandArgs)

	// remove preceding commands (e.g. ./bin/etcdctl watch)
	// handle "./bin/etcdctl watch foo -- echo watch event"
	for idx := range rawArgs {
		if rawArgs[idx] == "watch" {
			rawArgs = rawArgs[idx+1:]
			break
		}
	}

	// remove preceding commands (e.g. "watch foo bar" in interactive mode)
	// handle "./bin/etcdctl watch foo -- echo watch event"
	if interactive {
		if watchArgs[0] != "watch" {
			// "watch" not found
			watchPrefix, watchRev, watchPrevKey = false, 0, false
			return nil, nil, errBadArgsInteractiveWatch
		}
		watchArgs = watchArgs[1:]
	}

	execIdx, execExist := 0, false
	if !interactive {
		for execIdx = range rawArgs {
			if rawArgs[execIdx] == "--" {
				execExist = true
				break
			}
		}
		if execExist && execIdx == len(rawArgs)-1 {
			// "watch foo bar --" should error
			return nil, nil, errBadArgsNumSeparator
		}
		// "watch" with no argument should error
		if !execExist && len(rawArgs) < 1 && envKey == "" {
			return nil, nil, errBadArgsNum
		}
		if execExist && envKey != "" {
			// "ETCDCTL_WATCH_KEY=foo watch foo -- echo 1" should error
			// (watchArgs==["foo","echo","1"])
			widx, ridx := len(watchArgs)-1, len(rawArgs)-1
			for ; widx >= 0; widx-- {
				if watchArgs[widx] == rawArgs[ridx] {
					ridx--
					continue
				}
				// watchArgs has extra:
				// ETCDCTL_WATCH_KEY=foo watch foo  --  echo 1
				// watchArgs:                       foo echo 1
				if ridx == execIdx {
					return nil, nil, errBadArgsNumConflictEnv
				}
			}
		}
		// check conflicting arguments
		// e.g. "watch --rev 1 -- echo Hello World" has no conflict
		if !execExist && len(watchArgs) > 0 && envKey != "" {
			// "ETCDCTL_WATCH_KEY=foo watch foo" should error
			// (watchArgs==["foo"])
			return nil, nil, errBadArgsNumConflictEnv
		}
	} else {
		for execIdx = range watchArgs {
			if watchArgs[execIdx] == "--" {
				execExist = true
				break
			}
		}
		if execExist && execIdx == len(watchArgs)-1 {
			// "watch foo bar --" should error
			watchPrefix, watchRev, watchPrevKey = false, 0, false
			return nil, nil, errBadArgsNumSeparator
		}

		flagset := NewWatchCommand().Flags()
		if perr := flagset.Parse(watchArgs); perr != nil {
			watchPrefix, watchRev, watchPrevKey = false, 0, false
			return nil, nil, perr
		}
		pArgs := flagset.Args()

		// "watch" with no argument should error
		if !execExist && envKey == "" && len(pArgs) < 1 {
			watchPrefix, watchRev, watchPrevKey = false, 0, false
			return nil, nil, errBadArgsNum
		}
		// check conflicting arguments
		// e.g. "watch --rev 1 -- echo Hello World" has no conflict
		if !execExist && len(pArgs) > 0 && envKey != "" {
			// "ETCDCTL_WATCH_KEY=foo watch foo" should error
			// (watchArgs==["foo"])
			watchPrefix, watchRev, watchPrevKey = false, 0, false
			return nil, nil, errBadArgsNumConflictEnv
		}
	}

	argsWithSep := rawArgs
	if interactive {
		// interactive mode directly passes "--" to the command args
		argsWithSep = watchArgs
	}

	idx, foundSep := 0, false
	for idx = range argsWithSep {
		if argsWithSep[idx] == "--" {
			foundSep = true
			break
		}
	}
	if foundSep {
		execArgs = argsWithSep[idx+1:]
	}

	if interactive {
		flagset := NewWatchCommand().Flags()
		if perr := flagset.Parse(argsWithSep); perr != nil {
			return nil, nil, perr
		}
		watchArgs = flagset.Args()

		watchPrefix, err = flagset.GetBool("prefix")
		if err != nil {
			return nil, nil, err
		}
		watchRev, err = flagset.GetInt64("rev")
		if err != nil {
			return nil, nil, err
		}
		watchPrevKey, err = flagset.GetBool("prev-kv")
		if err != nil {
			return nil, nil, err
		}
	}

	// "ETCDCTL_WATCH_KEY=foo watch -- echo hello"
	// should translate "watch foo -- echo hello"
	// (watchArgs=["echo","hello"] should be ["foo","echo","hello"])
	if envKey != "" {
		ranges := []string{envKey}
		if envRange != "" {
			ranges = append(ranges, envRange)
		}
		watchArgs = append(ranges, watchArgs...)
	}

	if !foundSep {
		return watchArgs, nil, nil
	}

	// "watch foo bar --rev 1 -- echo hello" or "watch foo --rev 1 bar -- echo hello",
	// then "watchArgs" is "foo bar echo hello"
	// so need ignore args after "argsWithSep[idx]", which is "--"
	endIdx := 0
	for endIdx = len(watchArgs) - 1; endIdx >= 0; endIdx-- {
		if watchArgs[endIdx] == argsWithSep[idx+1] {
			break
		}
	}
	watchArgs = watchArgs[:endIdx]

	return watchArgs, execArgs, nil
}
func parseWatchArgs(osArgs, commandArgs []string, envKey, envRange string, interactive bool) (watchArgs []string, execArgs []string, err error) {
	rawArgs := make([]string, len(osArgs))
	copy(rawArgs, osArgs)
	watchArgs = make([]string, len(commandArgs))
	copy(watchArgs, commandArgs)

	// remove preceding commands (e.g. ./bin/etcdctl watch)
	// handle "./bin/etcdctl watch foo -- echo watch event"
	for idx := range rawArgs {
		if rawArgs[idx] == "watch" {
			rawArgs = rawArgs[idx+1:]
			break
		}
	}

	// remove preceding commands (e.g. "watch foo bar" in interactive mode)
	// handle "./bin/etcdctl watch foo -- echo watch event"
	if interactive {
		if watchArgs[0] != "watch" {
			// "watch" not found
			watchPrefix, watchRev, watchPrevKey = false, 0, false
			return nil, nil, errBadArgsInteractiveWatch
		}
		watchArgs = watchArgs[1:]
	}

	execIdx, execExist := 0, false
	if !interactive {
		for execIdx = range rawArgs {
			if rawArgs[execIdx] == "--" {
				execExist = true
				break
			}
		}
		if execExist && execIdx == len(rawArgs)-1 {
			// "watch foo bar --" should error
			return nil, nil, errBadArgsNumSeparator
		}
		// "watch" with no argument should error
		if !execExist && len(rawArgs) < 1 && envKey == "" {
			return nil, nil, errBadArgsNum
		}
		if execExist && envKey != "" {
			// "ETCDCTL_WATCH_KEY=foo watch foo -- echo 1" should error
			// (watchArgs==["foo","echo","1"])
			widx, ridx := len(watchArgs)-1, len(rawArgs)-1
			for ; widx >= 0; widx-- {
				if watchArgs[widx] == rawArgs[ridx] {
					ridx--
					continue
				}
				// watchArgs has extra:
				// ETCDCTL_WATCH_KEY=foo watch foo  --  echo 1
				// watchArgs:                       foo echo 1
				if ridx == execIdx {
					return nil, nil, errBadArgsNumConflictEnv
				}
			}
		}
		// check conflicting arguments
		// e.g. "watch --rev 1 -- echo Hello World" has no conflict
		if !execExist && len(watchArgs) > 0 && envKey != "" {
			// "ETCDCTL_WATCH_KEY=foo watch foo" should error
			// (watchArgs==["foo"])
			return nil, nil, errBadArgsNumConflictEnv
		}
	} else {
		for execIdx = range watchArgs {
			if watchArgs[execIdx] == "--" {
				execExist = true
				break
			}
		}
		if execExist && execIdx == len(watchArgs)-1 {
			// "watch foo bar --" should error
			watchPrefix, watchRev, watchPrevKey = false, 0, false
			return nil, nil, errBadArgsNumSeparator
		}

		flagset := NewWatchCommand().Flags()
		if perr := flagset.Parse(watchArgs); perr != nil {
			watchPrefix, watchRev, watchPrevKey = false, 0, false
			return nil, nil, perr
		}
		pArgs := flagset.Args()

		// "watch" with no argument should error
		if !execExist && envKey == "" && len(pArgs) < 1 {
			watchPrefix, watchRev, watchPrevKey = false, 0, false
			return nil, nil, errBadArgsNum
		}
		// check conflicting arguments
		// e.g. "watch --rev 1 -- echo Hello World" has no conflict
		if !execExist && len(pArgs) > 0 && envKey != "" {
			// "ETCDCTL_WATCH_KEY=foo watch foo" should error
			// (watchArgs==["foo"])
			watchPrefix, watchRev, watchPrevKey = false, 0, false
			return nil, nil, errBadArgsNumConflictEnv
		}
	}

	argsWithSep := rawArgs
	if interactive {
		// interactive mode directly passes "--" to the command args
		argsWithSep = watchArgs
	}

	idx, foundSep := 0, false
	for idx = range argsWithSep {
		if argsWithSep[idx] == "--" {
			foundSep = true
			break
		}
	}
	if foundSep {
		execArgs = argsWithSep[idx+1:]
	}

	if interactive {
		flagset := NewWatchCommand().Flags()
		if perr := flagset.Parse(argsWithSep); perr != nil {
			return nil, nil, perr
		}
		watchArgs = flagset.Args()

		watchPrefix, err = flagset.GetBool("prefix")
		if err != nil {
			return nil, nil, err
		}
		watchRev, err = flagset.GetInt64("rev")
		if err != nil {
			return nil, nil, err
		}
		watchPrevKey, err = flagset.GetBool("prev-kv")
		if err != nil {
			return nil, nil, err
		}
	}

	// "ETCDCTL_WATCH_KEY=foo watch -- echo hello"
	// should translate "watch foo -- echo hello"
	// (watchArgs=["echo","hello"] should be ["foo","echo","hello"])
	if envKey != "" {
		ranges := []string{envKey}
		if envRange != "" {
			ranges = append(ranges, envRange)
		}
		watchArgs = append(ranges, watchArgs...)
	}

	if !foundSep {
		return watchArgs, nil, nil
	}

	// "watch foo bar --rev 1 -- echo hello" or "watch foo --rev 1 bar -- echo hello",
	// then "watchArgs" is "foo bar echo hello"
	// so need ignore args after "argsWithSep[idx]", which is "--"
	endIdx := 0
	for endIdx = len(watchArgs) - 1; endIdx >= 0; endIdx-- {
		if watchArgs[endIdx] == argsWithSep[idx+1] {
			break
		}
	}
	watchArgs = watchArgs[:endIdx]

	return watchArgs, execArgs, nil
}
// "commandArgs" is the command arguments after "spf13/cobra" parses
// all "watch" command flags, strips out special characters (e.g. "--").
// "orArgs" is the raw arguments passed to "watch" command
// (e.g. ./bin/etcdctl watch foo --rev 1 bar).
// "--" characters are invalid arguments for "spf13/cobra" library,
// so no need to handle such cases.