@@ -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 := "\n error 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 {
0 commit comments