mirror of https://github.com/status-im/migrate.git
improve postgres errors and error formatting in general
This commit is contained in:
parent
2353a03eb4
commit
fbfb50d4e7
|
@ -2,9 +2,12 @@ package postgres
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
_ "github.com/lib/pq"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/lib/pq"
|
||||
"github.com/mattes/migrate/file"
|
||||
"github.com/mattes/migrate/migrate/direction"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Driver struct {
|
||||
|
@ -77,7 +80,16 @@ func (driver *Driver) Migrate(files file.Files, pipe chan interface{}) {
|
|||
}
|
||||
|
||||
if _, err := tx.Exec(string(f.Content)); err != nil {
|
||||
pipe <- err
|
||||
pqErr := err.(*pq.Error)
|
||||
offset, err := strconv.Atoi(pqErr.Position)
|
||||
if err == nil && offset >= 0 {
|
||||
lineNo, columnNo := file.LineColumnFromOffset(f.Content, offset-1)
|
||||
errorPart := file.LinesBeforeAndAfter(f.Content, lineNo, 5, 5, true)
|
||||
pipe <- errors.New(fmt.Sprintf("%s %v: %s in line %v, column %v:\n\n%s", pqErr.Severity, pqErr.Code, pqErr.Message, lineNo, columnNo, string(errorPart)))
|
||||
} else {
|
||||
pipe <- errors.New(fmt.Sprintf("%s %v: %s", pqErr.Severity, pqErr.Code, pqErr.Message))
|
||||
}
|
||||
|
||||
if err := tx.Rollback(); err != nil {
|
||||
pipe <- err
|
||||
}
|
||||
|
|
56
file/file.go
56
file/file.go
|
@ -1,14 +1,17 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mattes/migrate/migrate/direction"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var filenameRegex = "^([0-9]+)_(.*)\\.(up|down)\\.%s$"
|
||||
|
@ -233,20 +236,69 @@ func parseFilenameSchema(filename string, filenameRegex *regexp.Regexp) (version
|
|||
return version, matches[2], d, nil
|
||||
}
|
||||
|
||||
// implement sort interface ...
|
||||
|
||||
// Len is the number of elements in the collection.
|
||||
// Required by Sort Interface{}
|
||||
func (mf MigrationFiles) Len() int {
|
||||
return len(mf)
|
||||
}
|
||||
|
||||
// Less reports whether the element with
|
||||
// index i should sort before the element with index j.
|
||||
// Required by Sort Interface{}
|
||||
func (mf MigrationFiles) Less(i, j int) bool {
|
||||
return mf[i].Version < mf[j].Version
|
||||
}
|
||||
|
||||
// Swap swaps the elements with indexes i and j.
|
||||
// Required by Sort Interface{}
|
||||
func (mf MigrationFiles) Swap(i, j int) {
|
||||
mf[i], mf[j] = mf[j], mf[i]
|
||||
}
|
||||
|
||||
// LineColumnFromOffset reads data and returns line and column integer
|
||||
// for a given offset.
|
||||
// TODO is there a better way?
|
||||
func LineColumnFromOffset(data []byte, offset int) (line, column int) {
|
||||
fs := token.NewFileSet()
|
||||
tf := fs.AddFile("", fs.Base(), len(data))
|
||||
tf.SetLinesForContent(data)
|
||||
pos := tf.Position(tf.Pos(offset))
|
||||
return pos.Line, pos.Column
|
||||
}
|
||||
|
||||
// LinesBeforeAndAfter reads n lines before and after a given line.
|
||||
// Set lineNumbers to true, to prepend line numbers.
|
||||
// TODO Trim empty lines at the beginning and at the end
|
||||
// TODO Trim offset whitespace at the beginning of each line, so that indentation is preserved
|
||||
func LinesBeforeAndAfter(data []byte, line, before, after int, lineNumbers bool) []byte {
|
||||
startLine := line - before
|
||||
endLine := line + after
|
||||
lines := bytes.SplitN(data, []byte("\n"), endLine+1)
|
||||
|
||||
if startLine < 0 {
|
||||
startLine = 0
|
||||
}
|
||||
if endLine > len(lines) {
|
||||
endLine = len(lines)
|
||||
}
|
||||
|
||||
selectLines := lines[startLine:endLine]
|
||||
newLines := make([][]byte, 0)
|
||||
lineCounter := startLine + 1
|
||||
lineNumberDigits := len(strconv.Itoa(len(selectLines)))
|
||||
for _, l := range selectLines {
|
||||
lineCounterStr := strconv.Itoa(lineCounter)
|
||||
if len(lineCounterStr)%lineNumberDigits != 0 {
|
||||
lineCounterStr = strings.Repeat(" ", lineNumberDigits-len(lineCounterStr)%lineNumberDigits) + lineCounterStr
|
||||
}
|
||||
|
||||
lNew := l
|
||||
if lineNumbers {
|
||||
lNew = append([]byte(lineCounterStr+": "), lNew...)
|
||||
}
|
||||
newLines = append(newLines, lNew)
|
||||
lineCounter += 1
|
||||
}
|
||||
|
||||
return bytes.Join(newLines, []byte("\n"))
|
||||
}
|
||||
|
|
34
main.go
34
main.go
|
@ -3,12 +3,14 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/fatih/color"
|
||||
"github.com/mattes/migrate/file"
|
||||
"github.com/mattes/migrate/migrate"
|
||||
"github.com/mattes/migrate/migrate/direction"
|
||||
pipep "github.com/mattes/migrate/pipe"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -31,11 +33,10 @@ func main() {
|
|||
|
||||
case "migrate":
|
||||
verifyMigrationsPath(*migrationsPath)
|
||||
|
||||
relativeN := flag.Arg(1)
|
||||
relativeNInt, err := strconv.Atoi(relativeN)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println("Unable to parse parse param <n>.")
|
||||
os.Exit(1)
|
||||
}
|
||||
migrateCmd(*url, *migrationsPath, relativeNInt)
|
||||
|
@ -75,6 +76,15 @@ func verifyMigrationsPath(path string) {
|
|||
}
|
||||
}
|
||||
|
||||
func textPadding(text string) string {
|
||||
textSplit := strings.Split(text, "\n")
|
||||
newText := make([]string, 0)
|
||||
for _, line := range textSplit {
|
||||
newText = append(newText, " "+line)
|
||||
}
|
||||
return strings.Join(newText, "\n")
|
||||
}
|
||||
|
||||
func writePipe(pipe chan interface{}) {
|
||||
if pipe != nil {
|
||||
for {
|
||||
|
@ -84,21 +94,27 @@ func writePipe(pipe chan interface{}) {
|
|||
return
|
||||
} else {
|
||||
switch item.(type) {
|
||||
|
||||
case string:
|
||||
fmt.Println(" ", item.(string))
|
||||
fmt.Println(item.(string))
|
||||
|
||||
case error:
|
||||
fmt.Println(" ", item.(error).Error())
|
||||
c := color.New(color.FgRed)
|
||||
c.Println(item.(error).Error())
|
||||
|
||||
case file.File:
|
||||
f := item.(file.File)
|
||||
direc := " "
|
||||
|
||||
if f.Direction == direction.Up {
|
||||
direc = " →"
|
||||
fmt.Print("[ → ]")
|
||||
} else if f.Direction == direction.Down {
|
||||
direc = "← "
|
||||
fmt.Print("[ ← ]")
|
||||
}
|
||||
fmt.Printf("%s %s\n", direc, f.FileName)
|
||||
fmt.Printf(" %s\n", f.FileName)
|
||||
|
||||
default:
|
||||
fmt.Printf(" %v\n", item)
|
||||
text := fmt.Sprint(item)
|
||||
fmt.Println(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue