mirror of
https://github.com/containers/podman.git
synced 2025-06-21 01:19:15 +08:00
Merge pull request #2760 from mheon/misc_small_changes
Remove ulele/deepcopier in favor of JSON deep copy
This commit is contained in:
@ -96,9 +96,14 @@ func commitCmd(c *cliconfig.CommitValues) error {
|
|||||||
return errors.Wrapf(err, "error looking up container %q", container)
|
return errors.Wrapf(err, "error looking up container %q", container)
|
||||||
}
|
}
|
||||||
|
|
||||||
sc := image.GetSystemContext(runtime.GetConfig().SignaturePolicyPath, "", false)
|
rtc, err := runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sc := image.GetSystemContext(rtc.SignaturePolicyPath, "", false)
|
||||||
coptions := buildah.CommitOptions{
|
coptions := buildah.CommitOptions{
|
||||||
SignaturePolicyPath: runtime.GetConfig().SignaturePolicyPath,
|
SignaturePolicyPath: rtc.SignaturePolicyPath,
|
||||||
ReportWriter: writer,
|
ReportWriter: writer,
|
||||||
SystemContext: sc,
|
SystemContext: sc,
|
||||||
PreferredManifestType: mimeType,
|
PreferredManifestType: mimeType,
|
||||||
|
@ -12,12 +12,14 @@ import (
|
|||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
"github.com/fatih/camelcase"
|
"github.com/fatih/camelcase"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
stores = make(map[storage.Store]struct{})
|
stores = make(map[storage.Store]struct{})
|
||||||
|
json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/buildah/pkg/formats"
|
"github.com/containers/buildah/pkg/formats"
|
||||||
|
@ -71,7 +71,11 @@ func mountCmd(c *cliconfig.MountValues) error {
|
|||||||
defer runtime.Shutdown(false)
|
defer runtime.Shutdown(false)
|
||||||
|
|
||||||
if os.Geteuid() != 0 {
|
if os.Geteuid() != 0 {
|
||||||
if driver := runtime.GetConfig().StorageConfig.GraphDriverName; driver != "vfs" {
|
rtc, err := runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if driver := rtc.StorageConfig.GraphDriverName; driver != "vfs" {
|
||||||
// Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part
|
// Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part
|
||||||
// of the mount command.
|
// of the mount command.
|
||||||
return fmt.Errorf("cannot mount using driver %s in rootless mode", driver)
|
return fmt.Errorf("cannot mount using driver %s in rootless mode", driver)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"encoding/json"
|
|
||||||
tm "github.com/buger/goterm"
|
tm "github.com/buger/goterm"
|
||||||
"github.com/containers/buildah/pkg/formats"
|
"github.com/containers/buildah/pkg/formats"
|
||||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||||
@ -17,7 +16,6 @@ import (
|
|||||||
"github.com/containers/libpod/pkg/adapter"
|
"github.com/containers/libpod/pkg/adapter"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/ulule/deepcopier"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -187,7 +185,9 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error {
|
|||||||
}
|
}
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
previousPodStats := new([]*libpod.PodContainerStats)
|
previousPodStats := new([]*libpod.PodContainerStats)
|
||||||
deepcopier.Copy(newStats).To(previousPodStats)
|
if err := libpod.JSONDeepCopy(newStats, previousPodStats); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
pods, err = runtime.GetStatPods(c)
|
pods, err = runtime.GetStatPods(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
@ -647,7 +646,7 @@ func printFormat(format string, containers []shared.PsContainerOutput) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func dumpJSON(containers []shared.PsContainerOutput) error {
|
func dumpJSON(containers []shared.PsContainerOutput) error {
|
||||||
b, err := json.MarshalIndent(containers, "", "\t")
|
b, err := json.MarshalIndent(containers, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,11 @@ func runCmd(c *cliconfig.RunValues) error {
|
|||||||
if errors.Cause(err) == libpod.ErrNoSuchCtr {
|
if errors.Cause(err) == libpod.ErrNoSuchCtr {
|
||||||
// The container may have been removed
|
// The container may have been removed
|
||||||
// Go looking for an exit file
|
// Go looking for an exit file
|
||||||
ctrExitCode, err := readExitFile(runtime.GetConfig().TmpDir, ctr.ID())
|
rtc, err := runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctrExitCode, err := readExitFile(rtc.TmpDir, ctr.ID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Cannot get exit code: %v", err)
|
logrus.Errorf("Cannot get exit code: %v", err)
|
||||||
exitCode = 127
|
exitCode = 127
|
||||||
|
@ -43,20 +43,23 @@ func getContext() context.Context {
|
|||||||
func CreateContainer(ctx context.Context, c *cliconfig.PodmanCommand, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) {
|
func CreateContainer(ctx context.Context, c *cliconfig.PodmanCommand, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) {
|
||||||
var (
|
var (
|
||||||
healthCheck *manifest.Schema2HealthConfig
|
healthCheck *manifest.Schema2HealthConfig
|
||||||
|
err error
|
||||||
|
cidFile *os.File
|
||||||
)
|
)
|
||||||
if c.Bool("trace") {
|
if c.Bool("trace") {
|
||||||
span, _ := opentracing.StartSpanFromContext(ctx, "createContainer")
|
span, _ := opentracing.StartSpanFromContext(ctx, "createContainer")
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc := runtime.GetConfig()
|
rtc, err := runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
rootfs := ""
|
rootfs := ""
|
||||||
if c.Bool("rootfs") {
|
if c.Bool("rootfs") {
|
||||||
rootfs = c.InputArgs[0]
|
rootfs = c.InputArgs[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
|
||||||
var cidFile *os.File
|
|
||||||
if c.IsSet("cidfile") && os.Geteuid() == 0 {
|
if c.IsSet("cidfile") && os.Geteuid() == 0 {
|
||||||
cidFile, err = libpod.OpenExclusiveFile(c.String("cidfile"))
|
cidFile, err = libpod.OpenExclusiveFile(c.String("cidfile"))
|
||||||
if err != nil && os.IsExist(err) {
|
if err != nil && os.IsExist(err) {
|
||||||
@ -721,7 +724,11 @@ func ParseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
|
|||||||
if c.Bool("init") {
|
if c.Bool("init") {
|
||||||
initPath := c.String("init-path")
|
initPath := c.String("init-path")
|
||||||
if initPath == "" {
|
if initPath == "" {
|
||||||
initPath = runtime.GetConfig().InitPath
|
rtc, err := runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
initPath = rtc.InitPath
|
||||||
}
|
}
|
||||||
if err := config.AddContainerInitBinary(initPath); err != nil {
|
if err := config.AddContainerInitBinary(initPath); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -108,7 +108,11 @@ func signCmd(c *cliconfig.SignValues) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create the signstore file
|
// create the signstore file
|
||||||
newImage, err := runtime.ImageRuntime().New(getContext(), signimage, runtime.GetConfig().SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, false, nil)
|
rtc, err := runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newImage, err := runtime.ImageRuntime().New(getContext(), signimage, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, false, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error pulling image %s", signimage)
|
return errors.Wrapf(err, "error pulling image %s", signimage)
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,11 @@ func startCmd(c *cliconfig.StartValues) error {
|
|||||||
if errors.Cause(err) == libpod.ErrNoSuchCtr {
|
if errors.Cause(err) == libpod.ErrNoSuchCtr {
|
||||||
// The container may have been removed
|
// The container may have been removed
|
||||||
// Go looking for an exit file
|
// Go looking for an exit file
|
||||||
ctrExitCode, err := readExitFile(runtime.GetConfig().TmpDir, ctr.ID())
|
rtc, err := runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctrExitCode, err := readExitFile(rtc.TmpDir, ctr.ID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Cannot get exit code: %v", err)
|
logrus.Errorf("Cannot get exit code: %v", err)
|
||||||
exitCode = 127
|
exitCode = 127
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -151,7 +151,6 @@ Provides: bundled(golang(github.com/stretchr/testify)) = 4d4bfba8f1d1027c4fdbe37
|
|||||||
Provides: bundled(golang(github.com/syndtr/gocapability)) = e7cb7fa329f456b3855136a2642b197bad7366ba
|
Provides: bundled(golang(github.com/syndtr/gocapability)) = e7cb7fa329f456b3855136a2642b197bad7366ba
|
||||||
Provides: bundled(golang(github.com/tchap/go-patricia)) = v2.2.6
|
Provides: bundled(golang(github.com/tchap/go-patricia)) = v2.2.6
|
||||||
Provides: bundled(golang(github.com/ulikunitz/xz)) = v0.5.4
|
Provides: bundled(golang(github.com/ulikunitz/xz)) = v0.5.4
|
||||||
Provides: bundled(golang(github.com/ulule/deepcopier)) = master
|
|
||||||
# "-" are not accepted in version strings, so comment out below line
|
# "-" are not accepted in version strings, so comment out below line
|
||||||
#Provides: bundled(golang(github.com/urfave/cli)) = fix-short-opts-parsing
|
#Provides: bundled(golang(github.com/urfave/cli)) = fix-short-opts-parsing
|
||||||
Provides: bundled(golang(github.com/varlink/go)) = master
|
Provides: bundled(golang(github.com/varlink/go)) = master
|
||||||
@ -237,7 +236,6 @@ BuildRequires: golang(github.com/opencontainers/selinux/go-selinux)
|
|||||||
BuildRequires: golang(github.com/opencontainers/selinux/go-selinux/label)
|
BuildRequires: golang(github.com/opencontainers/selinux/go-selinux/label)
|
||||||
BuildRequires: golang(github.com/pkg/errors)
|
BuildRequires: golang(github.com/pkg/errors)
|
||||||
BuildRequires: golang(github.com/sirupsen/logrus)
|
BuildRequires: golang(github.com/sirupsen/logrus)
|
||||||
BuildRequires: golang(github.com/ulule/deepcopier)
|
|
||||||
BuildRequires: golang(golang.org/x/crypto/ssh/terminal)
|
BuildRequires: golang(golang.org/x/crypto/ssh/terminal)
|
||||||
BuildRequires: golang(golang.org/x/sys/unix)
|
BuildRequires: golang(golang.org/x/sys/unix)
|
||||||
BuildRequires: golang(k8s.io/apimachinery/pkg/util/wait)
|
BuildRequires: golang(k8s.io/apimachinery/pkg/util/wait)
|
||||||
@ -290,7 +288,6 @@ Requires: golang(github.com/opencontainers/selinux/go-selinux)
|
|||||||
Requires: golang(github.com/opencontainers/selinux/go-selinux/label)
|
Requires: golang(github.com/opencontainers/selinux/go-selinux/label)
|
||||||
Requires: golang(github.com/pkg/errors)
|
Requires: golang(github.com/pkg/errors)
|
||||||
Requires: golang(github.com/sirupsen/logrus)
|
Requires: golang(github.com/sirupsen/logrus)
|
||||||
Requires: golang(github.com/ulule/deepcopier)
|
|
||||||
Requires: golang(golang.org/x/crypto/ssh/terminal)
|
Requires: golang(golang.org/x/crypto/ssh/terminal)
|
||||||
Requires: golang(golang.org/x/sys/unix)
|
Requires: golang(golang.org/x/sys/unix)
|
||||||
Requires: golang(k8s.io/apimachinery/pkg/util/wait)
|
Requires: golang(k8s.io/apimachinery/pkg/util/wait)
|
||||||
|
@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/ulule/deepcopier"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerStatus represents the current state of a container
|
// ContainerStatus represents the current state of a container
|
||||||
@ -407,7 +406,9 @@ func (t ContainerStatus) String() string {
|
|||||||
// Config returns the configuration used to create the container
|
// Config returns the configuration used to create the container
|
||||||
func (c *Container) Config() *ContainerConfig {
|
func (c *Container) Config() *ContainerConfig {
|
||||||
returnConfig := new(ContainerConfig)
|
returnConfig := new(ContainerConfig)
|
||||||
deepcopier.Copy(c.config).To(returnConfig)
|
if err := JSONDeepCopy(c.config, returnConfig); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return returnConfig
|
return returnConfig
|
||||||
}
|
}
|
||||||
@ -417,7 +418,9 @@ func (c *Container) Config() *ContainerConfig {
|
|||||||
// spec may differ slightly as mounts are added based on the image
|
// spec may differ slightly as mounts are added based on the image
|
||||||
func (c *Container) Spec() *spec.Spec {
|
func (c *Container) Spec() *spec.Spec {
|
||||||
returnSpec := new(spec.Spec)
|
returnSpec := new(spec.Spec)
|
||||||
deepcopier.Copy(c.config.Spec).To(returnSpec)
|
if err := JSONDeepCopy(c.config.Spec, returnSpec); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return returnSpec
|
return returnSpec
|
||||||
}
|
}
|
||||||
@ -1094,7 +1097,9 @@ func (c *Container) ContainerState() (*ContainerState, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
returnConfig := new(ContainerState)
|
returnConfig := new(ContainerState)
|
||||||
deepcopier.Copy(c.state).To(returnConfig)
|
if err := JSONDeepCopy(c.state, returnConfig); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error copying container %s state", c.ID())
|
||||||
|
}
|
||||||
return c.state, nil
|
return c.state, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,10 @@ func (v *Volume) newVolumeEvent(status events.Status) {
|
|||||||
// Events is a wrapper function for everyone to begin tailing the events log
|
// Events is a wrapper function for everyone to begin tailing the events log
|
||||||
// with options
|
// with options
|
||||||
func (r *Runtime) Events(fromStart, stream bool, options []events.EventFilter, eventChannel chan *events.Event) error {
|
func (r *Runtime) Events(fromStart, stream bool, options []events.EventFilter, eventChannel chan *events.Event) error {
|
||||||
|
if !r.valid {
|
||||||
|
return ErrRuntimeStopped
|
||||||
|
}
|
||||||
|
|
||||||
t, err := r.getTail(fromStart, stream)
|
t, err := r.getTail(fromStart, stream)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -71,7 +75,7 @@ func (r *Runtime) Events(fromStart, stream bool, options []events.EventFilter, e
|
|||||||
case events.Image, events.Volume, events.Pod, events.Container:
|
case events.Image, events.Volume, events.Pod, events.Container:
|
||||||
// no-op
|
// no-op
|
||||||
default:
|
default:
|
||||||
return errors.Errorf("event type %s is not valid in %s", event.Type.String(), r.GetConfig().EventsLogFilePath)
|
return errors.Errorf("event type %s is not valid in %s", event.Type.String(), r.config.EventsLogFilePath)
|
||||||
}
|
}
|
||||||
include := true
|
include := true
|
||||||
for _, filter := range options {
|
for _, filter := range options {
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/containers/libpod/libpod/events"
|
"github.com/containers/libpod/libpod/events"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/ulule/deepcopier"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start starts all containers within a pod
|
// Start starts all containers within a pod
|
||||||
@ -441,7 +440,9 @@ func (p *Pod) Inspect() (*PodInspect, error) {
|
|||||||
infraContainerID := p.state.InfraContainerID
|
infraContainerID := p.state.InfraContainerID
|
||||||
|
|
||||||
config := new(PodConfig)
|
config := new(PodConfig)
|
||||||
deepcopier.Copy(p.config).To(config)
|
if err := JSONDeepCopy(p.config, config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
inspectData := PodInspect{
|
inspectData := PodInspect{
|
||||||
Config: config,
|
Config: config,
|
||||||
State: &PodInspectState{
|
State: &PodInspectState{
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"github.com/docker/docker/pkg/namesgenerator"
|
"github.com/docker/docker/pkg/namesgenerator"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/ulule/deepcopier"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RuntimeStateStore is a constant indicating which state store implementation
|
// RuntimeStateStore is a constant indicating which state store implementation
|
||||||
@ -355,7 +354,9 @@ func newRuntimeFromConfig(userConfigPath string, options ...RuntimeOption) (runt
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
deepcopier.Copy(defaultRuntimeConfig).To(runtime.config)
|
if err := JSONDeepCopy(defaultRuntimeConfig, runtime.config); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error copying runtime default config")
|
||||||
|
}
|
||||||
runtime.config.TmpDir = tmpDir
|
runtime.config.TmpDir = tmpDir
|
||||||
|
|
||||||
storageConf, err := util.GetDefaultStoreOptions()
|
storageConf, err := util.GetDefaultStoreOptions()
|
||||||
@ -923,20 +924,22 @@ func makeRuntime(runtime *Runtime) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetConfig returns a copy of the configuration used by the runtime
|
// GetConfig returns a copy of the configuration used by the runtime
|
||||||
func (r *Runtime) GetConfig() *RuntimeConfig {
|
func (r *Runtime) GetConfig() (*RuntimeConfig, error) {
|
||||||
r.lock.RLock()
|
r.lock.RLock()
|
||||||
defer r.lock.RUnlock()
|
defer r.lock.RUnlock()
|
||||||
|
|
||||||
if !r.valid {
|
if !r.valid {
|
||||||
return nil
|
return nil, ErrRuntimeStopped
|
||||||
}
|
}
|
||||||
|
|
||||||
config := new(RuntimeConfig)
|
config := new(RuntimeConfig)
|
||||||
|
|
||||||
// Copy so the caller won't be able to modify the actual config
|
// Copy so the caller won't be able to modify the actual config
|
||||||
deepcopier.Copy(r.config).To(config)
|
if err := JSONDeepCopy(r.config, config); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error copying config")
|
||||||
|
}
|
||||||
|
|
||||||
return config
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown shuts down the runtime and associated containers and storage
|
// Shutdown shuts down the runtime and associated containers and storage
|
||||||
|
@ -19,7 +19,6 @@ import (
|
|||||||
opentracing "github.com/opentracing/opentracing-go"
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/ulule/deepcopier"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CtrRemoveTimeout is the default number of seconds to wait after stopping a container
|
// CtrRemoveTimeout is the default number of seconds to wait after stopping a container
|
||||||
@ -63,7 +62,9 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
|
|||||||
ctr.config.ID = stringid.GenerateNonCryptoID()
|
ctr.config.ID = stringid.GenerateNonCryptoID()
|
||||||
|
|
||||||
ctr.config.Spec = new(spec.Spec)
|
ctr.config.Spec = new(spec.Spec)
|
||||||
deepcopier.Copy(rSpec).To(ctr.config.Spec)
|
if err := JSONDeepCopy(rSpec, ctr.config.Spec); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error copying runtime spec while creating container")
|
||||||
|
}
|
||||||
ctr.config.CreatedTime = time.Now()
|
ctr.config.CreatedTime = time.Now()
|
||||||
|
|
||||||
ctr.config.ShmSize = DefaultShmSize
|
ctr.config.ShmSize = DefaultShmSize
|
||||||
|
@ -187,3 +187,13 @@ func validPodNSOption(p *Pod, ctrPod string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JSONDeepCopy performs a deep copy by performing a JSON encode/decode of the
|
||||||
|
// given structures. From and To should be identically typed structs.
|
||||||
|
func JSONDeepCopy(from, to interface{}) error {
|
||||||
|
tmp, err := json.Marshal(from)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(tmp, to)
|
||||||
|
}
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
"github.com/containers/libpod/pkg/varlinkapi"
|
"github.com/containers/libpod/pkg/varlinkapi"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/ulule/deepcopier"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pod ...
|
// Pod ...
|
||||||
@ -99,7 +98,9 @@ func (r *LocalRuntime) LookupPod(nameOrID string) (*Pod, error) {
|
|||||||
// the data of a remotepod data struct
|
// the data of a remotepod data struct
|
||||||
func (p *Pod) Inspect() (*libpod.PodInspect, error) {
|
func (p *Pod) Inspect() (*libpod.PodInspect, error) {
|
||||||
config := new(libpod.PodConfig)
|
config := new(libpod.PodConfig)
|
||||||
deepcopier.Copy(p.remotepod.config).To(config)
|
if err := libpod.JSONDeepCopy(p.remotepod.config, config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
inspectData := libpod.PodInspect{
|
inspectData := libpod.PodInspect{
|
||||||
Config: config,
|
Config: config,
|
||||||
State: p.remotepod.state,
|
State: p.remotepod.state,
|
||||||
|
@ -346,8 +346,11 @@ func (c *CreateConfig) GetTmpfsMounts() []spec.Mount {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CreateConfig) createExitCommand() []string {
|
func (c *CreateConfig) createExitCommand() ([]string, error) {
|
||||||
config := c.Runtime.GetConfig()
|
config, err := c.Runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
cmd, _ := os.Executable()
|
cmd, _ := os.Executable()
|
||||||
command := []string{cmd,
|
command := []string{cmd,
|
||||||
@ -372,7 +375,7 @@ func (c *CreateConfig) createExitCommand() []string {
|
|||||||
command = append(command, "--rm")
|
command = append(command, "--rm")
|
||||||
}
|
}
|
||||||
|
|
||||||
return command
|
return command, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions
|
// GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions
|
||||||
@ -567,7 +570,11 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime, pod *l
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Always use a cleanup process to clean up Podman after termination
|
// Always use a cleanup process to clean up Podman after termination
|
||||||
options = append(options, libpod.WithExitCommand(c.createExitCommand()))
|
exitCmd, err := c.createExitCommand()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, libpod.WithExitCommand(exitCmd))
|
||||||
|
|
||||||
if c.HealthCheck != nil {
|
if c.HealthCheck != nil {
|
||||||
options = append(options, libpod.WithHealthCheck(c.HealthCheck))
|
options = append(options, libpod.WithHealthCheck(c.HealthCheck))
|
||||||
|
@ -22,7 +22,10 @@ import (
|
|||||||
|
|
||||||
// CreateContainer ...
|
// CreateContainer ...
|
||||||
func (i *LibpodAPI) CreateContainer(call iopodman.VarlinkCall, config iopodman.Create) error {
|
func (i *LibpodAPI) CreateContainer(call iopodman.VarlinkCall, config iopodman.Create) error {
|
||||||
rtc := i.Runtime.GetConfig()
|
rtc, err := i.Runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
|
}
|
||||||
ctx := getContext()
|
ctx := getContext()
|
||||||
|
|
||||||
newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, nil)
|
newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, nil)
|
||||||
|
@ -514,7 +514,11 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return call.ReplyContainerNotFound(name, err.Error())
|
return call.ReplyContainerNotFound(name, err.Error())
|
||||||
}
|
}
|
||||||
sc := image.GetSystemContext(i.Runtime.GetConfig().SignaturePolicyPath, "", false)
|
rtc, err := i.Runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return call.ReplyErrorOccurred(err.Error())
|
||||||
|
}
|
||||||
|
sc := image.GetSystemContext(rtc.SignaturePolicyPath, "", false)
|
||||||
var mimeType string
|
var mimeType string
|
||||||
switch manifestType {
|
switch manifestType {
|
||||||
case "oci", "": //nolint
|
case "oci", "": //nolint
|
||||||
@ -525,7 +529,7 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
|
|||||||
return call.ReplyErrorOccurred(fmt.Sprintf("unrecognized image format %q", manifestType))
|
return call.ReplyErrorOccurred(fmt.Sprintf("unrecognized image format %q", manifestType))
|
||||||
}
|
}
|
||||||
coptions := buildah.CommitOptions{
|
coptions := buildah.CommitOptions{
|
||||||
SignaturePolicyPath: i.Runtime.GetConfig().SignaturePolicyPath,
|
SignaturePolicyPath: rtc.SignaturePolicyPath,
|
||||||
ReportWriter: nil,
|
ReportWriter: nil,
|
||||||
SystemContext: sc,
|
SystemContext: sc,
|
||||||
PreferredManifestType: mimeType,
|
PreferredManifestType: mimeType,
|
||||||
|
@ -73,7 +73,6 @@ github.com/syndtr/gocapability d98352740cb2c55f81556b63d4a1ec64c5a319c2
|
|||||||
github.com/tchap/go-patricia v2.2.6
|
github.com/tchap/go-patricia v2.2.6
|
||||||
github.com/uber/jaeger-client-go 64f57863bf63d3842dbe79cdc793d57baaff9ab5
|
github.com/uber/jaeger-client-go 64f57863bf63d3842dbe79cdc793d57baaff9ab5
|
||||||
github.com/uber/jaeger-lib d036253de8f5b698150d81b922486f1e8e7628ec
|
github.com/uber/jaeger-lib d036253de8f5b698150d81b922486f1e8e7628ec
|
||||||
github.com/ulule/deepcopier ca99b135e50f526fde9cd88705f0ff2f3f95b77c
|
|
||||||
github.com/vbatts/tar-split v0.11.1
|
github.com/vbatts/tar-split v0.11.1
|
||||||
github.com/vishvananda/netlink v1.0.0
|
github.com/vishvananda/netlink v1.0.0
|
||||||
github.com/vishvananda/netns 13995c7128ccc8e51e9a6bd2b551020a27180abd
|
github.com/vishvananda/netns 13995c7128ccc8e51e9a6bd2b551020a27180abd
|
||||||
|
22
vendor/github.com/ulule/deepcopier/LICENSE
generated
vendored
22
vendor/github.com/ulule/deepcopier/LICENSE
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 Ulule
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
129
vendor/github.com/ulule/deepcopier/README.md
generated
vendored
129
vendor/github.com/ulule/deepcopier/README.md
generated
vendored
@ -1,129 +0,0 @@
|
|||||||
# Deepcopier
|
|
||||||
|
|
||||||
[](http://travis-ci.org/ulule/deepcopier)
|
|
||||||
|
|
||||||
This package is meant to make copying of structs to/from others structs a bit easier.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go get -u github.com/ulule/deepcopier
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```golang
|
|
||||||
// Deep copy instance1 into instance2
|
|
||||||
Copy(instance1).To(instance2)
|
|
||||||
|
|
||||||
// Deep copy instance1 into instance2 and passes the following context (which
|
|
||||||
// is basically a map[string]interface{}) as first argument
|
|
||||||
// to methods of instance2 that defined the struct tag "context".
|
|
||||||
Copy(instance1).WithContext(map[string]interface{}{"foo": "bar"}).To(instance2)
|
|
||||||
|
|
||||||
// Deep copy instance2 into instance1
|
|
||||||
Copy(instance1).From(instance2)
|
|
||||||
|
|
||||||
// Deep copy instance2 into instance1 and passes the following context (which
|
|
||||||
// is basically a map[string]interface{}) as first argument
|
|
||||||
// to methods of instance1 that defined the struct tag "context".
|
|
||||||
Copy(instance1).WithContext(map[string]interface{}{"foo": "bar"}).From(instance2)
|
|
||||||
```
|
|
||||||
|
|
||||||
Available options for `deepcopier` struct tag:
|
|
||||||
|
|
||||||
| Option | Description |
|
|
||||||
| --------- | -------------------------------------------------------------------- |
|
|
||||||
| `field` | Field or method name in source instance |
|
|
||||||
| `skip` | Ignores the field |
|
|
||||||
| `context` | Takes a `map[string]interface{}` as first argument (for methods) |
|
|
||||||
| `force` | Set the value of a `sql.Null*` field (instead of copying the struct) |
|
|
||||||
|
|
||||||
**Options example:**
|
|
||||||
|
|
||||||
```golang
|
|
||||||
type Source struct {
|
|
||||||
Name string
|
|
||||||
SkipMe string
|
|
||||||
SQLNullStringToSQLNullString sql.NullString
|
|
||||||
SQLNullStringToString sql.NullString
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Source) MethodThatTakesContext(c map[string]interface{}) string {
|
|
||||||
return "whatever"
|
|
||||||
}
|
|
||||||
|
|
||||||
type Destination struct {
|
|
||||||
FieldWithAnotherNameInSource string `deepcopier:"field:Name"`
|
|
||||||
SkipMe string `deepcopier:"skip"`
|
|
||||||
MethodThatTakesContext string `deepcopier:"context"`
|
|
||||||
SQLNullStringToSQLNullString sql.NullString
|
|
||||||
SQLNullStringToString string `deepcopier:"force"`
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```golang
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ulule/deepcopier"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Model
|
|
||||||
type User struct {
|
|
||||||
// Basic string field
|
|
||||||
Name string
|
|
||||||
// Deepcopier supports https://golang.org/pkg/database/sql/driver/#Valuer
|
|
||||||
Email sql.NullString
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *User) MethodThatTakesContext(ctx map[string]interface{}) string {
|
|
||||||
// do whatever you want
|
|
||||||
return "hello from this method"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resource
|
|
||||||
type UserResource struct {
|
|
||||||
DisplayName string `deepcopier:"field:Name"`
|
|
||||||
SkipMe string `deepcopier:"skip"`
|
|
||||||
MethodThatTakesContext string `deepcopier:"context"`
|
|
||||||
Email string `deepcopier:"force"`
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
user := &User{
|
|
||||||
Name: "gilles",
|
|
||||||
Email: sql.NullString{
|
|
||||||
Valid: true,
|
|
||||||
String: "gilles@example.com",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
resource := &UserResource{}
|
|
||||||
|
|
||||||
deepcopier.Copy(user).To(resource)
|
|
||||||
|
|
||||||
fmt.Println(resource.DisplayName)
|
|
||||||
fmt.Println(resource.Email)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Looking for more information about the usage?
|
|
||||||
|
|
||||||
We wrote [an introduction article](https://github.com/ulule/deepcopier/blob/master/examples/rest-usage/README.rst).
|
|
||||||
Have a look and feel free to give us your feedback.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
* Ping us on twitter [@oibafsellig](https://twitter.com/oibafsellig), [@thoas](https://twitter.com/thoas)
|
|
||||||
* Fork the [project](https://github.com/ulule/deepcopier)
|
|
||||||
* Help us improving and fixing [issues](https://github.com/ulule/deepcopier/issues)
|
|
||||||
|
|
||||||
Don't hesitate ;)
|
|
362
vendor/github.com/ulule/deepcopier/deepcopier.go
generated
vendored
362
vendor/github.com/ulule/deepcopier/deepcopier.go
generated
vendored
@ -1,362 +0,0 @@
|
|||||||
package deepcopier
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql/driver"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// TagName is the deepcopier struct tag name.
|
|
||||||
TagName = "deepcopier"
|
|
||||||
// FieldOptionName is the from field option name for struct tag.
|
|
||||||
FieldOptionName = "field"
|
|
||||||
// ContextOptionName is the context option name for struct tag.
|
|
||||||
ContextOptionName = "context"
|
|
||||||
// SkipOptionName is the skip option name for struct tag.
|
|
||||||
SkipOptionName = "skip"
|
|
||||||
// ForceOptionName is the skip option name for struct tag.
|
|
||||||
ForceOptionName = "force"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// TagOptions is a map that contains extracted struct tag options.
|
|
||||||
TagOptions map[string]string
|
|
||||||
|
|
||||||
// Options are copier options.
|
|
||||||
Options struct {
|
|
||||||
// Context given to WithContext() method.
|
|
||||||
Context map[string]interface{}
|
|
||||||
// Reversed reverses struct tag checkings.
|
|
||||||
Reversed bool
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// DeepCopier deep copies a struct to/from a struct.
|
|
||||||
type DeepCopier struct {
|
|
||||||
dst interface{}
|
|
||||||
src interface{}
|
|
||||||
ctx map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy sets source or destination.
|
|
||||||
func Copy(src interface{}) *DeepCopier {
|
|
||||||
return &DeepCopier{src: src}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithContext injects the given context into the builder instance.
|
|
||||||
func (dc *DeepCopier) WithContext(ctx map[string]interface{}) *DeepCopier {
|
|
||||||
dc.ctx = ctx
|
|
||||||
return dc
|
|
||||||
}
|
|
||||||
|
|
||||||
// To sets the destination.
|
|
||||||
func (dc *DeepCopier) To(dst interface{}) error {
|
|
||||||
dc.dst = dst
|
|
||||||
return process(dc.dst, dc.src, Options{Context: dc.ctx})
|
|
||||||
}
|
|
||||||
|
|
||||||
// From sets the given the source as destination and destination as source.
|
|
||||||
func (dc *DeepCopier) From(src interface{}) error {
|
|
||||||
dc.dst = dc.src
|
|
||||||
dc.src = src
|
|
||||||
return process(dc.dst, dc.src, Options{Context: dc.ctx, Reversed: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
// process handles copy.
|
|
||||||
func process(dst interface{}, src interface{}, args ...Options) error {
|
|
||||||
var (
|
|
||||||
options = Options{}
|
|
||||||
srcValue = reflect.Indirect(reflect.ValueOf(src))
|
|
||||||
dstValue = reflect.Indirect(reflect.ValueOf(dst))
|
|
||||||
srcFieldNames = getFieldNames(src)
|
|
||||||
srcMethodNames = getMethodNames(src)
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(args) > 0 {
|
|
||||||
options = args[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dstValue.CanAddr() {
|
|
||||||
return fmt.Errorf("destination %+v is unaddressable", dstValue.Interface())
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range srcFieldNames {
|
|
||||||
var (
|
|
||||||
srcFieldValue = srcValue.FieldByName(f)
|
|
||||||
srcFieldType, srcFieldFound = srcValue.Type().FieldByName(f)
|
|
||||||
srcFieldName = srcFieldType.Name
|
|
||||||
dstFieldName = srcFieldName
|
|
||||||
tagOptions TagOptions
|
|
||||||
)
|
|
||||||
|
|
||||||
if !srcFieldFound {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Reversed {
|
|
||||||
tagOptions = getTagOptions(srcFieldType.Tag.Get(TagName))
|
|
||||||
if v, ok := tagOptions[FieldOptionName]; ok && v != "" {
|
|
||||||
dstFieldName = v
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if name, opts := getRelatedField(dst, srcFieldName); name != "" {
|
|
||||||
dstFieldName, tagOptions = name, opts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := tagOptions[SkipOptionName]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
dstFieldType, dstFieldFound = dstValue.Type().FieldByName(dstFieldName)
|
|
||||||
dstFieldValue = dstValue.FieldByName(dstFieldName)
|
|
||||||
)
|
|
||||||
|
|
||||||
if !dstFieldFound {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force option for empty interfaces and nullable types
|
|
||||||
_, force := tagOptions[ForceOptionName]
|
|
||||||
|
|
||||||
// Valuer -> ptr
|
|
||||||
if isNullableType(srcFieldType.Type) && dstFieldValue.Kind() == reflect.Ptr && force {
|
|
||||||
// We have same nullable type on both sides
|
|
||||||
if srcFieldValue.Type().AssignableTo(dstFieldType.Type) {
|
|
||||||
dstFieldValue.Set(srcFieldValue)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
v, _ := srcFieldValue.Interface().(driver.Valuer).Value()
|
|
||||||
if v == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
valueType := reflect.TypeOf(v)
|
|
||||||
|
|
||||||
ptr := reflect.New(valueType)
|
|
||||||
ptr.Elem().Set(reflect.ValueOf(v))
|
|
||||||
|
|
||||||
if valueType.AssignableTo(dstFieldType.Type.Elem()) {
|
|
||||||
dstFieldValue.Set(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Valuer -> value
|
|
||||||
if isNullableType(srcFieldType.Type) {
|
|
||||||
// We have same nullable type on both sides
|
|
||||||
if srcFieldValue.Type().AssignableTo(dstFieldType.Type) {
|
|
||||||
dstFieldValue.Set(srcFieldValue)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if force {
|
|
||||||
v, _ := srcFieldValue.Interface().(driver.Valuer).Value()
|
|
||||||
if v == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
rv := reflect.ValueOf(v)
|
|
||||||
if rv.Type().AssignableTo(dstFieldType.Type) {
|
|
||||||
dstFieldValue.Set(rv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if dstFieldValue.Kind() == reflect.Interface {
|
|
||||||
if force {
|
|
||||||
dstFieldValue.Set(srcFieldValue)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ptr -> Value
|
|
||||||
if srcFieldType.Type.Kind() == reflect.Ptr && !srcFieldValue.IsNil() && dstFieldType.Type.Kind() != reflect.Ptr {
|
|
||||||
indirect := reflect.Indirect(srcFieldValue)
|
|
||||||
|
|
||||||
if indirect.Type().AssignableTo(dstFieldType.Type) {
|
|
||||||
dstFieldValue.Set(indirect)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other types
|
|
||||||
if srcFieldType.Type.AssignableTo(dstFieldType.Type) {
|
|
||||||
dstFieldValue.Set(srcFieldValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range srcMethodNames {
|
|
||||||
name, opts := getRelatedField(dst, m)
|
|
||||||
if name == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := opts[SkipOptionName]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
method := reflect.ValueOf(src).MethodByName(m)
|
|
||||||
if !method.IsValid() {
|
|
||||||
return fmt.Errorf("method %s is invalid", m)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
dstFieldType, _ = dstValue.Type().FieldByName(name)
|
|
||||||
dstFieldValue = dstValue.FieldByName(name)
|
|
||||||
_, withContext = opts[ContextOptionName]
|
|
||||||
_, force = opts[ForceOptionName]
|
|
||||||
)
|
|
||||||
|
|
||||||
args := []reflect.Value{}
|
|
||||||
if withContext {
|
|
||||||
args = []reflect.Value{reflect.ValueOf(options.Context)}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
result = method.Call(args)[0]
|
|
||||||
resultInterface = result.Interface()
|
|
||||||
resultValue = reflect.ValueOf(resultInterface)
|
|
||||||
resultType = resultValue.Type()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Value -> Ptr
|
|
||||||
if dstFieldValue.Kind() == reflect.Ptr && force {
|
|
||||||
ptr := reflect.New(resultType)
|
|
||||||
ptr.Elem().Set(resultValue)
|
|
||||||
|
|
||||||
if ptr.Type().AssignableTo(dstFieldType.Type) {
|
|
||||||
dstFieldValue.Set(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ptr -> value
|
|
||||||
if resultValue.Kind() == reflect.Ptr && force {
|
|
||||||
if resultValue.Elem().Type().AssignableTo(dstFieldType.Type) {
|
|
||||||
dstFieldValue.Set(resultValue.Elem())
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if resultType.AssignableTo(dstFieldType.Type) && result.IsValid() {
|
|
||||||
dstFieldValue.Set(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getTagOptions parses deepcopier tag field and returns options.
|
|
||||||
func getTagOptions(value string) TagOptions {
|
|
||||||
options := TagOptions{}
|
|
||||||
|
|
||||||
for _, opt := range strings.Split(value, ";") {
|
|
||||||
o := strings.Split(opt, ":")
|
|
||||||
|
|
||||||
// deepcopier:"keyword; without; value;"
|
|
||||||
if len(o) == 1 {
|
|
||||||
options[o[0]] = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// deepcopier:"key:value; anotherkey:anothervalue"
|
|
||||||
if len(o) == 2 {
|
|
||||||
options[strings.TrimSpace(o[0])] = strings.TrimSpace(o[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return options
|
|
||||||
}
|
|
||||||
|
|
||||||
// getRelatedField returns first matching field.
|
|
||||||
func getRelatedField(instance interface{}, name string) (string, TagOptions) {
|
|
||||||
var (
|
|
||||||
value = reflect.Indirect(reflect.ValueOf(instance))
|
|
||||||
fieldName string
|
|
||||||
tagOptions TagOptions
|
|
||||||
)
|
|
||||||
|
|
||||||
for i := 0; i < value.NumField(); i++ {
|
|
||||||
var (
|
|
||||||
vField = value.Field(i)
|
|
||||||
tField = value.Type().Field(i)
|
|
||||||
tagOptions = getTagOptions(tField.Tag.Get(TagName))
|
|
||||||
)
|
|
||||||
|
|
||||||
if tField.Type.Kind() == reflect.Struct && tField.Anonymous {
|
|
||||||
if n, o := getRelatedField(vField.Interface(), name); n != "" {
|
|
||||||
return n, o
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if v, ok := tagOptions[FieldOptionName]; ok && v == name {
|
|
||||||
return tField.Name, tagOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
if tField.Name == name {
|
|
||||||
return tField.Name, tagOptions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fieldName, tagOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
// getMethodNames returns instance's method names.
|
|
||||||
func getMethodNames(instance interface{}) []string {
|
|
||||||
var methods []string
|
|
||||||
|
|
||||||
t := reflect.TypeOf(instance)
|
|
||||||
for i := 0; i < t.NumMethod(); i++ {
|
|
||||||
methods = append(methods, t.Method(i).Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return methods
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFieldNames returns instance's field names.
|
|
||||||
func getFieldNames(instance interface{}) []string {
|
|
||||||
var (
|
|
||||||
fields []string
|
|
||||||
v = reflect.Indirect(reflect.ValueOf(instance))
|
|
||||||
t = v.Type()
|
|
||||||
)
|
|
||||||
|
|
||||||
if t.Kind() != reflect.Struct {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < v.NumField(); i++ {
|
|
||||||
var (
|
|
||||||
vField = v.Field(i)
|
|
||||||
tField = v.Type().Field(i)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Is exportable?
|
|
||||||
if tField.PkgPath != "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if tField.Type.Kind() == reflect.Struct && tField.Anonymous {
|
|
||||||
fields = append(fields, getFieldNames(vField.Interface())...)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fields = append(fields, tField.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fields
|
|
||||||
}
|
|
||||||
|
|
||||||
// isNullableType returns true if the given type is a nullable one.
|
|
||||||
func isNullableType(t reflect.Type) bool {
|
|
||||||
return t.ConvertibleTo(reflect.TypeOf((*driver.Valuer)(nil)).Elem())
|
|
||||||
}
|
|
Reference in New Issue
Block a user