Skip to content
Snippets Groups Projects
Verified Commit 821a4470 authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

documentation/

parent 34f88e9a
Branches
Tags
No related merge requests found
Showing
with 3 additions and 1084 deletions
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package diff
import "reflect"
func (d *Differ) diffString(path []string, a, b reflect.Value, parent interface{}) error {
if a.Kind() == reflect.Invalid {
d.cl.Add(CREATE, path, nil, exportInterface(b))
return nil
}
if b.Kind() == reflect.Invalid {
d.cl.Add(DELETE, path, exportInterface(a), nil)
return nil
}
if a.Kind() != b.Kind() {
return ErrTypeMismatch
}
if a.String() != b.String() {
if a.CanInterface() {
// If a and/or b is of a type that is an alias for String, store that type in changelog
d.cl.Add(UPDATE, path, exportInterface(a), exportInterface(b), parent)
} else {
d.cl.Add(UPDATE, path, a.String(), b.String(), parent)
}
}
return nil
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package diff
import (
"reflect"
"time"
)
func (d *Differ) diffStruct(path []string, a, b reflect.Value, parent interface{}) error {
if AreType(a, b, reflect.TypeOf(time.Time{})) {
return d.diffTime(path, a, b)
}
if a.Kind() == reflect.Invalid {
if d.DisableStructValues {
d.cl.Add(CREATE, path, nil, exportInterface(b))
return nil
}
return d.structValues(CREATE, path, b)
}
if b.Kind() == reflect.Invalid {
if d.DisableStructValues {
d.cl.Add(DELETE, path, exportInterface(a), nil)
return nil
}
return d.structValues(DELETE, path, a)
}
for i := 0; i < a.NumField(); i++ {
field := a.Type().Field(i)
tname := tagName(d.TagName, field)
if tname == "-" || hasTagOption(d.TagName, field, "immutable") {
continue
}
if tname == "" {
tname = field.Name
}
af := a.Field(i)
bf := b.FieldByName(field.Name)
fpath := path
if !(d.FlattenEmbeddedStructs && field.Anonymous) {
fpath = copyAppend(fpath, tname)
}
if d.Filter != nil && !d.Filter(fpath, a.Type(), field) {
continue
}
// skip private fields
if !a.CanInterface() {
continue
}
err := d.diff(fpath, af, bf, exportInterface(a))
if err != nil {
return err
}
}
return nil
}
func (d *Differ) structValues(t string, path []string, a reflect.Value) error {
var nd Differ
nd.Filter = d.Filter
nd.customValueDiffers = d.customValueDiffers
if t != CREATE && t != DELETE {
return ErrInvalidChangeType
}
if a.Kind() == reflect.Ptr {
a = reflect.Indirect(a)
}
if a.Kind() != reflect.Struct {
return ErrTypeMismatch
}
x := reflect.New(a.Type()).Elem()
for i := 0; i < a.NumField(); i++ {
field := a.Type().Field(i)
tname := tagName(d.TagName, field)
if tname == "-" {
continue
}
if tname == "" {
tname = field.Name
}
af := a.Field(i)
xf := x.FieldByName(field.Name)
fpath := copyAppend(path, tname)
if nd.Filter != nil && !nd.Filter(fpath, a.Type(), field) {
continue
}
err := nd.diff(fpath, xf, af, exportInterface(a))
if err != nil {
return err
}
}
for i := 0; i < len(nd.cl); i++ {
(d.cl) = append(d.cl, swapChange(t, nd.cl[i]))
}
return nil
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package diff
import (
"reflect"
"time"
)
func (d *Differ) diffTime(path []string, a, b reflect.Value) error {
if a.Kind() == reflect.Invalid {
d.cl.Add(CREATE, path, nil, exportInterface(b))
return nil
}
if b.Kind() == reflect.Invalid {
d.cl.Add(DELETE, path, exportInterface(a), nil)
return nil
}
if a.Kind() != b.Kind() {
return ErrTypeMismatch
}
// Marshal and unmarshal time type will lose accuracy. Using unix nano to compare time type.
au := exportInterface(a).(time.Time).UnixNano()
bu := exportInterface(b).(time.Time).UnixNano()
if au != bu {
d.cl.Add(UPDATE, path, exportInterface(a), exportInterface(b))
}
return nil
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package diff
import (
"reflect"
)
func (d *Differ) diffUint(path []string, a, b reflect.Value, parent interface{}) error {
if a.Kind() == reflect.Invalid {
d.cl.Add(CREATE, path, nil, exportInterface(b))
return nil
}
if b.Kind() == reflect.Invalid {
d.cl.Add(DELETE, path, exportInterface(a), nil)
return nil
}
if a.Kind() != b.Kind() {
return ErrTypeMismatch
}
if a.Uint() != b.Uint() {
if a.CanInterface() {
d.cl.Add(UPDATE, path, exportInterface(a), exportInterface(b), parent)
} else {
d.cl.Add(UPDATE, path, a.Uint(), b.Uint(), parent)
}
}
return nil
}
package diff
import (
"fmt"
)
var (
// ErrTypeMismatch Compared types do not match
ErrTypeMismatch = NewError("types do not match")
// ErrInvalidChangeType The specified change values are not unsupported
ErrInvalidChangeType = NewError("change type must be one of 'create' or 'delete'")
)
//our own version of an error, which can wrap others
type DiffError struct {
count int
message string
next error
}
//Unwrap implement 1.13 unwrap feature for compatibility
func (s *DiffError) Unwrap() error {
return s.next
}
//Error implements the error interface
func (s DiffError) Error() string {
cause := ""
if s.next != nil {
cause = s.next.Error()
}
return fmt.Sprintf(" %s (cause count %d)\n%s", s.message, s.count, cause)
}
//AppendCause appends a new cause error to the chain
func (s *DiffError) WithCause(err error) *DiffError {
if s != nil && err != nil {
s.count++
if s.next != nil {
if v, ok := err.(DiffError); ok {
s.next = v.WithCause(s.next)
} else if v, ok := err.(*DiffError); ok {
s.next = v.WithCause(s.next)
} else {
v = &DiffError{
message: "auto wrapped error",
next: err,
}
s.next = v.WithCause(s.next)
}
} else {
s.next = err
}
}
return s
}
//NewErrorf just give me a plain error with formatting
func NewErrorf(format string, messages ...interface{}) *DiffError {
return &DiffError{
message: fmt.Sprintf(format, messages...),
}
}
//NewError just give me a plain error
func NewError(message string, causes ...error) *DiffError {
s := &DiffError{
message: message,
}
for _, cause := range causes {
s.WithCause(cause) // nolint: errcheck
}
return s
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package diff
import "regexp"
func pathmatch(filter, path []string) bool {
for i, f := range filter {
if len(path) < i+1 {
return false
}
matched, _ := regexp.MatchString(f, path[i])
if !matched {
return false
}
}
return true
}
package diff
// ConvertTypes enables values that are convertible to the target type to be converted when patching
func ConvertCompatibleTypes() func(d *Differ) error {
return func(d *Differ) error {
d.ConvertCompatibleTypes = true
return nil
}
}
// FlattenEmbeddedStructs determines whether fields of embedded structs should behave as if they are directly under the parent
func FlattenEmbeddedStructs() func(d *Differ) error {
return func(d *Differ) error {
d.FlattenEmbeddedStructs = true
return nil
}
}
// SliceOrdering determines whether the ordering of items in a slice results in a change
func SliceOrdering(enabled bool) func(d *Differ) error {
return func(d *Differ) error {
d.SliceOrdering = enabled
return nil
}
}
// TagName sets the tag name to use when getting field names and options
func TagName(tag string) func(d *Differ) error {
return func(d *Differ) error {
d.TagName = tag
return nil
}
}
// DisableStructValues disables populating a separate change for each item in a struct,
// where the struct is being compared to a nil value
func DisableStructValues() func(d *Differ) error {
return func(d *Differ) error {
d.DisableStructValues = true
return nil
}
}
// CustomValueDiffers allows you to register custom differs for specific types
func CustomValueDiffers(vd ...ValueDiffer) func(d *Differ) error {
return func(d *Differ) error {
d.customValueDiffers = append(d.customValueDiffers, vd...)
for k := range d.customValueDiffers {
d.customValueDiffers[k].InsertParentDiffer(d.diff)
}
return nil
}
}
// AllowTypeMismatch changed behaviour to report value as "updated" when its type has changed instead of error
func AllowTypeMismatch(enabled bool) func(d *Differ) error {
return func(d *Differ) error {
d.AllowTypeMismatch = enabled
return nil
}
}
//StructMapKeySupport - Changelog paths do not provided structured object values for maps that contain complex
//keys (such as other structs). You must enable this support via an option and it then uses msgpack to encode
//path elements that are structs. If you don't have this on, and try to patch, your apply will fail for that
//element.
func StructMapKeySupport() func(d *Differ) error {
return func(d *Differ) error {
d.StructMapKeys = true
return nil
}
}
//DiscardComplexOrigin - by default, we are now keeping the complex struct associated with a create entry.
//This allows us to fix the merge to new object issue of not having enough change log details when allocating
//new objects. This however is a trade off of memory size and complexity vs correctness which is often only
//necessary when embedding structs in slices and arrays. It memory constrained environments, it may be desirable
//to turn this feature off however from a computational perspective, keeping the complex origin is actually quite
//cheap so, make sure you're extremely clear on the pitfalls of turning this off prior to doing so.
func DiscardComplexOrigin() func(d *Differ) error {
return func(d *Differ) error {
d.DiscardParent = true
return nil
}
}
// Filter allows you to determine which fields the differ descends into
func Filter(f FilterFunc) func(d *Differ) error {
return func(d *Differ) error {
d.Filter = f
return nil
}
}
package diff
import (
"reflect"
)
/**
This is a method of applying a changelog to a value or struct. change logs
should be generated with Diff and never manually created. This DOES NOT
apply fuzzy logic as would be in the case of a text patch. It does however
have a few additional features added to our struct tags.
1) create. This tag on a struct field indicates that the patch should
create the value if it's not there. I.e. if it's nil. This works for
pointers, maps and slices.
2) omitunequal. Generally, you don't want to do this, the expectation is
that if an item isn't there, you want to add it. For example, if your
diff shows an array element at index 6 is a string 'hello' but your target
only has 3 elements, none of them matching... you want to add 'hello'
regardless of the index. (think in a distributed context, another process
may have deleted more than one entry and 'hello' may no longer be in that
indexed spot.
So given this scenario, the default behavior is to scan for the previous
value and replace it anyway, or simply append the new value. For maps the
default behavior is to simply add the key if it doesn't match.
However, if you don't like the default behavior, and add the omitunequal
tag to your struct, patch will *NOT* update an array or map with the key
or array value unless they key or index contains a 'match' to the
previous value. In which case it will skip over that change.
Patch is implemented as a best effort algorithm. That means you can receive
multiple nested errors and still successfully have a modified target. This
may even be acceptable depending on your use case. So keep in mind, just
because err != nil *DOESN'T* mean that the patch didn't accomplish your goal
in setting those changes that are actually available. For example, you may
diff two structs of the same type, then attempt to apply to an entirely
different struct that is similar in constitution (think interface here) and
you may in fact get all of the values populated you wished to anyway.
*/
//Not strictly necessary but might be nice in some cases
//go:generate stringer -type=PatchFlags
type PatchFlags uint32
const (
OptionCreate PatchFlags = 1 << iota
OptionNoCreate
OptionOmitUnequal
OptionImmutable
FlagInvalidTarget
FlagApplied
FlagFailed
FlagCreated
FlagIgnored
FlagDeleted
FlagUpdated
FlagParentSetApplied
FlagParentSetFailed
)
//PatchLogEntry defines how a DiffLog entry was applied
type PatchLogEntry struct {
Path []string `json:"path"`
From interface{} `json:"from"`
To interface{} `json:"to"`
Flags PatchFlags `json:"flags"`
Errors error `json:"errors"`
}
type PatchLog []PatchLogEntry
//HasFlag - convenience function for users
func (p PatchLogEntry) HasFlag(flag PatchFlags) bool {
return (p.Flags & flag) != 0
}
//Applied - returns true if all change log entries were actually
// applied, regardless of if any errors were encountered
func (p PatchLog) Applied() bool {
if p.HasErrors() {
for _, ple := range p {
if !ple.HasFlag(FlagApplied) {
return false
}
}
}
return true
}
//HasErrors - indicates if a patch log contains any errors
func (p PatchLog) HasErrors() (ret bool) {
for _, ple := range p {
if ple.Errors != nil {
ret = true
}
}
return
}
//ErrorCount -- counts the number of errors encountered while patching
func (p PatchLog) ErrorCount() (ret uint) {
for _, ple := range p {
if ple.Errors != nil {
ret++
}
}
return
}
func Merge(original interface{}, changed interface{}, target interface{}) (PatchLog, error) {
d, _ := NewDiffer()
return d.Merge(original, changed, target)
}
// Merge is a convenience function that diffs, the original and changed items
// and merges said changes with target all in one call.
func (d *Differ) Merge(original interface{}, changed interface{}, target interface{}) (PatchLog, error) {
StructMapKeySupport()(d) // nolint: errcheck
if cl, err := d.Diff(original, changed); err == nil {
return Patch(cl, target), nil
} else {
return nil, err
}
}
func Patch(cl Changelog, target interface{}) (ret PatchLog) {
d, _ := NewDiffer()
return d.Patch(cl, target)
}
//Patch... the missing feature.
func (d *Differ) Patch(cl Changelog, target interface{}) (ret PatchLog) {
for _, c := range cl {
ret = append(ret, NewPatchLogEntry(NewChangeValue(d, c, target)))
}
return ret
}
//NewPatchLogEntry converts our complicated reflection based struct to
//a simpler format for the consumer
func NewPatchLogEntry(cv *ChangeValue) PatchLogEntry {
return PatchLogEntry{
Path: cv.change.Path,
From: cv.change.From,
To: cv.change.To,
Flags: cv.flags,
Errors: cv.err,
}
}
//NewChangeValue idiomatic constructor (also invokes render)
func NewChangeValue(d *Differ, c Change, target interface{}) (ret *ChangeValue) {
val := reflect.ValueOf(target)
ret = &ChangeValue{
target: &val,
change: &c,
}
d.renderChangeTarget(ret)
return
}
//renderChangeValue applies 'path' in change to target. nil check is foregone
// here as we control usage
func (d *Differ) renderChangeTarget(c *ChangeValue) {
//This particular change element may potentially have the immutable flag
if c.HasFlag(OptionImmutable) {
c.AddError(NewError("Option immutable set, cannot apply change"))
return
} //the we always set a failure, and only unset if we successfully render the element
c.SetFlag(FlagInvalidTarget)
//substitute and solve for t (path)
switch c.target.Kind() {
//path element that is a map
case reflect.Map:
//map elements are 'copies' and immutable so if we set the new value to the
//map prior to editing the value, it will fail to stick. To fix this, we
//defer the safe until the stack unwinds
m, k, v := d.renderMap(c)
defer d.updateMapEntry(c, m, k, v)
//path element that is a slice
case reflect.Slice:
d.renderSlice(c)
//walking a path means dealing with real elements
case reflect.Interface, reflect.Ptr:
if c.target.IsNil() {
n := reflect.New(c.target.Type().Elem())
c.target.Set(n)
c.target = &n
d.renderChangeTarget(c)
return
}
el := c.target.Elem()
c.target = &el
c.ClearFlag(FlagInvalidTarget)
//path element that is a struct
case reflect.Struct:
d.patchStruct(c)
}
//if for some reason, rendering this element fails, c will no longer be valid
//we are best effort though, so we keep on trucking
if !c.IsValid() {
c.AddError(NewErrorf("Unable to access path position %d. Target field is invalid", c.pos))
}
//we've taken care of this path element, are there any more? if so, process
//else, let's take some action
if c.pos < len(c.change.Path) && !c.HasFlag(FlagInvalidTarget) {
d.renderChangeTarget(c)
} else { //we're at the end of the line... set the Value
switch c.change.Type {
case DELETE:
switch c.ParentKind() {
case reflect.Slice:
d.deleteSliceEntry(c)
case reflect.Struct:
d.deleteStructEntry(c)
default:
c.SetFlag(FlagIgnored)
}
case UPDATE, CREATE:
// this is generic because... we only deal in primitives here. AND
// the diff format To field already contains the correct type.
c.Set(reflect.ValueOf(c.change.To), d.ConvertCompatibleTypes)
c.SetFlag(FlagUpdated)
}
}
}
package diff
import (
"errors"
"reflect"
"github.com/vmihailenco/msgpack/v5"
)
// renderMap - handle map rendering for patch
func (d *Differ) renderMap(c *ChangeValue) (m, k, v *reflect.Value) {
//we must tease out the type of the key, we use the msgpack from diff to recreate the key
kt := c.target.Type().Key()
field := reflect.New(kt)
if d.StructMapKeys {
if err := msgpack.Unmarshal([]byte(c.change.Path[c.pos]), field.Interface()); err != nil {
c.SetFlag(FlagIgnored)
c.AddError(NewError("Unable to unmarshal path element to target type for key in map", err))
return
}
c.key = field.Elem()
} else {
c.key = reflect.ValueOf(c.change.Path[c.pos])
}
if c.target.IsNil() && c.target.IsValid() {
c.target.Set(reflect.MakeMap(c.target.Type()))
}
// we need to check that MapIndex does not panic here
// when the key type is not a string
defer func() {
if err := recover(); err != nil {
switch x := err.(type) {
case error:
c.AddError(NewError("Unable to unmarshal path element to target type for key in map", x))
case string:
c.AddError(NewError("Unable to unmarshal path element to target type for key in map", errors.New(x)))
}
c.SetFlag(FlagIgnored)
}
}()
x := c.target.MapIndex(c.key)
if !x.IsValid() && c.change.Type != DELETE && !c.HasFlag(OptionNoCreate) {
x = c.NewElement()
}
if x.IsValid() { //Map elements come out as read only so we must convert
nv := reflect.New(x.Type()).Elem()
nv.Set(x)
x = nv
}
if x.IsValid() && !reflect.DeepEqual(c.change.From, x.Interface()) &&
c.HasFlag(OptionOmitUnequal) {
c.SetFlag(FlagIgnored)
c.AddError(NewError("target change doesn't match original"))
return
}
mp := *c.target //these may change out from underneath us as we recurse
key := c.key //so we make copies and pass back pointers to them
c.swap(&x)
return &mp, &key, &x
}
// updateMapEntry - deletes are special, they are handled differently based on options
//
// container type etc. We have to have special handling for each
// type. Set values are more generic even if they must be instanced
func (d *Differ) updateMapEntry(c *ChangeValue, m, k, v *reflect.Value) {
if k == nil || m == nil {
return
}
switch c.change.Type {
case DELETE:
if c.HasFlag(FlagDeleted) {
return
}
if !m.CanSet() && v.IsValid() && v.Kind() == reflect.Struct {
for x := 0; x < v.NumField(); x++ {
if !v.Field(x).IsZero() {
m.SetMapIndex(*k, *v)
return
}
} //if all the fields are zero, remove from map
}
m.SetMapIndex(*k, reflect.Value{})
c.SetFlag(FlagDeleted)
case CREATE:
m.SetMapIndex(*k, *v)
c.SetFlag(FlagCreated)
case UPDATE:
m.SetMapIndex(*k, *v)
c.SetFlag(FlagUpdated)
}
}
package diff
/**
Types are being split out to more closely follow the library structure already
in place. Keeps the file simpler as well.
*/
import (
"reflect"
"strconv"
)
//renderSlice - handle slice rendering for patch
func (d *Differ) renderSlice(c *ChangeValue) {
var err error
field := c.change.Path[c.pos]
//field better be an index of the slice
if c.index, err = strconv.Atoi(field); err != nil {
//if struct element is has identifier, use it instead
if identifier(d.TagName, reflect.Zero(c.target.Type().Elem())) != nil {
for c.index = 0; c.index < c.Len(); c.index++ {
if identifier(d.TagName, c.Index(c.index)) == field {
break
}
}
} else {
c.AddError(NewErrorf("invalid index in path. %s is not a number", field).
WithCause(err))
}
}
var x reflect.Value
if c.Len() > c.index {
x = c.Index(c.index)
} else if c.change.Type == CREATE && !c.HasFlag(OptionNoCreate) {
x = c.NewArrayElement()
}
if !x.IsValid() {
if !c.HasFlag(OptionOmitUnequal) {
c.AddError(NewErrorf("Value index %d is invalid", c.index).
WithCause(NewError("scanning for Value index")))
for c.index = 0; c.index < c.Len(); c.index++ {
y := c.Index(c.index)
if reflect.DeepEqual(y, c.change.From) {
c.AddError(NewErrorf("Value changed index to %d", c.index))
x = y
break
}
}
}
}
if !x.IsValid() && c.change.Type != DELETE && !c.HasFlag(OptionNoCreate) {
x = c.NewArrayElement()
}
if !x.IsValid() && c.change.Type == DELETE {
c.index = -1 //no existing element to delete so don't bother
}
c.swap(&x) //containers must swap out the parent Value
}
//deleteSliceEntry - deletes are special, they are handled differently based on options
// container type etc. We have to have special handling for each
// type. Set values are more generic even if they must be instanced
func (d *Differ) deleteSliceEntry(c *ChangeValue) {
//for a slice with only one element
if c.ParentLen() == 1 && c.index != -1 {
c.ParentSet(reflect.MakeSlice(c.parent.Type(), 0, 0), d.ConvertCompatibleTypes)
c.SetFlag(FlagDeleted)
//for a slice with multiple elements
} else if c.index != -1 { //this is an array delete the element from the parent
c.ParentIndex(c.index).Set(c.ParentIndex(c.ParentLen() - 1))
c.ParentSet(c.parent.Slice(0, c.ParentLen()-1), d.ConvertCompatibleTypes)
c.SetFlag(FlagDeleted)
//for other slice elements, we ignore
} else {
c.SetFlag(FlagIgnored)
}
}
package diff
import "reflect"
/**
Types are being split out to more closely follow the library structure already
in place. Keeps the file simpler as well.
*/
type structField struct {
f reflect.StructField
v reflect.Value
}
func getNestedFields(v reflect.Value, flattenEmbedded bool) []structField {
fields := make([]structField, 0)
for i := 0; i < v.NumField(); i++ {
f := v.Type().Field(i)
fv := v.Field(i)
if fv.Kind() == reflect.Struct && f.Anonymous && flattenEmbedded {
fields = append(fields, getNestedFields(fv, flattenEmbedded)...)
} else {
fields = append(fields, structField{f, fv})
}
}
return fields
}
//patchStruct - handles the rendering of a struct field
func (d *Differ) patchStruct(c *ChangeValue) {
field := c.change.Path[c.pos]
structFields := getNestedFields(*c.target, d.FlattenEmbeddedStructs)
for _, structField := range structFields {
f := structField.f
tname := tagName(d.TagName, f)
if tname == "-" {
continue
}
if tname == field || f.Name == field {
x := structField.v
if hasTagOption(d.TagName, f, "nocreate") {
c.SetFlag(OptionNoCreate)
}
if hasTagOption(d.TagName, f, "omitunequal") {
c.SetFlag(OptionOmitUnequal)
}
if hasTagOption(d.TagName, f, "immutable") {
c.SetFlag(OptionImmutable)
}
c.swap(&x)
break
}
}
}
//track and zero out struct members
func (d *Differ) deleteStructEntry(c *ChangeValue) {
//deleting a struct value set's it to the 'basic' type
c.Set(reflect.Zero(c.target.Type()), d.ConvertCompatibleTypes)
}
Copyright (c) 2013 The github.com/vmihailenco/msgpack Authors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Copyright (c) 2019 The github.com/vmihailenco/tagparser Authors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The MIT License (MIT) MIT License
go-toml v2 Copyright (c) 2021 Ivan Shalganov
Copyright (c) 2021 - 2023 Thomas Pelletier
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
......
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This project is covered by two different licenses: MIT and Apache.
#### MIT License ####
The following files were ported to Go from C files of libyaml, and thus
are still covered by their original MIT license, with the additional
copyright staring in 2011 when the project was ported over:
apic.go emitterc.go parserc.go readerc.go scannerc.go
writerc.go yamlh.go yamlprivateh.go
Copyright (c) 2006-2010 Kirill Simonov
Copyright (c) 2006-2011 Kirill Simonov
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
### Apache License ###
All the remaining project files are covered by the Apache license:
Copyright (c) 2011-2019 Canonical Ltd
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.
Copyright 2011-2016 Canonical Ltd.
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.
...@@ -9,10 +9,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ ...@@ -9,10 +9,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/volker-schukai/tokenizer v1.0.0 h1:wF4haFoCodq7lgAk8c+th/DZmpFpL2WVD8wDzAGU1mA= github.com/volker-schukai/tokenizer v1.0.0 h1:wF4haFoCodq7lgAk8c+th/DZmpFpL2WVD8wDzAGU1mA=
github.com/volker-schukai/tokenizer v1.0.0/go.mod h1:LPw7lLIxUnZgeg96818N7IvwLE1x8ya31J/Aa0aCq9M= github.com/volker-schukai/tokenizer v1.0.0/go.mod h1:LPw7lLIxUnZgeg96818N7IvwLE1x8ya31J/Aa0aCq9M=
gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.9.2 h1:cbrnohA6SyqH6NGvYDyIFcrh3lH4DcwLcGUbmaSKWlY= gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.9.2 h1:cbrnohA6SyqH6NGvYDyIFcrh3lH4DcwLcGUbmaSKWlY=
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment