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  }