Skip to content

Commit

Permalink
make main() runnable externally
Browse files Browse the repository at this point in the history
  • Loading branch information
murfffi committed Mar 19, 2024
1 parent 0d2aca0 commit 964212d
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 193 deletions.
194 changes: 2 additions & 192 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,197 +1,7 @@
// Command usql is the universal command-line interface for SQL databases.
package main

//go:generate go run gen.go

import (
"context"
"errors"
"fmt"
"io"
"os"
"os/user"
"strings"

"github.com/mattn/go-isatty"
"github.com/xo/usql/drivers"
"github.com/xo/usql/env"
"github.com/xo/usql/handler"
"github.com/xo/usql/internal"
"github.com/xo/usql/rline"
"github.com/xo/usql/text"
)
import "github.com/xo/usql/shell"

func main() {
// get available drivers and known build tags
available, known := drivers.Available(), internal.KnownBuildTags()
// report if database is supported
if len(os.Args) == 2 &&
strings.HasPrefix(os.Args[1], "--has-") &&
strings.HasSuffix(os.Args[1], "-support") {
n := os.Args[1][6 : len(os.Args[1])-8]
if v, ok := known[n]; ok {
n = v
}
var out int
if _, ok := available[n]; ok {
out = 1
}
fmt.Fprintf(os.Stdout, "%d", out)
return
}
// load current user
cur, err := user.Current()
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
args := NewArgs()
// run
err = run(args, cur)
if err != nil && err != io.EOF && err != rline.ErrInterrupt {
var he *handler.Error
if !errors.As(err, &he) {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
}
var e *drivers.Error
if errors.As(err, &e) && e.Err == text.ErrDriverNotAvailable {
m := make(map[string]string, len(known))
for k, v := range known {
m[v] = k
}
tag := e.Driver
if t, ok := m[tag]; ok {
tag = t
}
rev := "latest"
if text.CommandVersion == "0.0.0-dev" || strings.Contains(text.CommandVersion, "-") {
rev = "master"
}
fmt.Fprintf(os.Stderr, "\ntry:\n\n go install -tags %s github.com/xo/usql@%s\n\n", tag, rev)
}
os.Exit(1)
}
}

// run processes args, processing args.CommandOrFiles if non-empty, if
// specified, otherwise launch an interactive readline from stdin.
func run(args *Args, u *user.User) error {
// get working directory
wd, err := os.Getwd()
if err != nil {
return err
}
// determine if interactive
interactive := isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stdin.Fd())
cygwin := isatty.IsCygwinTerminal(os.Stdout.Fd()) && isatty.IsCygwinTerminal(os.Stdin.Fd())
forceNonInteractive := len(args.CommandOrFiles) != 0
// enable term graphics
if !forceNonInteractive && interactive && !cygwin {
// NOTE: this is done here and not in the env.init() package, because
// NOTE: we need to determine if it is interactive first, otherwise it
// NOTE: could mess up the non-interactive output with control characters
var typ string
if s, _ := env.Getenv(text.CommandUpper()+"_TERM_GRAPHICS", "TERM_GRAPHICS"); s != "" {
typ = s
}
if err := env.Set("TERM_GRAPHICS", typ); err != nil {
return err
}
}
// handle variables
for _, v := range args.Variables {
if i := strings.Index(v, "="); i != -1 {
_ = env.Set(v[:i], v[i+1:])
} else {
_ = env.Unset(v)
}
}
for _, v := range args.PVariables {
if i := strings.Index(v, "="); i != -1 {
vv := v[i+1:]
if c := vv[0]; c == '\'' || c == '"' {
var err error
vv, err = env.Dequote(vv, c)
if err != nil {
return err
}
}
if _, err = env.Pset(v[:i], vv); err != nil {
return err
}
} else {
if _, err = env.Ptoggle(v, ""); err != nil {
return err
}
}
}
// create input/output
l, err := rline.New(interactive, cygwin, forceNonInteractive, args.Out, env.HistoryFile(u))
if err != nil {
return err
}
defer l.Close()
// create handler
h := handler.New(l, u, wd, args.NoPassword)
// force a password ...
dsn := args.DSN
if args.ForcePassword {
dsn, err = h.Password(dsn)
if err != nil {
return err
}
}
// open dsn
if err = h.Open(context.Background(), dsn); err != nil {
return err
}
// start transaction
if args.SingleTransaction {
if h.IO().Interactive() {
return text.ErrSingleTransactionCannotBeUsedWithInteractiveMode
}
if err = h.BeginTx(context.Background(), nil); err != nil {
return err
}
}
// rc file
if rc := env.RCFile(u); !args.NoRC && rc != "" {
if err = h.Include(rc, false); err != nil && err != text.ErrNoSuchFileOrDirectory {
return err
}
}
// setup runner
f := h.Run
if len(args.CommandOrFiles) != 0 {
f = runCommandOrFiles(h, args.CommandOrFiles)
}
// run
if err = f(); err != nil {
return err
}
// commit
if args.SingleTransaction {
return h.Commit()
}
return nil
}

// runCommandOrFiles processes all the supplied commands or files.
func runCommandOrFiles(h *handler.Handler, commandsOrFiles []CommandOrFile) func() error {
return func() error {
for _, x := range commandsOrFiles {
h.SetSingleLineMode(x.Command)
if x.Command {
h.Reset([]rune(x.Value))
if err := h.Run(); err != nil {
return err
}
} else {
if err := h.Include(x.Value, false); err != nil {
return err
}
}
}
return nil
}
shell.Run()
}
2 changes: 1 addition & 1 deletion args.go → shell/args.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package shell

import (
"fmt"
Expand Down
File renamed without changes.
Loading

0 comments on commit 964212d

Please sign in to comment.