Loading main.go +24 −6 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import ( "log" "os" "path" "reflect" "regexp" "runtime" "sync" Loading @@ -14,16 +15,22 @@ import ( "repositories.muehmer.net/boris.muehmer/sotatool/offline" ) // main() entry point for the program. func main() { example01() } const ( pattern = `.*\.sota` sourcedir = "data/sample/offline/savedgames" destdir = "data/sample/offline/analyse" pattern = `.*\.sota` // filename pattern for SotA savegame files sourcedir = "data/sample/offline/savedgames" // where to search destdir = "data/sample/offline/analyse" // where to write ) // getFunctionName() returns the name of a function. func getFunctionName(i interface{}) string { return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() } // Scan the `sourcedir` for `*.sota` files, and extract the JSON segements // under `destdir`. func example01() { Loading @@ -38,8 +45,10 @@ func example01() { // work on the file list tasks := []func(re *regexp.Regexp, files []os.FileInfo){processFiles001, processFiles002, processFiles003} //tasks := []func(re *regexp.Regexp, files []os.FileInfo){processFiles003} results := make(chan string, len(tasks)) for i, f := range tasks { fmt.Printf("%d. %s\n", i, getFunctionName(f)) start := time.Now() f(re, files) stop := time.Now() Loading @@ -64,7 +73,10 @@ func processFiles001(re *regexp.Regexp, files []os.FileInfo) { continue } filename := file.Name() savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) err := savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) if err != nil { fmt.Printf("* error: %v\n", err) } } } Loading @@ -81,7 +93,10 @@ func processFiles002(re *regexp.Regexp, files []os.FileInfo) { wg.Add(1) go func(filename string) { defer wg.Done() savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) err := savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) if err != nil { fmt.Printf("* error: %v\n", err) } }(file.Name()) } wg.Wait() Loading @@ -105,7 +120,10 @@ func processFiles003(re *regexp.Regexp, files []os.FileInfo) { go func() { defer wg.Done() filename := <-filenames savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) err := savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) if err != nil { fmt.Printf("* error: %v\n", err) } }() } wg.Wait() Loading offline/savegame.go +28 −24 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ func savegame2xml(filename string) (*data.Database, error) { if err != nil { return nil, fmt.Errorf("failed to open file %s", filename) } defer f.Close() //defer f.Close() xdec := xml.NewDecoder(f) for { Loading @@ -43,6 +43,11 @@ func savegame2xml(filename string) (*data.Database, error) { } } } if f != nil { f.Close() } return nil, fmt.Errorf("not implemented yet") } Loading Loading @@ -91,36 +96,35 @@ func DumpJSONContents(filepath string, destdir string) error { return err } fmt.Printf("file: %s\n", filename) for i, c := range database.Collections.Collection { //fmt.Printf(" - collection %s (%03d)\n", c.Name, i) for j, r := range c.Records.Record { //fmt.Printf(" - record %s (%04d)\n", r.ID, j) // beautify JSON and dump to file var msg string var result map[string]interface{} json.Unmarshal([]byte(r.DataJSON), &result) jtext, jmerr := json.MarshalIndent(result, "", " ") //_, jmerr := json.MarshalIndent(result, "", " ") if jmerr != nil { msg = fmt.Sprintf("error: %v", jmerr) } else { msg = "ok" return fmt.Errorf("error %s/%s-%d-%d: %v", filename, c.Name, i, j, jmerr) } fmt.Printf(" JSON convert: %s\n", msg) //fmt.Printf("\n\n%s\n\n", string(jtext)) if jmerr == nil { // dump to file outdirname := fmt.Sprintf("%s-%s", filename[:len(filename)-5], database.Build) outfilename := fmt.Sprintf("%03d-%s-%04d.json", i, c.Name, j) fmt.Printf(" - %s/%s\n", outdirname, outfilename) os.MkdirAll(path.Join(destdir, outdirname), os.ModeDir|0755) f, err := os.OpenFile(path.Join(destdir, outdirname, outfilename), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) defer f.Close() if err == nil { f.WriteString(string(jtext)) } newpath := path.Join(destdir, outdirname) merr := os.MkdirAll(newpath, os.ModeDir|0755) if merr != nil { return fmt.Errorf("failed to create directory \"%s\": %v", newpath, merr) } newfile := path.Join(destdir, outdirname, outfilename) f, oferr := os.OpenFile(newfile, os.O_CREATE|os.O_WRONLY, 0644) //defer f.Close() - see note below!!! if oferr != nil { return fmt.Errorf("open file \"%s\" failed: %v", newfile, oferr) } _, wserr := f.WriteString(string(jtext)) if wserr != nil { return fmt.Errorf("failed to write JSON to \"%s\": %v", newfile, wserr) } // f.Close() must NOT be deferred, because it will run out of free open file handles // very very very fast!!! if f != nil { f.Close() } } } Loading Loading
main.go +24 −6 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import ( "log" "os" "path" "reflect" "regexp" "runtime" "sync" Loading @@ -14,16 +15,22 @@ import ( "repositories.muehmer.net/boris.muehmer/sotatool/offline" ) // main() entry point for the program. func main() { example01() } const ( pattern = `.*\.sota` sourcedir = "data/sample/offline/savedgames" destdir = "data/sample/offline/analyse" pattern = `.*\.sota` // filename pattern for SotA savegame files sourcedir = "data/sample/offline/savedgames" // where to search destdir = "data/sample/offline/analyse" // where to write ) // getFunctionName() returns the name of a function. func getFunctionName(i interface{}) string { return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() } // Scan the `sourcedir` for `*.sota` files, and extract the JSON segements // under `destdir`. func example01() { Loading @@ -38,8 +45,10 @@ func example01() { // work on the file list tasks := []func(re *regexp.Regexp, files []os.FileInfo){processFiles001, processFiles002, processFiles003} //tasks := []func(re *regexp.Regexp, files []os.FileInfo){processFiles003} results := make(chan string, len(tasks)) for i, f := range tasks { fmt.Printf("%d. %s\n", i, getFunctionName(f)) start := time.Now() f(re, files) stop := time.Now() Loading @@ -64,7 +73,10 @@ func processFiles001(re *regexp.Regexp, files []os.FileInfo) { continue } filename := file.Name() savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) err := savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) if err != nil { fmt.Printf("* error: %v\n", err) } } } Loading @@ -81,7 +93,10 @@ func processFiles002(re *regexp.Regexp, files []os.FileInfo) { wg.Add(1) go func(filename string) { defer wg.Done() savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) err := savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) if err != nil { fmt.Printf("* error: %v\n", err) } }(file.Name()) } wg.Wait() Loading @@ -105,7 +120,10 @@ func processFiles003(re *regexp.Regexp, files []os.FileInfo) { go func() { defer wg.Done() filename := <-filenames savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) err := savegame.DumpJSONContents(path.Join(sourcedir, filename), destdir) if err != nil { fmt.Printf("* error: %v\n", err) } }() } wg.Wait() Loading
offline/savegame.go +28 −24 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ func savegame2xml(filename string) (*data.Database, error) { if err != nil { return nil, fmt.Errorf("failed to open file %s", filename) } defer f.Close() //defer f.Close() xdec := xml.NewDecoder(f) for { Loading @@ -43,6 +43,11 @@ func savegame2xml(filename string) (*data.Database, error) { } } } if f != nil { f.Close() } return nil, fmt.Errorf("not implemented yet") } Loading Loading @@ -91,36 +96,35 @@ func DumpJSONContents(filepath string, destdir string) error { return err } fmt.Printf("file: %s\n", filename) for i, c := range database.Collections.Collection { //fmt.Printf(" - collection %s (%03d)\n", c.Name, i) for j, r := range c.Records.Record { //fmt.Printf(" - record %s (%04d)\n", r.ID, j) // beautify JSON and dump to file var msg string var result map[string]interface{} json.Unmarshal([]byte(r.DataJSON), &result) jtext, jmerr := json.MarshalIndent(result, "", " ") //_, jmerr := json.MarshalIndent(result, "", " ") if jmerr != nil { msg = fmt.Sprintf("error: %v", jmerr) } else { msg = "ok" return fmt.Errorf("error %s/%s-%d-%d: %v", filename, c.Name, i, j, jmerr) } fmt.Printf(" JSON convert: %s\n", msg) //fmt.Printf("\n\n%s\n\n", string(jtext)) if jmerr == nil { // dump to file outdirname := fmt.Sprintf("%s-%s", filename[:len(filename)-5], database.Build) outfilename := fmt.Sprintf("%03d-%s-%04d.json", i, c.Name, j) fmt.Printf(" - %s/%s\n", outdirname, outfilename) os.MkdirAll(path.Join(destdir, outdirname), os.ModeDir|0755) f, err := os.OpenFile(path.Join(destdir, outdirname, outfilename), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) defer f.Close() if err == nil { f.WriteString(string(jtext)) } newpath := path.Join(destdir, outdirname) merr := os.MkdirAll(newpath, os.ModeDir|0755) if merr != nil { return fmt.Errorf("failed to create directory \"%s\": %v", newpath, merr) } newfile := path.Join(destdir, outdirname, outfilename) f, oferr := os.OpenFile(newfile, os.O_CREATE|os.O_WRONLY, 0644) //defer f.Close() - see note below!!! if oferr != nil { return fmt.Errorf("open file \"%s\" failed: %v", newfile, oferr) } _, wserr := f.WriteString(string(jtext)) if wserr != nil { return fmt.Errorf("failed to write JSON to \"%s\": %v", newfile, wserr) } // f.Close() must NOT be deferred, because it will run out of free open file handles // very very very fast!!! if f != nil { f.Close() } } } Loading