github.com/cayleygraph/cayley@v0.7.7/cmd/cayley/command/convert.go (about) 1 package command 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 8 "github.com/spf13/cobra" 9 10 "github.com/cayleygraph/cayley/clog" 11 "github.com/cayleygraph/cayley/internal" 12 "github.com/cayleygraph/quad" 13 ) 14 15 func newLazyReader(open func() (quad.ReadCloser, error)) quad.ReadCloser { 16 return &lazyReader{open: open} 17 } 18 19 type lazyReader struct { 20 rc quad.ReadCloser 21 open func() (quad.ReadCloser, error) 22 } 23 24 func (r *lazyReader) ReadQuad() (quad.Quad, error) { 25 if r.rc == nil { 26 rc, err := r.open() 27 if err != nil { 28 return quad.Quad{}, err 29 } 30 r.rc = rc 31 } 32 return r.rc.ReadQuad() 33 } 34 func (r *lazyReader) Close() (err error) { 35 if r.rc != nil { 36 err = r.rc.Close() 37 } 38 return 39 } 40 41 type multiReader struct { 42 rc []quad.ReadCloser 43 i int 44 } 45 46 func (r *multiReader) ReadQuad() (quad.Quad, error) { 47 for { 48 if r.i >= len(r.rc) { 49 return quad.Quad{}, io.EOF 50 } 51 rc := r.rc[r.i] 52 q, err := rc.ReadQuad() 53 if err == io.EOF { 54 rc.Close() 55 r.i++ 56 continue 57 } 58 return q, err 59 } 60 } 61 func (r *multiReader) Close() error { 62 var first error 63 if r.i < len(r.rc) { 64 for _, rc := range r.rc[r.i:] { 65 if err := rc.Close(); err != nil && first == nil { 66 first = err 67 } 68 } 69 } 70 return nil 71 } 72 73 func NewConvertCmd() *cobra.Command { 74 cmd := &cobra.Command{ 75 Use: "convert", 76 Aliases: []string{"conv"}, 77 Short: "Convert quad files between supported formats.", 78 RunE: func(cmd *cobra.Command, args []string) error { 79 dump, _ := cmd.Flags().GetString(flagDump) 80 dumpf, _ := cmd.Flags().GetString(flagDumpFormat) 81 if dump == "" && len(args) > 0 { 82 i := len(args) - 1 83 dump, args = args[i], args[:i] 84 } 85 86 var files []string 87 if load, _ := cmd.Flags().GetString(flagLoad); load != "" { 88 files = append(files, load) 89 } 90 files = append(files, args...) 91 if len(files) == 0 || dump == "" { 92 return errors.New("both input and output files must be specified") 93 } 94 loadf, _ := cmd.Flags().GetString(flagLoadFormat) 95 var multi multiReader 96 for _, path := range files { 97 path := path 98 multi.rc = append(multi.rc, newLazyReader(func() (quad.ReadCloser, error) { 99 if dump == "-" { 100 clog.Infof("reading %q", path) 101 } else { 102 fmt.Printf("reading %q\n", path) 103 } 104 return internal.QuadReaderFor(path, loadf) 105 })) 106 } 107 // TODO: print additional stats 108 return writerQuadsTo(dump, dumpf, &multi) 109 }, 110 } 111 registerLoadFlags(cmd) 112 registerDumpFlags(cmd) 113 return cmd 114 }