Skip to content

Commit 168b8c1

Browse files
committed
state file support
1 parent d7aeffe commit 168b8c1

File tree

4 files changed

+90
-18
lines changed

4 files changed

+90
-18
lines changed

flow/cascade.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,23 @@ func Cascade(outer dynaml.Binding, template yaml.Node, partial bool, stubs ...ya
3434
return Apply(outer, template, prepared)
3535
}
3636

37-
func discardTemporary(node yaml.Node) yaml.Node {
37+
func discardTemporary(node yaml.Node) (yaml.Node, CleanupFunction) {
3838
if node.Temporary() || node.Local() {
39-
return nil
39+
return nil, discardTemporary
4040
}
41-
return node
41+
return node, discardTemporary
4242
}
43-
func discardLocal(node yaml.Node) yaml.Node {
43+
44+
func discardLocal(node yaml.Node) (yaml.Node, CleanupFunction) {
4445
if node.Local() {
45-
return nil
46+
return nil, discardLocal
4647
}
47-
return node
48+
return node, discardLocal
4849
}
4950

50-
func Cleanup(node yaml.Node, test func(yaml.Node) yaml.Node) yaml.Node {
51+
type CleanupFunction func(yaml.Node) (yaml.Node, CleanupFunction)
52+
53+
func Cleanup(node yaml.Node, test CleanupFunction) yaml.Node {
5154
if node == nil {
5255
return nil
5356
}
@@ -56,17 +59,17 @@ func Cleanup(node yaml.Node, test func(yaml.Node) yaml.Node) yaml.Node {
5659
case []yaml.Node:
5760
r := []yaml.Node{}
5861
for _, e := range v {
59-
if n := test(e); n != nil {
60-
r = append(r, Cleanup(n, test))
62+
if n, t := test(e); n != nil {
63+
r = append(r, Cleanup(n, t))
6164
}
6265
}
6366
value = r
6467

6568
case map[string]yaml.Node:
6669
r := map[string]yaml.Node{}
6770
for k, e := range v {
68-
if n := test(e); n != nil {
69-
r[k] = Cleanup(n, test)
71+
if n, t := test(e); n != nil {
72+
r[k] = Cleanup(n, t)
7073
}
7174
}
7275
value = r

flow/environment.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,9 @@ type Updateable interface {
282282
Deactivate() dynaml.Binding
283283
}
284284

285-
func updateBinding(root yaml.Node) func(yaml.Node) yaml.Node {
286-
return func(node yaml.Node) yaml.Node {
285+
func updateBinding(root yaml.Node) CleanupFunction {
286+
var me CleanupFunction
287+
me = func(node yaml.Node) (yaml.Node, CleanupFunction) {
287288
if v := node.Value(); v != nil {
288289
if static, ok := v.(dynaml.StaticallyScopedValue); ok {
289290
debug.Debug("update found static scoped %q\n", static)
@@ -304,20 +305,21 @@ func updateBinding(root yaml.Node) func(yaml.Node) yaml.Node {
304305
}
305306
}
306307
}
307-
return node
308+
return node, me
308309
}
310+
return me
309311
}
310312

311-
func deactivateScopes(node yaml.Node) yaml.Node {
313+
func deactivateScopes(node yaml.Node) (yaml.Node, CleanupFunction) {
312314
if v := node.Value(); v != nil {
313315
if lambda, ok := v.(dynaml.StaticallyScopedValue); ok {
314316
debug.Debug("deactivate statically scoped node %q\n", lambda)
315317
if env := lambda.StaticResolver().(Updateable); env.Active() {
316-
return yaml.ReplaceValue(lambda.SetStaticResolver(env.Deactivate()), node)
318+
return yaml.ReplaceValue(lambda.SetStaticResolver(env.Deactivate()), node), deactivateScopes
317319
}
318320
}
319321
}
320-
return node
322+
return node, deactivateScopes
321323
}
322324

323325
func resolveSymbol(env *DefaultEnvironment, name string, scope *Scope) (yaml.Node, bool, *Scope) {

spiff++.go

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func main() {
5252
Name: "path",
5353
Usage: "output is taken from given path",
5454
},
55+
cli.StringFlag{
56+
Name: "state",
57+
Usage: "select state file to maintain",
58+
},
5559
cli.StringSliceFlag{
5660
Name: "select",
5761
Usage: "filter dedicated output fields",
@@ -67,6 +71,7 @@ func main() {
6771
merge(c.Args()[0], c.Bool("partial"),
6872
c.Bool("json"), c.Bool("split"),
6973
c.String("path"), c.StringSlice("select"),
74+
c.String("state"),
7075
c.Args()[1:])
7176
},
7277
},
@@ -116,7 +121,27 @@ func main() {
116121
app.Run(os.Args)
117122
}
118123

119-
func merge(templateFilePath string, partial bool, json, split bool, subpath string, selection []string, stubFilePaths []string) {
124+
func keepAll(node yaml.Node) (yaml.Node, flow.CleanupFunction) {
125+
return node, keepAll
126+
}
127+
128+
func discardNonState(node yaml.Node) (yaml.Node, flow.CleanupFunction) {
129+
if node.State() {
130+
return node, keepAll
131+
}
132+
return nil, discardNonState
133+
}
134+
135+
func fileExists(filename string) bool {
136+
info, err := os.Stat(filename)
137+
if os.IsNotExist(err) {
138+
return false
139+
}
140+
return !info.IsDir()
141+
}
142+
143+
func merge(templateFilePath string, partial bool, json, split bool,
144+
subpath string, selection []string, stateFilePath string, stubFilePaths []string) {
120145
var templateFile []byte
121146
var err error
122147
var stdin = false
@@ -137,6 +162,17 @@ func merge(templateFilePath string, partial bool, json, split bool, subpath stri
137162
log.Fatalln(fmt.Sprintf("error parsing template [%s]:", path.Clean(templateFilePath)), err)
138163
}
139164

165+
var stateData []byte
166+
167+
if stateFilePath != "" {
168+
if len(templateYAMLs) > 1 {
169+
log.Fatalln(fmt.Sprintf("state handling not supported gor multi documents [%s]:", path.Clean(templateFilePath)), err)
170+
}
171+
if fileExists(stateFilePath) {
172+
stateData, err = ioutil.ReadFile(stateFilePath)
173+
}
174+
}
175+
140176
stubs := []yaml.Node{}
141177

142178
for _, stubFilePath := range stubFilePaths {
@@ -163,6 +199,14 @@ func merge(templateFilePath string, partial bool, json, split bool, subpath stri
163199
stubs = append(stubs, stubYAML)
164200
}
165201

202+
if stateData != nil {
203+
stateYAML, err := yaml.Parse(stateFilePath, stateData)
204+
if err != nil {
205+
log.Fatalln(fmt.Sprintf("error parsing state [%s]:", path.Clean(stateFilePath)), err)
206+
}
207+
stubs = append(stubs, stateYAML)
208+
}
209+
166210
legend := "\nerror classification:\n" +
167211
" *: error in local dynaml expression\n" +
168212
" @: dependent of or involved in a cycle\n" +
@@ -198,6 +242,28 @@ func merge(templateFilePath string, partial bool, json, split bool, subpath stri
198242
}
199243
flowed = node
200244
}
245+
if stateFilePath != "" {
246+
state := flow.Cleanup(flowed, discardNonState)
247+
if json {
248+
bytes, err = yaml.ToJSON(state)
249+
} else {
250+
bytes, err = candiedyaml.Marshal(state)
251+
}
252+
old := false
253+
if fileExists(stateFilePath) {
254+
os.Rename(stateFilePath, stateFilePath+".bak")
255+
old = true
256+
}
257+
err := ioutil.WriteFile(stateFilePath, bytes, 0664)
258+
if err != nil {
259+
os.Remove(stateFilePath)
260+
os.Remove(stateFilePath)
261+
if old {
262+
os.Rename(stateFilePath+".bak", stateFilePath)
263+
}
264+
log.Fatalln(fmt.Sprintf("cannot write state file %q", stateFilePath))
265+
}
266+
}
201267
if len(selection) > 0 {
202268
new := map[string]yaml.Node{}
203269
for _, p := range selection {

yaml/node.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type Node interface {
2323
Flags() NodeFlags
2424
Temporary() bool
2525
Local() bool
26+
State() bool
2627
ReplaceFlag() bool
2728
Preferred() bool
2829
Merged() bool

0 commit comments

Comments
 (0)