Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refator: unify diff util functions, remove dup implements #94

Merged
merged 1 commit into from
Jul 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 7 additions & 60 deletions pkg/engine/operation/diff.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
package operation

import (
"bytes"
"fmt"
"strings"

"kusionstack.io/kusion/pkg/engine/operation/utils"

opsmodels "kusionstack.io/kusion/pkg/engine/operation/models"

"github.com/gonvenience/wrap"
"github.com/pkg/errors"
yamlv3 "gopkg.in/yaml.v3"

"kusionstack.io/kusion/pkg/engine/models"
opsmodels "kusionstack.io/kusion/pkg/engine/operation/models"
"kusionstack.io/kusion/pkg/engine/states"
"kusionstack.io/kusion/pkg/kusionctl/cmd/diff"
"kusionstack.io/kusion/pkg/log"
"kusionstack.io/kusion/pkg/util"
"kusionstack.io/kusion/pkg/util/diff"
jsonutil "kusionstack.io/kusion/pkg/util/json"
"kusionstack.io/kusion/third_party/dyff"
)
Expand Down Expand Up @@ -65,61 +56,17 @@ func (d *Diff) Diff(request *DiffRequest) (string, error) {

func DiffWithRequestResourceAndState(plan *models.Spec, latest *states.State) (string, error) {
planString := jsonutil.MustMarshal2String(plan.Resources)
var report *dyff.Report
var err error
if latest == nil {
return DiffReport("", planString, diff.OutputHuman)
report, err = diff.ToReport("", planString)
} else {
latestResources := latest.Resources
priorString := jsonutil.MustMarshal2String(latestResources)
return DiffReport(priorString, planString, diff.OutputHuman)
}
}

func DiffReport(prior, plan, mode string) (string, error) {
from, err := utils.LoadFile(prior, "Last State")
if err != nil {
return "", err
}
to, err := utils.LoadFile(plan, "Request State")
if err != nil {
return "", err
report, err = diff.ToReport(priorString, priorString)
}

report, err := dyff.CompareInputFiles(from, to, dyff.IgnoreOrderChanges(true))
if err != nil {
return "", wrap.Errorf(err, "failed to compare input files")
}
return buildReport(mode, report)
}

func buildReport(mode string, report dyff.Report) (string, error) {
switch strings.ToLower(mode) {
case diff.OutputHuman:
return writeReport(report)
case diff.OutputRaw:
// output stdout/file
reportMap := map[string]interface{}{
"diffs": report.Diffs,
}
reportYAML, err := yamlv3.Marshal(reportMap)
if err != nil {
return "", wrap.Errorf(err, "failed to marshal report diffs")
}
return string(reportYAML), nil
default:
return "", fmt.Errorf("invalid output style `%s`", mode)
}
}

// WriteReport writes a human-readable report to the provided writer
func writeReport(report dyff.Report) (string, error) {
reportWriter := &dyff.HumanReport{
Report: report,
MinorChangeThreshold: 0.1,
}

buffer := new(bytes.Buffer)
if err := reportWriter.WriteReport(buffer); err != nil {
return "", err
}
return buffer.String(), nil
return diff.ToHumanString(diff.NewHumanReport(report))
}
2 changes: 1 addition & 1 deletion pkg/engine/operation/models/change.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (cs *ChangeStep) Diff() (string, error) {
return "", err
}

reportString, err := diff.ToReportString(*diffReport)
reportString, err := diff.ToHumanString(diff.NewHumanReport(diffReport))
if err != nil {
log.Warn("diff to string error: %v", err)
return "", err
Expand Down
27 changes: 0 additions & 27 deletions pkg/engine/operation/utils/file.go

This file was deleted.

9 changes: 2 additions & 7 deletions pkg/kusionctl/cmd/diff/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,12 @@ import (
"k8s.io/kubectl/pkg/util/templates"
"sigs.k8s.io/yaml"

diffutil "kusionstack.io/kusion/pkg/util/diff"
"kusionstack.io/kusion/pkg/util/i18n"
"kusionstack.io/kusion/third_party/diff"
"kusionstack.io/kusion/third_party/dyff"
)

// Supported output option values
const (
OutputHuman = "human"
OutputRaw = "raw"
)

var (
diffShort = "Compare differences between input files <from> and <to>"

Expand Down Expand Up @@ -78,7 +73,7 @@ func NewCmdDiff() *cobra.Command {
cmd.Flags().StringVar(&o.diffMode, "diff-mode", "normal",
i18n.T(fmt.Sprintf("Diff mode. One of %s and %s. The default is normal", DiffModeNormal, DiffModeIgnoreAdded)))
cmd.Flags().StringVarP(&o.outStyle, "output", "o", "human",
i18n.T(fmt.Sprintf("Specify the output style. One of %s and %s. The default is human", OutputHuman, OutputRaw)))
i18n.T(fmt.Sprintf("Specify the output style. One of %s and %s. The default is human", diffutil.OutputHuman, diffutil.OutputRaw)))
cmd.Flags().BoolVarP(&o.ignoreOrderChanges, "ignore-order-changes", "i", false,
i18n.T("Ignore order changes in lists. The default is false"))
cmd.Flags().BoolVarP(&o.omitHeader, "omit-header", "b", false,
Expand Down
5 changes: 3 additions & 2 deletions pkg/kusionctl/cmd/diff/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

diffutil "kusionstack.io/kusion/pkg/util/diff"
"kusionstack.io/kusion/third_party/diff"
)

Expand Down Expand Up @@ -84,7 +85,7 @@ func TestNewCmdDiff(t *testing.T) {
t.Run("diff by files with flags", func(t *testing.T) {
cmd := NewCmdDiff()
assert.Nil(t, cmd.Flags().Set("diff-mode", DiffModeIgnoreAdded))
assert.Nil(t, cmd.Flags().Set("output", OutputRaw))
assert.Nil(t, cmd.Flags().Set("output", diffutil.OutputRaw))
assert.Nil(t, cmd.Flags().Set("sort-by-kubernetes-resource", "true"))
assert.Nil(t, cmd.Flags().Set("swap", "true"))
cmd.SetArgs([]string{"testdata/pod1.yaml", "testdata/pod2.yaml"})
Expand All @@ -106,7 +107,7 @@ func TestNewCmdDiff(t *testing.T) {

cmd := NewCmdDiff()
assert.Nil(t, cmd.Flags().Set("diff-mode", DiffModeIgnoreAdded))
assert.Nil(t, cmd.Flags().Set("output", OutputRaw))
assert.Nil(t, cmd.Flags().Set("output", diffutil.OutputRaw))
assert.Nil(t, cmd.Flags().Set("sort-by-kubernetes-resource", "true"))
assert.Nil(t, cmd.Flags().Set("swap", "true"))
cmd.SetArgs([]string{"testdata/pod-full.yaml"})
Expand Down
43 changes: 11 additions & 32 deletions pkg/kusionctl/cmd/diff/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package diff

import (
"fmt"
"os"
"sort"
"strings"

"github.com/gonvenience/wrap"
"github.com/gonvenience/ytbx"
yamlv3 "gopkg.in/yaml.v3"

diffutil "kusionstack.io/kusion/pkg/util/diff"
"kusionstack.io/kusion/third_party/dyff"
)

Expand Down Expand Up @@ -79,8 +80,8 @@ func (o *DiffOptions) Validate() error {
}

switch strings.ToLower(o.outStyle) {
case OutputHuman:
case OutputRaw:
case diffutil.OutputHuman:
case diffutil.OutputRaw:
break
default:
return fmt.Errorf("invalid output style `%s`", o.outStyle)
Expand Down Expand Up @@ -166,41 +167,19 @@ func (o *DiffOptions) Run() error {
}

// handle output option
switch strings.ToLower(o.outStyle) {
case OutputHuman:
return o.writeReport(report)
case OutputRaw:
// output stdout/file
reportMap := map[string]interface{}{
"diffs": report.Diffs,
}

reportYAML, err := yamlv3.Marshal(reportMap)
if err != nil {
return wrap.Errorf(err, "failed to marshal report diffs")
}

fmt.Println(string(reportYAML))

return nil
}

return nil
}

func (o *DiffOptions) writeReport(report dyff.Report) error {
reportWriter := &dyff.HumanReport{
Report: report,
DoNotInspectCerts: o.doNotInspectCerts,
humanReport := &dyff.HumanReport{
NoTableStyle: o.noTableStyle,
DoNotInspectCerts: o.doNotInspectCerts,
OmitHeader: o.omitHeader,
UseGoPatchPaths: o.useGoPatchPaths,
MinorChangeThreshold: 0.1,
Report: report,
}

if err := reportWriter.WriteReport(os.Stdout); err != nil {
return wrap.Errorf(err, "failed to print report")
reportString, err := diffutil.ToReportString(humanReport, o.outStyle)
if err != nil {
return err
}
fmt.Println(reportString)

return nil
}
103 changes: 103 additions & 0 deletions pkg/util/diff/diff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package diff

import (
"bytes"
"fmt"

"github.com/gonvenience/wrap"
"github.com/gonvenience/ytbx"
yamlv3 "gopkg.in/yaml.v3"

"kusionstack.io/kusion/pkg/util/yaml"
"kusionstack.io/kusion/third_party/dyff"
)

// Supported output option values
const (
OutputHuman = "human"
OutputRaw = "raw"
)

// NewHumanReport return a default *dyff.HumanReport with head omitted
func NewHumanReport(report *dyff.Report) *dyff.HumanReport {
return &dyff.HumanReport{
NoTableStyle: false,
DoNotInspectCerts: false,
OmitHeader: true,
UseGoPatchPaths: false,
MinorChangeThreshold: 0.1,
Report: *report,
}
}

// ToReportString return a report string base on mode, valid mode: "human" and "raw"
func ToReportString(humanReport *dyff.HumanReport, mode string) (string, error) {
switch mode {
case OutputHuman:
return ToHumanString(humanReport)
case OutputRaw:
return ToRawString(humanReport)
default:
return "", fmt.Errorf("invalid output style `%s`", mode)
}
}

func ToHumanString(humanReport *dyff.HumanReport) (string, error) {
buf := bytes.NewBuffer([]byte{})
err := humanReport.WriteReport(buf)
if err != nil {
return "", err
}
return buf.String(), nil
}

func ToRawString(humanReport *dyff.HumanReport) (string, error) {
reportMap := map[string]interface{}{
"diffs": humanReport.Diffs,
}
reportYAML, err := yamlv3.Marshal(reportMap)
if err != nil {
return "", wrap.Errorf(err, "failed to marshal report diffs")
}
return string(reportYAML), nil
}

// ToReport compares objects, oldData and newData,
// and returns a report with the list of differences.
func ToReport(oldData, newData interface{}) (*dyff.Report, error) {
from, err := LoadFile(yaml.MergeToOneYAML(oldData), "Old item")
if err != nil {
return nil, err
}

to, err := LoadFile(yaml.MergeToOneYAML(newData), "New item")
if err != nil {
return nil, err
}

report, err := dyff.CompareInputFiles(from, to, dyff.IgnoreOrderChanges(true))
if err != nil {
return nil, err
}
return &report, nil
}

// LoadFile reads the provided input data slice as a YAML, JSON, or TOML
// file with potential multiple documents.
func LoadFile(input, location string) (ytbx.InputFile, error) {
var (
documents []*yamlv3.Node
data []byte
err error
)

data = []byte(input)
if documents, err = ytbx.LoadDocuments(data); err != nil {
return ytbx.InputFile{}, wrap.Errorf(err, "unable to parse data %v", data)
}

return ytbx.InputFile{
Location: location,
Documents: documents,
}, nil
}
Loading