forked from tronprotocol/tron-deployment
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdiff.go
More file actions
155 lines (135 loc) · 3.98 KB
/
Copy pathdiff.go
File metadata and controls
155 lines (135 loc) · 3.98 KB
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package config
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
"github.com/tronprotocol/tron-deployment/internal/intent"
"github.com/tronprotocol/tron-deployment/internal/output"
"github.com/tronprotocol/tron-deployment/internal/paths"
"github.com/tronprotocol/tron-deployment/internal/render"
"github.com/tronprotocol/tron-deployment/internal/state"
)
var diffCmd = &cobra.Command{
Use: "diff <intent-path>",
Short: "Show differences between rendered and deployed config",
Args: cobra.ExactArgs(1),
RunE: runDiff,
}
func init() {
Cmd.AddCommand(diffCmd)
}
func runDiff(cmd *cobra.Command, args []string) error {
intentPath := args[0]
outputFmt, _ := cmd.Flags().GetString("output")
parsed, err := intent.Load(intentPath)
if err != nil {
return output.NewError("VALIDATION_ERROR", output.ExitValidationError, err.Error())
}
// Render new config
templateDir := findTemplateDir()
node := &parsed.Nodes[0]
rendered, err := render.RenderHOCONWithSecrets(templateDir, parsed, node)
if err != nil {
return output.NewError("RENDER_ERROR", output.ExitGeneralError, err.Error())
}
// Compare the REAL bytes against the deployed file so a rotated
// witness key still shows up as a difference; simpleDiff redacts
// each line as it emits it, so no key reaches stdout or the JSON.
newConfig := rendered.Deployable()
// Load deployed config from state
store, err := state.NewStore(paths.State())
if err != nil {
return err
}
deployState, err := store.Load()
if err != nil {
return err
}
existing := store.GetNode(deployState, parsed.Name)
if existing == nil {
if outputFmt == "json" {
output.WriteJSON(os.Stdout, map[string]any{
"name": parsed.Name,
"status": "new",
"message": "Node not yet deployed; entire config is new",
})
} else {
fmt.Printf("Node %q not yet deployed. Entire config will be new.\n", parsed.Name)
}
return nil
}
// Try to read the deployed config
deployedConfigPath := filepath.Join(paths.Deployments(), parsed.Name, parsed.Name+".conf")
deployedData, err := os.ReadFile(deployedConfigPath)
if err != nil {
if outputFmt == "json" {
output.WriteJSON(os.Stdout, map[string]any{
"name": parsed.Name,
"status": "unknown",
"message": "Could not read deployed config for comparison",
})
} else {
fmt.Printf("Could not read deployed config at %s\n", deployedConfigPath)
}
return nil
}
oldLines := strings.Split(string(deployedData), "\n")
newLines := strings.Split(newConfig, "\n")
diffs := simpleDiff(oldLines, newLines)
if outputFmt == "json" {
output.WriteJSON(os.Stdout, map[string]any{
"name": parsed.Name,
"has_changes": len(diffs) > 0,
"diff_count": len(diffs),
"diffs": diffs,
})
} else {
if len(diffs) == 0 {
fmt.Println("No config differences.")
} else {
for _, d := range diffs {
fmt.Println(d)
}
}
}
return nil
}
// simpleDiff does a basic line-by-line comparison.
//
// Secret handling: comparison uses the raw lines so genuine drift is
// still reported, but every emitted line goes through
// render.RedactWitnessLine first. The comparison is positional and
// LCS-free, so any line-count change above the `localwitness`
// assignment misaligns the tail and would otherwise print the SR
// private key into `diffs[]`.
func simpleDiff(old, new []string) []string {
// Redact whole-slice: a multi-line `localwitness = [` array keeps its
// key on a line that does not itself start with the key name.
oldR := render.RedactWitnessLines(old)
newR := render.RedactWitnessLines(new)
var diffs []string
maxLen := len(old)
if len(new) > maxLen {
maxLen = len(new)
}
for i := 0; i < maxLen; i++ {
var oldLine, newLine string
if i < len(old) {
oldLine = old[i]
}
if i < len(new) {
newLine = new[i]
}
if oldLine != newLine {
if oldLine != "" {
diffs = append(diffs, fmt.Sprintf("- %s", oldR[i]))
}
if newLine != "" {
diffs = append(diffs, fmt.Sprintf("+ %s", newR[i]))
}
}
}
return diffs
}