go-hep.org/x/hep@v0.38.1/cmd/rio2yoda/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 // rio2yoda converts rio files containing hbook values (H1D, H2D, P1D, ...) 6 // into YODA files. 7 // 8 // Example: 9 // 10 // $> rio2yoda file1.rio file2.rio > out.yoda 11 // $> rio2yoda -o out.yoda file1.rio file2.rio 12 // $> rio2yoda -o out.yoda.gz file1.rio file2.rio 13 package main 14 15 import ( 16 "compress/gzip" 17 "flag" 18 "fmt" 19 "io" 20 "log" 21 "os" 22 "path/filepath" 23 "reflect" 24 25 "go-hep.org/x/hep/hbook" 26 "go-hep.org/x/hep/rio" 27 ) 28 29 func main() { 30 31 log.SetFlags(0) 32 log.SetPrefix("rio2yoda: ") 33 34 flag.Usage = func() { 35 fmt.Fprintf( 36 os.Stderr, 37 `Usage: rio2yoda [options] <file.rio> [<file2.rio> [...]] 38 39 ex: 40 $> rio2yoda file1.rio > out.yoda 41 $> rio2yoda -o out.yoda file1.rio file2.rio 42 $> rio2yoda -o out.yoda.gz file1.rio file2.rio 43 `) 44 } 45 46 oname := flag.String("o", "", "path to YODA output file") 47 48 flag.Parse() 49 50 if flag.NArg() < 1 { 51 log.Printf("missing input file name") 52 flag.Usage() 53 flag.PrintDefaults() 54 } 55 56 var out io.WriteCloser = os.Stdout 57 if *oname != "" { 58 f, err := os.Create(*oname) 59 if err != nil { 60 log.Fatal(err) 61 } 62 defer func() { 63 err = f.Close() 64 if err != nil { 65 log.Fatal(err) 66 } 67 }() 68 out = f 69 if filepath.Ext(*oname) == ".gz" { 70 wz := gzip.NewWriter(f) 71 defer func() { 72 err = wz.Close() 73 if err != nil { 74 log.Fatal(err) 75 } 76 }() 77 out = wz 78 } 79 } else { 80 defer out.Close() 81 } 82 83 for _, fname := range flag.Args() { 84 convert(out, fname) 85 } 86 } 87 88 func convert(out io.Writer, fname string) { 89 f, err := os.Open(fname) 90 if err != nil { 91 log.Fatal(err) 92 } 93 defer f.Close() 94 95 r, err := rio.Open(f) 96 if err != nil { 97 log.Fatalf("error opening rio stream %q: %v\n", fname, err) 98 } 99 defer r.Close() 100 101 for _, key := range r.Keys() { 102 rt := typeFrom(key.Blocks[0].Type) 103 if rt == nil { 104 continue 105 } 106 v := reflect.New(rt.Elem()) 107 err = r.Get(key.Name, v.Interface()) 108 if err != nil { 109 log.Fatalf( 110 "error reading block %q from file %q: %v\n", 111 key.Name, fname, err, 112 ) 113 } 114 115 yoda, err := v.Interface().(yodaMarshaler).MarshalYODA() 116 if err != nil { 117 log.Fatalf( 118 "error marshaling block %q from file %q to YODA: %v\n", 119 key.Name, fname, err, 120 ) 121 } 122 123 _, err = out.Write(yoda) 124 if err != nil { 125 log.Fatalf( 126 "error streaming out YODA format for block %q from file %q: %v\n", 127 key.Name, fname, err, 128 ) 129 } 130 } 131 } 132 133 func nameFromType(rt reflect.Type) string { 134 if rt == nil { 135 return "interface" 136 } 137 // Default to printed representation for unnamed types 138 name := rt.String() 139 140 // But for named types (or pointers to them), qualify with import path. 141 // Dereference one pointer looking for a named type. 142 star := "" 143 if rt.Name() == "" { 144 pt := rt 145 if pt.Kind() == reflect.Ptr { 146 star = "*" 147 rt = pt.Elem() 148 } 149 } 150 151 if rt.Name() != "" { 152 switch rt.PkgPath() { 153 case "": 154 name = star + rt.Name() 155 default: 156 name = star + rt.PkgPath() + "." + rt.Name() 157 } 158 } 159 160 return name 161 } 162 163 func typeFrom(name string) reflect.Type { 164 for _, t := range hbookTypes { 165 if name == nameFromType(t) { 166 return t 167 } 168 } 169 return nil 170 } 171 172 var hbookTypes = []reflect.Type{ 173 reflect.TypeOf((*hbook.H1D)(nil)), 174 reflect.TypeOf((*hbook.H2D)(nil)), 175 reflect.TypeOf((*hbook.P1D)(nil)), 176 reflect.TypeOf((*hbook.S2D)(nil)), 177 } 178 179 type yodaMarshaler interface { 180 MarshalYODA() ([]byte, error) 181 }