Files
wehub-resource-sync 5357c39144
Fuzzer / Run Fuzzer (push) Has been cancelled
Race tests / Go race tests (ubuntu-22.04) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:01:40 +08:00

769 lines
24 KiB
Go

// Copyright 2019 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"bytes"
"context"
"fmt"
"io"
"os"
"strings"
"github.com/dolthub/go-mysql-server/sql"
"github.com/fatih/color"
"github.com/gocraft/dbr/v2"
"github.com/gocraft/dbr/v2/dialect"
goisatty "github.com/mattn/go-isatty"
"github.com/dolthub/dolt/go/cmd/dolt/cli"
"github.com/dolthub/dolt/go/cmd/dolt/errhand"
"github.com/dolthub/dolt/go/libraries/doltcore/branch_control"
"github.com/dolthub/dolt/go/libraries/doltcore/dconfig"
"github.com/dolthub/dolt/go/libraries/doltcore/diff"
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
"github.com/dolthub/dolt/go/libraries/doltcore/env"
"github.com/dolthub/dolt/go/libraries/doltcore/env/actions"
"github.com/dolthub/dolt/go/libraries/utils/argparser"
"github.com/dolthub/dolt/go/libraries/utils/config"
"github.com/dolthub/dolt/go/libraries/utils/iohelp"
"github.com/dolthub/dolt/go/libraries/utils/set"
"github.com/dolthub/dolt/go/store/datas"
"github.com/dolthub/dolt/go/store/util/outputpager"
)
var commitDocs = cli.CommandDocumentationContent{
ShortDesc: "Record changes to the database",
LongDesc: `
Stores the current contents of the staged tables in a new commit along with a log message from the user describing the changes.
The content to be added can be specified by using dolt add to incrementally \"add\" changes to the staged tables before using the commit command (Note: even modified tables must be \"added\").
The log message can be added with the parameter {{.EmphasisLeft}}-m <msg>{{.EmphasisRight}}. If the {{.LessThan}}-m{{.GreaterThan}} parameter is not provided an editor will be opened where you can review the commit and provide a log message.
The commit timestamp can be modified using the --date parameter. Dates can be specified in the formats {{.LessThan}}YYYY-MM-DD{{.GreaterThan}}, {{.LessThan}}YYYY-MM-DDTHH:MM:SS{{.GreaterThan}}, or {{.LessThan}}YYYY-MM-DDTHH:MM:SSZ07:00{{.GreaterThan}} (where {{.LessThan}}07:00{{.GreaterThan}} is the time zone offset)."`,
Synopsis: []string{
"[options]",
},
}
type CommitCmd struct{}
// Name is returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
func (cmd CommitCmd) Name() string {
return "commit"
}
// Description returns a description of the command
func (cmd CommitCmd) Description() string {
return "Record changes to the repository."
}
func (cmd CommitCmd) Docs() *cli.CommandDocumentation {
ap := cli.CreateCommitArgParser(false)
return cli.NewCommandDocumentation(commitDocs, ap)
}
func (cmd CommitCmd) ArgParser() *argparser.ArgParser {
return cli.CreateCommitArgParser(false)
}
// Exec executes the command
func (cmd CommitCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv, cliCtx cli.CliContext) int {
res, skipped := performCommit(ctx, commandStr, args, cliCtx, dEnv)
if res != 0 {
return res
}
if skipped {
iohelp.WriteLine(cli.CliOut, "Skipping empty commit")
}
return 0
}
// performCommit creates a new Dolt commit using the specified |commandStr| and |args|. The response is an integer
// status code indicating success or failure, as well as a boolean that indicates if the commit was skipped
// (e.g. because --skip-empty was specified as an argument).
func performCommit(ctx context.Context, commandStr string, args []string, cliCtx cli.CliContext, temporaryDEnv *env.DoltEnv) (int, bool) {
ap := cli.CreateCommitArgParser(false)
apr, usage, terminate, status := ParseArgsOrPrintHelp(ap, commandStr, args, commitDocs)
if terminate {
return status, false
}
if err := cli.VerifyCommitArgs(apr); err != nil {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage), false
}
queryist, err := cliCtx.QueryEngine(ctx)
if err != nil {
cli.Println(err.Error())
return 1, false
}
// TODO: This is not a nice solution. Currently, the cliCtx parameter's sqlCtx that we get from QueryEngine() is never refreshed.
// TODO: It would be ideal to have it generate/regenerate it's sqlCtx more often, as it likely has impacts beyond just the time.
if c, ok := ctx.(*sql.Context); ok {
queryist.Context.SetQueryTime(c.QueryTime())
}
// dolt_commit performs this check as well. This nips the problem in the bud early, but is not required.
err = branch_control.CheckAccess(queryist.Context, branch_control.Permissions_Write)
if err != nil {
cli.Println(err.Error())
return 1, false
}
msg, msgOk := apr.GetValue(cli.MessageArg)
if !msgOk {
amendStr := ""
if apr.Contains(cli.AmendFlag) {
_, rowIter, _, err := queryist.Queryist.Query(queryist.Context, "select message from dolt_log() limit 1")
if err != nil {
cli.Println(err.Error())
return 1, false
}
row, err := rowIter.Next(queryist.Context)
if err != nil {
cli.Println(err.Error())
return 1, false
}
amendStr = row[0].(string)
}
msg, err = getCommitMessageFromEditor(queryist.Context, queryist.Queryist, "", amendStr, false, cliCtx)
if err != nil {
return handleCommitErr(queryist.Context, queryist.Queryist, err, usage), false
}
}
// process query through prepared statement to prevent sql injection
query, params, err := constructParametrizedDoltCommitQuery(msg, apr, cliCtx)
if err != nil {
return handleCommitErr(queryist.Context, queryist.Queryist, err, usage), false
}
interpolatedQuery, err := dbr.InterpolateForDialect(query, params, dialect.MySQL)
if err != nil {
cli.Println(err.Error())
return 1, false
}
_, rowIter, _, err := queryist.Queryist.Query(queryist.Context, interpolatedQuery)
if err != nil {
return handleCommitErr(queryist.Context, queryist.Queryist, err, usage), false
}
resultRow, err := sql.RowIterToRows(queryist.Context, rowIter)
if err != nil {
cli.Println(err.Error())
return 1, false
}
if resultRow == nil {
return 0, true
}
commit, err := getCommitInfo(queryist.Context, queryist.Queryist, "HEAD")
if err != nil {
cli.Printf("Commit completed, but failure to get commit details occurred: %s\n", err.Error())
return 0, false
}
if cli.ExecuteWithStdioRestored != nil {
cli.ExecuteWithStdioRestored(func() {
pager := outputpager.Start()
defer pager.Stop()
PrintCommitInfo(pager, 0, false, false, "auto", commit)
})
}
return 0, false
}
// constructParametrizedDoltCommitQuery generates the sql query necessary to call the DOLT_COMMIT() stored procedure with placeholders
// for arg input. Also returns a list of the inputs in the order in which they appear in the query.
func constructParametrizedDoltCommitQuery(msg string, apr *argparser.ArgParseResults, cliCtx cli.CliContext) (string, []interface{}, error) {
var params []interface{}
var param bool
var buffer bytes.Buffer
var first bool
first = true
buffer.WriteString("CALL DOLT_COMMIT(")
writeToBuffer := func(s string) {
if !first {
buffer.WriteString(", ")
}
if !param {
buffer.WriteString("'")
}
buffer.WriteString(s)
if !param {
buffer.WriteString("'")
}
first = false
param = false
}
if msg != "" {
writeToBuffer("-m")
param = true
writeToBuffer("?")
params = append(params, msg)
}
if apr.Contains(cli.AllowEmptyFlag) {
writeToBuffer("--allow-empty")
}
if apr.Contains(cli.DateParam) {
writeToBuffer("--date")
param = true
writeToBuffer("?")
date, _ := apr.GetValue(cli.DateParam)
params = append(params, date)
}
if apr.Contains(cli.ForceFlag) {
writeToBuffer("-f")
}
if apr.Contains(cli.AuthorParam) {
writeToBuffer("--author")
param = true
writeToBuffer("?")
author, _ := apr.GetValue(cli.AuthorParam)
params = append(params, author)
} else if _, _, err := env.GetNameAndEmail(cliCtx.Config()); err != nil {
return "", nil, err
}
if apr.Contains(cli.AllFlag) {
writeToBuffer("-a")
}
if apr.Contains(cli.UpperCaseAllFlag) {
writeToBuffer("-A")
}
if apr.Contains(cli.AmendFlag) {
writeToBuffer("--amend")
}
if apr.Contains(cli.SkipEmptyFlag) {
writeToBuffer("--skip-empty")
}
if apr.Contains(cli.SkipVerificationFlag) {
writeToBuffer("--skip-verification")
}
cfgSign := cliCtx.Config().GetStringOrDefault("sqlserver.global.gpgsign", "")
if apr.Contains(cli.SignFlag) || strings.ToLower(cfgSign) == "true" {
writeToBuffer("--gpg-sign")
gpgKey := apr.GetValueOrDefault(cli.SignFlag, "")
if gpgKey != "" {
param = true
writeToBuffer("?")
params = append(params, gpgKey)
}
}
buffer.WriteString(")")
return buffer.String(), params, nil
}
func handleCommitErr(sqlCtx *sql.Context, queryist cli.Queryist, err error, usage cli.UsagePrinter) int {
if err == nil {
return 0
}
if datas.ErrNameNotConfigured.Is(err) {
bdr := errhand.BuildDError("Could not determine %s.", config.UserNameKey)
bdr.AddDetails("Log into DoltHub: dolt login")
bdr.AddDetails("OR add name to config: dolt config [--global|--local] --add %[1]s \"FIRST LAST\"", config.UserNameKey)
return HandleVErrAndExitCode(bdr.Build(), usage)
}
if datas.ErrEmailNotConfigured.Is(err) {
bdr := errhand.BuildDError("Could not determine %s.", config.UserEmailKey)
bdr.AddDetails("Log into DoltHub: dolt login")
bdr.AddDetails("OR add email to config: dolt config [--global|--local] --add %[1]s \"EMAIL_ADDRESS\"", config.UserEmailKey)
return HandleVErrAndExitCode(bdr.Build(), usage)
}
if err == datas.ErrEmptyCommitMessage {
bdr := errhand.BuildDError("Aborting commit due to empty commit message.")
return HandleVErrAndExitCode(bdr.Build(), usage)
}
if err.Error() == "nothing to commit" {
_, ri, _, err := queryist.Query(sqlCtx, "select table_name, status from dolt_status where staged = false")
if err != nil {
cli.Println(err)
return 1
}
notStagedRows, err := sql.RowIterToRows(sqlCtx, ri)
if err != nil {
cli.Println(err)
return 1
}
n, newErr := PrintDiffsNotStaged(sqlCtx, queryist, cli.CliOut, notStagedRows, false, false, 0)
if newErr != nil {
bdr := errhand.BuildDError(`No changes added to commit (use "dolt add")\nCould not print diff because of additional error`)
bdr.AddCause(newErr)
return HandleVErrAndExitCode(bdr.Build(), usage)
}
if n == 0 {
bdr := errhand.BuildDError(`no changes added to commit (use "dolt add")`)
return HandleVErrAndExitCode(bdr.Build(), usage)
}
}
if actions.IsTblInConflict(err) {
inConflict := actions.GetTablesForError(err)
bdr := errhand.BuildDError(`tables %v have unresolved conflicts from the merge. resolve the conflicts before committing`, inConflict)
return HandleVErrAndExitCode(bdr.Build(), usage)
}
verr := errhand.BuildDError("error: Failed to commit changes.").AddCause(err).Build()
return HandleVErrAndExitCode(verr, usage)
}
// getCommitMessageFromEditor opens editor to ask user for commit message if none defined from command line.
// suggestedMsg will be returned if no-edit flag is defined or if this function was called from sql dolt_merge command.
func getCommitMessageFromEditor(sqlCtx *sql.Context, queryist cli.Queryist, suggestedMsg, amendString string, noEdit bool, cliCtx cli.CliContext) (string, error) {
var finalMsg string
initialMsg, err := buildInitalCommitMsg(sqlCtx, queryist, suggestedMsg)
if err != nil {
return "", err
}
if amendString != "" {
initialMsg = fmt.Sprintf("%s\n%s", amendString, initialMsg)
}
if cli.ExecuteWithStdioRestored == nil || noEdit {
return suggestedMsg, nil
}
if !checkIsTerminal() {
return suggestedMsg, nil
}
commitMsg, err := execEditor(initialMsg, "", cliCtx)
if err != nil {
return "", fmt.Errorf("Failed to open commit editor: %v \n Check your `EDITOR` environment variable with `echo $EDITOR` or your dolt config with `dolt config --list` to ensure that your editor is valid", err)
}
finalMsg = parseCommitMessage(commitMsg)
return finalMsg, nil
}
func checkIsTerminal() bool {
// In tests that drive cli commands without InitIO the stdio swap helper is unset, so
// treat the absence as a non-terminal context to avoid dereferencing a nil function.
if cli.ExecuteWithStdioRestored == nil {
return false
}
isTerminal := false
cli.ExecuteWithStdioRestored(func() {
fd := os.Stdout.Fd()
// IsCygwinTerminal catches MSYS and Git Bash on Windows, where stdout is a named pipe.
if goisatty.IsTerminal(fd) || goisatty.IsCygwinTerminal(fd) || os.Getenv(dconfig.EnvTestForceOpenEditor) == "1" {
isTerminal = true
}
})
return isTerminal
}
func buildInitalCommitMsg(sqlCtx *sql.Context, queryist cli.Queryist, suggestedMsg string) (string, error) {
initialNoColor := color.NoColor
color.NoColor = true
_, ri, _, err := queryist.Query(sqlCtx, "select table_name, status from dolt_status where staged = true")
if err != nil {
return "", err
}
stagedRows, err := sql.RowIterToRows(sqlCtx, ri)
if err != nil {
return "", err
}
_, ri, _, err = queryist.Query(sqlCtx, "select table_name, status from dolt_status where staged = false")
if err != nil {
return "", err
}
notStagedRows, err := sql.RowIterToRows(sqlCtx, ri)
if err != nil {
return "", err
}
buf := bytes.NewBuffer([]byte{})
n := printStagedDiffs(buf, stagedRows, true)
n, err = PrintDiffsNotStaged(sqlCtx, queryist, buf, notStagedRows, true, false, n)
if err != nil {
return "", err
}
// get current branch
currBranch, err := getActiveBranchName(sqlCtx, queryist)
if err != nil {
return "", err
}
initialCommitMessage := fmt.Sprintf("%s\n# Please enter the commit message for your changes. Lines starting"+
"\n# with '#' will be ignored, and an empty message aborts the commit."+
"\n# On branch %s\n#\n", suggestedMsg, currBranch)
msgLines := strings.Split(buf.String(), "\n")
for i, msg := range msgLines {
msgLines[i] = "# " + msg
}
statusMsg := strings.Join(msgLines, "\n")
color.NoColor = initialNoColor
return initialCommitMessage + statusMsg, nil
}
func parseCommitMessage(cm string) string {
lines := strings.Split(cm, "\n")
filtered := make([]string, 0, len(lines))
for _, line := range lines {
if len(line) >= 1 && line[0] == '#' {
continue
}
filtered = append(filtered, line)
}
return strings.Join(filtered, "\n")
}
func PrintDiffsNotStaged(
sqlCtx *sql.Context,
queryist cli.Queryist,
wr io.Writer,
notStagedRows []sql.Row,
printHelp bool,
printIgnored bool,
linesPrinted int,
) (int, error) {
// get data conflict tables
_, ri, _, err := queryist.Query(sqlCtx, "select `table` from dolt_conflicts")
if err != nil {
return 0, err
}
conflictRows, err := sql.RowIterToRows(sqlCtx, ri)
if err != nil {
return 0, err
}
var conflictTables []string
for i, _ := range conflictRows {
conflictTables = append(conflictTables, conflictRows[i][0].(string))
}
inCnfSet := set.NewStrSet(conflictTables)
// get schema conflict tables
_, ri, _, err = queryist.Query(sqlCtx, "select table_name from dolt_status where status = 'schema conflict'")
if err != nil {
return 0, err
}
schemaConflictRows, err := sql.RowIterToRows(sqlCtx, ri)
if err != nil {
return 0, err
}
var schemaConflictTables []string
for i, _ := range schemaConflictRows {
schemaConflictTables = append(schemaConflictTables, schemaConflictRows[i][0].(string))
}
inCnfSet.Add(schemaConflictTables...)
// get constraint violation tables
_, ri, _, err = queryist.Query(sqlCtx, "select `table` from dolt_constraint_violations")
if err != nil {
return 0, err
}
constraintViolationRows, err := sql.RowIterToRows(sqlCtx, ri)
if err != nil {
return 0, err
}
var constraintViolationTables []string
for i, _ := range constraintViolationRows {
constraintViolationTables = append(constraintViolationTables, constraintViolationRows[i][0].(string))
}
violationSet := set.NewStrSet(constraintViolationTables)
if len(conflictTables) > 0 || len(constraintViolationTables) > 0 {
if linesPrinted > 0 {
cli.Println()
}
iohelp.WriteLine(wr, unmergedPathsHeader)
if printHelp {
iohelp.WriteLine(wr, mergedTableHelp)
}
if len(conflictTables) > 0 || len(schemaConflictTables) > 0 {
lines := make([]string, 0, len(notStagedRows))
for _, tblName := range schemaConflictTables {
lines = append(lines, fmt.Sprintf(statusFmt, schemaConflictLabel, tblName))
}
for _, tblName := range conflictTables {
lines = append(lines, fmt.Sprintf(statusFmt, bothModifiedLabel, tblName))
}
iohelp.WriteLine(wr, color.RedString(strings.Join(lines, "\n")))
linesPrinted += len(lines)
}
if len(constraintViolationTables) > 0 {
violationOnly, _, _ := violationSet.LeftIntersectionRight(inCnfSet)
lines := make([]string, 0, len(notStagedRows))
for _, tblName := range violationOnly.AsSortedSlice() {
lines = append(lines, fmt.Sprintf(statusFmt, "modified", tblName))
}
iohelp.WriteLine(wr, color.RedString(strings.Join(lines, "\n")))
linesPrinted += len(lines)
}
}
added := 0
removeModified := 0
for _, row := range notStagedRows {
if row[1] == "new table" {
added++
} else if row[1] == "renamed" {
added++
removeModified++
} else {
removeModified++
}
}
numRemovedOrModified := removeModified
if numRemovedOrModified-inCnfSet.Size()-violationSet.Size() > 0 {
if linesPrinted > 0 {
cli.Println()
}
iohelp.WriteLine(wr, workingHeader)
if printHelp {
iohelp.WriteLine(wr, workingHeaderHelp)
}
lines := getModifiedAndRemovedNotStaged(notStagedRows, inCnfSet, violationSet)
iohelp.WriteLine(wr, color.RedString(strings.Join(lines, "\n")))
linesPrinted += len(lines)
}
if added > 0 {
if linesPrinted > 0 {
cli.Println()
}
iohelp.WriteLine(wr, untrackedHeader)
if printHelp {
iohelp.WriteLine(wr, untrackedHeaderHelp)
}
addedNotStagedTables := getAddedNotStagedTables(notStagedRows)
filteredTables, err := filterIgnoredTables(sqlCtx, queryist, addedNotStagedTables)
if err != nil && doltdb.AsDoltIgnoreInConflict(err) == nil {
return 0, err
}
lines := make([]string, len(filteredTables.DontIgnore))
for i, tableName := range filteredTables.DontIgnore {
lines[i] = fmt.Sprintf(statusFmt, tblDiffTypeToLabel[diff.AddedTable], tableName)
}
iohelp.WriteLine(wr, color.RedString(strings.Join(lines, "\n")))
linesPrinted += len(lines)
if printIgnored && len(filteredTables.Ignore) > 0 {
if linesPrinted > 0 {
cli.Println()
}
iohelp.WriteLine(wr, ignoredHeader)
if printHelp {
iohelp.WriteLine(wr, ignoredHeaderHelp)
}
lines := make([]string, len(filteredTables.Ignore))
for i, tableName := range filteredTables.Ignore {
lines[i] = fmt.Sprintf(statusFmt, tblDiffTypeToLabel[diff.AddedTable], tableName)
}
iohelp.WriteLine(wr, color.RedString(strings.Join(lines, "\n")))
linesPrinted += len(lines)
}
if len(filteredTables.Conflicts) > 0 {
if linesPrinted > 0 {
cli.Println()
}
iohelp.WriteLine(wr, conflictedIgnoredHeader)
if printHelp {
iohelp.WriteLine(wr, conflictedIgnoredHeaderHelp)
}
lines := make([]string, len(filteredTables.Conflicts))
for i, conflict := range filteredTables.Conflicts {
lines[i] = fmt.Sprintf(statusFmt, tblDiffTypeToLabel[diff.AddedTable], conflict.Table)
}
iohelp.WriteLine(wr, color.RedString(strings.Join(lines, "\n")))
linesPrinted += len(lines)
}
}
return linesPrinted, nil
}
func getModifiedAndRemovedNotStaged(notStagedRows []sql.Row, inCnfSet, violationSet *set.StrSet) (lines []string) {
lines = make([]string, 0, len(notStagedRows))
for _, row := range notStagedRows {
if row[1] == "added" || inCnfSet.Contains(row[0].(string)) || violationSet.Contains(row[0].(string)) {
continue
}
if row[1] == "deleted" {
lines = append(lines, fmt.Sprintf(statusFmt, tblDiffTypeToLabel[diff.RemovedTable], row[0].(string)))
} else if row[1] == "renamed" {
// per Git, unstaged renames are shown as drop + add
names := strings.Split(row[0].(string), " -> ")
lines = append(lines, fmt.Sprintf(statusFmt, tblDiffTypeToLabel[diff.RemovedTable], names[0]))
} else {
lines = append(lines, fmt.Sprintf(statusFmt, tblDiffTypeToLabel[diff.ModifiedTable], row[0].(string)))
}
}
return lines
}
func getAddedNotStagedTables(notStagedRows []sql.Row) (tables []doltdb.TableName) {
tables = make([]doltdb.TableName, 0, len(notStagedRows))
for _, row := range notStagedRows {
if row[1] == "added" || row[1] == "renamed" {
names := strings.Split(row[0].(string), " -> ")
// TODO: schema name
tables = append(tables, doltdb.TableName{Name: names[0]})
}
}
return tables
}
const (
branchHeader = "On branch %s\n"
stagedHeader = `Changes to be committed:`
stagedHeaderHelp = ` (use "dolt reset <table>..." to unstage)`
unmergedTablesHeader = `You have unmerged tables.
(fix %s and run "dolt commit")
(use "dolt merge --abort" to abort the merge)
`
allMergedHeader = `All conflicts and constraint violations fixed but you are still merging.
(use "dolt commit" to conclude merge)`
unmergedPathsHeader = `Unmerged paths:`
mergedTableHelp = ` (use "dolt add <table>..." to mark resolution)`
workingHeader = `Changes not staged for commit:`
workingHeaderHelp = ` (use "dolt add <table>" to update what will be committed)
(use "dolt checkout <table>" to discard changes in working directory)`
untrackedHeader = `Untracked tables:`
untrackedHeaderHelp = ` (use "dolt add <table>" to include in what will be committed)`
ignoredHeader = `Ignored tables:`
ignoredHeaderHelp = ` (use "dolt add -f <table>" to include in what will be committed)`
conflictedIgnoredHeader = `Tables with conflicting dolt_ignore patterns:`
conflictedIgnoredHeaderHelp = ` (use "dolt add -f <table>" to include in what will be committed)`
statusFmt = "\t%-18s%s"
statusRenameFmt = "\t%-18s%s -> %s"
schemaConflictLabel = "schema conflict:"
bothModifiedLabel = "both modified:"
)
var tblDiffTypeToLabel = map[diff.TableDiffType]string{
diff.ModifiedTable: "modified:",
diff.RenamedTable: "renamed:",
diff.RemovedTable: "deleted:",
diff.AddedTable: "new table:",
}
func printStagedDiffs(wr io.Writer, stagedRows []sql.Row, printHelp bool) int {
if len(stagedRows) > 0 {
iohelp.WriteLine(wr, stagedHeader)
if printHelp {
iohelp.WriteLine(wr, stagedHeaderHelp)
}
lines := make([]string, 0, len(stagedRows))
for _, row := range stagedRows {
if !doltdb.IsReadOnlySystemTable(doltdb.TableName{Name: row[0].(string)}) {
switch row[1].(string) {
case "new table":
lines = append(lines, fmt.Sprintf(statusFmt, tblDiffTypeToLabel[diff.AddedTable], row[0].(string)))
case "deleted":
lines = append(lines, fmt.Sprintf(statusFmt, tblDiffTypeToLabel[diff.RemovedTable], row[0].(string)))
case "renamed":
names := strings.Split(row[0].(string), " -> ")
lines = append(lines, fmt.Sprintf(statusRenameFmt, tblDiffTypeToLabel[diff.RenamedTable], names[0], names[1]))
default:
lines = append(lines, fmt.Sprintf(statusFmt, tblDiffTypeToLabel[diff.ModifiedTable], row[0].(string)))
}
}
}
iohelp.WriteLine(wr, color.GreenString(strings.Join(lines, "\n")))
return len(stagedRows)
}
return 0
}
// filterIgnoredTables takes a slice of table names and divides it into new slices based on whether the table is ignored, not ignored, or matches conflicting ignore patterns.
func filterIgnoredTables(sqlCtx *sql.Context, queryist cli.Queryist, addedNotStagedTables []doltdb.TableName) (ignoredTables doltdb.IgnoredTables, err error) {
ignorePatterns, err := getIgnoredTablePatternsFromSql(queryist, sqlCtx)
if err != nil {
return ignoredTables, err
}
for _, tableName := range addedNotStagedTables {
ignored, err := ignorePatterns.IsTableNameIgnored(tableName)
if conflict := doltdb.AsDoltIgnoreInConflict(err); conflict != nil {
ignoredTables.Conflicts = append(ignoredTables.Conflicts, *conflict)
} else if err != nil {
return ignoredTables, err
} else if ignored == doltdb.DontIgnore {
ignoredTables.DontIgnore = append(ignoredTables.DontIgnore, tableName)
} else if ignored == doltdb.Ignore {
ignoredTables.Ignore = append(ignoredTables.Ignore, tableName)
} else {
return ignoredTables, fmt.Errorf("IsTableNameIgnored returned ErrorOccurred but no error!")
}
}
return ignoredTables, nil
}