blob: c18153495ce6bc3c9b179b6dbbd68bbfeaf5d0ca [file] [log] [blame]
package main
import (
"fmt"
"io"
"os"
"strings"
isatty "github.com/mattn/go-isatty"
"v.io/v23/context"
wire "v.io/v23/services/syncbase"
"v.io/v23/syncbase"
"v.io/x/lib/cmdline"
"v.io/x/ref/cmd/sb/sb2/commands"
"v.io/x/ref/cmd/sb/internal/reader"
"v.io/x/ref/lib/v23cmd"
)
var cmdSbShell = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runSbShell),
Name: "sh",
Short: "Start a syncQL shell",
Long: `
Connect to a database on the Syncbase service and start a syncQL shell.
`,
}
// Runs the shell.
// Takes commands as input, executes them, and spits out output.
func runSbShell(ctx *context.T, env *cmdline.Env, args []string) error {
if len(args) != 0 {
return env.UsageErrorf("no arguments expected")
}
// open a connection to syncbase
sbService := syncbase.NewService(flagService)
dbId := wire.Id{Blessing: flagBlessing, Name: flagDBName}
db, err := openDB(ctx, sbService, dbId, flagCreateIfAbsent)
if err != nil {
return err
}
// test if input is interactive and get reader
var input *reader.T
stdinFile, ok := env.Stdin.(*os.File)
isTerminal := ok && isatty.IsTerminal(stdinFile.Fd())
if isTerminal {
input = reader.NewInteractive()
} else {
input = reader.NewNonInteractive()
}
defer input.Close()
// read-exec loop
for true {
// read command
query, err := input.GetQueryWithTerminator('\n')
if err != nil {
if err == io.EOF && isTerminal {
// ctrl-d
fmt.Println()
}
break
}
// exec command
fields := strings.Fields(query)
if len(fields) > 0 {
if err := runCommand(ctx, env, db, fields[0], fields[1:], isTerminal);
err != nil {
return err
}
}
}
return nil
}
func runCommand(ctx *context.T, env *cmdline.Env, db syncbase.Database,
command string, args []string, isTerminal bool) error {
cmd, err := commands.GetCommand(command)
if err != nil {
// command not found, inform the user
if isTerminal {
fmt.Printf("no command %q\n", command)
return nil
} else {
return err
}
}
// command was found, run it
commands.SetCtx(context.WithValue(ctx, "database", db))
if err := cmd.Runner.Run(env, args); err != nil {
if isTerminal {
fmt.Fprintln(env.Stderr, "Error:", err)
//printUsage(cmd)
} else {
// if running non-interactively, errors halt execution
return err
}
}
return nil
}