From 8ed5c1bedf074401dfc54773379dd6395567df52 Mon Sep 17 00:00:00 2001 From: James Shubin Date: Sat, 29 Dec 2018 01:16:58 -0500 Subject: [PATCH] engine: Add a resource copy interface and implementation If we want to copy an entire resource, we should use this helper method. --- engine/copy.go | 110 ++++++++++++++++++++++++++++++++++++++++++++ engine/resources.go | 11 +++++ 2 files changed, 121 insertions(+) create mode 100644 engine/copy.go diff --git a/engine/copy.go b/engine/copy.go new file mode 100644 index 00000000..330707a6 --- /dev/null +++ b/engine/copy.go @@ -0,0 +1,110 @@ +// Mgmt +// Copyright (C) 2013-2018+ James Shubin and the project contributors +// Written by James Shubin and the project contributors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package engine + +import ( + "fmt" + + errwrap "github.com/pkg/errors" +) + +// ResCopy copies a resource. This is the main entry point for copying a +// resource since it does all the common engine-level copying as well. +func ResCopy(r CopyableRes) (CopyableRes, error) { + res := r.Copy() + res.SetKind(r.Kind()) + res.SetName(r.Name()) + + if x, ok := r.(MetaRes); ok { + dst, ok := res.(MetaRes) + if !ok { + // programming error + panic("meta interfaces are illogical") + } + dst.SetMetaParams(x.MetaParams().Copy()) // copy b/c we have it + } + + if x, ok := r.(RefreshableRes); ok { + dst, ok := res.(RefreshableRes) + if !ok { + // programming error + panic("refresh interfaces are illogical") + } + dst.SetRefresh(x.Refresh()) // no need to copy atm + } + + // copy meta params for resources with auto edges + if x, ok := r.(EdgeableRes); ok { + dst, ok := res.(EdgeableRes) + if !ok { + // programming error + panic("autoedge interfaces are illogical") + } + dst.SetAutoEdgeMeta(x.AutoEdgeMeta()) // no need to copy atm + } + + // copy meta params for resources with auto grouping + if x, ok := r.(GroupableRes); ok { + dst, ok := res.(GroupableRes) + if !ok { + // programming error + panic("autogroup interfaces are illogical") + } + dst.SetAutoGroupMeta(x.AutoGroupMeta()) // no need to copy atm + + grouped := []GroupableRes{} + for _, g := range x.GetGroup() { + g0, ok := g.(CopyableRes) + if !ok { + return nil, fmt.Errorf("resource wasn't copyable") + } + g1, err := ResCopy(g0) + if err != nil { + return nil, err + } + g2, ok := g1.(GroupableRes) + if !ok { + return nil, fmt.Errorf("resource wasn't groupable") + } + grouped = append(grouped, g2) + } + dst.SetGroup(grouped) + } + + if x, ok := r.(RecvableRes); ok { + dst, ok := res.(RecvableRes) + if !ok { + // programming error + panic("recv interfaces are illogical") + } + dst.SetRecv(x.Recv()) // no need to copy atm + } + + if x, ok := r.(SendableRes); ok { + dst, ok := res.(SendableRes) + if !ok { + // programming error + panic("send interfaces are illogical") + } + if err := dst.Send(x.Sent()); err != nil { // no need to copy atm + return nil, errwrap.Wrapf(err, "can't copy send") + } + } + + return res, nil +} diff --git a/engine/resources.go b/engine/resources.go index 1823eb08..8e0966c1 100644 --- a/engine/resources.go +++ b/engine/resources.go @@ -255,6 +255,17 @@ type InterruptableRes interface { Interrupt() error } +// CopyableRes is an interface that a resource can implement if we want to be +// able to copy the resource to build another one. +type CopyableRes interface { + Res + + // Copy returns a new resource which has a copy of the public data. + // Don't call this directly, use engine.ResCopy instead. + // TODO: should we copy any private state or not? + Copy() CopyableRes +} + // CollectableRes is an interface for resources that support collection. It is // currently temporary until a proper API for all resources is invented. type CollectableRes interface {