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