go-hep.org/x/hep@v0.38.1/cmd/root2yoda/main.go (about) 1 // Copyright ©2017 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // root2yoda converts ROOT files containing hbook-like values (H1D, H2D, ...) 6 // into YODA files. 7 // 8 // Example: 9 // 10 // $> root2yoda file1.root file2.root > out.yoda 11 // $> root2yoda -o out.yoda file1.root file2.root 12 // $> root2yoda -o out.yoda.gz file1.root file2.root 13 package main // import "go-hep.org/x/hep/cmd/root2yoda" 14 15 import ( 16 "compress/gzip" 17 "flag" 18 "fmt" 19 "io" 20 "log" 21 "os" 22 "path/filepath" 23 24 "go-hep.org/x/hep/groot" 25 "go-hep.org/x/hep/groot/riofs" 26 _ "go-hep.org/x/hep/groot/riofs/plugin/http" 27 _ "go-hep.org/x/hep/groot/riofs/plugin/xrootd" 28 "go-hep.org/x/hep/hbook/yodacnv" 29 ) 30 31 func main() { 32 log.SetFlags(0) 33 log.SetPrefix("root2yoda: ") 34 35 flag.Usage = func() { 36 fmt.Fprintf( 37 os.Stderr, 38 `Usage: root2yoda [options] file1.root [file2.root [...]] > out.yoda 39 40 ex: 41 $> root2yoda file1.root file2.root > out.yoda 42 $> root2yoda -o out.yoda file1.root file2.root 43 $> root2yoda -o out.yoda.gz file1.root file2.root 44 45 options: 46 `, 47 ) 48 flag.PrintDefaults() 49 } 50 51 oname := flag.String("o", "", "path to YODA output file") 52 53 flag.Parse() 54 55 if flag.NArg() < 1 { 56 log.Printf("missing input ROOT file name(s)") 57 flag.Usage() 58 flag.PrintDefaults() 59 } 60 61 var out io.WriteCloser = os.Stdout 62 if *oname != "" { 63 f, err := os.Create(*oname) 64 if err != nil { 65 log.Fatal(err) 66 } 67 defer func() { 68 err = f.Close() 69 if err != nil { 70 log.Fatal(err) 71 } 72 }() 73 out = f 74 if filepath.Ext(*oname) == ".gz" { 75 wz := gzip.NewWriter(f) 76 defer func() { 77 err = wz.Close() 78 if err != nil { 79 log.Fatal(err) 80 } 81 }() 82 out = wz 83 } 84 } else { 85 defer out.Close() 86 } 87 88 for _, fname := range flag.Args() { 89 log.Printf("processing %s\n", fname) 90 f, err := groot.Open(fname) 91 if err != nil { 92 log.Fatalf("failed to open [%s]: %v\n", fname, err) 93 } 94 defer f.Close() 95 for _, k := range uniq(f.Keys()) { 96 walk(out, k) 97 } 98 } 99 100 err := out.Close() 101 if err != nil { 102 log.Fatalf("error closing output file: %v\n", err) 103 } 104 } 105 106 func walk(w io.Writer, k riofs.Key) { 107 obj := k.Value() 108 switch obj := obj.(type) { 109 case riofs.Directory: 110 for _, k := range uniq(obj.Keys()) { 111 walk(w, k) 112 } 113 case yodacnv.Marshaler: 114 raw, err := obj.MarshalYODA() 115 if err != nil { 116 log.Fatalf("root2yoda: error converting %v: %v", k.Name(), err) 117 } 118 _, err = w.Write(raw) 119 if err != nil { 120 log.Fatalf("root2yoda: error writing %v: %v", k.Name(), err) 121 } 122 } 123 } 124 125 func uniq(keys []riofs.Key) []riofs.Key { 126 set := make(map[string]riofs.Key, len(keys)) 127 for _, k := range keys { 128 kk, dup := set[k.Name()] 129 if dup && kk.Cycle() > k.Cycle() { 130 continue 131 } 132 set[k.Name()] = k 133 } 134 out := make([]riofs.Key, 0, len(set)) 135 for _, k := range set { 136 out = append(out, k) 137 } 138 return out 139 }