Skip to content

Commit

Permalink
Re-implement render UI using terminal UI components (based on PTerm…
Browse files Browse the repository at this point in the history
….sh) (#430)
  • Loading branch information
ezodude committed Mar 30, 2021
1 parent 1353ecf commit 28b36df
Show file tree
Hide file tree
Showing 19 changed files with 815 additions and 801 deletions.
42 changes: 10 additions & 32 deletions cmd/kev/cmd/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
package cmd

import (
"os"

"github.com/appvia/kev/pkg/kev"
"github.com/appvia/kev/pkg/kev/log"
"github.com/spf13/cobra"
)

Expand All @@ -38,20 +35,7 @@ var renderCmd = &cobra.Command{
Use: "render",
Short: "Generates application's deployment artefacts according to the specified output format for a given environment (ALL environments by default).",
Long: renderLongDesc,
PreRunE: func(cmd *cobra.Command, args []string) error {
fns := []func(cmd *cobra.Command, args []string) error{
runReconcileCmd,
runDetectSecretsCmd,
}
for _, fn := range fns {
if err := fn(cmd, args); err != nil {
return err
}
os.Stdout.Write([]byte("\n"))
}
return nil
},
RunE: runRenderCmd,
RunE: runRenderCmd,
}

func init() {
Expand Down Expand Up @@ -90,8 +74,6 @@ func init() {
}

func runRenderCmd(cmd *cobra.Command, _ []string) error {
cmdName := "Render"

format, err := cmd.Flags().GetString("format")
singleFile, err := cmd.Flags().GetBool("single")
dir, err := cmd.Flags().GetString("dir")
Expand All @@ -103,19 +85,15 @@ func runRenderCmd(cmd *cobra.Command, _ []string) error {
}

setReporting(verbose)
displayCmdStarted(cmdName)

workingDir, err := os.Getwd()
if err != nil {
return displayError(err)
}

log.DebugTitlef("Output format: %s", format)
if err := kev.Render(workingDir, format, singleFile, dir, envs, nil); err != nil {
return displayError(err)
}

os.Stdout.Write([]byte("\n"))
// The working directory is always the current directory.
// This ensures created manifest yaml entries are portable between users and require no path fixing.
wd := "."

return nil
return kev.RenderProjectWithOptions(wd,
kev.WithManifestFormat(format),
kev.WithManifestsAsSingleFile(singleFile),
kev.WithOutputDir(dir),
kev.WithEnvs(envs),
)
}
482 changes: 0 additions & 482 deletions go.sum

Large diffs are not rendered by default.

161 changes: 37 additions & 124 deletions pkg/kev/changeset.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package kev

import (
"fmt"
"reflect"

"github.com/appvia/kev/pkg/kev/config"
Expand All @@ -29,113 +30,6 @@ const (
DELETE = "delete"
)

// newChangeset detects all changes between a destination override and source override.
// A change is either a create, update or delete event.
// A change targets an override's version, services or volumes and it's properties will depend on the actual target.
// Example: here's a Change that creates a new service:
// {
// Type: "create", //string
// Value: srcSvc, //interface{} in this case: ServiceConfig
// }
// Example: here's a Change that updates a service's label:
// {
// Type: "update", //string
// Index: index, // interface{} in this case: int
// Parent: "labels", // string
// Target: config.LabelServiceType, // string
// Value: srcSvc.GetLabels()[config.LabelServiceType], // interface{} in this case: string
// }
//
// ENV VARS NOTE:
// The changeset deals with the docker-compose `environment` attribute as a special case:
// - Env vars in overrides override a project's docker-compose env vars.
// - A changeset will ONLY REMOVE an env var if it is removed from a project's docker-compose env vars.
// - A changeset will NOT update or create env vars in deployment environments.
// - To create useful diffs a project's docker-compose env vars will be taken into account.
func newChangeset(dst *composeOverride, src *composeOverride) changeset {
cset := changeset{}
detectVersionUpdate(dst, src, &cset)
detectServicesCreate(dst, src, &cset)
detectServicesDelete(dst, src, &cset)
detectServicesEnvironmentDelete(dst, src, &cset)
detectVolumesCreate(dst, src, &cset)
detectVolumesDelete(dst, src, &cset)
return cset
}

func detectVersionUpdate(dst *composeOverride, src *composeOverride, cset *changeset) {
if dst.Version != src.Version {
cset.version = change{Value: src.Version, Type: UPDATE, Target: "version"}
}
}

func detectServicesCreate(dst *composeOverride, src *composeOverride, cset *changeset) {
dstSvcSet := dst.Services.Set()
for _, srcSvc := range src.Services {
if !dstSvcSet[srcSvc.Name] {
cset.services = append(cset.services, change{
Type: CREATE,
Value: srcSvc.minusEnvVars(),
})
}
}
}

func detectServicesDelete(dst *composeOverride, src *composeOverride, cset *changeset) {
srcSvcSet := src.Services.Set()
for index, dstSvc := range dst.Services {
if !srcSvcSet[dstSvc.Name] {
cset.services = append(cset.services, change{
Type: DELETE,
Index: index,
})
}
}
}

func detectServicesEnvironmentDelete(dst *composeOverride, src *composeOverride, cset *changeset) {
srcSvcMapping := src.Services.Map()
for index, dstSvc := range dst.Services {
srcSvc, ok := srcSvcMapping[dstSvc.Name]
if !ok {
continue
}
for envVarKey := range dstSvc.Environment {
if _, ok := srcSvc.Environment[envVarKey]; !ok {
cset.services = append(cset.services, change{
Type: DELETE,
Index: index,
Parent: "environment",
Target: envVarKey,
})
}
}
}
}

func detectVolumesCreate(dst *composeOverride, src *composeOverride, cset *changeset) {
for srcVolKey, srcVolConfig := range src.Volumes {
if _, ok := dst.Volumes[srcVolKey]; !ok {
cset.volumes = append(cset.volumes, change{
Type: CREATE,
Index: srcVolKey,
Value: srcVolConfig,
})
}
}
}

func detectVolumesDelete(dst *composeOverride, src *composeOverride, cset *changeset) {
for dstVolKey := range dst.Volumes {
if _, ok := src.Volumes[dstVolKey]; !ok {
cset.volumes = append(cset.volumes, change{
Type: DELETE,
Index: dstVolKey,
})
}
}
}

// changes returns a flat list of all available changes
func (cset changeset) changes() []change {
var out []change
Expand All @@ -152,51 +46,64 @@ func (cset changeset) HasNoPatches() bool {
return len(cset.changes()) <= 0
}

func (cset changeset) applyVersionPatchesIfAny(o *composeOverride) {
func (cset changeset) applyVersionPatchesIfAny(o *composeOverride) string {
chg := cset.version
if reflect.DeepEqual(chg, change{}) {
return
return ""
}
chg.patchVersion(o)
return chg.patchVersion(o)
}

func (cset changeset) applyServicesPatchesIfAny(o *composeOverride) {
func (cset changeset) applyServicesPatchesIfAny(o *composeOverride) []string {
var out []string
for _, change := range cset.services {
change.patchService(o)
out = append(out, change.patchService(o))
}
return out
}

func (cset changeset) applyVolumesPatchesIfAny(o *composeOverride) {
func (cset changeset) applyVolumesPatchesIfAny(o *composeOverride) []string {
var out []string
for _, change := range cset.volumes {
change.patchVolume(o)
out = append(out, change.patchVolume(o))
}
return out
}

func (chg change) patchVersion(override *composeOverride) {
func (chg change) patchVersion(override *composeOverride) string {
if chg.Type != UPDATE {
return
return ""
}
pre := override.Version
newValue := chg.Value.(string)
override.Version = newValue
log.Debugf("version updated, from:[%s] to:[%s]", pre, newValue)

msg := fmt.Sprintf("version %s updated to %s", pre, newValue)
log.Debugf(msg)
return msg
}

func (chg change) patchService(override *composeOverride) {
func (chg change) patchService(override *composeOverride) string {
switch chg.Type {
case CREATE:
newValue := chg.Value.(ServiceConfig).condenseLabels(config.BaseServiceLabels)
override.Services = append(override.Services, newValue)
log.Debugf("service [%s] added", newValue.Name)
msg := fmt.Sprintf("added service: %s", newValue.Name)
log.Debugf(msg)
return msg
case DELETE:
switch {
case chg.Parent == "environment":
delete(override.Services[chg.Index.(int)].Environment, chg.Target)
log.Debugf("service [%s], env var [%s] deleted", override.Services[chg.Index.(int)].Name, chg.Target)
msg := fmt.Sprintf("removed env var: %s from service %s", chg.Target, override.Services[chg.Index.(int)].Name)
log.Debugf(msg)
return msg
default:
deletedSvcName := override.Services[chg.Index.(int)].Name
override.Services = append(override.Services[:chg.Index.(int)], override.Services[chg.Index.(int)+1:]...)
log.Debugf("service [%s] deleted", deletedSvcName)
msg := fmt.Sprintf("removed service: %s", deletedSvcName)
log.Debugf(msg)
return msg
}
case UPDATE:
if chg.Parent == "labels" {
Expand All @@ -208,16 +115,22 @@ func (chg change) patchService(override *composeOverride) {
}
}
}
return ""
}

func (chg change) patchVolume(override *composeOverride) {
func (chg change) patchVolume(override *composeOverride) string {
switch chg.Type {
case CREATE:
newValue := chg.Value.(VolumeConfig).condenseLabels(config.BaseVolumeLabels)
override.Volumes[chg.Index.(string)] = newValue
log.Debugf("volume [%s] added", chg.Index.(string))
msg := fmt.Sprintf("added volume: %s", chg.Index.(string))
log.Debugf(msg)
return msg
case DELETE:
delete(override.Volumes, chg.Index.(string))
log.Debugf("volume [%s] deleted", chg.Index.(string))
msg := fmt.Sprintf("removed volume: %s", chg.Index.(string))
log.Debugf(msg)
return msg
}
return ""
}
8 changes: 6 additions & 2 deletions pkg/kev/converter/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package converter
import (
"github.com/appvia/kev/pkg/kev/converter/dummy"
"github.com/appvia/kev/pkg/kev/converter/kubernetes"
kmd "github.com/appvia/komando"
composego "github.com/compose-spec/compose-go/types"
)

Expand All @@ -34,13 +35,16 @@ type Converter interface {
}

// Factory returns a converter
func Factory(name string) Converter {
func Factory(name string, ui kmd.UI) Converter {
switch name {
case "dummy":
// Dummy converter example
return dummy.New()
default:
// Kubernetes manifests converter by default
return kubernetes.New()
if ui == nil {
return kubernetes.New()
}
return kubernetes.NewWithUI(ui)
}
}
Loading

0 comments on commit 28b36df

Please sign in to comment.