Merge pull request #91801 from liggitt/kubectl-explain

Improve kubectl explain formatting-preservation
This commit is contained in:
Kubernetes Prow Robot 2020-06-05 08:45:59 -07:00 committed by GitHub
commit 0281b85640
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 106 additions and 9 deletions

View File

@ -41,6 +41,7 @@ go_test(
deps = [ deps = [
"//staging/src/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/kubectl/pkg/scheme:go_default_library", "//staging/src/k8s.io/kubectl/pkg/scheme:go_default_library",
"//staging/src/k8s.io/kubectl/pkg/util/openapi/testing:go_default_library", "//staging/src/k8s.io/kubectl/pkg/util/openapi/testing:go_default_library",
], ],

View File

@ -19,6 +19,7 @@ package explain
import ( import (
"fmt" "fmt"
"io" "io"
"regexp"
"strings" "strings"
) )
@ -103,22 +104,75 @@ func (l *line) Add(word string) bool {
return false return false
} }
var bullet = regexp.MustCompile(`^(\d+\.?|-|\*)\s`)
func shouldStartNewLine(lastWord, str string) bool {
// preserve line breaks ending in :
if strings.HasSuffix(lastWord, ":") {
return true
}
// preserve code blocks
if strings.HasPrefix(str, " ") {
return true
}
str = strings.TrimSpace(str)
// preserve empty lines
if len(str) == 0 {
return true
}
// preserve lines that look like they're starting lists
if bullet.MatchString(str) == true {
return true
}
// otherwise combine
return false
}
func wrapString(str string, wrap int) []string { func wrapString(str string, wrap int) []string {
words := strings.Fields(str)
wrapped := []string{} wrapped := []string{}
l := line{wrap: wrap} l := line{wrap: wrap}
// track the last word added to the current line
for _, word := range words { lastWord := ""
if !l.Add(word) { flush := func() {
if !l.Empty() {
lastWord = ""
wrapped = append(wrapped, l.String()) wrapped = append(wrapped, l.String())
l = line{wrap: wrap} l = line{wrap: wrap}
}
}
// iterate over the lines in the original description
for _, str := range strings.Split(str, "\n") {
// preserve code blocks and blockquotes as-is
if strings.HasPrefix(str, " ") {
flush()
wrapped = append(wrapped, str)
continue
}
// preserve empty lines after the first line, since they can separate logical sections
if len(wrapped) > 0 && len(strings.TrimSpace(str)) == 0 {
flush()
wrapped = append(wrapped, "")
continue
}
// flush if we should start a new line
if shouldStartNewLine(lastWord, str) {
flush()
}
words := strings.Fields(str)
for _, word := range words {
lastWord = word
if !l.Add(word) { if !l.Add(word) {
panic("Couldn't add to empty line.") flush()
if !l.Add(word) {
panic("Couldn't add to empty line.")
}
} }
} }
} }
if !l.Empty() { flush()
wrapped = append(wrapped, l.String())
}
return wrapped return wrapped
} }

View File

@ -19,6 +19,8 @@ package explain
import ( import (
"bytes" "bytes"
"testing" "testing"
"k8s.io/apimachinery/pkg/util/diff"
) )
func TestFormatterWrite(t *testing.T) { func TestFormatterWrite(t *testing.T) {
@ -54,6 +56,30 @@ func TestFormatterWrappedWrite(t *testing.T) {
f.Indent(10).WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at turpis faucibus, gravida dolor ut, fringilla velit.") f.Indent(10).WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at turpis faucibus, gravida dolor ut, fringilla velit.")
// Test long words (especially urls) on their own line. // Test long words (especially urls) on their own line.
f.Indent(20).WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. ThisIsAVeryLongWordThatDoesn'tFitOnALineOnItsOwn. Morbi at turpis faucibus, gravida dolor ut, fringilla velit.") f.Indent(20).WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. ThisIsAVeryLongWordThatDoesn'tFitOnALineOnItsOwn. Morbi at turpis faucibus, gravida dolor ut, fringilla velit.")
// Test content that includes newlines, bullet points, and blockquotes/code blocks
f.Indent(4).WriteWrapped(`
This is an
introductory paragraph
that should end
up on a continuous line.
Example:
Example text on its own line
List:
1. Item with
wrapping text
11. Another
item with wrapping text
* Bullet item
with wrapping text
- Dash item
with wrapping text
base64(
code goes here
and here
)`)
want := `Lorem ipsum dolor sit amet, consectetur adipiscing want := `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Morbi at turpis faucibus, gravida dolor ut, elit. Morbi at turpis faucibus, gravida dolor ut,
@ -68,10 +94,26 @@ fringilla velit.
Morbi at turpis faucibus, Morbi at turpis faucibus,
gravida dolor ut, fringilla gravida dolor ut, fringilla
velit. velit.
This is an introductory paragraph that should
end up on a continuous line.
Example:
Example text on its own line
List:
1. Item with wrapping text
11. Another item with wrapping text
* Bullet item with wrapping text
- Dash item with wrapping text
base64(
code goes here
and here
)
` `
if buf.String() != want { if buf.String() != want {
t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want) t.Errorf("Diff:\n%s", diff.StringDiff(buf.String(), want))
} }
} }