1
0
mirror of https://github.com/MontFerret/ferret.git synced 2025-07-03 00:46:51 +02:00
Files
ferret/e2e/cli.go

267 lines
5.2 KiB
Go
Raw Normal View History

package main
import (
"bufio"
"context"
"encoding/json"
"flag"
"fmt"
"github.com/rs/zerolog"
"io/ioutil"
"os"
"os/signal"
"path/filepath"
"strings"
"github.com/MontFerret/ferret"
"github.com/MontFerret/ferret/pkg/drivers/cdp"
"github.com/MontFerret/ferret/pkg/drivers/http"
"github.com/MontFerret/ferret/pkg/runtime"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/logging"
)
type Params []string
func (p *Params) String() string {
return "[" + strings.Join(*p, ",") + "]"
}
func (p *Params) Set(value string) error {
*p = append(*p, value)
return nil
}
func (p *Params) ToMap() (map[string]interface{}, error) {
res := make(map[string]interface{})
for _, entry := range *p {
pair := strings.SplitN(entry, ":", 2)
if len(pair) < 2 {
return nil, core.Error(core.ErrInvalidArgument, entry)
}
var value interface{}
key := pair[0]
err := json.Unmarshal([]byte(pair[1]), &value)
if err != nil {
fmt.Println(pair[1])
return nil, err
}
res[key] = value
}
return res, nil
}
var (
conn = flag.String(
"cdp",
"",
"set CDP address",
)
logLevel = flag.String(
"log-level",
logging.ErrorLevel.String(),
"log level",
)
)
var logger zerolog.Logger
func main() {
var params Params
flag.Var(
&params,
"param",
`query parameter (--param=foo:\"bar\", --param=id:1)`,
)
flag.Parse()
console := zerolog.ConsoleWriter{
Out: os.Stderr,
TimeFormat: "15:04:05.999",
}
logger = zerolog.New(console).
Level(zerolog.Level(logging.MustParseLevel(*logLevel))).
With().
Timestamp().
Logger()
stat, _ := os.Stdin.Stat()
var query string
var files []string
if (stat.Mode() & os.ModeCharDevice) == 0 {
// check whether the app is getting a query via standard input
std := bufio.NewReader(os.Stdin)
b, err := ioutil.ReadAll(std)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
query = string(b)
} else if flag.NArg() > 0 {
files = flag.Args()
} else {
fmt.Println(flag.NArg())
fmt.Println("File or input stream are required")
os.Exit(1)
}
p, err := params.ToMap()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
engine := ferret.New()
_ = engine.Drivers().Register(http.NewDriver())
_ = engine.Drivers().Register(cdp.NewDriver(cdp.WithAddress(*conn)))
opts := []runtime.Option{
runtime.WithParams(p),
runtime.WithLog(console),
runtime.WithLogLevel(logging.MustParseLevel(*logLevel)),
}
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
signal.Notify(c, os.Kill)
ctx, cancel := context.WithCancel(context.Background())
go func() {
for {
<-c
cancel()
}
}()
if query != "" {
err = execQuery(ctx, engine, opts, query)
} else {
err = execFiles(ctx, engine, opts, files)
}
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func execFiles(ctx context.Context, engine *ferret.Instance, opts []runtime.Option, files []string) error {
errList := make([]error, 0, len(files))
for _, path := range files {
log := logger.With().Str("path", path).Logger()
log.Debug().Msg("checking path...")
info, err := os.Stat(path)
if err != nil {
log.Debug().Err(err).Msg("failed to get path info")
errList = append(errList, err)
continue
}
if info.IsDir() {
log.Debug().Msg("path points to a directory. retrieving list of files...")
fileInfos, err := ioutil.ReadDir(path)
if err != nil {
log.Debug().Err(err).Msg("failed to retrieve list of files")
errList = append(errList, err)
continue
}
log.Debug().Int("size", len(fileInfos)).Msg("retrieved list of files. starting to iterate...")
dirFiles := make([]string, 0, len(fileInfos))
for _, info := range fileInfos {
if filepath.Ext(info.Name()) == ".fql" {
dirFiles = append(dirFiles, filepath.Join(path, info.Name()))
}
}
if len(dirFiles) > 0 {
if err := execFiles(ctx, engine, opts, dirFiles); err != nil {
log.Debug().Err(err).Msg("failed to execute files")
errList = append(errList, err)
} else {
log.Debug().Int("size", len(fileInfos)).Err(err).Msg("successfully executed files")
}
} else {
log.Debug().Int("size", len(fileInfos)).Err(err).Msg("no FQL files found")
}
continue
}
log.Debug().Msg("path points to a file. starting to read content")
out, err := ioutil.ReadFile(path)
if err != nil {
log.Debug().Err(err).Msg("failed to read content")
errList = append(errList, err)
continue
}
log.Debug().Msg("successfully read file")
log.Debug().Msg("executing file...")
err = execQuery(ctx, engine, opts, string(out))
if err != nil {
log.Debug().Err(err).Msg("failed to execute file")
errList = append(errList, err)
continue
}
log.Debug().Msg("successfully executed file")
}
if len(errList) > 0 {
if len(errList) == len(files) {
logger.Debug().Errs("errors", errList).Msg("failed to execute file(s)")
} else {
logger.Debug().Errs("errors", errList).Msg("executed with errors")
}
return core.Errors(errList...)
}
return nil
}
func execQuery(ctx context.Context, engine *ferret.Instance, opts []runtime.Option, query string) error {
out, err := engine.Exec(ctx, query, opts...)
if err != nil {
return err
}
fmt.Println(string(out))
return nil
}