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
This commit is contained in:
kargakis
2015-10-23 17:31:03 +02:00
parent e05819f36a
commit 73713ce268
8 changed files with 120 additions and 22 deletions

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
}