Beispiel #1
0
func runTerm(cmd *cobra.Command, args []string) {
	if len(args) != 0 {
		cmd.Usage()
		return
	}

	db := makeSQLClient()

	liner := liner.NewLiner()
	defer func() {
		_ = liner.Close()
	}()

	for {
		l, err := liner.Prompt("> ")
		if err != nil {
			if err != io.EOF {
				fmt.Fprintf(os.Stderr, "Input error: %s\n", err)
			}
			break
		}
		if len(l) == 0 {
			continue
		}
		liner.AppendHistory(l)

		if err := processOneLine(db, l); err != nil {
			fmt.Printf("Error: %s\n", err)
		}
	}
}
Beispiel #2
0
func RunRepl(store *Secstore) {
	var sections []string
	var line string
	var err error

	liner := liner.NewLiner()
	defer liner.Close()

	liner.SetCompleter(completer)

	for {
		line, err = liner.Prompt("> ")
		if err != nil {
			break
		}

		liner.AppendHistory(line)

		sections = splitSections(line)

		if len(sections) == 0 {

		} else if strings.HasPrefix("quit", sections[0]) {
			break
		} else {
			err = EvalCommand(store, sections)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
			}
		}
	}

	fmt.Fprintln(os.Stderr, "Exiting...")
}
Beispiel #3
0
func runTerm(cmd *cobra.Command, args []string) {
	if len(args) != 0 {
		mustUsage(cmd)
		return
	}

	db := makeSQLClient()

	liner := liner.NewLiner()
	defer func() {
		_ = liner.Close()
	}()

	fmt.Fprint(osStdout, infoMessage)

	// Default prompt is "hostname> "
	// continued statement prompt it: "        -> "
	// TODO(marc): maybe switch to "user@hostname" and strip port if present.
	fullPrompt := context.Addr
	if len(fullPrompt) == 0 {
		fullPrompt = " "
	}
	continuePrompt := strings.Repeat(" ", len(fullPrompt)-1) + "-"

	fullPrompt += "> "
	continuePrompt += "> "

	// TODO(marc): allow passing statements on the command line,
	// or specifying a flag. This would make testing much simpler.
	// TODO(marc): detect if we're actually on a terminal. If not,
	// we may want to repeat the statements on stdout.
	// TODO(marc): add test.
	var stmt []string
	var l string
	var err error
	for {
		if len(stmt) == 0 {
			l, err = liner.Prompt(fullPrompt)
		} else {
			l, err = liner.Prompt(continuePrompt)
		}
		if err != nil {
			if err != io.EOF {
				fmt.Fprintf(osStderr, "Input error: %s\n", err)
			}
			break
		}

		stmt = append(stmt, l)

		// See if we have a semicolon at the end of the line (ignoring
		// trailing whitespace).
		if !strings.HasSuffix(strings.TrimSpace(l), ";") {
			// No semicolon: read some more.
			continue
		}

		// We always insert a newline when continuing statements.
		// However, it causes problems with lines in the middle of:
		// - qualified names (eg: database.<newline>table)
		// - quoted strings (eg: 'foo<newline>bar')
		// This also makes the history replay horrible.
		// mysql replaces newlines with spaces in the history, which works
		// because string concatenation with newlines can also be done with spaces.
		// postgres keeps the line intact in the history.
		fullStmt := strings.Join(stmt, "\n")
		liner.AppendHistory(fullStmt)

		if err := runPrettyQuery(db, fullStmt); err != nil {
			fmt.Fprintln(osStdout, err)
		}

		// Clear the saved statement.
		stmt = stmt[:0]
	}
}
Beispiel #4
0
// runInteractive runs the SQL client interactively, presenting
// a prompt to the user for each statement.
func runInteractive(db *sql.DB, dbURL string) {
	liner := liner.NewLiner()
	defer func() {
		_ = liner.Close()
	}()

	fmt.Print(infoMessage)

	// Default prompt is part of the connection URL. eg: "marc@localhost>"
	// continued statement prompt is: "        -> "
	fullPrompt := dbURL
	if parsedURL, err := url.Parse(dbURL); err == nil {
		// If parsing fails, we keep the entire URL. The Open call succeeded, and that
		// is the important part.
		fullPrompt = fmt.Sprintf("%s@%s", parsedURL.User, parsedURL.Host)
	}

	if len(fullPrompt) == 0 {
		fullPrompt = " "
	}
	continuePrompt := strings.Repeat(" ", len(fullPrompt)-1) + "-"

	fullPrompt += "> "
	continuePrompt += "> "

	// TODO(marc): allow passing statements on the command line,
	// or specifying a flag. This would make testing much simpler.
	// TODO(marc): detect if we're actually on a terminal. If not,
	// we may want to repeat the statements on stdout.
	// TODO(marc): add test.
	var stmt []string
	var l string
	var err error

	exitCode := 0

	for {
		if len(stmt) == 0 {
			l, err = liner.Prompt(fullPrompt)
		} else {
			l, err = liner.Prompt(continuePrompt)
		}
		if err != nil {
			if err != io.EOF {
				fmt.Fprintf(osStderr, "Input error: %s\n", err)
				exitCode = 1
			}
			break
		}

		stmt = append(stmt, l)

		// See if we have a semicolon at the end of the line (ignoring
		// trailing whitespace).
		if !strings.HasSuffix(strings.TrimSpace(l), ";") {
			// No semicolon: read some more.
			continue
		}

		// We always insert a newline when continuing statements.
		// However, it causes problems with lines in the middle of:
		// - qualified names (eg: database.<newline>table)
		// - quoted strings (eg: 'foo<newline>bar')
		// This also makes the history replay horrible.
		// mysql replaces newlines with spaces in the history, which works
		// because string concatenation with newlines can also be done with spaces.
		// postgres keeps the line intact in the history.
		fullStmt := strings.Join(stmt, "\n")
		liner.AppendHistory(fullStmt)

		exitCode = 0
		if err := runPrettyQuery(db, os.Stdout, fullStmt); err != nil {
			fmt.Fprintln(osStderr, err)
			exitCode = 1
		}

		// Clear the saved statement.
		stmt = stmt[:0]
	}

	if exitCode != 0 {
		os.Exit(exitCode)
	}
}