diff --git a/go.mod b/go.mod index 0dc3b85d91..b6d70baff3 100644 --- a/go.mod +++ b/go.mod @@ -130,7 +130,7 @@ require ( yunion.io/x/executor v0.0.0-20200227030256-a18417815e74 yunion.io/x/jsonutils v0.0.0-20200330063846-589d9924bb8b yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3 - yunion.io/x/pkg v0.0.0-20200403115157-880d716ed624 + yunion.io/x/pkg v0.0.0-20200414143921-085f89a6e1e9 yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e yunion.io/x/sqlchemy v0.0.0-20200312002602-1177cd8fbc57 yunion.io/x/structarg v0.0.0-20190809075558-115bed041de3 diff --git a/go.sum b/go.sum index 6286316b46..ba2f410f33 100644 --- a/go.sum +++ b/go.sum @@ -1116,8 +1116,8 @@ yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3/go.mod h1:LC6f/4FozL0iaAbnFt2 yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= yunion.io/x/pkg v0.0.0-20200302034534-fdf44d54b070/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= -yunion.io/x/pkg v0.0.0-20200403115157-880d716ed624 h1:yPayJlTJHOP0vKY6ovliZyTwJY9RvdWEF+QDqnxt/iw= -yunion.io/x/pkg v0.0.0-20200403115157-880d716ed624/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= +yunion.io/x/pkg v0.0.0-20200414143921-085f89a6e1e9 h1:baz7ZPSEPXG24d30B1a8CuYXvG7reykwCW2nzdTTs3s= +yunion.io/x/pkg v0.0.0-20200414143921-085f89a6e1e9/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo= yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo= yunion.io/x/sqlchemy v0.0.0-20200312002602-1177cd8fbc57 h1:KtQAuLJ00RSUVqkiRmJ1DiDABiw0U3xxXnzD3lGavaY= diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index 2b27d6c051..46359214cb 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -30,7 +30,7 @@ type ServerListInput struct { HostFilterListInput - NetworkFilterListInput + NetworkFilterListInput `"yunion:ambiguous-prefix":"vpc_"` billing.BillingResourceListInput diff --git a/pkg/mcclient/options/servers.go b/pkg/mcclient/options/servers.go index 259be0ec03..aa91b6be62 100644 --- a/pkg/mcclient/options/servers.go +++ b/pkg/mcclient/options/servers.go @@ -61,6 +61,8 @@ type ServerListOptions struct { ScalingGroup string `help:"ScalingGroup's id or name'"` BaseListOptions + + VpcProvider string `help:"filter by vpc's provider" json:"vpc_provider"` } type ServerIdOptions struct { diff --git a/vendor/yunion.io/x/pkg/prettytable/prettytable.go b/vendor/yunion.io/x/pkg/prettytable/prettytable.go index c2872d2aca..73938de31e 100644 --- a/vendor/yunion.io/x/pkg/prettytable/prettytable.go +++ b/vendor/yunion.io/x/pkg/prettytable/prettytable.go @@ -16,8 +16,11 @@ package prettytable import ( "bytes" + "os" "strings" "unicode" + + "golang.org/x/sys/unix" ) type AlignmentType uint8 @@ -37,10 +40,15 @@ type ptColumn struct { type PrettyTable struct { columns []ptColumn + + maxLineWidth int + tryTermWidth bool } func NewPrettyTable(fields []string) *PrettyTable { - var pt = PrettyTable{} + var pt = PrettyTable{ + tryTermWidth: true, + } for _, field := range fields { col := ptColumn{Title: field, Align: AlignLeft} pt.columns = append(pt.columns, col) @@ -48,6 +56,15 @@ func NewPrettyTable(fields []string) *PrettyTable { return &pt } +func termWidth() (int, error) { + fd := int(os.Stdout.Fd()) + wsz, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) + if err != nil { + return -1, err + } + return int(wsz.Col), nil +} + func rowLine(buf *bytes.Buffer, widths []int) { buf.WriteByte('+') for _, w := range widths { @@ -128,9 +145,14 @@ func runeDisplayWidth(r rune) int { return 1 } -// cellDisplayWidth returns display width of the cell when printed as the -// nthCol. prevWidth is the total display width (as return by this same func) -// of previous cells in the same line +// cellDisplayWidth returns display width of the cell content (excluding bars +// and paddings) when printed as the nthCol. +// +// nthCol is 0-based +// +// prevWidth is the total display width (as return by this same func) of +// previous cells in the same line. It will be used to calculate width of tab +// characters func cellDisplayWidth(cell string, nthCol int, prevWidth int) int { // `| ` at the front and ` | ` in the middle sX := prevWidth + nthCol*3 + 2 @@ -157,14 +179,100 @@ func cellDisplayWidth(cell string, nthCol int, prevWidth int) int { return width } +func wrapCell(cell string, nthCol int, prevWidth int, newWidth int) string { + sX := prevWidth + nthCol*3 + 2 + var ( + wrapped = false + newCell = "" + cline = make([]rune, 0, newWidth+1) + cw = 0 + cx = sX + ) + for _, c := range cell { + var incr int + if c == '\n' { + cline = append(cline, c) + newCell += string(cline) + cline = cline[:0] + cw = 0 + cx = sX + continue + } else if c != '\t' { + incr = runeDisplayWidth(c) + } else { + // terminal with have the char TabWidth aligned + incr = TabWidth - (cx & (TabWidth - 1)) + } + t := cw + incr + if t < newWidth { + cline = append(cline, c) + cw += incr + cx += incr + } else if t == newWidth { + cline = append(cline, c, '\n') + newCell += string(cline) + cline = cline[:0] + cw = 0 + cx = sX + if !wrapped { + wrapped = true + } + } else { + if len(cline) == 0 { + newCell += string(c) + "\n" + } else { + newCell += string(cline) + "\n" + cline = cline[:1] + cline[0] = c + } + cw = 0 + cx = sX + if !wrapped { + wrapped = true + } + } + } + if len(cline) > 0 { + newCell += string(cline) + } else if !wrapped && newCell != "" { + l := len(newCell) - 1 + c := newCell[l] + if c == '\n' { + newCell = newCell[:l] + } + } + return newCell +} + +func (this *PrettyTable) MaxLineWidth(w int) { + this.maxLineWidth = w +} + +func (this *PrettyTable) hasMaxLineWidth() (int, bool) { + if this.maxLineWidth > 0 { + return this.maxLineWidth, true + } + if this.tryTermWidth { + w, err := termWidth() + if err != nil { + return 0, false + } + return w, true + } + return 0, false +} + func (this *PrettyTable) GetString(fields [][]string) string { if len(fields) == 0 { return "" } - var widths = make([]int, len(this.columns)) + var ( + widths = make([]int, len(this.columns)) + widthAcc = 0 + ) { // width of title columns - widthAcc := 0 + widthAcc = 0 for i, c := range this.columns { widths[i] = cellDisplayWidth(c.Title, i, widthAcc) widthAcc += widths[i] @@ -172,7 +280,7 @@ func (this *PrettyTable) GetString(fields [][]string) string { } { // width of content columns - widthAcc := 0 + widthAcc = 0 for col := 0; ; col++ { cont := false colWidth := 0 @@ -195,6 +303,48 @@ func (this *PrettyTable) GetString(fields [][]string) string { } } } + if maxLineWidth, ok := this.hasMaxLineWidth(); ok { + nCols := len(this.columns) + maxContWidth := maxLineWidth - 3*nCols - 1 + if maxContWidth < nCols { + // ensure at least 1 ascii char print + maxContWidth = nCols + } + if widthAcc > maxContWidth { + assured := maxContWidth / len(this.columns) + + rem := maxContWidth + nwrap := 0 + for _, w := range widths { + if w <= assured { + rem -= w + } else { + nwrap += 1 + } + } + // break long lines + widthAcc := 0 + wrapped := rem / nwrap + wrappedRem := rem % nwrap + for col, w := range widths { + if w > assured { + newW := wrapped + if wrappedRem > 0 { + newW += 1 + wrappedRem -= 1 + } + this.columns[col].Title = wrapCell(this.columns[col].Title, col, widthAcc, newW) + for _, line := range fields { + line[col] = wrapCell(line[col], col, widthAcc, newW) + } + widths[col] = newW // later tabs may need correction + widthAcc += newW + } else { + widthAcc += w + } + } + } + } var columns = make([]ptColumn, len(this.columns)) var buf bytes.Buffer rowLine(&buf, widths) diff --git a/vendor/yunion.io/x/pkg/util/reflectutils/ambiguous.go b/vendor/yunion.io/x/pkg/util/reflectutils/ambiguous.go new file mode 100644 index 0000000000..bd84c2d3f5 --- /dev/null +++ b/vendor/yunion.io/x/pkg/util/reflectutils/ambiguous.go @@ -0,0 +1,57 @@ +// Copyright 2019 Yunion +// +// 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 reflectutils + +import ( + "fmt" +) + +const ( + TAG_AMBIGUOUS_PREFIX = "yunion:ambiguous-prefix" + TAG_DEPRECATED_BY = "yunion:deprecated-by" + TAG_OLD_DEPRECATED_BY = "deprecated-by" +) + +func expandAmbiguousPrefix(fields SStructFieldValueSet) SStructFieldValueSet { + keyIndexMap := make(map[string][]int) + for i := range fields { + if fields[i].Info.Ignore { + continue + } + key := fields[i].Info.MarshalName() + values, ok := keyIndexMap[key] + if !ok { + values = make([]int, 0, 2) + } + keyIndexMap[key] = append(values, i) + } + for _, indexes := range keyIndexMap { + if len(indexes) > 1 { + // ambiguous found + for _, idx := range indexes { + if amPrefix, ok := fields[idx].Info.Tags[TAG_AMBIGUOUS_PREFIX]; ok { + fields[idx].Info.Name = fmt.Sprintf("%s%s", amPrefix, fields[idx].Info.Name) + if depBy, ok := fields[idx].Info.Tags[TAG_DEPRECATED_BY]; ok { + fields[idx].Info.Tags[TAG_DEPRECATED_BY] = fmt.Sprintf("%s%s", amPrefix, depBy) + } + if depBy, ok := fields[idx].Info.Tags[TAG_OLD_DEPRECATED_BY]; ok { + fields[idx].Info.Tags[TAG_OLD_DEPRECATED_BY] = fmt.Sprintf("%s%s", amPrefix, depBy) + } + } + } + } + } + return fields +} diff --git a/vendor/yunion.io/x/pkg/util/reflectutils/jsonfield.go b/vendor/yunion.io/x/pkg/util/reflectutils/jsonfield.go index 9b70f0d4a2..15aaff5b0f 100644 --- a/vendor/yunion.io/x/pkg/util/reflectutils/jsonfield.go +++ b/vendor/yunion.io/x/pkg/util/reflectutils/jsonfield.go @@ -138,11 +138,11 @@ type SStructFieldValue struct { type SStructFieldValueSet []SStructFieldValue func FetchStructFieldValueSet(dataValue reflect.Value) SStructFieldValueSet { - return fetchStructFieldValueSet(dataValue, false, nil) + return expandAmbiguousPrefix(fetchStructFieldValueSet(dataValue, false, nil)) } func FetchStructFieldValueSetForWrite(dataValue reflect.Value) SStructFieldValueSet { - return fetchStructFieldValueSet(dataValue, true, nil) + return expandAmbiguousPrefix(fetchStructFieldValueSet(dataValue, true, nil)) } type sStructFieldInfoMap map[string]SStructFieldInfo @@ -256,13 +256,15 @@ func fetchStructFieldValueSet(dataValue reflect.Value, allocatePtr bool, tags ma return fields } -func (set SStructFieldValueSet) GetStructFieldIndex(name string) int { - for i := 0; i < len(set); i += 1 { - jsonInfo := set[i].Info - if jsonInfo.MarshalName() == name { +func (fields SStructFieldValueSet) GetStructFieldIndex(name string) int { + for i := range fields { + if fields[i].Info.Ignore { + continue + } + if fields[i].Info.MarshalName() == name { return i } - if utils.CamelSplit(jsonInfo.FieldName, "_") == utils.CamelSplit(name, "_") { + /*if utils.CamelSplit(jsonInfo.FieldName, "_") == utils.CamelSplit(name, "_") { return i } if jsonInfo.FieldName == name { @@ -270,20 +272,22 @@ func (set SStructFieldValueSet) GetStructFieldIndex(name string) int { } if jsonInfo.FieldName == utils.Capitalize(name) { return i - } + }*/ } return -1 } -func (set SStructFieldValueSet) GetStructFieldIndexes(name string) []int { +func (fields SStructFieldValueSet) GetStructFieldIndexes(name string) []int { ret := make([]int, 0) - for i := 0; i < len(set); i += 1 { - jsonInfo := set[i].Info - if jsonInfo.MarshalName() == name { + for i := range fields { + if fields[i].Info.Ignore { + continue + } + if fields[i].Info.MarshalName() == name { ret = append(ret, i) continue } - if utils.CamelSplit(jsonInfo.FieldName, "_") == utils.CamelSplit(name, "_") { + /*if utils.CamelSplit(jsonInfo.FieldName, "_") == utils.CamelSplit(name, "_") { ret = append(ret, i) continue } @@ -294,11 +298,27 @@ func (set SStructFieldValueSet) GetStructFieldIndexes(name string) []int { if jsonInfo.FieldName == utils.Capitalize(name) { ret = append(ret, i) continue - } + }*/ } return ret } +func (fields SStructFieldValueSet) GetStructFieldIndexesMap() map[string][]int { + keyIndexMap := make(map[string][]int) + for i := range fields { + if fields[i].Info.Ignore { + continue + } + key := fields[i].Info.MarshalName() + values, ok := keyIndexMap[key] + if !ok { + values = make([]int, 0, 2) + } + keyIndexMap[key] = append(values, i) + } + return keyIndexMap +} + func (set SStructFieldValueSet) GetValue(name string) (reflect.Value, bool) { idx := set.GetStructFieldIndex(name) if idx < 0 {