From 0a0af5cfa2e3fa4e33af152abcd0f0dd5b5eab69 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 5 Jun 2020 11:03:15 +0800 Subject: [PATCH] climc:allow disable term line width --- go.mod | 8 +- go.sum | 22 +-- pkg/util/printutils/printjson.go | 8 +- vendor/modules.txt | 8 +- vendor/yunion.io/x/jsonutils/currency.go | 1 + vendor/yunion.io/x/jsonutils/unmarshal.go | 41 +++-- vendor/yunion.io/x/pkg/gotypes/gotypes.go | 8 +- .../x/pkg/prettytable/prettytable.go | 6 + .../x/pkg/util/reflectutils/jsonfield.go | 22 ++- vendor/yunion.io/x/sqlchemy/column.go | 26 ++- vendor/yunion.io/x/sqlchemy/conditions.go | 26 +++ vendor/yunion.io/x/sqlchemy/parser.go | 103 ++++++----- vendor/yunion.io/x/sqlchemy/reflect.go | 156 ++++++++-------- vendor/yunion.io/x/sqlchemy/table.go | 6 +- vendor/yunion.io/x/structarg/structarg.go | 172 +++++++++++++----- 15 files changed, 392 insertions(+), 221 deletions(-) diff --git a/go.mod b/go.mod index b429a820d5..8d8e886f67 100644 --- a/go.mod +++ b/go.mod @@ -127,13 +127,13 @@ require ( k8s.io/cluster-bootstrap v0.17.3 k8s.io/kubernetes v1.16.0 yunion.io/x/executor v0.0.0-20200227030256-a18417815e74 - yunion.io/x/jsonutils v0.0.0-20200415132054-2bf8a5e94501 + yunion.io/x/jsonutils v0.0.0-20200601015434-d61aefddfe79 yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3 yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7 - yunion.io/x/pkg v0.0.0-20200516092703-0a53bc9270aa + yunion.io/x/pkg v0.0.0-20200603123312-ad58e621aec0 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-20200423163001-168d0687be7e + yunion.io/x/sqlchemy v0.0.0-20200603015906-56eda65f53e4 + yunion.io/x/structarg v0.0.0-20200603035440-0690e9bc7655 ) replace ( diff --git a/go.sum b/go.sum index fdf04d03fa..5e70ae2cc9 100644 --- a/go.sum +++ b/go.sum @@ -769,8 +769,6 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yousong/ovsdb v0.0.0-20200526055947-05168ba66aaf h1:MfwaIeKiVUqeWZSKyO5GwOccti0O/ENZDdqOkB3OPnU= -github.com/yousong/ovsdb v0.0.0-20200526055947-05168ba66aaf/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc= github.com/yunionio/go-ceph v0.0.0-20190912101231-6f05a06b3859 h1:wu596gn6sV3j5wy+GDfiG8nwtzIDpalJihfmC/TjoYc= github.com/yunionio/go-ceph v0.0.0-20190912101231-6f05a06b3859/go.mod h1:8XuBae5AzsgotLArJSewMruYVaQs8AlfsK5jBCG8T9Y= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= @@ -1110,27 +1108,23 @@ vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj yunion.io/x/executor v0.0.0-20200227030256-a18417815e74 h1:A15C6VdVRWvmQ9pAJHrUs9yan5qKlYH7uaRxHg1kRbk= yunion.io/x/executor v0.0.0-20200227030256-a18417815e74/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws= yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634= -yunion.io/x/jsonutils v0.0.0-20200415132054-2bf8a5e94501 h1:i1r9XvbdxH3FgTCLmTaRi3MzQqhiQimXJRlUOPgrxnU= -yunion.io/x/jsonutils v0.0.0-20200415132054-2bf8a5e94501/go.mod h1:T7kxQJR13+t7z0TuT+Wzd7MTxBOk2H9c0pO1ONQSv90= +yunion.io/x/jsonutils v0.0.0-20200601015434-d61aefddfe79 h1:MP8wgqdmGbg8Tb1O2/HQlyeKMrEPsq3R0pClQFMJmlg= +yunion.io/x/jsonutils v0.0.0-20200601015434-d61aefddfe79/go.mod h1:T7kxQJR13+t7z0TuT+Wzd7MTxBOk2H9c0pO1ONQSv90= yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b/go.mod h1:+gauLs73omeJAPlsXcevLsJLKixV+sR/E7WSYTSx1fE= yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d h1:59zrDL7Ft+hDukguJRmLr/Gdu/9V75x+yX99ovZwfaA= yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d/go.mod h1:LC6f/4FozL0iaAbnFt2eDX9jlsyo3WiOUPm03d7+U4U= yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3 h1:5Wc5hkB8PtMudmHuzCyok960RuOa9I55imIGrigSdjs= yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3/go.mod h1:LC6f/4FozL0iaAbnFt2eDX9jlsyo3WiOUPm03d7+U4U= -yunion.io/x/ovsdb v0.0.0-20200512112253-a3601d1ee987 h1:BlHpXbNhqG1rZ57io0+XI4L9ckWunn7LHR2JQikGqQg= -yunion.io/x/ovsdb v0.0.0-20200512112253-a3601d1ee987/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc= -yunion.io/x/ovsdb v0.0.0-20200526062315-c921cb58f76e h1:v5AnakAKVOvYoYEtsTkntcr4MIgawTAI106/5mmaMAs= -yunion.io/x/ovsdb v0.0.0-20200526062315-c921cb58f76e/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc= yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7 h1:gjqNa2uQzIEXyySsbvVz0UltTEbGsnFFlvnzOpCfHdo= yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc= 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-20200516092703-0a53bc9270aa h1:VizPfW8+mLFEE7W/97zxQJbfdxchi2dn1M/Y7YBwTTc= -yunion.io/x/pkg v0.0.0-20200516092703-0a53bc9270aa/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= +yunion.io/x/pkg v0.0.0-20200603123312-ad58e621aec0 h1:i2AghhUX3Xr/iri9yRJ5spsE6OX+akutGwZ2XVcE02U= +yunion.io/x/pkg v0.0.0-20200603123312-ad58e621aec0/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= -yunion.io/x/sqlchemy v0.0.0-20200312002602-1177cd8fbc57/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI= -yunion.io/x/structarg v0.0.0-20200423163001-168d0687be7e h1:pctCe/EPel3F1B83pJ2q9b34Umd1NdbLW1Yd+Lzur2s= -yunion.io/x/structarg v0.0.0-20200423163001-168d0687be7e/go.mod h1:EP6NSv2C0zzqBDTKumv8hPWLb3XvgMZDHQRfyuOrQng= +yunion.io/x/sqlchemy v0.0.0-20200603015906-56eda65f53e4 h1:y6lrMWPt/xd8f6B1E0s+iL7xx/Y8ui4S6h9UJBzUDk4= +yunion.io/x/sqlchemy v0.0.0-20200603015906-56eda65f53e4/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI= +yunion.io/x/structarg v0.0.0-20200603035440-0690e9bc7655 h1:Y01W3976TSUm3S9QDbZS4ZgHKoP79PgE+1IF/iPu5bc= +yunion.io/x/structarg v0.0.0-20200603035440-0690e9bc7655/go.mod h1:EP6NSv2C0zzqBDTKumv8hPWLb3XvgMZDHQRfyuOrQng= diff --git a/pkg/util/printutils/printjson.go b/pkg/util/printutils/printjson.go index a602e5d9e9..3275551c06 100644 --- a/pkg/util/printutils/printjson.go +++ b/pkg/util/printutils/printjson.go @@ -16,6 +16,7 @@ package printutils import ( "fmt" + "os" "sort" "yunion.io/x/jsonutils" @@ -57,7 +58,12 @@ func PrintJSONList(list *modulebase.ListResult, columns []string) { } } } - pt := prettytable.NewPrettyTable(colsWithData) + osTryTermWidth := os.Getenv("OS_TRY_TERM_WIDTH") + tryTermWidth := true + if osTryTermWidth == "false" { + tryTermWidth = false + } + pt := prettytable.NewPrettyTableWithTryTermWidth(colsWithData, tryTermWidth) rows := make([][]string, 0) for _, obj := range list.Data { row := make([]string, 0) diff --git a/vendor/modules.txt b/vendor/modules.txt index ffc4d8492d..2db17009fd 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -991,7 +991,7 @@ sigs.k8s.io/yaml yunion.io/x/executor/apis yunion.io/x/executor/client yunion.io/x/executor/server -# yunion.io/x/jsonutils v0.0.0-20200415132054-2bf8a5e94501 +# yunion.io/x/jsonutils v0.0.0-20200601015434-d61aefddfe79 yunion.io/x/jsonutils # yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3 yunion.io/x/log @@ -1000,7 +1000,7 @@ yunion.io/x/log/hooks yunion.io/x/ovsdb/cli_util yunion.io/x/ovsdb/schema/ovn_nb yunion.io/x/ovsdb/types -# yunion.io/x/pkg v0.0.0-20200516092703-0a53bc9270aa +# yunion.io/x/pkg v0.0.0-20200603123312-ad58e621aec0 yunion.io/x/pkg/errors yunion.io/x/pkg/gotypes yunion.io/x/pkg/prettytable @@ -1032,7 +1032,7 @@ yunion.io/x/pkg/util/workqueue yunion.io/x/pkg/utils # yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e yunion.io/x/s3cli -# yunion.io/x/sqlchemy v0.0.0-20200312002602-1177cd8fbc57 +# yunion.io/x/sqlchemy v0.0.0-20200603015906-56eda65f53e4 yunion.io/x/sqlchemy -# yunion.io/x/structarg v0.0.0-20200423163001-168d0687be7e +# yunion.io/x/structarg v0.0.0-20200603035440-0690e9bc7655 yunion.io/x/structarg diff --git a/vendor/yunion.io/x/jsonutils/currency.go b/vendor/yunion.io/x/jsonutils/currency.go index ed2abbc76e..b896aebedc 100644 --- a/vendor/yunion.io/x/jsonutils/currency.go +++ b/vendor/yunion.io/x/jsonutils/currency.go @@ -17,6 +17,7 @@ package jsonutils import ( "fmt" "strings" + "yunion.io/x/pkg/util/regutils" ) diff --git a/vendor/yunion.io/x/jsonutils/unmarshal.go b/vendor/yunion.io/x/jsonutils/unmarshal.go index 4a464503e5..9367ea8092 100644 --- a/vendor/yunion.io/x/jsonutils/unmarshal.go +++ b/vendor/yunion.io/x/jsonutils/unmarshal.go @@ -337,19 +337,30 @@ func (this *JSONString) unmarshalValue(val reflect.Value) error { } } switch val.Kind() { - case reflect.Int, reflect.Uint, reflect.Int8, reflect.Uint8, - reflect.Int16, reflect.Uint16, reflect.Int32, reflect.Uint32, reflect.Int64, reflect.Uint64: - intVal, err := strconv.ParseInt(this.data, 10, 64) - if err != nil { - return err + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if len(this.data) > 0 { + intVal, err := strconv.ParseInt(normalizeCurrencyString(this.data), 10, 64) + if err != nil { + return err + } + val.SetInt(intVal) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + if len(this.data) > 0 { + intVal, err := strconv.ParseUint(normalizeCurrencyString(this.data), 10, 64) + if err != nil { + return err + } + val.SetUint(intVal) } - val.SetInt(intVal) case reflect.Float32, reflect.Float64: - floatVal, err := strconv.ParseFloat(normalizeCurrencyString(this.data), 64) - if err != nil { - return err + if len(this.data) > 0 { + floatVal, err := strconv.ParseFloat(normalizeCurrencyString(this.data), 64) + if err != nil { + return err + } + val.SetFloat(floatVal) } - val.SetFloat(floatVal) case reflect.Bool: val.SetBool(utils.ToBool(this.data)) case reflect.String: @@ -557,14 +568,20 @@ func setStructFieldAt(key string, v JSONObject, fieldValues reflectutils.SStruct func (this *JSONDict) unmarshalStruct(val reflect.Value) error { fieldValues := reflectutils.FetchStructFieldValueSetForWrite(val) keyIndexMap := fieldValues.GetStructFieldIndexesMap() + errs := make([]error, 0) for k, v := range this.data { err := setStructFieldAt(k, v, fieldValues, keyIndexMap, nil) if err != nil { - return errors.Wrapf(err, "setStructFieldAt %s: %s", k, v) + // store error, not interrupt the process + errs = append(errs, errors.Wrapf(err, "setStructFieldAt %s: %s", k, v)) } } callStructAfterUnmarshal(val) - return nil + if len(errs) > 0 { + return errors.NewAggregate(errs) + } else { + return nil + } } func callStructAfterUnmarshal(val reflect.Value) { diff --git a/vendor/yunion.io/x/pkg/gotypes/gotypes.go b/vendor/yunion.io/x/pkg/gotypes/gotypes.go index d5925f6b5a..25e8ffac15 100644 --- a/vendor/yunion.io/x/pkg/gotypes/gotypes.go +++ b/vendor/yunion.io/x/pkg/gotypes/gotypes.go @@ -134,7 +134,9 @@ func ParseValue(val string, tp reflect.Type) (reflect.Value, error) { return reflect.ValueOf(val_float), err } case reflect.String: - return reflect.ValueOf(val), nil + v := reflect.New(tp).Elem() + v.SetString(val) + return v, nil case reflect.Ptr: tpElem := tp.Elem() rv, err := ParseValue(val, tpElem) @@ -229,10 +231,10 @@ func SliceBaseType(tp reflect.Type) reflect.Type { } func AppendValue(value reflect.Value, val string) error { - tp := SliceBaseType(value.Type()) - if tp == nil { + if value.Kind() != reflect.Slice { return fmt.Errorf("Cannot append to non-slice type") } + tp := value.Type().Elem() val_raw, e := ParseValue(val, tp) if e != nil { return e diff --git a/vendor/yunion.io/x/pkg/prettytable/prettytable.go b/vendor/yunion.io/x/pkg/prettytable/prettytable.go index f5ab7046f4..c8696b7e99 100644 --- a/vendor/yunion.io/x/pkg/prettytable/prettytable.go +++ b/vendor/yunion.io/x/pkg/prettytable/prettytable.go @@ -53,6 +53,12 @@ func NewPrettyTable(fields []string) *PrettyTable { return &pt } +func NewPrettyTableWithTryTermWidth(fields []string, tryTermWidth bool) *PrettyTable { + pt := NewPrettyTable(fields) + pt.tryTermWidth = tryTermWidth + return pt +} + func rowLine(buf *bytes.Buffer, widths []int) { buf.WriteByte('+') for _, w := range widths { diff --git a/vendor/yunion.io/x/pkg/util/reflectutils/jsonfield.go b/vendor/yunion.io/x/pkg/util/reflectutils/jsonfield.go index 2dd417b617..1702796089 100644 --- a/vendor/yunion.io/x/pkg/util/reflectutils/jsonfield.go +++ b/vendor/yunion.io/x/pkg/util/reflectutils/jsonfield.go @@ -138,11 +138,19 @@ type SStructFieldValue struct { type SStructFieldValueSet []SStructFieldValue func FetchStructFieldValueSet(dataValue reflect.Value) SStructFieldValueSet { - return expandAmbiguousPrefix(fetchStructFieldValueSet(dataValue, false, nil)) + return expandAmbiguousPrefix(fetchStructFieldValueSet(dataValue, false)) } func FetchStructFieldValueSetForWrite(dataValue reflect.Value) SStructFieldValueSet { - return expandAmbiguousPrefix(fetchStructFieldValueSet(dataValue, true, nil)) + return expandAmbiguousPrefix(fetchStructFieldValueSet(dataValue, true)) +} + +func FetchAllStructFieldValueSet(dataValue reflect.Value) SStructFieldValueSet { + return expandAmbiguousPrefix(fetchStructFieldValueSet2(dataValue, false, nil, true)) +} + +func FetchAllStructFieldValueSetForWrite(dataValue reflect.Value) SStructFieldValueSet { + return expandAmbiguousPrefix(fetchStructFieldValueSet2(dataValue, true, nil, true)) } type sStructFieldInfoMap map[string]SStructFieldInfo @@ -186,7 +194,11 @@ func fetchStructFieldInfos(dataType reflect.Type) sStructFieldInfoMap { return smap } -func fetchStructFieldValueSet(dataValue reflect.Value, allocatePtr bool, tags map[string]string) SStructFieldValueSet { +func fetchStructFieldValueSet(dataValue reflect.Value, allocatePtr bool) SStructFieldValueSet { + return fetchStructFieldValueSet2(dataValue, allocatePtr, nil, false) +} + +func fetchStructFieldValueSet2(dataValue reflect.Value, allocatePtr bool, tags map[string]string, includeIgnore bool) SStructFieldValueSet { fields := SStructFieldValueSet{} dataType := dataValue.Type() fieldInfos := fetchCacheStructFieldInfos(dataType) @@ -223,13 +235,13 @@ func fetchStructFieldValueSet(dataValue reflect.Value, allocatePtr bool, tags ma // field of interface type. if fv.Kind() == reflect.Struct && sf.Type != gotypes.TimeType { anonymousTags := utils.TagMap(sf.Tag) - subfields := fetchStructFieldValueSet(fv, allocatePtr, anonymousTags) + subfields := fetchStructFieldValueSet2(fv, allocatePtr, anonymousTags, includeIgnore) fields = append(fields, subfields...) continue } } fieldInfo := fieldInfos[sf.Name].deepCopy() - if !fieldInfo.Ignore { + if !fieldInfo.Ignore || includeIgnore { fields = append(fields, SStructFieldValue{ Info: fieldInfo, Value: fv, diff --git a/vendor/yunion.io/x/sqlchemy/column.go b/vendor/yunion.io/x/sqlchemy/column.go index a3b1c24bfb..5741ce2a5e 100644 --- a/vendor/yunion.io/x/sqlchemy/column.go +++ b/vendor/yunion.io/x/sqlchemy/column.go @@ -387,6 +387,8 @@ type SIntegerColumn struct { IsAutoIncrement bool IsAutoVersion bool IsUnsigned bool + + AutoIncrementOffset int64 } func (c *SIntegerColumn) IsNumeric() bool { @@ -426,9 +428,16 @@ func (c *SIntegerColumn) ColType() string { func NewIntegerColumn(name string, sqltype string, unsigned bool, tagmap map[string]string, isPointer bool) SIntegerColumn { autoinc := false + autoincBase := int64(0) tagmap, v, ok := utils.TagPop(tagmap, TAG_AUTOINCREMENT) if ok { - autoinc = utils.ToBool(v) + base, err := strconv.ParseInt(v, 10, 64) + if err == nil && base > 0 { + autoinc = true + autoincBase = base + } else { + autoinc = utils.ToBool(v) + } } autover := false tagmap, v, ok = utils.TagPop(tagmap, TAG_AUTOVERSION) @@ -436,10 +445,11 @@ func NewIntegerColumn(name string, sqltype string, unsigned bool, tagmap map[str autover = utils.ToBool(v) } c := SIntegerColumn{ - SBaseWidthColumn: NewBaseWidthColumn(name, sqltype, tagmap, isPointer), - IsAutoIncrement: autoinc, - IsAutoVersion: autover, - IsUnsigned: unsigned, + SBaseWidthColumn: NewBaseWidthColumn(name, sqltype, tagmap, isPointer), + IsAutoIncrement: autoinc, + AutoIncrementOffset: autoincBase, + IsAutoVersion: autover, + IsUnsigned: unsigned, } if autoinc { c.isPrimary = true // autoincrement column must be primary key @@ -585,11 +595,9 @@ func (c *STextColumn) DefinitionString() string { func (c *STextColumn) IsZero(val interface{}) bool { if c.isPointer { - bval := val.(*string) - return bval == nil + return gotypes.IsNil(val) } else { - bVal := val.(string) - return len(bVal) == 0 + return reflect.ValueOf(val).Len() == 0 } } diff --git a/vendor/yunion.io/x/sqlchemy/conditions.go b/vendor/yunion.io/x/sqlchemy/conditions.go index 7cca310062..b4e1f0408c 100644 --- a/vendor/yunion.io/x/sqlchemy/conditions.go +++ b/vendor/yunion.io/x/sqlchemy/conditions.go @@ -225,6 +225,32 @@ func IsFalse(f IQueryField) ICondition { return &c } +type SNoLaterThanCondition struct { + SSingleCondition +} + +func (c *SNoLaterThanCondition) WhereClause() string { + return fmt.Sprintf("%s >= NOW()", c.field.Reference()) +} + +func NoLaterThan(f IQueryField) ICondition { + c := SNoLaterThanCondition{NewSingleCondition(f)} + return &c +} + +type SNoEarlierThanCondition struct { + SSingleCondition +} + +func (c *SNoEarlierThanCondition) WhereClause() string { + return fmt.Sprintf("%s <= NOW()", c.field.Reference()) +} + +func NoEarlierThan(f IQueryField) ICondition { + c := SNoEarlierThanCondition{NewSingleCondition(f)} + return &c +} + type STupleCondition struct { left IQueryField right interface{} diff --git a/vendor/yunion.io/x/sqlchemy/parser.go b/vendor/yunion.io/x/sqlchemy/parser.go index f20aa95490..d1faab489b 100644 --- a/vendor/yunion.io/x/sqlchemy/parser.go +++ b/vendor/yunion.io/x/sqlchemy/parser.go @@ -15,6 +15,7 @@ package sqlchemy import ( + "fmt" "reflect" "yunion.io/x/pkg/gotypes" @@ -41,50 +42,55 @@ func structField2ColumnSpec(field *reflectutils.SStructFieldValue) IColumnSpec { func getFiledTypeCol(fieldType reflect.Type, fieldname string, tagmap map[string]string, isPointer bool) IColumnSpec { switch fieldType { - case gotypes.StringType: - col := NewTextColumn(fieldname, tagmap, isPointer) - return &col - case gotypes.IntType, gotypes.Int32Type: - tagmap[TAG_WIDTH] = "11" - col := NewIntegerColumn(fieldname, "INT", false, tagmap, isPointer) - return &col - case gotypes.Int8Type: - tagmap[TAG_WIDTH] = "4" - col := NewIntegerColumn(fieldname, "TINYINT", false, tagmap, isPointer) - return &col - case gotypes.Int16Type: - tagmap[TAG_WIDTH] = "6" - col := NewIntegerColumn(fieldname, "SMALLINT", false, tagmap, isPointer) - return &col - case gotypes.Int64Type: - tagmap[TAG_WIDTH] = "20" - col := NewIntegerColumn(fieldname, "BIGINT", false, tagmap, isPointer) - return &col - case gotypes.UintType, gotypes.Uint32Type: - tagmap[TAG_WIDTH] = "11" - col := NewIntegerColumn(fieldname, "INT", true, tagmap, isPointer) - return &col - case gotypes.Uint8Type: - tagmap[TAG_WIDTH] = "4" - col := NewIntegerColumn(fieldname, "TINYINT", true, tagmap, isPointer) - return &col - case gotypes.Uint16Type: - tagmap[TAG_WIDTH] = "6" - col := NewIntegerColumn(fieldname, "SMALLINT", true, tagmap, isPointer) - return &col - case gotypes.Uint64Type: - tagmap[TAG_WIDTH] = "20" - col := NewIntegerColumn(fieldname, "BIGINT", true, tagmap, isPointer) - return &col - case gotypes.BoolType: - tagmap[TAG_WIDTH] = "1" - col := NewBooleanColumn(fieldname, tagmap, isPointer) - return &col case tristate.TriStateType: tagmap[TAG_WIDTH] = "1" col := NewTristateColumn(fieldname, tagmap, isPointer) return &col - case gotypes.Float32Type, gotypes.Float64Type: + case gotypes.TimeType: + col := NewDateTimeColumn(fieldname, tagmap, isPointer) + return &col + } + switch fieldType.Kind() { + case reflect.String: + col := NewTextColumn(fieldname, tagmap, isPointer) + return &col + case reflect.Int, reflect.Int32: + tagmap[TAG_WIDTH] = "11" + col := NewIntegerColumn(fieldname, "INT", false, tagmap, isPointer) + return &col + case reflect.Int8: + tagmap[TAG_WIDTH] = "4" + col := NewIntegerColumn(fieldname, "TINYINT", false, tagmap, isPointer) + return &col + case reflect.Int16: + tagmap[TAG_WIDTH] = "6" + col := NewIntegerColumn(fieldname, "SMALLINT", false, tagmap, isPointer) + return &col + case reflect.Int64: + tagmap[TAG_WIDTH] = "20" + col := NewIntegerColumn(fieldname, "BIGINT", false, tagmap, isPointer) + return &col + case reflect.Uint, reflect.Uint32: + tagmap[TAG_WIDTH] = "11" + col := NewIntegerColumn(fieldname, "INT", true, tagmap, isPointer) + return &col + case reflect.Uint8: + tagmap[TAG_WIDTH] = "4" + col := NewIntegerColumn(fieldname, "TINYINT", true, tagmap, isPointer) + return &col + case reflect.Uint16: + tagmap[TAG_WIDTH] = "6" + col := NewIntegerColumn(fieldname, "SMALLINT", true, tagmap, isPointer) + return &col + case reflect.Uint64: + tagmap[TAG_WIDTH] = "20" + col := NewIntegerColumn(fieldname, "BIGINT", true, tagmap, isPointer) + return &col + case reflect.Bool: + tagmap[TAG_WIDTH] = "1" + col := NewBooleanColumn(fieldname, tagmap, isPointer) + return &col + case reflect.Float32, reflect.Float64: if _, ok := tagmap[TAG_WIDTH]; ok { col := NewDecimalColumn(fieldname, tagmap, isPointer) return &col @@ -96,23 +102,26 @@ func getFiledTypeCol(fieldType reflect.Type, fieldname string, tagmap map[string col := NewFloatColumn(fieldname, colType, tagmap, isPointer) return &col } - case gotypes.TimeType: - col := NewDateTimeColumn(fieldname, tagmap, isPointer) + } + if fieldType.Implements(gotypes.ISerializableType) { + col := NewCompoundColumn(fieldname, tagmap, isPointer) return &col - default: - if fieldType.Implements(gotypes.ISerializableType) { - col := NewCompoundColumn(fieldname, tagmap, isPointer) - return &col - } } return nil } func struct2TableSpec(sv reflect.Value, table *STableSpec) { fields := reflectutils.FetchStructFieldValueSet(sv) + autoIncCnt := 0 for i := 0; i < len(fields); i += 1 { column := structField2ColumnSpec(&fields[i]) if column != nil { + if intC, ok := column.(*SIntegerColumn); ok && intC.IsAutoIncrement { + autoIncCnt += 1 + if autoIncCnt > 1 { + panic(fmt.Sprintf("Table %s contains multiple autoincremental columns!!", table.name)) + } + } if column.IsIndex() { table.AddIndex(column.IsUnique(), column.Name()) } diff --git a/vendor/yunion.io/x/sqlchemy/reflect.go b/vendor/yunion.io/x/sqlchemy/reflect.go index ce44f12c54..e7bec0db32 100644 --- a/vendor/yunion.io/x/sqlchemy/reflect.go +++ b/vendor/yunion.io/x/sqlchemy/reflect.go @@ -20,9 +20,9 @@ import ( "strconv" "time" - "yunion.io/x/pkg/errors" "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/gotypes" "yunion.io/x/pkg/tristate" "yunion.io/x/pkg/util/timeutils" @@ -31,22 +31,10 @@ import ( func getStringValue(dat interface{}) string { value := reflect.ValueOf(dat) switch value.Type() { - case gotypes.BoolType: - if value.Bool() { - return "true" - } else { - return "false" - } - case gotypes.IntType, gotypes.Int8Type, gotypes.Int16Type, gotypes.Int32Type, gotypes.Int64Type: - return fmt.Sprintf("%d", value.Int()) - case gotypes.UintType, gotypes.Uint8Type, gotypes.Uint16Type, gotypes.Uint32Type, gotypes.Uint64Type: - return fmt.Sprintf("%d", value.Uint()) - case gotypes.Float32Type, gotypes.Float64Type: - return fmt.Sprintf("%f", value.Float()) - case gotypes.StringType: - return value.String() + case tristate.TriStateType: + return dat.(tristate.TriState).String() case gotypes.TimeType: - tm, ok := value.Interface().(time.Time) + tm, ok := dat.(time.Time) if !ok { log.Errorf("Fail to convert to time.Time %s", value) } else { @@ -67,14 +55,28 @@ func getStringValue(dat interface{}) string { } else { return string(rawBytes) } - default: - serializable, ok := value.Interface().(gotypes.ISerializable) - if !ok { - log.Errorf("cannot convert %v to string", value) - return "" + } + switch value.Kind() { + case reflect.Bool: + if value.Bool() { + return "true" + } else { + return "false" } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return fmt.Sprintf("%d", value.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return fmt.Sprintf("%d", value.Uint()) + case reflect.Float32, reflect.Float64: + return fmt.Sprintf("%f", value.Float()) + case reflect.String: + return value.String() + } + serializable, ok := value.Interface().(gotypes.ISerializable) + if ok { return serializable.String() } + log.Errorf("cannot convert %v to string", value) return "" } @@ -83,12 +85,6 @@ func setValueBySQLString(value reflect.Value, val string) error { return errors.Wrap(ErrReadOnly, "value is not settable") } switch value.Type() { - case gotypes.BoolType: - if val == "0" { - value.SetBool(false) - } else { - value.SetBool(true) - } case tristate.TriStateType: if val == "0" { value.Set(tristate.TriStateFalseValue) @@ -97,63 +93,71 @@ func setValueBySQLString(value reflect.Value, val string) error { } else { value.Set(tristate.TriStateNoneValue) } - case gotypes.IntType, gotypes.Int8Type, gotypes.Int16Type, gotypes.Int32Type, gotypes.Int64Type: - valInt, err := strconv.ParseInt(val, 10, 64) - if err != nil { - return err - } - value.SetInt(valInt) - case gotypes.UintType, gotypes.Uint8Type, gotypes.Uint16Type, gotypes.Uint32Type, gotypes.Uint64Type: - valUint, err := strconv.ParseUint(val, 10, 64) - if err != nil { - return err - } - value.SetUint(valUint) - case gotypes.Float32Type, gotypes.Float64Type: - valFloat, err := strconv.ParseFloat(val, 64) - if err != nil { - return err - } - value.SetFloat(valFloat) - case gotypes.StringType: - value.SetString(val) + return nil case gotypes.TimeType: if val != "0000-00-00 00:00:00" { tm, err := timeutils.ParseTimeStr(val) if err != nil { - return err + return errors.Wrap(err, "ParseTimeStr") } value.Set(reflect.ValueOf(tm)) } - /*case jsonutils.JSONDictType, jsonutils.JSONArrayType, jsonutils.JSONStringType, jsonutils.JSONIntType, - jsonutils.JSONFloatType, jsonutils.JSONBoolType, jsonutils.JSONObjectType: - log.Debugf("Decode JSON value: $%s$", val) - json, err := jsonutils.ParseString(val) - if err != nil { - return err + return nil } - value.Set(reflect.ValueOf(json))*/ - case gotypes.BoolSliceType, gotypes.IntSliceType, gotypes.Int8SliceType, gotypes.Int16SliceType, - gotypes.Int32SliceType, gotypes.Int64SliceType, gotypes.UintSliceType, gotypes.Uint8SliceType, - gotypes.Uint16SliceType, gotypes.Uint32SliceType, gotypes.Uint64SliceType, - gotypes.Float32SliceType, gotypes.Float64SliceType, gotypes.StringSliceType: - reflect.Append(value, reflect.ValueOf(val)) - default: - valueType := value.Type() - if valueType.Implements(gotypes.ISerializableType) { - serializable, err := jsonutils.JSONDeserialize(valueType, val) - if err != nil { - return err - } - value.Set(reflect.ValueOf(serializable)) - return nil - } else if value.Kind() == reflect.Ptr { - if value.IsNil() { - value.Set(reflect.New(value.Type().Elem())) - } - return setValueBySQLString(value.Elem(), val) + switch value.Kind() { + case reflect.Bool: + if val == "0" { + value.SetBool(false) + } else { + value.SetBool(true) } - return errors.Wrapf(ErrNotSupported, "not supported type: %s", valueType) + return nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + valInt, err := strconv.ParseInt(val, 10, 64) + if err != nil { + return errors.Wrap(err, "ParseInt") + } + value.SetInt(valInt) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + valUint, err := strconv.ParseUint(val, 10, 64) + if err != nil { + return errors.Wrap(err, "ParseUint") + } + value.SetUint(valUint) + return nil + case reflect.Float32, reflect.Float64: + valFloat, err := strconv.ParseFloat(val, 64) + if err != nil { + return errors.Wrap(err, "ParseFloat") + } + value.SetFloat(valFloat) + return nil + case reflect.String: + value.SetString(val) + return nil + case reflect.Slice: + elemValue := reflect.New(value.Type().Elem()).Elem() + err := setValueBySQLString(elemValue, val) + if err != nil { + return errors.Wrap(err, "reflect.Slice") + } + value.Set(reflect.Append(value, elemValue)) + return nil + case reflect.Ptr: + if value.IsNil() { + value.Set(reflect.New(value.Type().Elem())) + } + return setValueBySQLString(value.Elem(), val) } - return nil + valueType := value.Type() + if valueType.Implements(gotypes.ISerializableType) { + serializable, err := jsonutils.JSONDeserialize(valueType, val) + if err != nil { + return errors.Wrap(err, "jsonutils.JSONDeserialize") + } + value.Set(reflect.ValueOf(serializable)) + return nil + } + return errors.Wrapf(ErrNotSupported, "not supported type: %s", valueType) } diff --git a/vendor/yunion.io/x/sqlchemy/table.go b/vendor/yunion.io/x/sqlchemy/table.go index 4b7fa6ad5b..8f35a379f0 100644 --- a/vendor/yunion.io/x/sqlchemy/table.go +++ b/vendor/yunion.io/x/sqlchemy/table.go @@ -83,10 +83,14 @@ func (ts *STableSpec) CreateSQL() string { cols := make([]string, 0) primaries := make([]string, 0) indexes := make([]string, 0) + autoInc := "" for _, c := range ts.columns { cols = append(cols, c.DefinitionString()) if c.IsPrimary() { primaries = append(primaries, fmt.Sprintf("`%s`", c.Name())) + if intC, ok := c.(*SIntegerColumn); ok && intC.AutoIncrementOffset > 1 { + autoInc = fmt.Sprintf(" AUTO_INCREMENT=%d", intC.AutoIncrementOffset) + } } if c.IsIndex() { indexes = append(indexes, fmt.Sprintf("KEY `ix_%s_%s` (`%s`)", ts.name, c.Name(), c.Name())) @@ -98,7 +102,7 @@ func (ts *STableSpec) CreateSQL() string { if len(indexes) > 0 { cols = append(cols, indexes...) } - return fmt.Sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n%s\n) ENGINE=InnoDB DEFAULT CHARSET=utf8", ts.name, strings.Join(cols, ",\n")) + return fmt.Sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n%s\n) ENGINE=InnoDB DEFAULT CHARSET=utf8%s", ts.name, strings.Join(cols, ",\n"), autoInc) } func (ts *STableSpec) Instance() *STable { diff --git a/vendor/yunion.io/x/structarg/structarg.go b/vendor/yunion.io/x/structarg/structarg.go index 697708e402..9aa863fbd3 100644 --- a/vendor/yunion.io/x/structarg/structarg.go +++ b/vendor/yunion.io/x/structarg/structarg.go @@ -27,6 +27,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/gotypes" "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/pkg/utils" @@ -44,6 +45,7 @@ type Argument interface { Token() string AliasToken() string ShortToken() string + NegativeToken() string MetaVar() string IsPositional() bool IsRequired() bool @@ -53,7 +55,7 @@ type Argument interface { String() string SetValue(val string) error Reset() - DoAction() error + DoAction(nega bool) error Validate() error SetDefault() IsSet() bool @@ -63,6 +65,7 @@ type SingleArgument struct { token string aliasToken string shortToken string + negaToken string metavar string positional bool required bool @@ -104,9 +107,12 @@ type ArgumentParser struct { func NewArgumentParser(target interface{}, prog, desc, epilog string) (*ArgumentParser, error) { parser := ArgumentParser{prog: prog, description: desc, epilog: epilog, target: target} - target_type := reflect.TypeOf(target).Elem() - target_value := reflect.ValueOf(target).Elem() - e := parser.addStructArgument("", target_type, target_value) + targetValue := reflect.ValueOf(target) + if targetValue.Kind() != reflect.Ptr { + return nil, fmt.Errorf("target must be a pointer") + } + targetValue = targetValue.Elem() + e := parser.addStructArgument("", targetValue) if e != nil { return nil, e } @@ -182,37 +188,46 @@ const ( Alias name of argument */ TAG_ALIAS = "alias" + /* + Token for negative value, applicable to boolean values + */ + TAG_NEGATIVE_TOKEN = "negative" ) -func (this *ArgumentParser) addStructArgument(prefix string, tp reflect.Type, val reflect.Value) error { - for i := 0; i < tp.NumField(); i++ { - v := val.Field(i) - if !v.CanSet() { - continue - } - f := tp.Field(i) - if f.Type.Kind() == reflect.Struct { - p := prefix - if !f.Anonymous { - p += f.Name + "-" +func (this *ArgumentParser) addStructArgument(prefix string, tpVal reflect.Value) error { + sets := reflectutils.FetchAllStructFieldValueSetForWrite(tpVal) + for i := range sets { + if sets[i].Value.Kind() == reflect.Struct && sets[i].Value.Type() != gotypes.TimeType { + tagMap := sets[i].Info.Tags + if _, ok := tagMap[reflectutils.TAG_DEPRECATED_BY]; ok { + // deprecated field, ignore + return nil } - e := this.addStructArgument(p, f.Type, v) - if e != nil { - return e + token, ok := tagMap[TAG_TOKEN] + if !ok { + token = sets[i].Info.MarshalName() + } + token = prefix + token + "-" + err := this.addStructArgument(token, sets[i].Value) + if err != nil { + return errors.Wrap(err, "addStructArgument") } } else { - e := this.addArgument(prefix, f, v) - if e != nil { - return e + err := this.addArgument(prefix, sets[i].Value, sets[i].Info) + if err != nil { + return errors.Wrap(err, "addArgument") } } } return nil } -func (this *ArgumentParser) addArgument(prefix string, f reflect.StructField, v reflect.Value) error { - info := reflectutils.ParseStructFieldJsonInfo(f) +func (this *ArgumentParser) addArgument(prefix string, fv reflect.Value, info *reflectutils.SStructFieldInfo) error { tagMap := info.Tags + if _, ok := tagMap[reflectutils.TAG_DEPRECATED_BY]; ok { + // deprecated field, ignore + return nil + } help := tagMap[TAG_HELP] token, ok := tagMap[TAG_TOKEN] if !ok { @@ -221,6 +236,7 @@ func (this *ArgumentParser) addArgument(prefix string, f reflect.StructField, v token = prefix + token shorttoken := tagMap[TAG_SHORT_TOKEN] alias := tagMap[TAG_ALIAS] + negative := tagMap[TAG_NEGATIVE_TOKEN] metavar := tagMap[TAG_METAVAR] defval := tagMap[TAG_DEFAULT] if len(defval) > 0 { @@ -234,6 +250,9 @@ func (this *ArgumentParser) addArgument(prefix string, f reflect.StructField, v } } } + if len(negative) > 0 && !valueIsBool(fv) { + return fmt.Errorf("negative token is applicable to boolean option ONLY") + } use_default := true if len(defval) == 0 { use_default = false @@ -249,7 +268,7 @@ func (this *ArgumentParser) addArgument(prefix string, f reflect.StructField, v } // heuristic guessing "positional" var positional bool - if f.Name == strings.ToUpper(f.Name) { + if info.FieldName == strings.ToUpper(info.FieldName) { positional = true } else { positional = false @@ -292,7 +311,7 @@ func (this *ArgumentParser) addArgument(prefix string, f reflect.StructField, v } var defval_t reflect.Value if use_default { - defval_t, err = gotypes.ParseValue(defval, f.Type) + defval_t, err = gotypes.ParseValue(defval, fv.Type()) if err != nil { return err } @@ -301,20 +320,21 @@ func (this *ArgumentParser) addArgument(prefix string, f reflect.StructField, v positional = true } var arg Argument = nil - ovalue := reflect.New(v.Type()).Elem() - ovalue.Set(v) + ovalue := reflect.New(fv.Type()).Elem() + ovalue.Set(fv) sarg := SingleArgument{ token: token, shortToken: shorttoken, + aliasToken: alias, + negaToken: negative, positional: positional, required: required, metavar: metavar, help: help, choices: choices, useDefault: use_default, - aliasToken: alias, defValue: defval_t, - value: v, + value: fv, ovalue: ovalue, parser: this, } @@ -322,7 +342,7 @@ func (this *ArgumentParser) addArgument(prefix string, f reflect.StructField, v if subcommand { arg = &SubcommandArgument{SingleArgument: sarg, subcommands: make(map[string]SubcommandArgumentData)} - } else if f.Type.Kind() == reflect.Array || f.Type.Kind() == reflect.Slice { + } else if fv.Kind() == reflect.Array || fv.Kind() == reflect.Slice || fv.Kind() == reflect.Map { var min, max int64 var err error nargs := tagMap[TAG_NARGS] @@ -413,8 +433,7 @@ func (this *ArgumentParser) Options() interface{} { return this.target } -func (this *SingleArgument) valueIsBool() bool { - rv := this.value +func valueIsBool(rv reflect.Value) bool { if rv.Kind() == reflect.Bool { return true } @@ -425,6 +444,13 @@ func (this *SingleArgument) valueIsBool() bool { return false } +func valueIsMap(rv reflect.Value) bool { + if rv.Kind() == reflect.Map { + return true + } + return false +} + func (this *SingleArgument) defaultBoolValue() bool { rv := this.defValue if rv.Kind() == reflect.Bool { @@ -438,7 +464,7 @@ func (this *SingleArgument) defaultBoolValue() bool { } func (this *SingleArgument) NeedData() bool { - if this.valueIsBool() { + if valueIsBool(this.value) { return false } else { return true @@ -467,6 +493,9 @@ func (this *SingleArgument) AllToken() string { if len(this.ShortToken()) != 0 { ret = fmt.Sprintf("%s|-%s", ret, this.ShortToken()) } + if len(this.NegativeToken()) != 0 { + ret = fmt.Sprintf("%s/--%s", ret, this.NegativeToken()) + } return ret } @@ -482,6 +511,10 @@ func (this *SingleArgument) ShortToken() string { return this.shortToken } +func (this *SingleArgument) NegativeToken() string { + return this.negaToken +} + func (this *SingleArgument) String() string { var start, end byte if this.IsRequired() { @@ -570,11 +603,13 @@ func (this *SingleArgument) Reset() { this.isSet = false } -func (this *SingleArgument) DoAction() error { - if this.valueIsBool() { +func (this *SingleArgument) DoAction(nega bool) error { + if valueIsBool(this.value) { var v bool if this.useDefault { v = !this.defaultBoolValue() + } else if nega { + v = false } else { v = true } @@ -605,7 +640,37 @@ func (this *MultiArgument) IsMulti() bool { return true } +func (this *MultiArgument) setKeyValue(val string) error { + pos := strings.IndexByte(val, '=') + var key, value string + if pos >= 0 { + key = val[:pos] + value = val[pos+1:] + } else { + key = val + } + keyType := this.value.Type().Key() + keyValue, err := gotypes.ParseValue(key, keyType) + if err != nil { + return errors.Wrapf(err, "ParseValue for key %s", key) + } + valType := this.value.Type().Elem() + valValue, err := gotypes.ParseValue(value, valType) + if err != nil { + return errors.Wrapf(err, "ParseValue for value %s", value) + } + if this.value.Len() == 0 { + this.value.Set(reflect.MakeMap(this.value.Type())) + } + this.value.SetMapIndex(keyValue, valValue) + this.isSet = true + return nil +} + func (this *MultiArgument) SetValue(val string) error { + if valueIsMap(this.value) { + return this.setKeyValue(val) + } if !this.InChoices(val) { return this.choicesErr(val) } @@ -777,28 +842,38 @@ func tokenMatch(argToken, input string, exactMatch bool) bool { } } -func (this *ArgumentParser) findOptionalArgument(token string, exactMatch bool) Argument { +func (this *ArgumentParser) findOptionalArgument(token string, exactMatch bool) (Argument, bool) { var match_arg Argument = nil match_len := -1 + negative := false for _, arg := range this.optArgs { if tokenMatch(arg.Token(), token, exactMatch) { if match_len < 0 || match_len > len(arg.Token()) { match_len = len(arg.Token()) match_arg = arg + negative = false } } else if tokenMatch(arg.ShortToken(), token, exactMatch) { if match_len < 0 || match_len > len(arg.ShortToken()) { match_len = len(arg.ShortToken()) match_arg = arg + negative = false } } else if tokenMatch(arg.AliasToken(), token, exactMatch) { if match_len < 0 || match_len > len(arg.AliasToken()) { match_len = len(arg.AliasToken()) match_arg = arg + negative = false + } + } else if tokenMatch(arg.NegativeToken(), token, exactMatch) { + if match_len < 0 || match_len > len(arg.AliasToken()) { + match_len = len(arg.AliasToken()) + match_arg = arg + negative = true } } } - return match_arg + return match_arg, negative } func validateArgs(args []Argument) error { @@ -838,9 +913,8 @@ func (this *ArgumentParser) ParseArgs(args []string, ignore_unknown bool) error } func (this *ArgumentParser) ParseArgs2(args []string, ignore_unknown bool, setDefaults bool) error { - var pos_idx int = 0 - var arg Argument = nil - var err error = nil + var pos_idx int + var err error var argStr string this.reset() @@ -848,7 +922,7 @@ func (this *ArgumentParser) ParseArgs2(args []string, ignore_unknown bool, setDe for i := 0; i < len(args) && err == nil; i++ { argStr = args[i] if strings.HasPrefix(argStr, "-") { - arg = this.findOptionalArgument(strings.TrimLeft(argStr, "-"), false) + arg, nega := this.findOptionalArgument(strings.TrimLeft(argStr, "-"), false) if arg != nil { if arg.NeedData() { if i+1 < len(args) { @@ -862,7 +936,7 @@ func (this *ArgumentParser) ParseArgs2(args []string, ignore_unknown bool, setDe break } } else { - err = arg.DoAction() + err = arg.DoAction(nega) if err != nil { break } @@ -886,7 +960,7 @@ func (this *ArgumentParser) ParseArgs2(args []string, ignore_unknown bool, setDe break } } else { - arg = this.posArgs[pos_idx] + arg := this.posArgs[pos_idx] pos_idx += 1 err = arg.SetValue(argStr) if err != nil { @@ -922,8 +996,12 @@ func isQuoted(str string) bool { } func (this *ArgumentParser) parseKeyValue(key, value string) error { - arg := this.findOptionalArgument(key, true) + arg, nega := this.findOptionalArgument(key, true) if arg != nil { + if nega { + log.Warningf("Ignore negative token when parse %s=%v", key, value) + return nil + } if arg.IsSet() { return nil } @@ -1019,11 +1097,15 @@ func keyToToken(key string) string { func (this *ArgumentParser) parseJSONKeyValue(key string, obj jsonutils.JSONObject) error { token := keyToToken(key) - arg := this.findOptionalArgument(token, true) + arg, nega := this.findOptionalArgument(token, true) if arg == nil { log.Warningf("Cannot find argument %s", token) return nil } + if nega { + log.Warningf("Ignore negative token when parse JSONKeyValue %s", token) + return nil + } if arg.IsSet() { return nil }