mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-06-04 14:15:15 -04:00
switch to go-viper/mapstructure
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
4
go.mod
4
go.mod
@@ -35,6 +35,7 @@ require (
|
||||
github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry v1.2.0
|
||||
github.com/go-playground/validator/v10 v10.30.2
|
||||
github.com/go-resty/resty/v2 v2.17.2
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/golang/protobuf v1.5.4
|
||||
github.com/google/go-cmp v0.7.0
|
||||
@@ -52,7 +53,6 @@ require (
|
||||
github.com/leonelquinteros/gotext v1.7.3-0.20260422134830-b012b4ccae69
|
||||
github.com/libregraph/idm v0.5.0
|
||||
github.com/libregraph/lico v0.66.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/mna/pigeon v1.3.0
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/nats-io/nats-server/v2 v2.14.0
|
||||
@@ -223,7 +223,6 @@ require (
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/go-test/deep v1.1.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
@@ -289,6 +288,7 @@ require (
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/minio-go/v7 v7.1.0 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/go-archive v0.2.0 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -466,8 +466,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
|
||||
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package revaconfig
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/go-viper/mapstructure/v2"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/services/app-registry/pkg/config"
|
||||
)
|
||||
|
||||
3
vendor/github.com/go-viper/mapstructure/v2/.editorconfig
generated
vendored
3
vendor/github.com/go-viper/mapstructure/v2/.editorconfig
generated
vendored
@@ -19,3 +19,6 @@ indent_size = 2
|
||||
|
||||
[.golangci.yaml]
|
||||
indent_size = 2
|
||||
|
||||
[devenv.yaml]
|
||||
indent_size = 2
|
||||
|
||||
10
vendor/github.com/go-viper/mapstructure/v2/.gitignore
generated
vendored
10
vendor/github.com/go-viper/mapstructure/v2/.gitignore
generated
vendored
@@ -1,6 +1,10 @@
|
||||
/.devenv/
|
||||
/.direnv/
|
||||
/.pre-commit-config.yaml
|
||||
/bin/
|
||||
/build/
|
||||
/var/
|
||||
|
||||
# Devenv
|
||||
.devenv*
|
||||
devenv.local.nix
|
||||
devenv.local.yaml
|
||||
.direnv
|
||||
.pre-commit-config.yaml
|
||||
|
||||
294
vendor/github.com/go-viper/mapstructure/v2/flake.lock
generated
vendored
294
vendor/github.com/go-viper/mapstructure/v2/flake.lock
generated
vendored
@@ -1,294 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"cachix": {
|
||||
"inputs": {
|
||||
"devenv": [
|
||||
"devenv"
|
||||
],
|
||||
"flake-compat": [
|
||||
"devenv"
|
||||
],
|
||||
"git-hooks": [
|
||||
"devenv"
|
||||
],
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742042642,
|
||||
"narHash": "sha256-D0gP8srrX0qj+wNYNPdtVJsQuFzIng3q43thnHXQ/es=",
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"rev": "a624d3eaf4b1d225f918de8543ed739f2f574203",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "latest",
|
||||
"repo": "cachix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv": {
|
||||
"inputs": {
|
||||
"cachix": "cachix",
|
||||
"flake-compat": "flake-compat",
|
||||
"git-hooks": "git-hooks",
|
||||
"nix": "nix",
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1744876578,
|
||||
"narHash": "sha256-8MTBj2REB8t29sIBLpxbR0+AEGJ7f+RkzZPAGsFd40c=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "7ff7c351bba20d0615be25ecdcbcf79b57b85fe1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1733328505,
|
||||
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"devenv",
|
||||
"nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712014858,
|
||||
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts_2": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743550720,
|
||||
"narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "c621e8422220273271f52058f618c94e405bb0f5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"git-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv"
|
||||
],
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742649964,
|
||||
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"git-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"libgit2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1697646580,
|
||||
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv"
|
||||
],
|
||||
"flake-parts": "flake-parts",
|
||||
"libgit2": "libgit2",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nixpkgs-23-11": [
|
||||
"devenv"
|
||||
],
|
||||
"nixpkgs-regression": [
|
||||
"devenv"
|
||||
],
|
||||
"pre-commit-hooks": [
|
||||
"devenv"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1741798497,
|
||||
"narHash": "sha256-E3j+3MoY8Y96mG1dUIiLFm2tZmNbRvSiyN7CrSKuAVg=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "f3f44b2baaf6c4c6e179de8cbb1cc6db031083cd",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "devenv-2.24",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1733212471,
|
||||
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1743296961,
|
||||
"narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1717432640,
|
||||
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1733477122,
|
||||
"narHash": "sha256-qamMCz5mNpQmgBwc8SB5tVMlD5sbwVIToVZtSxMph9s=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"rev": "7bd9e84d0452f6d2e63b6e6da29fe73fac951857",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "rolling",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_4": {
|
||||
"locked": {
|
||||
"lastModified": 1744536153,
|
||||
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"flake-parts": "flake-parts_2",
|
||||
"nixpkgs": "nixpkgs_4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
46
vendor/github.com/go-viper/mapstructure/v2/flake.nix
generated
vendored
46
vendor/github.com/go-viper/mapstructure/v2/flake.nix
generated
vendored
@@ -1,46 +0,0 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
devenv.url = "github:cachix/devenv";
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs@{ flake-parts, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
imports = [
|
||||
inputs.devenv.flakeModule
|
||||
];
|
||||
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
|
||||
perSystem =
|
||||
{ pkgs, ... }:
|
||||
rec {
|
||||
devenv.shells = {
|
||||
default = {
|
||||
languages = {
|
||||
go.enable = true;
|
||||
};
|
||||
|
||||
pre-commit.hooks = {
|
||||
nixpkgs-fmt.enable = true;
|
||||
};
|
||||
|
||||
packages = with pkgs; [
|
||||
golangci-lint
|
||||
];
|
||||
|
||||
# https://github.com/cachix/devenv/issues/528#issuecomment-1556108767
|
||||
containers = pkgs.lib.mkForce { };
|
||||
};
|
||||
|
||||
ci = devenv.shells.default;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
332
vendor/github.com/go-viper/mapstructure/v2/mapstructure.go
generated
vendored
332
vendor/github.com/go-viper/mapstructure/v2/mapstructure.go
generated
vendored
@@ -173,6 +173,25 @@
|
||||
// Public: "I made it through!"
|
||||
// }
|
||||
//
|
||||
// # Custom Decoding with Unmarshaler
|
||||
//
|
||||
// Types can implement the Unmarshaler interface to control their own decoding. The interface
|
||||
// behaves similarly to how UnmarshalJSON does in the standard library. It can be used as an
|
||||
// alternative or companion to a DecodeHook.
|
||||
//
|
||||
// type TrimmedString string
|
||||
//
|
||||
// func (t *TrimmedString) UnmarshalMapstructure(input any) error {
|
||||
// str, ok := input.(string)
|
||||
// if !ok {
|
||||
// return fmt.Errorf("expected string, got %T", input)
|
||||
// }
|
||||
// *t = TrimmedString(strings.TrimSpace(str))
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// See the Unmarshaler interface documentation for more details.
|
||||
//
|
||||
// # Other Configuration
|
||||
//
|
||||
// mapstructure is highly configurable. See the DecoderConfig struct
|
||||
@@ -218,6 +237,17 @@ type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, any) (any, error)
|
||||
// values.
|
||||
type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (any, error)
|
||||
|
||||
// Unmarshaler is the interface implemented by types that can unmarshal
|
||||
// themselves. UnmarshalMapstructure receives the input data (potentially
|
||||
// transformed by DecodeHook) and should populate the receiver with the
|
||||
// decoded values.
|
||||
//
|
||||
// The Unmarshaler interface takes precedence over the default decoding
|
||||
// logic for any type (structs, slices, maps, primitives, etc.).
|
||||
type Unmarshaler interface {
|
||||
UnmarshalMapstructure(any) error
|
||||
}
|
||||
|
||||
// DecoderConfig is the configuration that is used to create a new decoder
|
||||
// and allows customization of various aspects of decoding.
|
||||
type DecoderConfig struct {
|
||||
@@ -281,6 +311,13 @@ type DecoderConfig struct {
|
||||
// }
|
||||
Squash bool
|
||||
|
||||
// Deep will map structures in slices instead of copying them
|
||||
//
|
||||
// type Parent struct {
|
||||
// Children []Child `mapstructure:",deep"`
|
||||
// }
|
||||
Deep bool
|
||||
|
||||
// Metadata is the struct that will contain extra metadata about
|
||||
// the decoding. If this is nil, then no metadata will be tracked.
|
||||
Metadata *Metadata
|
||||
@@ -290,9 +327,15 @@ type DecoderConfig struct {
|
||||
Result any
|
||||
|
||||
// The tag name that mapstructure reads for field names. This
|
||||
// defaults to "mapstructure"
|
||||
// defaults to "mapstructure". Multiple tag names can be specified
|
||||
// as a comma-separated list (e.g., "yaml,json"), and the first
|
||||
// matching non-empty tag will be used.
|
||||
TagName string
|
||||
|
||||
// RootName specifies the name to use for the root element in error messages. For example:
|
||||
// '<rootName>' has unset fields: <fieldName>
|
||||
RootName string
|
||||
|
||||
// The option of the value in the tag that indicates a field should
|
||||
// be squashed. This defaults to "squash".
|
||||
SquashTagOption string
|
||||
@@ -304,11 +347,34 @@ type DecoderConfig struct {
|
||||
// MatchName is the function used to match the map key to the struct
|
||||
// field name or tag. Defaults to `strings.EqualFold`. This can be used
|
||||
// to implement case-sensitive tag values, support snake casing, etc.
|
||||
//
|
||||
// MatchName is used as a fallback comparison when the direct key lookup fails.
|
||||
// See also MapFieldName for transforming field names before lookup.
|
||||
MatchName func(mapKey, fieldName string) bool
|
||||
|
||||
// DecodeNil, if set to true, will cause the DecodeHook (if present) to run
|
||||
// even if the input is nil. This can be used to provide default values.
|
||||
DecodeNil bool
|
||||
|
||||
// MapFieldName is the function used to convert the struct field name to the map's key name.
|
||||
//
|
||||
// This is useful for automatically converting between naming conventions without
|
||||
// explicitly tagging each field. For example, to convert Go's PascalCase field names
|
||||
// to snake_case map keys:
|
||||
//
|
||||
// MapFieldName: func(s string) string {
|
||||
// return strcase.ToSnake(s)
|
||||
// }
|
||||
//
|
||||
// When decoding from a map to a struct, the transformed field name is used for
|
||||
// the initial lookup. If not found, MatchName is used as a fallback comparison.
|
||||
// Explicit struct tags always take precedence over MapFieldName.
|
||||
MapFieldName func(string) string
|
||||
|
||||
// DisableUnmarshaler, if set to true, disables the use of the Unmarshaler
|
||||
// interface. Types implementing Unmarshaler will be decoded using the
|
||||
// standard struct decoding logic instead.
|
||||
DisableUnmarshaler bool
|
||||
}
|
||||
|
||||
// A Decoder takes a raw interface value and turns it into structured
|
||||
@@ -445,6 +511,12 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
|
||||
config.MatchName = strings.EqualFold
|
||||
}
|
||||
|
||||
if config.MapFieldName == nil {
|
||||
config.MapFieldName = func(s string) string {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
result := &Decoder{
|
||||
config: config,
|
||||
}
|
||||
@@ -458,7 +530,7 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
|
||||
// Decode decodes the given raw interface to the target pointer specified
|
||||
// by the configuration.
|
||||
func (d *Decoder) Decode(input any) error {
|
||||
err := d.decode("", input, reflect.ValueOf(d.config.Result).Elem())
|
||||
err := d.decode(d.config.RootName, input, reflect.ValueOf(d.config.Result).Elem())
|
||||
|
||||
// Retain some of the original behavior when multiple errors ocurr
|
||||
var joinedErr interface{ Unwrap() []error }
|
||||
@@ -540,36 +612,50 @@ func (d *Decoder) decode(name string, input any, outVal reflect.Value) error {
|
||||
|
||||
var err error
|
||||
addMetaKey := true
|
||||
switch outputKind {
|
||||
case reflect.Bool:
|
||||
err = d.decodeBool(name, input, outVal)
|
||||
case reflect.Interface:
|
||||
err = d.decodeBasic(name, input, outVal)
|
||||
case reflect.String:
|
||||
err = d.decodeString(name, input, outVal)
|
||||
case reflect.Int:
|
||||
err = d.decodeInt(name, input, outVal)
|
||||
case reflect.Uint:
|
||||
err = d.decodeUint(name, input, outVal)
|
||||
case reflect.Float32:
|
||||
err = d.decodeFloat(name, input, outVal)
|
||||
case reflect.Complex64:
|
||||
err = d.decodeComplex(name, input, outVal)
|
||||
case reflect.Struct:
|
||||
err = d.decodeStruct(name, input, outVal)
|
||||
case reflect.Map:
|
||||
err = d.decodeMap(name, input, outVal)
|
||||
case reflect.Ptr:
|
||||
addMetaKey, err = d.decodePtr(name, input, outVal)
|
||||
case reflect.Slice:
|
||||
err = d.decodeSlice(name, input, outVal)
|
||||
case reflect.Array:
|
||||
err = d.decodeArray(name, input, outVal)
|
||||
case reflect.Func:
|
||||
err = d.decodeFunc(name, input, outVal)
|
||||
default:
|
||||
// If we reached this point then we weren't able to decode it
|
||||
return newDecodeError(name, fmt.Errorf("unsupported type: %s", outputKind))
|
||||
|
||||
// Check if the target implements Unmarshaler and use it if not disabled
|
||||
unmarshaled := false
|
||||
if !d.config.DisableUnmarshaler {
|
||||
if unmarshaler, ok := getUnmarshaler(outVal); ok {
|
||||
if err = unmarshaler.UnmarshalMapstructure(input); err != nil {
|
||||
err = newDecodeError(name, err)
|
||||
}
|
||||
unmarshaled = true
|
||||
}
|
||||
}
|
||||
|
||||
if !unmarshaled {
|
||||
switch outputKind {
|
||||
case reflect.Bool:
|
||||
err = d.decodeBool(name, input, outVal)
|
||||
case reflect.Interface:
|
||||
err = d.decodeBasic(name, input, outVal)
|
||||
case reflect.String:
|
||||
err = d.decodeString(name, input, outVal)
|
||||
case reflect.Int:
|
||||
err = d.decodeInt(name, input, outVal)
|
||||
case reflect.Uint:
|
||||
err = d.decodeUint(name, input, outVal)
|
||||
case reflect.Float32:
|
||||
err = d.decodeFloat(name, input, outVal)
|
||||
case reflect.Complex64:
|
||||
err = d.decodeComplex(name, input, outVal)
|
||||
case reflect.Struct:
|
||||
err = d.decodeStruct(name, input, outVal)
|
||||
case reflect.Map:
|
||||
err = d.decodeMap(name, input, outVal)
|
||||
case reflect.Ptr:
|
||||
addMetaKey, err = d.decodePtr(name, input, outVal)
|
||||
case reflect.Slice:
|
||||
err = d.decodeSlice(name, input, outVal)
|
||||
case reflect.Array:
|
||||
err = d.decodeArray(name, input, outVal)
|
||||
case reflect.Func:
|
||||
err = d.decodeFunc(name, input, outVal)
|
||||
default:
|
||||
// If we reached this point then we weren't able to decode it
|
||||
return newDecodeError(name, fmt.Errorf("unsupported type: %s", outputKind))
|
||||
}
|
||||
}
|
||||
|
||||
// If we reached here, then we successfully decoded SOMETHING, so
|
||||
@@ -668,7 +754,7 @@ func (d *Decoder) decodeString(name string, data any, val reflect.Value) error {
|
||||
case reflect.Uint8:
|
||||
var uints []uint8
|
||||
if dataKind == reflect.Array {
|
||||
uints = make([]uint8, dataVal.Len(), dataVal.Len())
|
||||
uints = make([]uint8, dataVal.Len())
|
||||
for i := range uints {
|
||||
uints[i] = dataVal.Index(i).Interface().(uint8)
|
||||
}
|
||||
@@ -1060,8 +1146,8 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
||||
)
|
||||
}
|
||||
|
||||
tagValue := f.Tag.Get(d.config.TagName)
|
||||
keyName := f.Name
|
||||
tagValue, _ := getTagValue(f, d.config.TagName)
|
||||
keyName := d.config.MapFieldName(f.Name)
|
||||
|
||||
if tagValue == "" && d.config.IgnoreUntaggedFields {
|
||||
continue
|
||||
@@ -1070,6 +1156,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
||||
// If Squash is set in the config, we squash the field down.
|
||||
squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous
|
||||
|
||||
// If Deep is set in the config, set as default value.
|
||||
deep := d.config.Deep
|
||||
|
||||
v = dereferencePtrToStructIfNeeded(v, d.config.TagName)
|
||||
|
||||
// Determine the name of the key in the map
|
||||
@@ -1078,12 +1167,12 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
||||
continue
|
||||
}
|
||||
// If "omitempty" is specified in the tag, it ignores empty values.
|
||||
if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) {
|
||||
if strings.Contains(tagValue[index+1:], "omitempty") && isEmptyValue(v) {
|
||||
continue
|
||||
}
|
||||
|
||||
// If "omitzero" is specified in the tag, it ignores zero values.
|
||||
if strings.Index(tagValue[index+1:], "omitzero") != -1 && v.IsZero() {
|
||||
if strings.Contains(tagValue[index+1:], "omitzero") && v.IsZero() {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1103,7 +1192,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if strings.Index(tagValue[index+1:], "remain") != -1 {
|
||||
if strings.Contains(tagValue[index+1:], "remain") {
|
||||
if v.Kind() != reflect.Map {
|
||||
return newDecodeError(
|
||||
name+"."+f.Name,
|
||||
@@ -1118,6 +1207,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
deep = deep || strings.Contains(tagValue[index+1:], "deep")
|
||||
|
||||
if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" {
|
||||
keyName = keyNameTagValue
|
||||
}
|
||||
@@ -1164,6 +1256,41 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
||||
valMap.SetMapIndex(reflect.ValueOf(keyName), vMap)
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
if deep {
|
||||
var childType reflect.Type
|
||||
switch v.Type().Elem().Kind() {
|
||||
case reflect.Struct:
|
||||
childType = reflect.TypeOf(map[string]any{})
|
||||
default:
|
||||
childType = v.Type().Elem()
|
||||
}
|
||||
|
||||
sType := reflect.SliceOf(childType)
|
||||
|
||||
addrVal := reflect.New(sType)
|
||||
|
||||
vSlice := reflect.MakeSlice(sType, v.Len(), v.Cap())
|
||||
|
||||
if v.Len() > 0 {
|
||||
reflect.Indirect(addrVal).Set(vSlice)
|
||||
|
||||
err := d.decode(keyName, v.Interface(), reflect.Indirect(addrVal))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
vSlice = reflect.Indirect(addrVal)
|
||||
|
||||
valMap.SetMapIndex(reflect.ValueOf(keyName), vSlice)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
// When deep mapping is not needed, fallthrough to normal copy
|
||||
fallthrough
|
||||
|
||||
default:
|
||||
valMap.SetMapIndex(reflect.ValueOf(keyName), v)
|
||||
}
|
||||
@@ -1471,7 +1598,10 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||
remain := false
|
||||
|
||||
// We always parse the tags cause we're looking for other tags too
|
||||
tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
|
||||
tagParts := getTagParts(fieldType, d.config.TagName)
|
||||
if len(tagParts) == 0 {
|
||||
tagParts = []string{""}
|
||||
}
|
||||
for _, tag := range tagParts[1:] {
|
||||
if tag == d.config.SquashTagOption {
|
||||
squash = true
|
||||
@@ -1492,6 +1622,18 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||
if !fieldVal.IsNil() {
|
||||
structs = append(structs, fieldVal.Elem().Elem())
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if fieldVal.Type().Elem().Kind() == reflect.Struct {
|
||||
if fieldVal.IsNil() {
|
||||
fieldVal.Set(reflect.New(fieldVal.Type().Elem()))
|
||||
}
|
||||
structs = append(structs, fieldVal.Elem())
|
||||
} else {
|
||||
errs = append(errs, newDecodeError(
|
||||
name+"."+fieldType.Name,
|
||||
fmt.Errorf("unsupported type for squashed pointer: %s", fieldVal.Type().Elem().Kind()),
|
||||
))
|
||||
}
|
||||
default:
|
||||
errs = append(errs, newDecodeError(
|
||||
name+"."+fieldType.Name,
|
||||
@@ -1516,13 +1658,15 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||
field, fieldValue := f.field, f.val
|
||||
fieldName := field.Name
|
||||
|
||||
tagValue := field.Tag.Get(d.config.TagName)
|
||||
tagValue, _ := getTagValue(field, d.config.TagName)
|
||||
if tagValue == "" && d.config.IgnoreUntaggedFields {
|
||||
continue
|
||||
}
|
||||
tagValue = strings.SplitN(tagValue, ",", 2)[0]
|
||||
if tagValue != "" {
|
||||
fieldName = tagValue
|
||||
} else {
|
||||
fieldName = d.config.MapFieldName(fieldName)
|
||||
}
|
||||
|
||||
rawMapKey := reflect.ValueOf(fieldName)
|
||||
@@ -1605,8 +1749,14 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
// Improve error message when name is empty by showing the target struct type
|
||||
// in the case where it is empty for embedded structs.
|
||||
errorName := name
|
||||
if errorName == "" {
|
||||
errorName = val.Type().String()
|
||||
}
|
||||
errs = append(errs, newDecodeError(
|
||||
name,
|
||||
errorName,
|
||||
fmt.Errorf("has invalid keys: %s", strings.Join(keys, ", ")),
|
||||
))
|
||||
}
|
||||
@@ -1692,7 +1842,7 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool,
|
||||
if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields
|
||||
return true
|
||||
}
|
||||
if checkMapstructureTags && f.Tag.Get(tagName) != "" { // check for mapstructure tags inside
|
||||
if checkMapstructureTags && hasAnyTag(f, tagName) { // check for mapstructure tags inside
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1700,13 +1850,99 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool,
|
||||
}
|
||||
|
||||
func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value {
|
||||
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
|
||||
if v.Kind() != reflect.Ptr {
|
||||
return v
|
||||
}
|
||||
deref := v.Elem()
|
||||
derefT := deref.Type()
|
||||
if isStructTypeConvertibleToMap(derefT, true, tagName) {
|
||||
return deref
|
||||
|
||||
switch v.Elem().Kind() {
|
||||
case reflect.Slice:
|
||||
return v.Elem()
|
||||
|
||||
case reflect.Struct:
|
||||
deref := v.Elem()
|
||||
derefT := deref.Type()
|
||||
if isStructTypeConvertibleToMap(derefT, true, tagName) {
|
||||
return deref
|
||||
}
|
||||
return v
|
||||
|
||||
default:
|
||||
return v
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func hasAnyTag(field reflect.StructField, tagName string) bool {
|
||||
_, ok := getTagValue(field, tagName)
|
||||
return ok
|
||||
}
|
||||
|
||||
func getTagParts(field reflect.StructField, tagName string) []string {
|
||||
tagValue, ok := getTagValue(field, tagName)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return strings.Split(tagValue, ",")
|
||||
}
|
||||
|
||||
func getTagValue(field reflect.StructField, tagName string) (string, bool) {
|
||||
for _, name := range splitTagNames(tagName) {
|
||||
if tag := field.Tag.Get(name); tag != "" {
|
||||
return tag, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func splitTagNames(tagName string) []string {
|
||||
if tagName == "" {
|
||||
return []string{"mapstructure"}
|
||||
}
|
||||
parts := strings.Split(tagName, ",")
|
||||
result := make([]string, 0, len(parts))
|
||||
|
||||
for _, name := range parts {
|
||||
name = strings.TrimSpace(name)
|
||||
if name != "" {
|
||||
result = append(result, name)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// unmarshalerType is cached for performance
|
||||
var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||
|
||||
// getUnmarshaler checks if the value implements Unmarshaler and returns
|
||||
// the Unmarshaler and a boolean indicating if it was found. It handles both
|
||||
// pointer and value receivers.
|
||||
func getUnmarshaler(val reflect.Value) (Unmarshaler, bool) {
|
||||
// Skip invalid or nil values
|
||||
if !val.IsValid() {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Pointer, reflect.Interface:
|
||||
if val.IsNil() {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// Check pointer receiver first (most common case)
|
||||
if val.CanAddr() {
|
||||
ptrVal := val.Addr()
|
||||
// Quick check: if no methods, can't implement any interface
|
||||
if ptrVal.Type().NumMethod() > 0 && ptrVal.Type().Implements(unmarshalerType) {
|
||||
return ptrVal.Interface().(Unmarshaler), true
|
||||
}
|
||||
}
|
||||
|
||||
// Check value receiver
|
||||
// Quick check: if no methods, can't implement any interface
|
||||
if val.Type().NumMethod() > 0 && val.CanInterface() && val.Type().Implements(unmarshalerType) {
|
||||
return val.Interface().(Unmarshaler), true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -627,7 +627,7 @@ github.com/go-task/slim-sprig
|
||||
github.com/go-task/slim-sprig/v3
|
||||
# github.com/go-test/deep v1.1.0
|
||||
## explicit; go 1.16
|
||||
# github.com/go-viper/mapstructure/v2 v2.4.0
|
||||
# github.com/go-viper/mapstructure/v2 v2.5.0
|
||||
## explicit; go 1.18
|
||||
github.com/go-viper/mapstructure/v2
|
||||
github.com/go-viper/mapstructure/v2/internal/errors
|
||||
|
||||
Reference in New Issue
Block a user