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  }