/
diff.go
121 lines (105 loc) · 2.38 KB
/
diff.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package util
import (
"encoding/json"
"fmt"
"github.com/rogpeppe/go-internal/diff"
"reflect"
)
const (
DiffAdd string = "add"
DiffDel string = "delete"
DiffMod string = "modify"
DiffEq string = "eq"
)
type DiffMarshaler interface {
MarshalForDiff() ([]byte, *Result)
}
type Diff struct {
From []byte `json:"-" yaml:"-"`
To []byte `json:"-" yaml:"-"`
Type string `json:"type" yaml:"type"`
Path string `json:"path" yaml:"path"`
Diff string `json:"diff" yaml:"diff"`
}
func (d *Diff) String() string {
return fmt.Sprintf("---------- START %s Path [%s] -------------\n%s---------- END %s Path [%s] -------------",
d.Type, d.Path, d.Diff, d.Type, d.Path)
}
func NewDiff(path string, from, to DiffMarshaler) (*Diff, *Result) {
if from != nil && (reflect.ValueOf(from).Kind() == reflect.Ptr && reflect.ValueOf(from).IsNil()) {
from = nil
}
if to != nil && (reflect.ValueOf(to).Kind() == reflect.Ptr && reflect.ValueOf(to).IsNil()) {
to = nil
}
if from == to {
return nil, nil
}
var fromBuf, toBuf []byte
var res *Result
if from != nil {
fromBuf, res = from.MarshalForDiff()
if res != nil {
return nil, res.With("from.MarshalForDiff")
}
fromBuf = append(fromBuf, '\n')
}
if to != nil {
toBuf, res = to.MarshalForDiff()
if res != nil {
return nil, res.With("to.MarshalForDiff")
}
toBuf = append(toBuf, '\n')
}
diffBuf := diff.Diff("left", fromBuf, "right", toBuf)
if len(diffBuf) == 0 {
return nil, nil
}
d := Diff{
From: fromBuf,
To: toBuf,
Path: path,
Diff: string(diffBuf),
}
if from == nil && to != nil {
d.Type = DiffAdd
} else if to == nil && from != nil {
d.Type = DiffDel
} else {
d.Type = DiffMod
}
return &d, nil
}
func NewJsonDiff[T any](path string, from, to *T) (*Diff, *Result) {
if from == to {
return nil, nil
}
fromBuf, err := json.MarshalIndent(from, "", " ")
if err != nil {
return nil, Error("MarshalFrom", err)
}
fromBuf = append(fromBuf, '\n')
toBuf, err := json.MarshalIndent(to, "", " ")
if err != nil {
return nil, Error("MarshalTo", err)
}
toBuf = append(toBuf, '\n')
diffBuf := diff.Diff("left", fromBuf, "right", toBuf)
if diffBuf == nil || len(diffBuf) == 0 {
return nil, nil
}
d := Diff{
From: fromBuf,
To: toBuf,
Path: path,
Diff: string(diffBuf),
}
if from == nil {
d.Type = DiffAdd
} else if to == nil {
d.Type = DiffDel
} else {
d.Type = DiffMod
}
return &d, nil
}