Parcourir la source

etcdctlv3: make member list beautiful

Xiang Li il y a 9 ans
Parent
commit
c37cd1f0a1

+ 9 - 0
Godeps/Godeps.json

@@ -102,10 +102,19 @@
 			"Comment": "release.r56-29-gf7ee69f",
 			"Rev": "f7ee69f31298ecbe5d2b349c711e2547a617d398"
 		},
+		{
+			"ImportPath": "github.com/mattn/go-runewidth",
+			"Comment": "travisish-46-gd6bea18",
+			"Rev": "d6bea18f789704b5f83375793155289da36a3c7f"
+		},
 		{
 			"ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil",
 			"Rev": "fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a"
 		},
+		{
+			"ImportPath": "github.com/olekukonko/tablewriter",
+			"Rev": "cca8bbc0798408af109aaaa239cbd2634846b340"
+		},
 		{
 			"ImportPath": "github.com/olekukonko/ts",
 			"Rev": "ecf753e7c962639ab5a1fb46f7da627d4c0a04b8"

+ 8 - 0
Godeps/_workspace/src/github.com/mattn/go-runewidth/.travis.yml

@@ -0,0 +1,8 @@
+language: go
+go:
+  - tip
+before_install:
+  - go get github.com/mattn/goveralls
+  - go get golang.org/x/tools/cmd/cover
+script:
+    - $HOME/gopath/bin/goveralls -repotoken lAKAWPzcGsD3A8yBX3BGGtRUdJ6CaGERL

+ 26 - 0
Godeps/_workspace/src/github.com/mattn/go-runewidth/README.mkd

@@ -0,0 +1,26 @@
+go-runewidth
+============
+
+[![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth)
+[![Coverage Status](https://coveralls.io/repos/mattn/go-runewidth/badge.png?branch=HEAD)](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD)
+[![GoDoc](https://godoc.org/github.com/mattn/go-runewidth?status.svg)](http://godoc.org/github.com/mattn/go-runewidth)
+
+Provides functions to get fixed width of the character or string.
+
+Usage
+-----
+
+```go
+runewidth.StringWidth("つのだ☆HIRO") == 12
+```
+
+
+Author
+------
+
+Yasuhiro Matsumoto
+
+License
+-------
+
+under the MIT License: http://mattn.mit-license.org/2013

+ 464 - 0
Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go

@@ -0,0 +1,464 @@
+package runewidth
+
+var EastAsianWidth = IsEastAsian()
+var DefaultCondition = &Condition{EastAsianWidth}
+
+type interval struct {
+	first rune
+	last  rune
+}
+
+var combining = []interval{
+	{0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489},
+	{0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2},
+	{0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603},
+	{0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670},
+	{0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED},
+	{0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A},
+	{0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902},
+	{0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D},
+	{0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981},
+	{0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD},
+	{0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C},
+	{0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D},
+	{0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC},
+	{0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD},
+	{0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C},
+	{0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D},
+	{0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0},
+	{0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48},
+	{0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC},
+	{0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD},
+	{0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D},
+	{0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6},
+	{0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E},
+	{0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
+	{0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35},
+	{0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E},
+	{0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97},
+	{0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030},
+	{0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039},
+	{0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F},
+	{0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753},
+	{0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD},
+	{0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD},
+	{0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922},
+	{0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B},
+	{0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34},
+	{0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42},
+	{0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF},
+	{0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063},
+	{0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F},
+	{0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B},
+	{0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F},
+	{0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB},
+	{0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F},
+	{0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169},
+	{0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
+	{0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F},
+	{0xE0100, 0xE01EF},
+}
+
+type ctype int
+
+const (
+	narrow ctype = iota
+	ambiguous
+	wide
+	halfwidth
+	fullwidth
+	neutral
+)
+
+type intervalType struct {
+	first rune
+	last  rune
+	ctype ctype
+}
+
+var ctypes = []intervalType{
+	{0x0020, 0x007E, narrow},
+	{0x00A1, 0x00A1, ambiguous},
+	{0x00A2, 0x00A3, narrow},
+	{0x00A4, 0x00A4, ambiguous},
+	{0x00A5, 0x00A6, narrow},
+	{0x00A7, 0x00A8, ambiguous},
+	{0x00AA, 0x00AA, ambiguous},
+	{0x00AC, 0x00AC, narrow},
+	{0x00AD, 0x00AE, ambiguous},
+	{0x00AF, 0x00AF, narrow},
+	{0x00B0, 0x00B4, ambiguous},
+	{0x00B6, 0x00BA, ambiguous},
+	{0x00BC, 0x00BF, ambiguous},
+	{0x00C6, 0x00C6, ambiguous},
+	{0x00D0, 0x00D0, ambiguous},
+	{0x00D7, 0x00D8, ambiguous},
+	{0x00DE, 0x00E1, ambiguous},
+	{0x00E6, 0x00E6, ambiguous},
+	{0x00E8, 0x00EA, ambiguous},
+	{0x00EC, 0x00ED, ambiguous},
+	{0x00F0, 0x00F0, ambiguous},
+	{0x00F2, 0x00F3, ambiguous},
+	{0x00F7, 0x00FA, ambiguous},
+	{0x00FC, 0x00FC, ambiguous},
+	{0x00FE, 0x00FE, ambiguous},
+	{0x0101, 0x0101, ambiguous},
+	{0x0111, 0x0111, ambiguous},
+	{0x0113, 0x0113, ambiguous},
+	{0x011B, 0x011B, ambiguous},
+	{0x0126, 0x0127, ambiguous},
+	{0x012B, 0x012B, ambiguous},
+	{0x0131, 0x0133, ambiguous},
+	{0x0138, 0x0138, ambiguous},
+	{0x013F, 0x0142, ambiguous},
+	{0x0144, 0x0144, ambiguous},
+	{0x0148, 0x014B, ambiguous},
+	{0x014D, 0x014D, ambiguous},
+	{0x0152, 0x0153, ambiguous},
+	{0x0166, 0x0167, ambiguous},
+	{0x016B, 0x016B, ambiguous},
+	{0x01CE, 0x01CE, ambiguous},
+	{0x01D0, 0x01D0, ambiguous},
+	{0x01D2, 0x01D2, ambiguous},
+	{0x01D4, 0x01D4, ambiguous},
+	{0x01D6, 0x01D6, ambiguous},
+	{0x01D8, 0x01D8, ambiguous},
+	{0x01DA, 0x01DA, ambiguous},
+	{0x01DC, 0x01DC, ambiguous},
+	{0x0251, 0x0251, ambiguous},
+	{0x0261, 0x0261, ambiguous},
+	{0x02C4, 0x02C4, ambiguous},
+	{0x02C7, 0x02C7, ambiguous},
+	{0x02C9, 0x02CB, ambiguous},
+	{0x02CD, 0x02CD, ambiguous},
+	{0x02D0, 0x02D0, ambiguous},
+	{0x02D8, 0x02DB, ambiguous},
+	{0x02DD, 0x02DD, ambiguous},
+	{0x02DF, 0x02DF, ambiguous},
+	{0x0300, 0x036F, ambiguous},
+	{0x0391, 0x03A2, ambiguous},
+	{0x03A3, 0x03A9, ambiguous},
+	{0x03B1, 0x03C1, ambiguous},
+	{0x03C3, 0x03C9, ambiguous},
+	{0x0401, 0x0401, ambiguous},
+	{0x0410, 0x044F, ambiguous},
+	{0x0451, 0x0451, ambiguous},
+	{0x1100, 0x115F, wide},
+	{0x2010, 0x2010, ambiguous},
+	{0x2013, 0x2016, ambiguous},
+	{0x2018, 0x2019, ambiguous},
+	{0x201C, 0x201D, ambiguous},
+	{0x2020, 0x2022, ambiguous},
+	{0x2024, 0x2027, ambiguous},
+	{0x2030, 0x2030, ambiguous},
+	{0x2032, 0x2033, ambiguous},
+	{0x2035, 0x2035, ambiguous},
+	{0x203B, 0x203B, ambiguous},
+	{0x203E, 0x203E, ambiguous},
+	{0x2074, 0x2074, ambiguous},
+	{0x207F, 0x207F, ambiguous},
+	{0x2081, 0x2084, ambiguous},
+	{0x20A9, 0x20A9, halfwidth},
+	{0x20AC, 0x20AC, ambiguous},
+	{0x2103, 0x2103, ambiguous},
+	{0x2105, 0x2105, ambiguous},
+	{0x2109, 0x2109, ambiguous},
+	{0x2113, 0x2113, ambiguous},
+	{0x2116, 0x2116, ambiguous},
+	{0x2121, 0x2122, ambiguous},
+	{0x2126, 0x2126, ambiguous},
+	{0x212B, 0x212B, ambiguous},
+	{0x2153, 0x2154, ambiguous},
+	{0x215B, 0x215E, ambiguous},
+	{0x2160, 0x216B, ambiguous},
+	{0x2170, 0x2179, ambiguous},
+	{0x2189, 0x218A, ambiguous},
+	{0x2190, 0x2199, ambiguous},
+	{0x21B8, 0x21B9, ambiguous},
+	{0x21D2, 0x21D2, ambiguous},
+	{0x21D4, 0x21D4, ambiguous},
+	{0x21E7, 0x21E7, ambiguous},
+	{0x2200, 0x2200, ambiguous},
+	{0x2202, 0x2203, ambiguous},
+	{0x2207, 0x2208, ambiguous},
+	{0x220B, 0x220B, ambiguous},
+	{0x220F, 0x220F, ambiguous},
+	{0x2211, 0x2211, ambiguous},
+	{0x2215, 0x2215, ambiguous},
+	{0x221A, 0x221A, ambiguous},
+	{0x221D, 0x2220, ambiguous},
+	{0x2223, 0x2223, ambiguous},
+	{0x2225, 0x2225, ambiguous},
+	{0x2227, 0x222C, ambiguous},
+	{0x222E, 0x222E, ambiguous},
+	{0x2234, 0x2237, ambiguous},
+	{0x223C, 0x223D, ambiguous},
+	{0x2248, 0x2248, ambiguous},
+	{0x224C, 0x224C, ambiguous},
+	{0x2252, 0x2252, ambiguous},
+	{0x2260, 0x2261, ambiguous},
+	{0x2264, 0x2267, ambiguous},
+	{0x226A, 0x226B, ambiguous},
+	{0x226E, 0x226F, ambiguous},
+	{0x2282, 0x2283, ambiguous},
+	{0x2286, 0x2287, ambiguous},
+	{0x2295, 0x2295, ambiguous},
+	{0x2299, 0x2299, ambiguous},
+	{0x22A5, 0x22A5, ambiguous},
+	{0x22BF, 0x22BF, ambiguous},
+	{0x2312, 0x2312, ambiguous},
+	{0x2329, 0x232A, wide},
+	{0x2460, 0x24E9, ambiguous},
+	{0x24EB, 0x254B, ambiguous},
+	{0x2550, 0x2573, ambiguous},
+	{0x2580, 0x258F, ambiguous},
+	{0x2592, 0x2595, ambiguous},
+	{0x25A0, 0x25A1, ambiguous},
+	{0x25A3, 0x25A9, ambiguous},
+	{0x25B2, 0x25B3, ambiguous},
+	{0x25B6, 0x25B7, ambiguous},
+	{0x25BC, 0x25BD, ambiguous},
+	{0x25C0, 0x25C1, ambiguous},
+	{0x25C6, 0x25C8, ambiguous},
+	{0x25CB, 0x25CB, ambiguous},
+	{0x25CE, 0x25D1, ambiguous},
+	{0x25E2, 0x25E5, ambiguous},
+	{0x25EF, 0x25EF, ambiguous},
+	{0x2605, 0x2606, ambiguous},
+	{0x2609, 0x2609, ambiguous},
+	{0x260E, 0x260F, ambiguous},
+	{0x2614, 0x2615, ambiguous},
+	{0x261C, 0x261C, ambiguous},
+	{0x261E, 0x261E, ambiguous},
+	{0x2640, 0x2640, ambiguous},
+	{0x2642, 0x2642, ambiguous},
+	{0x2660, 0x2661, ambiguous},
+	{0x2663, 0x2665, ambiguous},
+	{0x2667, 0x266A, ambiguous},
+	{0x266C, 0x266D, ambiguous},
+	{0x266F, 0x266F, ambiguous},
+	{0x269E, 0x269F, ambiguous},
+	{0x26BE, 0x26BF, ambiguous},
+	{0x26C4, 0x26CD, ambiguous},
+	{0x26CF, 0x26E1, ambiguous},
+	{0x26E3, 0x26E3, ambiguous},
+	{0x26E8, 0x26FF, ambiguous},
+	{0x273D, 0x273D, ambiguous},
+	{0x2757, 0x2757, ambiguous},
+	{0x2776, 0x277F, ambiguous},
+	{0x27E6, 0x27ED, narrow},
+	{0x2985, 0x2986, narrow},
+	{0x2B55, 0x2B59, ambiguous},
+	{0x2E80, 0x2E9A, wide},
+	{0x2E9B, 0x2EF4, wide},
+	{0x2F00, 0x2FD6, wide},
+	{0x2FF0, 0x2FFC, wide},
+	{0x3000, 0x3000, fullwidth},
+	{0x3001, 0x303E, wide},
+	{0x3041, 0x3097, wide},
+	{0x3099, 0x3100, wide},
+	{0x3105, 0x312E, wide},
+	{0x3131, 0x318F, wide},
+	{0x3190, 0x31BB, wide},
+	{0x31C0, 0x31E4, wide},
+	{0x31F0, 0x321F, wide},
+	{0x3220, 0x3247, wide},
+	{0x3248, 0x324F, ambiguous},
+	{0x3250, 0x32FF, wide},
+	{0x3300, 0x4DBF, wide},
+	{0x4E00, 0xA48D, wide},
+	{0xA490, 0xA4C7, wide},
+	{0xA960, 0xA97D, wide},
+	{0xAC00, 0xD7A4, wide},
+	{0xE000, 0xF8FF, ambiguous},
+	{0xF900, 0xFAFF, wide},
+	{0xFE00, 0xFE0F, ambiguous},
+	{0xFE10, 0xFE1A, wide},
+	{0xFE30, 0xFE53, wide},
+	{0xFE54, 0xFE67, wide},
+	{0xFE68, 0xFE6C, wide},
+	{0xFF01, 0xFF60, fullwidth},
+	{0xFF61, 0xFFBF, halfwidth},
+	{0xFFC2, 0xFFC8, halfwidth},
+	{0xFFCA, 0xFFD0, halfwidth},
+	{0xFFD2, 0xFFD8, halfwidth},
+	{0xFFDA, 0xFFDD, halfwidth},
+	{0xFFE0, 0xFFE7, fullwidth},
+	{0xFFE8, 0xFFEF, halfwidth},
+	{0xFFFD, 0xFFFE, ambiguous},
+	{0x1B000, 0x1B002, wide},
+	{0x1F100, 0x1F10A, ambiguous},
+	{0x1F110, 0x1F12D, ambiguous},
+	{0x1F130, 0x1F169, ambiguous},
+	{0x1F170, 0x1F19B, ambiguous},
+	{0x1F200, 0x1F203, wide},
+	{0x1F210, 0x1F23B, wide},
+	{0x1F240, 0x1F249, wide},
+	{0x1F250, 0x1F252, wide},
+	{0x20000, 0x2FFFE, wide},
+	{0x30000, 0x3FFFE, wide},
+	{0xE0100, 0xE01F0, ambiguous},
+	{0xF0000, 0xFFFFD, ambiguous},
+	{0x100000, 0x10FFFE, ambiguous},
+}
+
+type Condition struct {
+	EastAsianWidth bool
+}
+
+func NewCondition() *Condition {
+	return &Condition{EastAsianWidth}
+}
+
+// RuneWidth returns the number of cells in r.
+// See http://www.unicode.org/reports/tr11/
+func (c *Condition) RuneWidth(r rune) int {
+	if r == 0 {
+		return 0
+	}
+	if r < 32 || (r >= 0x7f && r < 0xa0) {
+		return 1
+	}
+	for _, iv := range combining {
+		if iv.first <= r && r <= iv.last {
+			return 0
+		}
+	}
+
+	if c.EastAsianWidth && IsAmbiguousWidth(r) {
+		return 2
+	}
+
+	if r >= 0x1100 &&
+		(r <= 0x115f || r == 0x2329 || r == 0x232a ||
+			(r >= 0x2e80 && r <= 0xa4cf && r != 0x303f) ||
+			(r >= 0xac00 && r <= 0xd7a3) ||
+			(r >= 0xf900 && r <= 0xfaff) ||
+			(r >= 0xfe30 && r <= 0xfe6f) ||
+			(r >= 0xff00 && r <= 0xff60) ||
+			(r >= 0xffe0 && r <= 0xffe6) ||
+			(r >= 0x20000 && r <= 0x2fffd) ||
+			(r >= 0x30000 && r <= 0x3fffd)) {
+		return 2
+	}
+	return 1
+}
+
+func (c *Condition) StringWidth(s string) (width int) {
+	for _, r := range []rune(s) {
+		width += c.RuneWidth(r)
+	}
+	return width
+}
+
+func (c *Condition) Truncate(s string, w int, tail string) string {
+	if c.StringWidth(s) <= w {
+		return s
+	}
+	r := []rune(s)
+	tw := c.StringWidth(tail)
+	w -= tw
+	width := 0
+	i := 0
+	for ; i < len(r); i++ {
+		cw := c.RuneWidth(r[i])
+		if width+cw > w {
+			break
+		}
+		width += cw
+	}
+	return string(r[0:i]) + tail
+}
+
+func (c *Condition) Wrap(s string, w int) string {
+	width := 0
+	out := ""
+	for _, r := range []rune(s) {
+		cw := RuneWidth(r)
+		if r == '\n' {
+			out += string(r)
+			width = 0
+			continue
+		} else if width+cw > w {
+			out += "\n"
+			width = 0
+			out += string(r)
+			width += cw
+			continue
+		}
+		out += string(r)
+		width += cw
+	}
+	return out
+}
+
+func (c *Condition) FillLeft(s string, w int) string {
+	width := c.StringWidth(s)
+	count := w - width
+	if count > 0 {
+		b := make([]byte, count)
+		for i := range b {
+			b[i] = ' '
+		}
+		return string(b) + s
+	}
+	return s
+}
+
+func (c *Condition) FillRight(s string, w int) string {
+	width := c.StringWidth(s)
+	count := w - width
+	if count > 0 {
+		b := make([]byte, count)
+		for i := range b {
+			b[i] = ' '
+		}
+		return s + string(b)
+	}
+	return s
+}
+
+// RuneWidth returns the number of cells in r.
+// See http://www.unicode.org/reports/tr11/
+func RuneWidth(r rune) int {
+	return DefaultCondition.RuneWidth(r)
+}
+
+func ct(r rune) ctype {
+	for _, iv := range ctypes {
+		if iv.first <= r && r <= iv.last {
+			return iv.ctype
+		}
+	}
+	return neutral
+}
+
+// IsAmbiguousWidth returns whether is ambiguous width or not.
+func IsAmbiguousWidth(r rune) bool {
+	return ct(r) == ambiguous
+}
+
+// IsAmbiguousWidth returns whether is ambiguous width or not.
+func IsNeutralWidth(r rune) bool {
+	return ct(r) == neutral
+}
+
+func StringWidth(s string) (width int) {
+	return DefaultCondition.StringWidth(s)
+}
+
+func Truncate(s string, w int, tail string) string {
+	return DefaultCondition.Truncate(s, w, tail)
+}
+
+func Wrap(s string, w int) string {
+	return DefaultCondition.Wrap(s, w)
+}
+
+func FillLeft(s string, w int) string {
+	return DefaultCondition.FillLeft(s, w)
+}
+
+func FillRight(s string, w int) string {
+	return DefaultCondition.FillRight(s, w)
+}

+ 8 - 0
Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_js.go

@@ -0,0 +1,8 @@
+// +build js
+
+package runewidth
+
+func IsEastAsian() bool {
+	// TODO: Implement this for the web. Detect east asian in a compatible way, and return true.
+	return false
+}

+ 69 - 0
Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_posix.go

@@ -0,0 +1,69 @@
+// +build !windows,!js
+
+package runewidth
+
+import (
+	"os"
+	"regexp"
+	"strings"
+)
+
+var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`)
+
+func IsEastAsian() bool {
+	locale := os.Getenv("LC_CTYPE")
+	if locale == "" {
+		locale = os.Getenv("LANG")
+	}
+
+	// ignore C locale
+	if locale == "POSIX" || locale == "C" {
+		return false
+	}
+	if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') {
+		return false
+	}
+
+	charset := strings.ToLower(locale)
+	r := reLoc.FindStringSubmatch(locale)
+	if len(r) == 2 {
+		charset = strings.ToLower(r[1])
+	}
+
+	if strings.HasSuffix(charset, "@cjk_narrow") {
+		return false
+	}
+
+	for pos, b := range []byte(charset) {
+		if b == '@' {
+			charset = charset[:pos]
+			break
+		}
+	}
+
+	mbc_max := 1
+	switch charset {
+	case "utf-8", "utf8":
+		mbc_max = 6
+	case "jis":
+		mbc_max = 8
+	case "eucjp":
+		mbc_max = 3
+	case "euckr", "euccn":
+		mbc_max = 2
+	case "sjis", "cp932", "cp51932", "cp936", "cp949", "cp950":
+		mbc_max = 2
+	case "big5":
+		mbc_max = 2
+	case "gbk", "gb2312":
+		mbc_max = 2
+	}
+
+	if mbc_max > 1 && (charset[0] != 'u' ||
+		strings.HasPrefix(locale, "ja") ||
+		strings.HasPrefix(locale, "ko") ||
+		strings.HasPrefix(locale, "zh")) {
+		return true
+	}
+	return false
+}

+ 24 - 0
Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_windows.go

@@ -0,0 +1,24 @@
+package runewidth
+
+import (
+	"syscall"
+)
+
+var (
+	kernel32               = syscall.NewLazyDLL("kernel32")
+	procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP")
+)
+
+func IsEastAsian() bool {
+	r1, _, _ := procGetConsoleOutputCP.Call()
+	if r1 == 0 {
+		return false
+	}
+
+	switch int(r1) {
+	case 932, 51932, 936, 949, 950:
+		return true
+	}
+
+	return false
+}

+ 8 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/.travis.yml

@@ -0,0 +1,8 @@
+language: go
+
+go:
+  - 1.1
+  - 1.2
+  - 1.3
+  - 1.4
+  - tip

+ 19 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/LICENCE.md

@@ -0,0 +1,19 @@
+Copyright (C) 2014 by Oleku Konko
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 141 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/README.md

@@ -0,0 +1,141 @@
+ASCII Table Writer
+=========
+
+[![Build Status](https://travis-ci.org/olekukonko/tablewriter.png?branch=master)](https://travis-ci.org/olekukonko/tablewriter) [![Total views](https://sourcegraph.com/api/repos/github.com/olekukonko/tablewriter/counters/views.png)](https://sourcegraph.com/github.com/olekukonko/tablewriter)
+
+Generate ASCII table on the fly ...  Installation is simple as
+
+    go get  github.com/olekukonko/tablewriter
+
+
+#### Features
+- Automatic Padding
+- Support Multiple Lines
+- Supports Alignment
+- Support Custom Separators
+- Automatic Alignment of numbers & percentage
+- Write directly to http , file etc via `io.Writer`
+- Read directly from CSV file
+- Optional row line via `SetRowLine`
+- Normalise table header
+- Make CSV Headers optional
+- Enable or disable table border
+- Set custom footer support
+
+
+#### Example   1 - Basic
+```go
+data := [][]string{
+    []string{"A", "The Good", "500"},
+    []string{"B", "The Very very Bad Man", "288"},
+    []string{"C", "The Ugly", "120"},
+    []string{"D", "The Gopher", "800"},
+}
+
+table := tablewriter.NewWriter(os.Stdout)
+table.SetHeader([]string{"Name", "Sign", "Rating"})
+
+for _, v := range data {
+    table.Append(v)
+}
+table.Render() // Send output
+```
+
+##### Output  1
+```
++------+-----------------------+--------+
+| NAME |         SIGN          | RATING |
++------+-----------------------+--------+
+|  A   |       The Good        |    500 |
+|  B   | The Very very Bad Man |    288 |
+|  C   |       The Ugly        |    120 |
+|  D   |      The Gopher       |    800 |
++------+-----------------------+--------+
+```
+
+#### Example 2 - Without Border / Footer / Bulk Append
+```go
+data := [][]string{
+    []string{"1/1/2014", "Domain name", "2233", "$10.98"},
+    []string{"1/1/2014", "January Hosting", "2233", "$54.95"},
+    []string{"1/4/2014", "February Hosting", "2233", "$51.00"},
+    []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
+}
+
+table := tablewriter.NewWriter(os.Stdout)
+table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
+table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer
+table.SetBorder(false)                                // Set Border to false
+table.AppendBulk(data)                                // Add Bulk Data
+table.Render()
+```
+
+##### Output 2
+```
+
+    DATE   |       DESCRIPTION        |  CV2  | AMOUNT
++----------+--------------------------+-------+---------+
+  1/1/2014 | Domain name              |  2233 | $10.98
+  1/1/2014 | January Hosting          |  2233 | $54.95
+  1/4/2014 | February Hosting         |  2233 | $51.00
+  1/4/2014 | February Extra Bandwidth |  2233 | $30.00
++----------+--------------------------+-------+---------+
+                                        TOTAL | $146 93
+                                      +-------+---------+
+
+```
+
+
+#### Example 3 - CSV
+```go
+table, _ := tablewriter.NewCSV(os.Stdout, "test_info.csv", true)
+table.SetAlignment(tablewriter.ALIGN_LEFT)   // Set Alignment
+table.Render()
+```
+
+##### Output 3
+```
++----------+--------------+------+-----+---------+----------------+
+|  FIELD   |     TYPE     | NULL | KEY | DEFAULT |     EXTRA      |
++----------+--------------+------+-----+---------+----------------+
+| user_id  | smallint(5)  | NO   | PRI | NULL    | auto_increment |
+| username | varchar(10)  | NO   |     | NULL    |                |
+| password | varchar(100) | NO   |     | NULL    |                |
++----------+--------------+------+-----+---------+----------------+
+```
+
+#### Example 4  - Custom Separator
+```go
+table, _ := tablewriter.NewCSV(os.Stdout, "test.csv", true)
+table.SetRowLine(true)         // Enable row line
+
+// Change table lines
+table.SetCenterSeparator("*")
+table.SetColumnSeparator("‡")
+table.SetRowSeparator("-")
+
+table.SetAlignment(tablewriter.ALIGN_LEFT)
+table.Render()
+```
+
+##### Output 4
+```
+*------------*-----------*---------*
+╪ FIRST NAME ╪ LAST NAME ╪   SSN   ╪
+*------------*-----------*---------*
+╪ John       ╪ Barry     ╪ 123456  ╪
+*------------*-----------*---------*
+╪ Kathy      ╪ Smith     ╪ 687987  ╪
+*------------*-----------*---------*
+╪ Bob        ╪ McCornick ╪ 3979870 ╪
+*------------*-----------*---------*
+```
+
+#### TODO
+- ~~Import Directly from CSV~~  - `done`
+- ~~Support for `SetFooter`~~  - `done`
+- ~~Support for `SetBorder`~~  - `done`
+- ~~Support table with uneven rows~~ - `done`
+- Support custom alignment
+- General Improvement & Optimisation
+- `NewHTML` Parse table from HTML

+ 52 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/csv.go

@@ -0,0 +1,52 @@
+// Copyright 2014 Oleku Konko All rights reserved.
+// Use of this source code is governed by a MIT
+// license that can be found in the LICENSE file.
+
+// This module is a Table Writer  API for the Go Programming Language.
+// The protocols were written in pure Go and works on windows and unix systems
+
+package tablewriter
+
+import (
+	"encoding/csv"
+	"io"
+	"os"
+)
+
+// Start A new table by importing from a CSV file
+// Takes io.Writer and csv File name
+func NewCSV(writer io.Writer, fileName string, hasHeader bool) (*Table, error) {
+	file, err := os.Open(fileName)
+	if err != nil {
+		return &Table{}, err
+	}
+	defer file.Close()
+	csvReader := csv.NewReader(file)
+	t, err := NewCSVReader(writer, csvReader, hasHeader)
+	return t, err
+}
+
+//  Start a New Table Writer with csv.Reader
+// This enables customisation such as reader.Comma = ';'
+// See http://golang.org/src/pkg/encoding/csv/reader.go?s=3213:3671#L94
+func NewCSVReader(writer io.Writer, csvReader *csv.Reader, hasHeader bool) (*Table, error) {
+	t := NewWriter(writer)
+	if hasHeader {
+		// Read the first row
+		headers, err := csvReader.Read()
+		if err != nil {
+			return &Table{}, err
+		}
+		t.SetHeader(headers)
+	}
+	for {
+		record, err := csvReader.Read()
+		if err == io.EOF {
+			break
+		} else if err != nil {
+			return &Table{}, err
+		}
+		t.Append(record)
+	}
+	return t, nil
+}

+ 43 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/csv2table/README.md

@@ -0,0 +1,43 @@
+ASCII Table Writer Tool
+=========
+
+Generate ASCII table on the fly via command line ...  Installation is simple as
+
+#### Get Tool
+
+    go get  github.com/olekukonko/tablewriter/csv2table
+
+#### Install Tool
+
+    go install  github.com/olekukonko/tablewriter/csv2table
+
+
+#### Usage
+
+    csv2table -f test.csv
+
+#### Support for Piping
+
+    cat test.csv | csv2table -p=true
+
+#### Output
+
+```
++------------+-----------+---------+
+| FIRST NAME | LAST NAME |   SSN   |
++------------+-----------+---------+
+|    John    |   Barry   |  123456 |
+|   Kathy    |   Smith   |  687987 |
+|    Bob     | McCornick | 3979870 |
++------------+-----------+---------+
+```
+
+#### Another Piping with Header set to `false`
+
+    echo dance,with,me | csv2table -p=true -h=false
+
+#### Output
+
+    +-------+------+-----+
+    | dance | with | me  |
+    +-------+------+-----+

+ 84 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/csv2table/csv2table.go

@@ -0,0 +1,84 @@
+package main
+
+import (
+	"encoding/csv"
+	"flag"
+	"fmt"
+	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/olekukonko/tablewriter"
+	"io"
+	"os"
+	"unicode/utf8"
+)
+
+var (
+	fileName  = flag.String("f", "", "Set file with  eg. sample.csv")
+	delimiter = flag.String("d", ",", "Set CSV File delimiter eg. ,|;|\t ")
+	header    = flag.Bool("h", true, "Set header options eg. true|false ")
+	align     = flag.String("a", "none", "Set aligmement with eg. none|left|right|centre")
+	pipe      = flag.Bool("p", false, "Suport for Piping from STDIN")
+	border    = flag.Bool("b", true, "Enable / disable table border")
+)
+
+func main() {
+	flag.Parse()
+	fmt.Println()
+	if *pipe || hasArg("-p") {
+		process(os.Stdin)
+	} else {
+		if *fileName == "" {
+			fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+			flag.PrintDefaults()
+			fmt.Println()
+			os.Exit(1)
+		}
+		processFile()
+	}
+	fmt.Println()
+}
+
+func hasArg(name string) bool {
+	for _, v := range os.Args {
+		if name == v {
+			return true
+		}
+	}
+	return false
+}
+func processFile() {
+	r, err := os.Open(*fileName)
+	if err != nil {
+		exit(err)
+	}
+	defer r.Close()
+	process(r)
+}
+func process(r io.Reader) {
+	csvReader := csv.NewReader(r)
+	rune, size := utf8.DecodeRuneInString(*delimiter)
+	if size == 0 {
+		rune = ','
+	}
+	csvReader.Comma = rune
+
+	table, err := tablewriter.NewCSVReader(os.Stdout, csvReader, *header)
+
+	if err != nil {
+		exit(err)
+	}
+
+	switch *align {
+	case "left":
+		table.SetAlignment(tablewriter.ALIGN_LEFT)
+	case "right":
+		table.SetAlignment(tablewriter.ALIGN_RIGHT)
+	case "center":
+		table.SetAlignment(tablewriter.ALIGN_CENTRE)
+	}
+	table.SetBorder(*border)
+	table.Render()
+}
+
+func exit(err error) {
+	fmt.Fprintf(os.Stderr, "#Error : %s", err)
+	os.Exit(1)
+}

+ 477 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/table.go

@@ -0,0 +1,477 @@
+// Copyright 2014 Oleku Konko All rights reserved.
+// Use of this source code is governed by a MIT
+// license that can be found in the LICENSE file.
+
+// This module is a Table Writer  API for the Go Programming Language.
+// The protocols were written in pure Go and works on windows and unix systems
+
+// Create & Generate text based table
+package tablewriter
+
+import (
+	"fmt"
+	"io"
+	"regexp"
+	"strings"
+)
+
+const (
+	MAX_ROW_WIDTH = 30
+)
+
+const (
+	CENTRE = "+"
+	ROW    = "-"
+	COLUMN = "|"
+	SPACE  = " "
+)
+
+const (
+	ALIGN_DEFAULT = iota
+	ALIGN_CENTRE
+	ALIGN_RIGHT
+	ALIGN_LEFT
+)
+
+var (
+	decimal = regexp.MustCompile(`^\d*\.?\d*$`)
+	percent = regexp.MustCompile(`^\d*\.?\d*$%$`)
+)
+
+type Table struct {
+	out      io.Writer
+	rows     [][]string
+	lines    [][][]string
+	cs       map[int]int
+	rs       map[int]int
+	headers  []string
+	footers  []string
+	autoFmt  bool
+	autoWrap bool
+	mW       int
+	pCenter  string
+	pRow     string
+	pColumn  string
+	tColumn  int
+	tRow     int
+	align    int
+	rowLine  bool
+	hdrLine  bool
+	border   bool
+	colSize  int
+}
+
+// Start New Table
+// Take io.Writer Directly
+func NewWriter(writer io.Writer) *Table {
+	t := &Table{
+		out:      writer,
+		rows:     [][]string{},
+		lines:    [][][]string{},
+		cs:       make(map[int]int),
+		rs:       make(map[int]int),
+		headers:  []string{},
+		footers:  []string{},
+		autoFmt:  true,
+		autoWrap: true,
+		mW:       MAX_ROW_WIDTH,
+		pCenter:  CENTRE,
+		pRow:     ROW,
+		pColumn:  COLUMN,
+		tColumn:  -1,
+		tRow:     -1,
+		align:    ALIGN_DEFAULT,
+		rowLine:  false,
+		hdrLine:  true,
+		border:   true,
+		colSize:  -1}
+	return t
+}
+
+// Render table output
+func (t Table) Render() {
+	if t.border {
+		t.printLine(true)
+	}
+	t.printHeading()
+	t.printRows()
+
+	if !t.rowLine && t.border {
+		t.printLine(true)
+	}
+	t.printFooter()
+
+}
+
+// Set table header
+func (t *Table) SetHeader(keys []string) {
+	t.colSize = len(keys)
+	for i, v := range keys {
+		t.parseDimension(v, i, -1)
+		t.headers = append(t.headers, v)
+	}
+}
+
+// Set table Footer
+func (t *Table) SetFooter(keys []string) {
+	//t.colSize = len(keys)
+	for i, v := range keys {
+		t.parseDimension(v, i, -1)
+		t.footers = append(t.footers, v)
+	}
+}
+
+// Turn header autoformatting on/off. Default is on (true).
+func (t *Table) SetAutoFormatHeaders(auto bool) {
+	t.autoFmt = auto
+}
+
+// Turn automatic multiline text adjustment on/off. Default is on (true).
+func (t *Table) SetAutoWrapText(auto bool) {
+	t.autoWrap = auto
+}
+
+// Set the Default column width
+func (t *Table) SetColWidth(width int) {
+	t.mW = width
+}
+
+// Set the Column Separator
+func (t *Table) SetColumnSeparator(sep string) {
+	t.pColumn = sep
+}
+
+// Set the Row Separator
+func (t *Table) SetRowSeparator(sep string) {
+	t.pRow = sep
+}
+
+// Set the center Separator
+func (t *Table) SetCenterSeparator(sep string) {
+	t.pCenter = sep
+}
+
+// Set Table Alignment
+func (t *Table) SetAlignment(align int) {
+	t.align = align
+}
+
+// Set Header Line
+// This would enable / disable a line after the header
+func (t *Table) SetHeaderLine(line bool) {
+	t.hdrLine = line
+}
+
+// Set Row Line
+// This would enable / disable a line on each row of the table
+func (t *Table) SetRowLine(line bool) {
+	t.rowLine = line
+}
+
+// Set Table Border
+// This would enable / disable line around the table
+func (t *Table) SetBorder(border bool) {
+	t.border = border
+}
+
+// Append row to table
+func (t *Table) Append(row []string) {
+	rowSize := len(t.headers)
+	if rowSize > t.colSize {
+		t.colSize = rowSize
+	}
+
+	n := len(t.lines)
+	line := [][]string{}
+	for i, v := range row {
+
+		// Detect string  width
+		// Detect String height
+		// Break strings into words
+		out := t.parseDimension(v, i, n)
+
+		// Append broken words
+		line = append(line, out)
+	}
+	t.lines = append(t.lines, line)
+}
+
+// Allow Support for Bulk Append
+// Eliminates repeated for loops
+func (t *Table) AppendBulk(rows [][]string) {
+	for _, row := range rows {
+		t.Append(row)
+	}
+}
+
+// Print line based on row width
+func (t Table) printLine(nl bool) {
+	fmt.Fprint(t.out, t.pCenter)
+	for i := 0; i < len(t.cs); i++ {
+		v := t.cs[i]
+		fmt.Fprintf(t.out, "%s%s%s%s",
+			t.pRow,
+			strings.Repeat(string(t.pRow), v),
+			t.pRow,
+			t.pCenter)
+	}
+	if nl {
+		fmt.Fprintln(t.out)
+	}
+}
+
+// Print heading information
+func (t Table) printHeading() {
+	// Check if headers is available
+	if len(t.headers) < 1 {
+		return
+	}
+
+	// Check if border is set
+	// Replace with space if not set
+	fmt.Fprint(t.out, ConditionString(t.border, t.pColumn, SPACE))
+
+	// Identify last column
+	end := len(t.cs) - 1
+
+	// Print Heading column
+	for i := 0; i <= end; i++ {
+		v := t.cs[i]
+		h := t.headers[i]
+		if t.autoFmt {
+			h = Title(h)
+		}
+		pad := ConditionString((i == end && !t.border), SPACE, t.pColumn)
+		fmt.Fprintf(t.out, " %s %s",
+			Pad(h, SPACE, v),
+			pad)
+	}
+	// Next line
+	fmt.Fprintln(t.out)
+	if t.hdrLine {
+		t.printLine(true)
+	}
+}
+
+// Print heading information
+func (t Table) printFooter() {
+	// Check if headers is available
+	if len(t.footers) < 1 {
+		return
+	}
+
+	// Only print line if border is not set
+	if !t.border {
+		t.printLine(true)
+	}
+	// Check if border is set
+	// Replace with space if not set
+	fmt.Fprint(t.out, ConditionString(t.border, t.pColumn, SPACE))
+
+	// Identify last column
+	end := len(t.cs) - 1
+
+	// Print Heading column
+	for i := 0; i <= end; i++ {
+		v := t.cs[i]
+		f := t.footers[i]
+		if t.autoFmt {
+			f = Title(f)
+		}
+		pad := ConditionString((i == end && !t.border), SPACE, t.pColumn)
+
+		if len(t.footers[i]) == 0 {
+			pad = SPACE
+		}
+		fmt.Fprintf(t.out, " %s %s",
+			Pad(f, SPACE, v),
+			pad)
+	}
+	// Next line
+	fmt.Fprintln(t.out)
+	//t.printLine(true)
+
+	hasPrinted := false
+
+	for i := 0; i <= end; i++ {
+		v := t.cs[i]
+		pad := t.pRow
+		center := t.pCenter
+		length := len(t.footers[i])
+
+		if length > 0 {
+			hasPrinted = true
+		}
+
+		// Set center to be space if length is 0
+		if length == 0 && !t.border {
+			center = SPACE
+		}
+
+		// Print first junction
+		if i == 0 {
+			fmt.Fprint(t.out, center)
+		}
+
+		// Pad With space of length is 0
+		if length == 0 {
+			pad = SPACE
+		}
+		// Ignore left space of it has printed before
+		if hasPrinted || t.border {
+			pad = t.pRow
+			center = t.pCenter
+		}
+
+		// Change Center start position
+		if center == SPACE {
+			if i < end && len(t.footers[i+1]) != 0 {
+				center = t.pCenter
+			}
+		}
+
+		// Print the footer
+		fmt.Fprintf(t.out, "%s%s%s%s",
+			pad,
+			strings.Repeat(string(pad), v),
+			pad,
+			center)
+
+	}
+
+	fmt.Fprintln(t.out)
+
+}
+
+func (t Table) printRows() {
+	for i, lines := range t.lines {
+		t.printRow(lines, i)
+	}
+
+}
+
+// Print Row Information
+// Adjust column alignment based on type
+
+func (t Table) printRow(columns [][]string, colKey int) {
+	// Get Maximum Height
+	max := t.rs[colKey]
+	total := len(columns)
+
+	// TODO Fix uneven col size
+	// if total < t.colSize {
+	//	for n := t.colSize - total; n < t.colSize ; n++ {
+	//		columns = append(columns, []string{SPACE})
+	//		t.cs[n] = t.mW
+	//	}
+	//}
+
+	// Pad Each Height
+	// pads := []int{}
+	pads := []int{}
+
+	for i, line := range columns {
+		length := len(line)
+		pad := max - length
+		pads = append(pads, pad)
+		for n := 0; n < pad; n++ {
+			columns[i] = append(columns[i], "  ")
+		}
+	}
+	//fmt.Println(max, "\n")
+	for x := 0; x < max; x++ {
+		for y := 0; y < total; y++ {
+
+			// Check if border is set
+			fmt.Fprint(t.out, ConditionString((!t.border && y == 0), SPACE, t.pColumn))
+
+			fmt.Fprintf(t.out, SPACE)
+			str := columns[y][x]
+
+			// This would print alignment
+			// Default alignment  would use multiple configuration
+			switch t.align {
+			case ALIGN_CENTRE: //
+				fmt.Fprintf(t.out, "%s", Pad(str, SPACE, t.cs[y]))
+			case ALIGN_RIGHT:
+				fmt.Fprintf(t.out, "%s", PadLeft(str, SPACE, t.cs[y]))
+			case ALIGN_LEFT:
+				fmt.Fprintf(t.out, "%s", PadRight(str, SPACE, t.cs[y]))
+			default:
+				if decimal.MatchString(strings.TrimSpace(str)) || percent.MatchString(strings.TrimSpace(str)) {
+					fmt.Fprintf(t.out, "%s", PadLeft(str, SPACE, t.cs[y]))
+				} else {
+					fmt.Fprintf(t.out, "%s", PadRight(str, SPACE, t.cs[y]))
+
+					// TODO Custom alignment per column
+					//if max == 1 || pads[y] > 0 {
+					//	fmt.Fprintf(t.out, "%s", Pad(str, SPACE, t.cs[y]))
+					//} else {
+					//	fmt.Fprintf(t.out, "%s", PadRight(str, SPACE, t.cs[y]))
+					//}
+
+				}
+			}
+			fmt.Fprintf(t.out, SPACE)
+		}
+		// Check if border is set
+		// Replace with space if not set
+		fmt.Fprint(t.out, ConditionString(t.border, t.pColumn, SPACE))
+		fmt.Fprintln(t.out)
+	}
+
+	if t.rowLine {
+		t.printLine(true)
+	}
+
+}
+
+func (t *Table) parseDimension(str string, colKey, rowKey int) []string {
+	var (
+		raw []string
+		max int
+	)
+	w := DisplayWidth(str)
+	// Calculate Width
+	// Check if with is grater than maximum width
+	if w > t.mW {
+		w = t.mW
+	}
+
+	// Check if width exists
+	v, ok := t.cs[colKey]
+	if !ok || v < w || v == 0 {
+		t.cs[colKey] = w
+	}
+
+	if rowKey == -1 {
+		return raw
+	}
+	// Calculate Height
+	if t.autoWrap {
+		raw, _ = WrapString(str, t.cs[colKey])
+	} else {
+		raw = getLines(str)
+	}
+
+	for _, line := range raw {
+		if w := DisplayWidth(line); w > max {
+			max = w
+		}
+	}
+
+	// Make sure the with is the same length as maximum word
+	// Important for cases where the width is smaller than maxu word
+	if max > t.cs[colKey] {
+		t.cs[colKey] = max
+	}
+
+	h := len(raw)
+	v, ok = t.rs[rowKey]
+
+	if !ok || v < h || v == 0 {
+		t.rs[rowKey] = h
+	}
+	//fmt.Printf("Raw %+v %d\n", raw, len(raw))
+	return raw
+}

+ 4 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/test.csv

@@ -0,0 +1,4 @@
+first_name,last_name,ssn
+John,Barry,123456
+Kathy,Smith,687987
+Bob,McCornick,3979870

+ 4 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/test_info.csv

@@ -0,0 +1,4 @@
+Field,Type,Null,Key,Default,Extra
+user_id,smallint(5),NO,PRI,NULL,auto_increment
+username,varchar(10),NO,,NULL, 
+password,varchar(100),NO,,NULL, 

+ 72 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/util.go

@@ -0,0 +1,72 @@
+// Copyright 2014 Oleku Konko All rights reserved.
+// Use of this source code is governed by a MIT
+// license that can be found in the LICENSE file.
+
+// This module is a Table Writer  API for the Go Programming Language.
+// The protocols were written in pure Go and works on windows and unix systems
+
+package tablewriter
+
+import (
+	"math"
+	"regexp"
+	"strings"
+
+	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/mattn/go-runewidth"
+)
+
+var ansi = regexp.MustCompile("\033\\[(?:[0-9]{1,3}(?:;[0-9]{1,3})*)?[m|K]")
+
+func DisplayWidth(str string) int {
+	return runewidth.StringWidth(ansi.ReplaceAllLiteralString(str, ""))
+}
+
+// Simple Condition for string
+// Returns value based on condition
+func ConditionString(cond bool, valid, inValid string) string {
+	if cond {
+		return valid
+	}
+	return inValid
+}
+
+// Format Table Header
+// Replace _ , . and spaces
+func Title(name string) string {
+	name = strings.Replace(name, "_", " ", -1)
+	name = strings.Replace(name, ".", " ", -1)
+	name = strings.TrimSpace(name)
+	return strings.ToUpper(name)
+}
+
+// Pad String
+// Attempts to play string in the center
+func Pad(s, pad string, width int) string {
+	gap := width - DisplayWidth(s)
+	if gap > 0 {
+		gapLeft := int(math.Ceil(float64(gap / 2)))
+		gapRight := gap - gapLeft
+		return strings.Repeat(string(pad), gapLeft) + s + strings.Repeat(string(pad), gapRight)
+	}
+	return s
+}
+
+// Pad String Right position
+// This would pace string at the left side fo the screen
+func PadRight(s, pad string, width int) string {
+	gap := width - DisplayWidth(s)
+	if gap > 0 {
+		return s + strings.Repeat(string(pad), gap)
+	}
+	return s
+}
+
+// Pad String Left position
+// This would pace string at the right side fo the screen
+func PadLeft(s, pad string, width int) string {
+	gap := width - DisplayWidth(s)
+	if gap > 0 {
+		return strings.Repeat(string(pad), gap) + s
+	}
+	return s
+}

+ 103 - 0
Godeps/_workspace/src/github.com/olekukonko/tablewriter/wrap.go

@@ -0,0 +1,103 @@
+// Copyright 2014 Oleku Konko All rights reserved.
+// Use of this source code is governed by a MIT
+// license that can be found in the LICENSE file.
+
+// This module is a Table Writer  API for the Go Programming Language.
+// The protocols were written in pure Go and works on windows and unix systems
+
+package tablewriter
+
+import (
+	"math"
+	"strings"
+	"unicode/utf8"
+)
+
+var (
+	nl = "\n"
+	sp = " "
+)
+
+const defaultPenalty = 1e5
+
+// Wrap wraps s into a paragraph of lines of length lim, with minimal
+// raggedness.
+func WrapString(s string, lim int) ([]string, int) {
+	words := strings.Split(strings.Replace(strings.TrimSpace(s), nl, sp, -1), sp)
+	var lines []string
+	max := 0
+	for _, v := range words {
+		max = len(v)
+		if max > lim {
+			lim = max
+		}
+	}
+	for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
+		lines = append(lines, strings.Join(line, sp))
+	}
+	return lines, lim
+}
+
+// WrapWords is the low-level line-breaking algorithm, useful if you need more
+// control over the details of the text wrapping process. For most uses,
+// WrapString will be sufficient and more convenient.
+//
+// WrapWords splits a list of words into lines with minimal "raggedness",
+// treating each rune as one unit, accounting for spc units between adjacent
+// words on each line, and attempting to limit lines to lim units. Raggedness
+// is the total error over all lines, where error is the square of the
+// difference of the length of the line and lim. Too-long lines (which only
+// happen when a single word is longer than lim units) have pen penalty units
+// added to the error.
+func WrapWords(words []string, spc, lim, pen int) [][]string {
+	n := len(words)
+
+	length := make([][]int, n)
+	for i := 0; i < n; i++ {
+		length[i] = make([]int, n)
+		length[i][i] = utf8.RuneCountInString(words[i])
+		for j := i + 1; j < n; j++ {
+			length[i][j] = length[i][j-1] + spc + utf8.RuneCountInString(words[j])
+		}
+	}
+	nbrk := make([]int, n)
+	cost := make([]int, n)
+	for i := range cost {
+		cost[i] = math.MaxInt32
+	}
+	for i := n - 1; i >= 0; i-- {
+		if length[i][n-1] <= lim {
+			cost[i] = 0
+			nbrk[i] = n
+		} else {
+			for j := i + 1; j < n; j++ {
+				d := lim - length[i][j-1]
+				c := d*d + cost[j]
+				if length[i][j-1] > lim {
+					c += pen // too-long lines get a worse penalty
+				}
+				if c < cost[i] {
+					cost[i] = c
+					nbrk[i] = j
+				}
+			}
+		}
+	}
+	var lines [][]string
+	i := 0
+	for i < n {
+		lines = append(lines, words[i:nbrk[i]])
+		i = nbrk[i]
+	}
+	return lines
+}
+
+// getLines decomposes a multiline string into a slice of strings.
+func getLines(s string) []string {
+	var lines []string
+
+	for _, line := range strings.Split(strings.TrimSpace(s), nl) {
+		lines = append(lines, line)
+	}
+	return lines
+}

+ 18 - 4
etcdctlv3/command/member_command.go

@@ -16,9 +16,11 @@ package command
 
 import (
 	"fmt"
+	"os"
 	"strconv"
 	"strings"
 
+	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/olekukonko/tablewriter"
 	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/cobra"
 	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
 )
@@ -166,12 +168,24 @@ func memberListCommandFunc(cmd *cobra.Command, args []string) {
 		ExitWithError(ExitError, err)
 	}
 
-	// use https://github.com/olekukonko/tablewriter to print out a pretty table?
+	table := tablewriter.NewWriter(os.Stdout)
+	table.SetHeader([]string{"ID", "Status", "Name", "Peer Addrs", "Client Addrs", "Is Leader"})
+
 	for _, m := range resp.Members {
+		status := "started"
 		if len(m.Name) == 0 {
-			fmt.Printf("%16x[unstarted]: peerURLs=%s\n", m.ID, strings.Join(m.PeerURLs, ","))
-		} else {
-			fmt.Printf("%16x: name=%s peerURLs=%s clientURLs=%s isLeader=%v\n", m.ID, m.Name, strings.Join(m.PeerURLs, ","), strings.Join(m.ClientURLs, ","), m.IsLeader)
+			status = "unstarted"
 		}
+
+		table.Append([]string{
+			fmt.Sprintf("%x", m.ID),
+			status,
+			m.Name,
+			strings.Join(m.PeerURLs, ","),
+			strings.Join(m.ClientURLs, ","),
+			fmt.Sprint(m.IsLeader),
+		})
 	}
+
+	table.Render()
 }