Merge pull request #31144 from ohmystack/fix/zsh-completion

Automatic merge from submit-queue

Fix named pipe in kubectl zsh completion

This PR fixes #28049

Though my zsh version > 5.0, I still got the problem. So, I think we need this fix.

---

### Env

```
OS: Ubuntu 14.04
$ zsh --version
zsh 5.0.2 (x86_64-pc-linux-gnu)
```

### A simple DEMO to show the root cause

In zsh and bash, a multi-line named pipe, who is wrapped by parenthesis, is possible to mismatch the "right parenthesis", even that parenthesis is in a here-document.

The following script was going to use `sed` to print the text in the 'BASH_COMPLETION_EOF' here-document. 
> * I made the `sed` simpler. As you can see, `sed` actually does nothing here. It just prints what it gets from `<<`). In real [`pkg/kubectl/cmd/completion.go`](https://github.com/kubernetes/kubernetes/blob/v1.3.5/pkg/kubectl/cmd/completion.go#L246-L258), `sed` will do some text replacement, changing bash functions to zsh functions. But that is not the point of the problem.
> * I use `cat <(...)` to replace the `source <(...)`.
> In this way, we can see how named pipe works.

run-bad.zsh:
```bash
#!/usr/bin/zsh
cat <(sed -e 's/foo/bar/g' <<'BASH_COMPLETION_EOF'
  aaa='aaa'
  case aaa in
    'aaa')      #  <- This ')' is in a here-document, but it is handled by named pipe by mistake.
      echo 'yes'
      ;;
  esac
BASH_COMPLETION_EOF
)
```

> Output:
> ```
> ./run-bad.zsh
>     aaa='aaa'
>     case aaa in
>       'aaa'yes     <- You can see the here-document `echo yes` has been executed!!!
> ./run-bad.zsh:8: parse error near `;;'
> ```

The named pipe `<(sed ...` "eats" the `)`, which should belong to `case aaa in 'aaa')`. So that the named pipe ends earlier than expectation. The left zsh code is broken, it fails.

### Here's the fix

Move the code into a function, and use an inline named pipe.

run.zsh:
```bash
#!/usr/bin/zsh

print_sed_result() {
  sed -e 's/foo/bar/g' <<'BASH_COMPLETION_EOF'
  aaa='aaa'
  case aaa in
    'aaa')
      echo 'yes'
      ;;
  esac
BASH_COMPLETION_EOF
}

cat <(print_sed_result)     # <- Use an inline named pipe
```

> Output:
> ```
> ./run.zsh                                                                                                                                                                    > stack@docker-dev01
>         aaa='aaa'
>         case aaa in
>           'aaa')
>             echo 'yes'
>             ;;
>         esac
> ```

Now, the here-document and named pipe work correctly.
This commit is contained in:
Kubernetes Submit Queue 2016-09-05 15:31:18 -07:00 committed by GitHub
commit ae3b956c65

View File

@ -245,7 +245,8 @@ if sed --help 2>&1 | grep -q GNU; then
RWORD='\>'
fi
__kubectl_bash_source <(sed \
__kubectl_convert_bash_to_zsh() {
sed \
-e 's/declare -F/whence -w/' \
-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
@ -267,7 +268,9 @@ __kubectl_bash_source <(sed \
zsh_tail := `
BASH_COMPLETION_EOF
)
}
__kubectl_bash_source <(__kubectl_convert_bash_to_zsh)
`
out.Write([]byte(zsh_tail))
return nil