edit: Windows fixes

Contains the following fixes for Windows users of kubectl edit:
* Defaults to notepad as the default Windows editor
* Uses CRLF line endings
* Ensures a file lock is freed
pull/6/head
kargakis 2015-10-23 17:31:03 +02:00
parent e05819f36a
commit 73713ce268
8 changed files with 120 additions and 22 deletions

View File

@ -498,6 +498,7 @@ _kubectl_edit()
flags+=("--output=")
two_word_flags+=("-o")
flags+=("--output-version=")
flags+=("--windows-line-endings")
must_have_one_flag=()
must_have_one_noun=()

View File

@ -18,15 +18,16 @@ Edit a resource from the default editor.
.PP
The edit command allows you to directly edit any API resource you can retrieve via the
command line tools. It will open the editor defined by your KUBE\_EDITOR, GIT\_EDITOR,
or EDITOR environment variables, or fall back to 'vi'. You can edit multiple objects,
although changes are applied one at a time. The command accepts filenames as well as
command line arguments, although the files you point to must be previously saved
versions of resources.
or EDITOR environment variables, or fall back to 'vi' for Linux or 'notepad' for Windows.
You can edit multiple objects, although changes are applied one at a time. The command
accepts filenames as well as command line arguments, although the files you point to must
be previously saved versions of resources.
.PP
The files to edit will be output in the default API version, or a version specified
by \-\-output\-version. The default format is YAML \- if you would like to edit in JSON
pass \-o json.
pass \-o json. The flag \-\-windows\-line\-endings can be used to force Windows line endings,
otherwise the default for your operating system will be used.
.PP
In the event an error occurs while updating, a temporary file will be created on disk
@ -49,6 +50,10 @@ saved copy to include the latest resource version.
\fB\-\-output\-version\fP=""
Output the formatted object with the given version (default api\-version).
.PP
\fB\-\-windows\-line\-endings\fP=false
Use Windows line\-endings (default Unix line\-endings)
.SH OPTIONS INHERITED FROM PARENT COMMANDS
.PP

View File

@ -42,14 +42,15 @@ Edit a resource from the default editor.
The edit command allows you to directly edit any API resource you can retrieve via the
command line tools. It will open the editor defined by your KUBE_EDITOR, GIT_EDITOR,
or EDITOR environment variables, or fall back to 'vi'. You can edit multiple objects,
although changes are applied one at a time. The command accepts filenames as well as
command line arguments, although the files you point to must be previously saved
versions of resources.
or EDITOR environment variables, or fall back to 'vi' for Linux or 'notepad' for Windows.
You can edit multiple objects, although changes are applied one at a time. The command
accepts filenames as well as command line arguments, although the files you point to must
be previously saved versions of resources.
The files to edit will be output in the default API version, or a version specified
by --output-version. The default format is YAML - if you would like to edit in JSON
pass -o json.
pass -o json. The flag --windows-line-endings can be used to force Windows line endings,
otherwise the default for your operating system will be used.
In the event an error occurs while updating, a temporary file will be created on disk
that contains your unapplied changes. The most common error when updating a resource
@ -80,6 +81,7 @@ kubectl edit (RESOURCE/NAME | -f FILENAME)
-f, --filename=[]: Filename, directory, or URL to file to use to edit the resource
-o, --output="yaml": Output format. One of: yaml|json.
--output-version="": Output the formatted object with the given version (default api-version).
--windows-line-endings[=false]: Use Windows line-endings (default Unix line-endings)
```
### Options inherited from parent commands
@ -114,7 +116,7 @@ kubectl edit (RESOURCE/NAME | -f FILENAME)
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-09-22 12:53:42.290401559 +0000 UTC
###### Auto generated by spf13/cobra on 23-Oct-2015
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_edit.md?pixel)]()

View File

@ -485,6 +485,10 @@ runTests() {
kube::test::get_object_assert pods "{{range.items}}{{$image_field}}:{{end}}" 'gcr.io/google_containers/serve_hostname:'
# cleaning
rm /tmp/tmp-editor.sh
[ "$(EDITOR=cat kubectl edit pod/valid-pod 2>&1 | grep 'Edit cancelled')" ]
[ "$(EDITOR=cat kubectl edit pod/valid-pod | grep 'name: valid-pod')" ]
[ "$(EDITOR=cat kubectl edit --windows-line-endings pod/valid-pod | file - | grep CRLF)" ]
[ ! "$(EDITOR=cat kubectl edit --windows-line-endings=false pod/valid-pod | file - | grep CRLF)" ]
### Overwriting an existing label is not permitted
# Pre-condition: name is valid-pod

View File

@ -304,6 +304,7 @@ user-whitelist
watch-cache
watch-only
whitelist-override-label
windows-line-endings
www-prefix
retry_time
file_content_in_loop

View File

@ -23,6 +23,7 @@ import (
"fmt"
"io"
"os"
"runtime"
"strings"
"k8s.io/kubernetes/pkg/api"
@ -33,6 +34,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
"k8s.io/kubernetes/pkg/kubectl/cmd/util/jsonmerge"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/strategicpatch"
"k8s.io/kubernetes/pkg/util/yaml"
@ -45,14 +47,15 @@ const (
The edit command allows you to directly edit any API resource you can retrieve via the
command line tools. It will open the editor defined by your KUBE_EDITOR, GIT_EDITOR,
or EDITOR environment variables, or fall back to 'vi'. You can edit multiple objects,
although changes are applied one at a time. The command accepts filenames as well as
command line arguments, although the files you point to must be previously saved
versions of resources.
or EDITOR environment variables, or fall back to 'vi' for Linux or 'notepad' for Windows.
You can edit multiple objects, although changes are applied one at a time. The command
accepts filenames as well as command line arguments, although the files you point to must
be previously saved versions of resources.
The files to edit will be output in the default API version, or a version specified
by --output-version. The default format is YAML - if you would like to edit in JSON
pass -o json.
pass -o json. The flag --windows-line-endings can be used to force Windows line endings,
otherwise the default for your operating system will be used.
In the event an error occurs while updating, a temporary file will be created on disk
that contains your unapplied changes. The most common error when updating a resource
@ -91,6 +94,7 @@ func NewCmdEdit(f *cmdutil.Factory, out io.Writer) *cobra.Command {
kubectl.AddJsonFilenameFlag(cmd, &filenames, usage)
cmd.Flags().StringP("output", "o", "yaml", "Output format. One of: yaml|json.")
cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version).")
cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows", "Use Windows line-endings (default Unix line-endings)")
return cmd
}
@ -142,6 +146,8 @@ func RunEdit(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
return err
}
windowsLineEndings := cmdutil.GetFlagBool(cmd, "windows-line-endings")
edit := editor.NewDefaultEditor()
defaultVersion := cmdutil.OutputVersion(cmd, clientConfig.Version)
results := editResults{}
for {
@ -156,16 +162,19 @@ func RunEdit(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
// generate the file to edit
buf := &bytes.Buffer{}
if err := results.header.writeTo(buf); err != nil {
var w io.Writer = buf
if windowsLineEndings {
w = util.NewCRLFWriter(w)
}
if err := results.header.writeTo(w); err != nil {
return preservedFile(err, results.file, out)
}
if err := printer.PrintObj(obj, buf); err != nil {
if err := printer.PrintObj(obj, w); err != nil {
return preservedFile(err, results.file, out)
}
original := buf.Bytes()
// launch the editor
edit := editor.NewDefaultEditor()
edited, file, err := edit.LaunchTempFile("kubectl-edit-", ext, buf)
if err != nil {
return preservedFile(err, results.file, out)

View File

@ -25,6 +25,7 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strings"
"github.com/docker/docker/pkg/term"
@ -33,8 +34,13 @@ import (
const (
// sorry, blame Git
// TODO: on Windows rely on 'start' to launch the editor associated
// with the given file type. If we can't because of the need of
// blocking, use a script with 'ftype' and 'assoc' to detect it.
defaultEditor = "vi"
defaultShell = "/bin/bash"
windowsEditor = "notepad"
windowsShell = "cmd"
)
type Editor struct {
@ -58,15 +64,19 @@ func NewDefaultEditor() Editor {
func defaultEnvShell() []string {
shell := os.Getenv("SHELL")
if len(shell) == 0 {
shell = defaultShell
shell = platformize(defaultShell, windowsShell)
}
return []string{shell, "-c"}
flag := "-c"
if shell == windowsShell {
flag = "/C"
}
return []string{shell, flag}
}
func defaultEnvEditor() ([]string, bool) {
editor := os.Getenv("EDITOR")
if len(editor) == 0 {
editor = defaultEditor
editor = platformize(defaultEditor, windowsEditor)
}
if !strings.Contains(editor, " ") {
return []string{editor}, false
@ -133,6 +143,8 @@ func (e Editor) LaunchTempFile(prefix, suffix string, r io.Reader) ([]byte, stri
os.Remove(path)
return nil, path, err
}
// This file descriptor needs to close so the next process (Launch) can claim it.
f.Close()
if err := e.Launch(path); err != nil {
return nil, path, err
}
@ -197,3 +209,10 @@ func randSeq(n int) string {
}
return string(b)
}
func platformize(linux, windows string) string {
if runtime.GOOS == "windows" {
return windows
}
return linux
}

57
pkg/util/crlf.go Normal file
View File

@ -0,0 +1,57 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
"bytes"
"io"
)
type crlfWriter struct {
io.Writer
}
// NewCRLFWriter implements a CR/LF line ending writer used for normalizing
// text for Windows platforms.
func NewCRLFWriter(w io.Writer) io.Writer {
return crlfWriter{w}
}
func (w crlfWriter) Write(b []byte) (n int, err error) {
for i, written := 0, 0; ; {
next := bytes.Index(b[i:], []byte("\n"))
if next == -1 {
n, err := w.Writer.Write(b[i:])
return written + n, err
}
next = next + i
n, err := w.Writer.Write(b[i:next])
if err != nil {
return written + n, err
}
written += n
n, err = w.Writer.Write([]byte("\r\n"))
if err != nil {
if n > 1 {
n = 1
}
return written + n, err
}
written += 1
i = next + 1
}
}