فهرست منبع

Add `truncate` function for Go templates

This fix is part of the discussion in 28199 about using
`truncate` to replace `--no-trunc`.

As part of the fix, a new function `truncate` has been
added for Go templates so that it is possible to use
```
docker stack services --format "{{truncate .ID 5}}: {{.Mode}} {{.Replicas}}"
```
to show truncated ID.

A unit test has been added.

This fix is related to 28199.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Yong Tang 8 سال پیش
والد
کامیت
7fa8d5e064
2فایلهای تغییر یافته به همراه53 افزوده شده و 23 حذف شده
  1. 15 6
      pkg/templates/templates.go
  2. 38 17
      pkg/templates/templates_test.go

+ 15 - 6
pkg/templates/templates.go

@@ -13,12 +13,13 @@ var basicFunctions = template.FuncMap{
 		a, _ := json.Marshal(v)
 		return string(a)
 	},
-	"split": strings.Split,
-	"join":  strings.Join,
-	"title": strings.Title,
-	"lower": strings.ToLower,
-	"upper": strings.ToUpper,
-	"pad":   padWithSpace,
+	"split":    strings.Split,
+	"join":     strings.Join,
+	"title":    strings.Title,
+	"lower":    strings.ToLower,
+	"upper":    strings.ToUpper,
+	"pad":      padWithSpace,
+	"truncate": truncateWithLength,
 }
 
 // Parse creates a new anonymous template with the basic functions
@@ -40,3 +41,11 @@ func padWithSpace(source string, prefix, suffix int) string {
 	}
 	return strings.Repeat(" ", prefix) + source + strings.Repeat(" ", suffix)
 }
+
+// truncateWithLength truncates the source string up to the length provided by the input
+func truncateWithLength(source string, length int) string {
+	if len(source) < length {
+		return source
+	}
+	return source[:length]
+}

+ 38 - 17
pkg/templates/templates_test.go

@@ -3,36 +3,57 @@ package templates
 import (
 	"bytes"
 	"testing"
+
+	"github.com/docker/docker/pkg/testutil/assert"
 )
 
 func TestParseStringFunctions(t *testing.T) {
 	tm, err := Parse(`{{join (split . ":") "/"}}`)
-	if err != nil {
-		t.Fatal(err)
-	}
+	assert.NilError(t, err)
 
 	var b bytes.Buffer
-	if err := tm.Execute(&b, "text:with:colon"); err != nil {
-		t.Fatal(err)
-	}
+	assert.NilError(t, tm.Execute(&b, "text:with:colon"))
 	want := "text/with/colon"
-	if b.String() != want {
-		t.Fatalf("expected %s, got %s", want, b.String())
-	}
+	assert.Equal(t, b.String(), want)
 }
 
 func TestNewParse(t *testing.T) {
 	tm, err := NewParse("foo", "this is a {{ . }}")
-	if err != nil {
-		t.Fatal(err)
-	}
+	assert.NilError(t, err)
 
 	var b bytes.Buffer
-	if err := tm.Execute(&b, "string"); err != nil {
-		t.Fatal(err)
-	}
+	assert.NilError(t, tm.Execute(&b, "string"))
 	want := "this is a string"
-	if b.String() != want {
-		t.Fatalf("expected %s, got %s", want, b.String())
+	assert.Equal(t, b.String(), want)
+}
+
+func TestParseTruncateFunction(t *testing.T) {
+	source := "tupx5xzf6hvsrhnruz5cr8gwp"
+
+	testCases := []struct {
+		template string
+		expected string
+	}{
+		{
+			template: `{{truncate . 5}}`,
+			expected: "tupx5",
+		},
+		{
+			template: `{{truncate . 25}}`,
+			expected: "tupx5xzf6hvsrhnruz5cr8gwp",
+		},
+		{
+			template: `{{truncate . 30}}`,
+			expected: "tupx5xzf6hvsrhnruz5cr8gwp",
+		},
+	}
+
+	for _, testCase := range testCases {
+		tm, err := Parse(testCase.template)
+		assert.NilError(t, err)
+
+		var b bytes.Buffer
+		assert.NilError(t, tm.Execute(&b, source))
+		assert.Equal(t, b.String(), testCase.expected)
 	}
 }