Switch remote deploy to vendored source builds
Move remote deployment to a vendored source bundle built on the target host via Docker so redeploys no longer require local cross-compilation or host Go installation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
202
vendor/github.com/tkrajina/go-reflector/LICENSE.txt
generated
vendored
Normal file
202
vendor/github.com/tkrajina/go-reflector/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [2016-] [Tomo Krajina]
|
||||
|
||||
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.
|
||||
748
vendor/github.com/tkrajina/go-reflector/reflector/reflector.go
generated
vendored
Normal file
748
vendor/github.com/tkrajina/go-reflector/reflector/reflector.go
generated
vendored
Normal file
@@ -0,0 +1,748 @@
|
||||
package reflector
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type fieldListingType int
|
||||
|
||||
const (
|
||||
fieldsAll fieldListingType = iota
|
||||
fieldsAnonymous
|
||||
fieldsFlattenAnonymous
|
||||
fieldsNoFlattenAnonymous
|
||||
)
|
||||
|
||||
var (
|
||||
metadataCache map[reflect.Type]ObjMetadata
|
||||
metadataCacheMutex sync.RWMutex
|
||||
)
|
||||
|
||||
func init() {
|
||||
metadataCache = map[reflect.Type]ObjMetadata{}
|
||||
}
|
||||
|
||||
func updateCache(ty reflect.Type, o *Obj) {
|
||||
metadataCacheMutex.Lock()
|
||||
defer metadataCacheMutex.Unlock()
|
||||
|
||||
metadataCache[ty] = o.ObjMetadata
|
||||
}
|
||||
|
||||
// ObjMetadata contains data which is always unique per Type.
|
||||
type ObjMetadata struct {
|
||||
isStruct bool
|
||||
isPtrToStruct bool
|
||||
|
||||
// If ptr to struct, this field will contain the type of that struct
|
||||
underlyingType reflect.Type
|
||||
|
||||
objType reflect.Type
|
||||
objKind reflect.Kind
|
||||
|
||||
fields map[string]ObjFieldMetadata
|
||||
|
||||
fieldNamesAll []string
|
||||
fieldNamesAnonymous []string
|
||||
fieldNamesFlattenAnonymous []string
|
||||
fieldNamesNoFlattenAnonymous []string
|
||||
|
||||
methods map[string]ObjMethodMetadata
|
||||
methodNames []string
|
||||
}
|
||||
|
||||
func newObjMetadata(ty reflect.Type) *ObjMetadata {
|
||||
res := new(ObjMetadata)
|
||||
if ty == nil {
|
||||
res.objKind = reflect.Invalid
|
||||
return res
|
||||
}
|
||||
|
||||
res.objType = ty
|
||||
res.objKind = res.objType.Kind()
|
||||
|
||||
if ty.Kind() == reflect.Struct {
|
||||
res.isStruct = true
|
||||
}
|
||||
if ty.Kind() == reflect.Ptr && ty.Elem().Kind() == reflect.Struct {
|
||||
ty = ty.Elem()
|
||||
res.isPtrToStruct = true
|
||||
}
|
||||
res.underlyingType = ty
|
||||
|
||||
allFields := res.getFields(res.objType, fieldsAll)
|
||||
|
||||
res.fieldNamesAll = allFields
|
||||
res.fieldNamesAnonymous = res.getFields(res.objType, fieldsAnonymous)
|
||||
res.fieldNamesFlattenAnonymous = res.getFields(res.objType, fieldsFlattenAnonymous)
|
||||
res.fieldNamesNoFlattenAnonymous = res.getFields(res.objType, fieldsNoFlattenAnonymous)
|
||||
|
||||
res.methods = map[string]ObjMethodMetadata{}
|
||||
res.methodNames = []string{}
|
||||
|
||||
if res.objKind != reflect.Invalid {
|
||||
res.fields = map[string]ObjFieldMetadata{}
|
||||
for _, fieldName := range allFields {
|
||||
res.fields[fieldName] = *newObjFieldMetadata(res.objType, fieldName, res)
|
||||
}
|
||||
for i := 0; i < res.objType.NumMethod(); i++ {
|
||||
method := res.objType.Method(i)
|
||||
res.methodNames = append(res.methodNames, method.Name)
|
||||
res.methods[method.Name] = *newObjMethodMetadata(res.objType, method.Name, res)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// IsStructOrPtrToStruct checks if the value is a struct or a pointer to a struct.
|
||||
func (om *ObjMetadata) IsStructOrPtrToStruct() bool {
|
||||
return om.isStruct || om.isPtrToStruct
|
||||
}
|
||||
|
||||
func (om *ObjMetadata) appendFields(fields []string, field reflect.StructField, listingType fieldListingType) []string {
|
||||
k := field.Type.Kind()
|
||||
if listingType == fieldsAnonymous {
|
||||
if field.Anonymous {
|
||||
fields = append(fields, field.Name)
|
||||
}
|
||||
} else if listingType == fieldsAll {
|
||||
fields = append(fields, field.Name)
|
||||
if k == reflect.Struct && field.Anonymous {
|
||||
fields = append(fields, om.getFields(field.Type, listingType)...)
|
||||
}
|
||||
} else {
|
||||
if listingType == fieldsFlattenAnonymous && k == reflect.Struct && field.Anonymous {
|
||||
fields = append(fields, om.getFields(field.Type, listingType)...)
|
||||
} else {
|
||||
fields = append(fields, field.Name)
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
func (om *ObjMetadata) getFields(ty reflect.Type, listingType fieldListingType) []string {
|
||||
var fields []string
|
||||
|
||||
if ty.Kind() == reflect.Ptr {
|
||||
ty = ty.Elem()
|
||||
}
|
||||
|
||||
if ty.Kind() != reflect.Struct {
|
||||
return fields // No need to populate nonstructs
|
||||
}
|
||||
|
||||
for i := 0; i < ty.NumField(); i++ {
|
||||
f := ty.Field(i)
|
||||
fields = om.appendFields(fields, f, listingType)
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// ObjFieldMetadata contains data which is always unique per Type/Field.
|
||||
type ObjFieldMetadata struct {
|
||||
name string
|
||||
|
||||
structField reflect.StructField
|
||||
|
||||
// Valid here is not yet the final info about an actual field validity,
|
||||
// because value field still have .IsValid()
|
||||
valid bool
|
||||
|
||||
fieldKind reflect.Kind
|
||||
fieldType reflect.Type
|
||||
}
|
||||
|
||||
func newObjFieldMetadata(ty reflect.Type, name string, objMetadata *ObjMetadata) *ObjFieldMetadata {
|
||||
res := &ObjFieldMetadata{}
|
||||
res.fieldKind = reflect.Invalid
|
||||
res.name = name
|
||||
if objMetadata.IsStructOrPtrToStruct() {
|
||||
var found bool
|
||||
var structField reflect.StructField
|
||||
if objMetadata.isPtrToStruct {
|
||||
structField, found = objMetadata.objType.Elem().FieldByName(res.name)
|
||||
} else {
|
||||
structField, found = objMetadata.objType.FieldByName(res.name)
|
||||
}
|
||||
res.structField = structField
|
||||
res.fieldType = structField.Type
|
||||
if res.fieldType == nil {
|
||||
res.valid = false
|
||||
} else {
|
||||
res.fieldKind = structField.Type.Kind()
|
||||
res.valid = found
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ObjMethodMetadata contains data
|
||||
// which is always unique per Type/Method.
|
||||
type ObjMethodMetadata struct {
|
||||
name string
|
||||
method reflect.Method
|
||||
valid bool
|
||||
}
|
||||
|
||||
func newObjMethodMetadata(ty reflect.Type, name string, objMetadata *ObjMetadata) *ObjMethodMetadata {
|
||||
res := &ObjMethodMetadata{name: name}
|
||||
|
||||
if objMetadata.objKind == reflect.Invalid {
|
||||
res.valid = false
|
||||
} else {
|
||||
if method, found := objMetadata.objType.MethodByName(name); found {
|
||||
res.method = method
|
||||
res.valid = res.method.Func.IsValid()
|
||||
} else {
|
||||
res.valid = false
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Obj is a wrapper for golang values which need to be reflected.
|
||||
// The value can be of any kind and any type.
|
||||
type Obj struct {
|
||||
iface interface{}
|
||||
// Value used to work with fields. The only special case is when iface is a pointer to a struct, in
|
||||
// that case this is the value of that struct:
|
||||
fieldsValue reflect.Value
|
||||
ObjMetadata
|
||||
}
|
||||
|
||||
// NewFromType creates a new Obj but using reflect.Type.
|
||||
func NewFromType(ty reflect.Type) *Obj {
|
||||
if ty == nil {
|
||||
return New(nil)
|
||||
}
|
||||
return New(reflect.New(ty).Interface())
|
||||
}
|
||||
|
||||
// New initializes a new Obj wrapper.
|
||||
func New(obj interface{}) *Obj {
|
||||
o := &Obj{iface: obj}
|
||||
|
||||
ty := reflect.TypeOf(obj)
|
||||
metadataCacheMutex.RLock()
|
||||
metadata, found := metadataCache[ty]
|
||||
metadataCacheMutex.RUnlock()
|
||||
if found {
|
||||
o.ObjMetadata = metadata
|
||||
} else {
|
||||
o.ObjMetadata = *newObjMetadata(reflect.TypeOf(obj))
|
||||
updateCache(ty, o)
|
||||
}
|
||||
|
||||
o.fieldsValue = reflect.Indirect(reflect.ValueOf(obj))
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
// IsValid checks if the underlying objects is valid.
|
||||
// Nil is an invalid value, for example.
|
||||
func (o *Obj) IsValid() bool {
|
||||
return o.objKind != reflect.Invalid
|
||||
}
|
||||
|
||||
// Len returns object length. Works for arrays, channels, maps, slices and strings.
|
||||
//
|
||||
// It doesn't panic for other types, returns 0 instead.
|
||||
//
|
||||
// In case the value is a pointer, len checks the underlying value.
|
||||
func (o *Obj) Len() int {
|
||||
switch o.fieldsValue.Kind() {
|
||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
|
||||
return o.fieldsValue.Len()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IsGettableByIndex returns true if underlying type is array, slice or string
|
||||
func (o *Obj) IsGettableByIndex() bool {
|
||||
switch o.fieldsValue.Kind() {
|
||||
case reflect.Array, reflect.Slice, reflect.String:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsSettableByIndex returns true if underlying type is array, slice (but not string, since they are immutable)
|
||||
func (o *Obj) IsSettableByIndex() bool {
|
||||
switch o.fieldsValue.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsMap returns true if underlying type is map or a pointer to a map
|
||||
func (o *Obj) IsMap() bool {
|
||||
switch o.fieldsValue.Kind() {
|
||||
case reflect.Map:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// GetByIndex returns a value by int index.
|
||||
//
|
||||
// Works for arrays, slices and strins. Won't panic when index or kind is invalid.
|
||||
func (o *Obj) GetByIndex(index int) (value interface{}, found bool) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
value = nil
|
||||
found = false
|
||||
}
|
||||
}()
|
||||
|
||||
if o.IsGettableByIndex() {
|
||||
if 0 <= index && index < o.fieldsValue.Len() {
|
||||
value = o.fieldsValue.Index(index).Interface()
|
||||
found = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SetByIndex sets a slice value by key.
|
||||
func (o *Obj) SetByIndex(index int, val interface{}) error {
|
||||
if index < 0 || o.Len() <= index {
|
||||
return fmt.Errorf("cannot set element %d", index)
|
||||
}
|
||||
|
||||
if o.IsSettableByIndex() {
|
||||
elem := o.fieldsValue.Index(index)
|
||||
elem.Set(reflect.ValueOf(val))
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("cannot set element %d of %s", index, o.fieldsValue.String())
|
||||
}
|
||||
|
||||
// Keys return map keys in unspecified order.
|
||||
func (o *Obj) Keys() ([]interface{}, error) {
|
||||
if o.IsMap() {
|
||||
keys := o.fieldsValue.MapKeys()
|
||||
res := make([]interface{}, len(keys))
|
||||
for n := range keys {
|
||||
res[n] = keys[n].Interface()
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid type %s", o.Type().String())
|
||||
}
|
||||
|
||||
// SetByKey sets a map value by key.
|
||||
func (o *Obj) SetByKey(key interface{}, val interface{}) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = fmt.Errorf("cannot set key %s: %v", key, e)
|
||||
}
|
||||
}()
|
||||
|
||||
if o.IsMap() {
|
||||
o.fieldsValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(val))
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("cannot set key %s: %w", key, err)
|
||||
return
|
||||
}
|
||||
|
||||
// GetByKey returns a value by map key.
|
||||
//
|
||||
// Won't panic when key is invalid or kind is not map.
|
||||
func (o *Obj) GetByKey(key interface{}) (value interface{}, found bool) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
value = nil
|
||||
found = false
|
||||
}
|
||||
}()
|
||||
|
||||
if o.IsMap() {
|
||||
v := o.fieldsValue.MapIndex(reflect.ValueOf(key))
|
||||
if !v.IsValid() {
|
||||
found = false
|
||||
return
|
||||
}
|
||||
value = v.Interface()
|
||||
found = true
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Fields returns fields.
|
||||
// Don't list fields inside Anonymous fields as distinct fields.
|
||||
func (o *Obj) Fields() []ObjField {
|
||||
return o.getFields(fieldsNoFlattenAnonymous)
|
||||
}
|
||||
|
||||
// FieldsFlattened returns fields.
|
||||
// Will not list Anonymous fields but it will list fields declared in those anonymous fields.
|
||||
func (o Obj) FieldsFlattened() []ObjField {
|
||||
return o.getFields(fieldsFlattenAnonymous)
|
||||
}
|
||||
|
||||
// FieldsAll returns fields.
|
||||
// List both anonymous fields and fields declared inside anonymous fields.
|
||||
func (o Obj) FieldsAll() []ObjField {
|
||||
return o.getFields(fieldsAll)
|
||||
}
|
||||
|
||||
// FieldsAnonymous returns only anonymous fields.
|
||||
func (o Obj) FieldsAnonymous() []ObjField {
|
||||
return o.getFields(fieldsAnonymous)
|
||||
}
|
||||
|
||||
func (o *Obj) getFields(listingType fieldListingType) []ObjField {
|
||||
var fieldNames []string
|
||||
switch listingType {
|
||||
case fieldsAll:
|
||||
fieldNames = o.fieldNamesAll
|
||||
case fieldsAnonymous:
|
||||
fieldNames = o.fieldNamesAnonymous
|
||||
case fieldsFlattenAnonymous:
|
||||
fieldNames = o.fieldNamesFlattenAnonymous
|
||||
case fieldsNoFlattenAnonymous:
|
||||
fieldNames = o.fieldNamesNoFlattenAnonymous
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid field listing type %d", listingType))
|
||||
}
|
||||
|
||||
res := make([]ObjField, len(fieldNames))
|
||||
for n, fieldName := range fieldNames {
|
||||
res[n] = *o.Field(fieldName)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// FindDoubleFields checks if this object has declared
|
||||
// multiple fields with a same name.
|
||||
// (by checking recursively Anonymous fields and their fields)
|
||||
func (o Obj) FindDoubleFields() []string {
|
||||
fields := map[string]int{}
|
||||
res := []string{}
|
||||
for _, f := range o.FieldsAll() {
|
||||
counter := fields[f.name]
|
||||
if counter == 1 {
|
||||
res = append(res, f.name)
|
||||
}
|
||||
fields[f.name] = counter + 1
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// IsPtr checks if the value is a pointer.
|
||||
func (o Obj) IsPtr() bool {
|
||||
return o.objKind == reflect.Ptr
|
||||
}
|
||||
|
||||
func (o Obj) Dereferenced() interface{} {
|
||||
val := o.fieldsValue
|
||||
for val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
return val.Interface()
|
||||
}
|
||||
|
||||
// Field get a field wrapper.
|
||||
// Note that the field name can be invalid.
|
||||
// You can check the field validity using ObjField.IsValid().
|
||||
func (o *Obj) Field(fieldName string) *ObjField {
|
||||
if o.fieldsValue.IsValid() {
|
||||
if metadata, found := o.fields[fieldName]; found {
|
||||
return newObjField(o, metadata)
|
||||
}
|
||||
}
|
||||
return newObjField(o, ObjFieldMetadata{name: fieldName, valid: false, fieldKind: reflect.Invalid})
|
||||
}
|
||||
|
||||
// Type returns the value type.
|
||||
// If kind is invalid, this will return a zero filled reflect.Type.
|
||||
func (o Obj) Type() reflect.Type {
|
||||
return o.objType
|
||||
}
|
||||
|
||||
// Kind returns the value's kind.
|
||||
func (o Obj) Kind() reflect.Kind {
|
||||
return o.objKind
|
||||
}
|
||||
|
||||
func (o Obj) String() string {
|
||||
if o.objType == nil {
|
||||
return "nil"
|
||||
}
|
||||
return o.objType.String()
|
||||
}
|
||||
|
||||
// Method returns a new method wrapper.
|
||||
// The method name can be invalid, check the method validity with ObjMethod.IsValid().
|
||||
func (o *Obj) Method(name string) *ObjMethod {
|
||||
if metadata, found := o.methods[name]; found {
|
||||
return newObjMethod(o, metadata)
|
||||
}
|
||||
return newObjMethod(o, ObjMethodMetadata{name: name, valid: false})
|
||||
}
|
||||
|
||||
// Methods returns the list of all methods.
|
||||
func (o *Obj) Methods() []ObjMethod {
|
||||
res := make([]ObjMethod, 0, len(o.methodNames))
|
||||
for _, name := range o.methodNames {
|
||||
res = append(res, *o.Method(name))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ObjField is a wrapper for the object's field.
|
||||
type ObjField struct {
|
||||
obj *Obj
|
||||
value reflect.Value
|
||||
|
||||
ObjFieldMetadata
|
||||
}
|
||||
|
||||
func newObjField(obj *Obj, metadata ObjFieldMetadata) *ObjField {
|
||||
res := &ObjField{
|
||||
obj: obj,
|
||||
ObjFieldMetadata: metadata,
|
||||
}
|
||||
|
||||
if metadata.valid && res.obj.IsStructOrPtrToStruct() {
|
||||
res.value = obj.fieldsValue.FieldByName(res.name)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (of *ObjField) assertValid() error {
|
||||
if !of.IsValid() {
|
||||
return fmt.Errorf("invalid field %s", of.name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid checks if the fields is valid.
|
||||
func (of *ObjField) IsValid() bool {
|
||||
return of.valid && of.value.IsValid()
|
||||
}
|
||||
|
||||
// Name returns the field's name.
|
||||
func (of *ObjField) Name() string {
|
||||
return of.name
|
||||
}
|
||||
|
||||
// Kind returns the field's kind.
|
||||
func (of *ObjField) Kind() reflect.Kind {
|
||||
return of.fieldKind
|
||||
}
|
||||
|
||||
// Type returns the field's type.
|
||||
func (of *ObjField) Type() reflect.Type {
|
||||
return of.fieldType
|
||||
}
|
||||
|
||||
// Tag returns the value of this specific tag
|
||||
// or error if the field is invalid.
|
||||
func (of *ObjField) Tag(tag string) (string, error) {
|
||||
if err := of.assertValid(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return of.structField.Tag.Get(tag), nil
|
||||
}
|
||||
|
||||
// Tags returns the map of all fields or error for invalid field.
|
||||
func (of *ObjField) Tags() (map[string]string, error) {
|
||||
if err := of.assertValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tag := of.structField.Tag
|
||||
return ParseTag(string(tag))
|
||||
}
|
||||
|
||||
// TagsString returns the complete tags string (everything inside “)
|
||||
func (of *ObjField) TagsString() (string, error) {
|
||||
if err := of.assertValid(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(of.structField.Tag), nil
|
||||
}
|
||||
|
||||
// TagExpanded returns the tag value "expanded" with commas.
|
||||
func (of *ObjField) TagExpanded(tag string) ([]string, error) {
|
||||
if err := of.assertValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return strings.Split(of.structField.Tag.Get(tag), ","), nil
|
||||
}
|
||||
|
||||
// IsAnonymous checks if this is an anonymous (embedded) field.
|
||||
func (of *ObjField) IsAnonymous() bool {
|
||||
if err := of.assertValid(); err != nil {
|
||||
return false
|
||||
}
|
||||
field, found := of.obj.underlyingType.FieldByName(of.name)
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
return field.Anonymous
|
||||
}
|
||||
|
||||
// IsExported returns true if the name starts with uppercase (i.e. field is public).
|
||||
func (of *ObjField) IsExported() bool {
|
||||
return of.structField.PkgPath == ""
|
||||
}
|
||||
|
||||
// IsSettable checks if this field is settable.
|
||||
func (of *ObjField) IsSettable() bool {
|
||||
return of.value.CanSet()
|
||||
}
|
||||
|
||||
// Set sets a value for this field or error if field is invalid (or not settable).
|
||||
func (of *ObjField) Set(value interface{}) error {
|
||||
if err := of.assertValid(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !of.IsSettable() {
|
||||
return fmt.Errorf("field %s in %T not settable", of.name, of.obj.iface)
|
||||
}
|
||||
|
||||
of.value.Set(reflect.ValueOf(value))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get gets the field value of error if field is invalid).
|
||||
func (of *ObjField) Get() (interface{}, error) {
|
||||
if err := of.assertValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !of.IsExported() {
|
||||
return nil, fmt.Errorf("cannot read unexported field %T.%s", of.obj.iface, of.name)
|
||||
}
|
||||
|
||||
return of.value.Interface(), nil
|
||||
}
|
||||
|
||||
// ObjMethod is a wrapper for an object method.
|
||||
// The name of the method can be invalid.
|
||||
type ObjMethod struct {
|
||||
obj *Obj
|
||||
ObjMethodMetadata
|
||||
}
|
||||
|
||||
func newObjMethod(obj *Obj, objMethodMetadata ObjMethodMetadata) *ObjMethod {
|
||||
return &ObjMethod{
|
||||
obj: obj,
|
||||
ObjMethodMetadata: objMethodMetadata,
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the method's name.
|
||||
func (om *ObjMethod) Name() string {
|
||||
return om.name
|
||||
}
|
||||
|
||||
const (
|
||||
onlyInTypes = 0
|
||||
onlyOutTypes = 1
|
||||
)
|
||||
|
||||
func (om *ObjMethod) methodTypes(kind int) []reflect.Type {
|
||||
m := reflect.ValueOf(om.obj.iface).MethodByName(om.name)
|
||||
if !m.IsValid() {
|
||||
return []reflect.Type{}
|
||||
}
|
||||
ty := m.Type()
|
||||
|
||||
// inTypes are default
|
||||
tyNum := ty.NumIn()
|
||||
tyFn := ty.In
|
||||
if kind == onlyOutTypes {
|
||||
tyNum = ty.NumOut()
|
||||
tyFn = ty.Out
|
||||
}
|
||||
|
||||
out := make([]reflect.Type, tyNum)
|
||||
for i := 0; i < tyNum; i++ {
|
||||
out[i] = tyFn(i)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// InTypes returns an slice with this method's input types.
|
||||
func (om *ObjMethod) InTypes() []reflect.Type {
|
||||
return om.methodTypes(onlyInTypes)
|
||||
}
|
||||
|
||||
// OutTypes returns an slice with this method's output types.
|
||||
func (om *ObjMethod) OutTypes() []reflect.Type {
|
||||
return om.methodTypes(onlyOutTypes)
|
||||
}
|
||||
|
||||
// IsValid returns this method's validity.
|
||||
func (om *ObjMethod) IsValid() bool {
|
||||
return om.valid
|
||||
}
|
||||
|
||||
// Call calls this method.
|
||||
// Note that in the error returning value is not the error from the method call.
|
||||
func (om *ObjMethod) Call(args ...interface{}) (*CallResult, error) {
|
||||
if !om.obj.IsValid() {
|
||||
return nil, fmt.Errorf("invalid object type %T for method %s", om.obj.iface, om.name)
|
||||
}
|
||||
if !om.IsValid() {
|
||||
return nil, fmt.Errorf("invalid method %s in %T", om.name, om.obj.iface)
|
||||
}
|
||||
in := make([]reflect.Value, len(args)+1)
|
||||
in[0] = reflect.ValueOf(om.obj.iface)
|
||||
for n := range args {
|
||||
in[n+1] = reflect.ValueOf(args[n])
|
||||
}
|
||||
out := om.method.Func.Call(in)
|
||||
res := make([]interface{}, len(out))
|
||||
for n := range out {
|
||||
res[n] = out[n].Interface()
|
||||
}
|
||||
return newCallResult(res), nil
|
||||
}
|
||||
|
||||
// CallResult is a wrapper of a method call result.
|
||||
type CallResult struct {
|
||||
Result []interface{}
|
||||
Error error
|
||||
}
|
||||
|
||||
func newCallResult(res []interface{}) *CallResult {
|
||||
cr := &CallResult{Result: res}
|
||||
if len(res) == 0 {
|
||||
return cr
|
||||
}
|
||||
errorCandidate := res[len(res)-1]
|
||||
if errorCandidate != nil {
|
||||
if err, is := errorCandidate.(error); is {
|
||||
cr.Error = err
|
||||
}
|
||||
}
|
||||
return cr
|
||||
}
|
||||
|
||||
// IsError checks if the last value is a non-nil error.
|
||||
func (cr *CallResult) IsError() bool {
|
||||
return cr.Error != nil
|
||||
}
|
||||
60
vendor/github.com/tkrajina/go-reflector/reflector/utils.go
generated
vendored
Normal file
60
vendor/github.com/tkrajina/go-reflector/reflector/utils.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package reflector
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ParseTag parses a golang struct tag into a map.
|
||||
func ParseTag(tag string) (map[string]string, error) {
|
||||
res := map[string]string{}
|
||||
|
||||
// This code is copied/modified from: reflect/type.go:
|
||||
for tag != "" {
|
||||
// Skip leading space.
|
||||
i := 0
|
||||
for i < len(tag) && tag[i] == ' ' {
|
||||
i++
|
||||
}
|
||||
tag = tag[i:]
|
||||
if tag == "" {
|
||||
break
|
||||
}
|
||||
|
||||
// Scan to colon. A space, a quote or a control character is a syntax error.
|
||||
// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
|
||||
// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
|
||||
// as it is simpler to inspect the tag's bytes than the tag's runes.
|
||||
i = 0
|
||||
for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
|
||||
i++
|
||||
}
|
||||
if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
|
||||
break
|
||||
}
|
||||
name := string(tag[:i])
|
||||
tag = tag[i+1:]
|
||||
|
||||
// Scan quoted string to find value.
|
||||
i = 1
|
||||
for i < len(tag) && tag[i] != '"' {
|
||||
if tag[i] == '\\' {
|
||||
i++
|
||||
}
|
||||
i++
|
||||
}
|
||||
if i >= len(tag) {
|
||||
break
|
||||
}
|
||||
qvalue := string(tag[:i+1])
|
||||
tag = tag[i+1:]
|
||||
|
||||
value, err := strconv.Unquote(qvalue)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot unquote tag %s in %s: %s", name, tag, err.Error())
|
||||
}
|
||||
res[name] = value
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
10
vendor/github.com/tkrajina/go-reflector/reflector/walk.go
generated
vendored
Normal file
10
vendor/github.com/tkrajina/go-reflector/reflector/walk.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package reflector
|
||||
|
||||
import "reflect"
|
||||
|
||||
func Walk(i interface{}, f func(i2 interface{})) {
|
||||
ty := reflect.TypeOf(i)
|
||||
if ty.Kind() == reflect.Ptr {
|
||||
ty = ty.Elem()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user