Files
threshold/internal/db/schema/migrations/generate/generate.go
T

146 lines
3.7 KiB
Go

package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"sort"
"strconv"
"strings"
"text/template"
)
// generate looks for migration sql in a directory for the given dialect and
// applies the templates below to the contents of the files, building up a
// migrations map for the dialect
func generate(dialect string) {
baseDir := os.Getenv("GEN_BASEPATH") + "/internal/db/schema"
srcDir := baseDir + "/migrations"
dir, err := os.Open(fmt.Sprintf("%s/%s", srcDir, dialect))
if err != nil {
fmt.Printf("error opening dir with dialect %s: %v\n", dialect, err)
os.Exit(1)
}
versions, err := dir.Readdirnames(0)
if err != nil {
fmt.Printf("error reading dir names with dialect %s: %v\n", dialect, err)
os.Exit(1)
}
sort.Strings(versions)
type ContentValues struct {
Name string
Content string
}
var upContents []ContentValues
var largestSchemaVersion int
for _, ver := range versions {
if strings.HasPrefix(ver, ".") {
continue
}
var verVal int
verVal, err := strconv.Atoi(ver)
if err != nil {
fmt.Printf("error reading major schema version directory %q. Must be a number: %v\n", ver, err)
os.Exit(1)
}
dir, err := os.Open(fmt.Sprintf("%s/%s/%s", srcDir, dialect, ver))
if err != nil {
fmt.Printf("error opening dir with dialect %s: %v\n", dialect, err)
os.Exit(1)
}
names, err := dir.Readdirnames(0)
if err != nil {
fmt.Printf("error reading dir names with dialect %s: %v\n", dialect, err)
os.Exit(1)
}
sort.Strings(names)
for _, name := range names {
if !strings.HasSuffix(name, ".sql") {
continue
}
nameParts := strings.SplitN(name, "_", 2)
if len(nameParts) != 2 {
continue
}
v, err := strconv.Atoi(nameParts[0])
if err != nil {
fmt.Printf("Unable to get file version from %q\n", name)
continue
}
fullV := (verVal * 1000) + v
if fullV > largestSchemaVersion {
largestSchemaVersion = fullV
}
cbts, err := ioutil.ReadFile(fmt.Sprintf("%s/%s/%s/%s", srcDir, dialect, ver, name))
if err != nil {
fmt.Printf("error opening file %s with dialect %s: %v", name, dialect, err)
os.Exit(1)
}
contents := strings.TrimSpace(string(cbts))
if strings.ToLower(contents[:len("begin;")]) == "begin;" {
contents = contents[len("begin;"):]
}
if strings.ToLower(contents[len(contents)-len("commit;"):]) == "commit;" {
contents = contents[:len(contents)-len("commit;")]
}
contents = strings.TrimSpace(contents)
cv := ContentValues{
Name: fmt.Sprint(fullV),
Content: contents,
}
switch {
case strings.Contains(nameParts[1], ".up."):
upContents = append(upContents, cv)
}
}
}
outBuf := bytes.NewBuffer(nil)
if err := migrationsTemplate.Execute(outBuf, struct {
Type string
UpValues []ContentValues
BinarySchemaVersion int
}{
Type: dialect,
UpValues: upContents,
BinarySchemaVersion: largestSchemaVersion,
}); err != nil {
fmt.Printf("error executing migrations value template for dialect %s: %s", dialect, err)
os.Exit(1)
}
outFile := fmt.Sprintf("%s/%s_migration.gen.go", baseDir, dialect)
if err := ioutil.WriteFile(outFile, outBuf.Bytes(), 0o644); err != nil {
fmt.Printf("error writing file %q: %v\n", outFile, err)
os.Exit(1)
}
}
var migrationsTemplate = template.Must(template.Must(template.New("Content").Parse(
`{{ .Name }}: []byte(` + "`\n{{ .Content }}\n`" + `),
`)).New("MainPage").Parse(`package schema
// Code generated by "make migrations"; DO NOT EDIT.
func init() {
migrationStates["{{ .Type }}"] = migrationState{
binarySchemaVersion: {{ .BinarySchemaVersion }},
upMigrations: map[int][]byte{
{{range .UpValues }}{{ template "Content" . }}{{end}}
},
}
}
`))