2020-01-09 20:23:47 +00:00
|
|
|
// Copyright (C) 2020 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
2022-03-31 08:55:19 +01:00
|
|
|
"flag"
|
2020-01-09 20:23:47 +00:00
|
|
|
"fmt"
|
|
|
|
"go/format"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"sort"
|
2022-03-31 08:55:19 +01:00
|
|
|
"strings"
|
2020-01-09 20:23:47 +00:00
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2021-04-23 10:52:40 +01:00
|
|
|
"storj.io/private/dbutil/dbschema"
|
|
|
|
"storj.io/private/dbutil/sqliteutil"
|
2020-01-09 20:23:47 +00:00
|
|
|
"storj.io/storj/storagenode/storagenodedb"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2022-03-31 08:55:19 +01:00
|
|
|
outfile := flag.String("o", "", "output file")
|
|
|
|
flag.Parse()
|
|
|
|
|
2020-01-09 20:23:47 +00:00
|
|
|
ctx := context.Background()
|
2020-01-30 19:30:34 +00:00
|
|
|
log := zap.L()
|
2020-01-09 20:23:47 +00:00
|
|
|
|
2022-03-31 08:55:19 +01:00
|
|
|
out, err := runSchemaGen(ctx, log)
|
2020-01-09 20:23:47 +00:00
|
|
|
if err != nil {
|
2022-03-31 08:55:19 +01:00
|
|
|
printWithLines(os.Stderr, out)
|
2020-03-27 18:50:57 +00:00
|
|
|
fmt.Fprintf(os.Stderr, "%v", err)
|
2020-01-09 20:23:47 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
2022-03-31 08:55:19 +01:00
|
|
|
|
|
|
|
if *outfile == "" {
|
|
|
|
fmt.Print(string(out))
|
|
|
|
} else {
|
|
|
|
err := os.WriteFile(*outfile, out, 0644)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "%v", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
2020-01-09 20:23:47 +00:00
|
|
|
}
|
|
|
|
|
2022-03-31 08:55:19 +01:00
|
|
|
func printWithLines(w io.Writer, data []byte) {
|
|
|
|
for i, line := range strings.Split(string(data), "\n") {
|
|
|
|
fmt.Fprintf(w, "%3d: %s\n", i, line)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func runSchemaGen(ctx context.Context, log *zap.Logger) (_ []byte, err error) {
|
2022-10-31 15:12:17 +00:00
|
|
|
storagePath, err := os.MkdirTemp("", "testdb")
|
2020-01-09 20:23:47 +00:00
|
|
|
if err != nil {
|
2022-03-31 08:55:19 +01:00
|
|
|
return nil, errs.New("Error getting test storage path: %+w", err)
|
2020-01-09 20:23:47 +00:00
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
removeErr := os.RemoveAll(storagePath)
|
|
|
|
if removeErr != nil {
|
|
|
|
err = errs.Combine(err, removeErr)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2020-10-29 07:52:37 +00:00
|
|
|
db, err := storagenodedb.OpenNew(ctx, log, storagenodedb.Config{
|
2020-01-09 20:23:47 +00:00
|
|
|
Storage: storagePath,
|
|
|
|
Info: filepath.Join(storagePath, "piecestore.db"),
|
|
|
|
Info2: filepath.Join(storagePath, "info.db"),
|
|
|
|
Pieces: storagePath,
|
2022-11-29 14:12:38 +00:00
|
|
|
|
|
|
|
TestingDisableWAL: true,
|
2020-01-09 20:23:47 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
2022-03-31 08:55:19 +01:00
|
|
|
return nil, errs.New("Error creating new storagenode db: %+w", err)
|
2020-01-09 20:23:47 +00:00
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
closeErr := db.Close()
|
|
|
|
if closeErr != nil {
|
|
|
|
err = errs.Combine(err, closeErr)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2020-04-30 07:36:59 +01:00
|
|
|
err = db.MigrateToLatest(ctx)
|
2020-01-09 20:23:47 +00:00
|
|
|
if err != nil {
|
2022-03-31 08:55:19 +01:00
|
|
|
return nil, errs.New("Error creating tables for storagenode db: %+w", err)
|
2020-01-09 20:23:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// get schemas
|
|
|
|
schemaList := []string{}
|
|
|
|
allSchemas := make(map[string]*dbschema.Schema)
|
|
|
|
for dbName, dbContainer := range db.SQLDBs {
|
|
|
|
schemaList = append(schemaList, dbName)
|
|
|
|
|
|
|
|
nextDB := dbContainer.GetDB()
|
|
|
|
schema, err := sqliteutil.QuerySchema(ctx, nextDB)
|
|
|
|
if err != nil {
|
2022-03-31 08:55:19 +01:00
|
|
|
return nil, errs.New("Error getting schema for db: %+w", err)
|
2020-01-09 20:23:47 +00:00
|
|
|
}
|
|
|
|
// we don't care about changes in versions table
|
|
|
|
schema.DropTable("versions")
|
|
|
|
// If tables and indexes of the schema are empty, set to nil
|
|
|
|
// to help with comparison to the snapshot.
|
|
|
|
if len(schema.Tables) == 0 {
|
|
|
|
schema.Tables = nil
|
|
|
|
}
|
|
|
|
if len(schema.Indexes) == 0 {
|
|
|
|
schema.Indexes = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
allSchemas[dbName] = schema
|
|
|
|
}
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
|
|
printf := func(format string, args ...interface{}) {
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
_, err = fmt.Fprintf(&buf, format, args...)
|
|
|
|
}
|
|
|
|
printf(`//lint:file-ignore * generated file
|
|
|
|
// AUTOGENERATED BY storj.io/storj/storagenode/storagenodedb/schemagen.go
|
|
|
|
// DO NOT EDIT
|
|
|
|
|
|
|
|
package storagenodedb
|
|
|
|
|
2021-04-23 10:52:40 +01:00
|
|
|
import "storj.io/private/dbutil/dbschema"
|
2020-01-09 20:23:47 +00:00
|
|
|
|
|
|
|
func Schema() map[string]*dbschema.Schema {
|
|
|
|
return map[string]*dbschema.Schema{
|
|
|
|
`)
|
|
|
|
|
|
|
|
// use a consistent order for the generated file
|
|
|
|
sort.StringSlice(schemaList).Sort()
|
|
|
|
for _, schemaName := range schemaList {
|
|
|
|
schema := allSchemas[schemaName]
|
|
|
|
(func() {
|
2022-03-31 08:55:19 +01:00
|
|
|
printf("%q: {\n", schemaName)
|
2020-01-09 20:23:47 +00:00
|
|
|
defer printf("},\n")
|
|
|
|
|
2022-03-31 08:55:19 +01:00
|
|
|
writeErr := writeSchemaGoStruct(&buf, schema)
|
2020-01-09 20:23:47 +00:00
|
|
|
if writeErr != nil {
|
|
|
|
err = errs.New("Error writing schema struct: %+w", writeErr)
|
|
|
|
}
|
|
|
|
})()
|
|
|
|
if err != nil {
|
2022-03-31 08:55:19 +01:00
|
|
|
return nil, err
|
2020-01-09 20:23:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// close bracket for returned map
|
|
|
|
printf("}\n")
|
|
|
|
// close bracket for Schema() {
|
|
|
|
printf("}\n")
|
|
|
|
|
|
|
|
formatted, err := format.Source(buf.Bytes())
|
|
|
|
if err != nil {
|
2022-03-31 08:55:19 +01:00
|
|
|
return buf.Bytes(), errs.New("Error formatting: %+w", err)
|
2020-01-09 20:23:47 +00:00
|
|
|
}
|
|
|
|
|
2022-03-31 08:55:19 +01:00
|
|
|
return formatted, nil
|
2020-01-09 20:23:47 +00:00
|
|
|
}
|
|
|
|
|
2022-03-31 08:55:19 +01:00
|
|
|
func writeSchemaGoStruct(w io.Writer, schema *dbschema.Schema) (err error) {
|
2020-01-09 20:23:47 +00:00
|
|
|
printf := func(format string, args ...interface{}) {
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
_, err = fmt.Fprintf(w, format, args...)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(schema.Tables) > 0 {
|
|
|
|
(func() {
|
|
|
|
printf("Tables: []*dbschema.Table{\n")
|
|
|
|
defer printf("},\n")
|
|
|
|
|
|
|
|
for _, table := range schema.Tables {
|
2022-03-31 08:55:19 +01:00
|
|
|
err = writeTableGoStruct(w, table)
|
2020-01-09 20:23:47 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
printf(",\n")
|
|
|
|
}
|
|
|
|
})()
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(schema.Indexes) > 0 {
|
|
|
|
(func() {
|
|
|
|
printf("Indexes: []*dbschema.Index{\n")
|
|
|
|
defer printf("},\n")
|
|
|
|
|
|
|
|
for _, index := range schema.Indexes {
|
2022-03-31 08:55:19 +01:00
|
|
|
printf("%v,\n", prettyValue(index))
|
2020-01-09 20:23:47 +00:00
|
|
|
}
|
|
|
|
})()
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:55:19 +01:00
|
|
|
func writeTableGoStruct(w io.Writer, table *dbschema.Table) (err error) {
|
2020-01-09 20:23:47 +00:00
|
|
|
printf := func(format string, args ...interface{}) {
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
_, err = fmt.Fprintf(w, format, args...)
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:55:19 +01:00
|
|
|
printf("{\n")
|
2020-01-09 20:23:47 +00:00
|
|
|
defer printf("}")
|
|
|
|
|
|
|
|
printf("Name: %q,\n", table.Name)
|
|
|
|
if table.PrimaryKey != nil {
|
|
|
|
printf("PrimaryKey: %#v,\n", table.PrimaryKey)
|
|
|
|
}
|
|
|
|
if table.Unique != nil {
|
2022-03-31 08:55:19 +01:00
|
|
|
printf("Unique: %v,\n", prettyValue(table.Unique))
|
2020-01-09 20:23:47 +00:00
|
|
|
}
|
|
|
|
if len(table.Columns) > 0 {
|
|
|
|
(func() {
|
|
|
|
printf("Columns: []*dbschema.Column{\n")
|
|
|
|
defer printf("},\n")
|
|
|
|
|
|
|
|
for _, column := range table.Columns {
|
2022-03-31 08:55:19 +01:00
|
|
|
err = writeColumnGoStruct(w, column)
|
2020-01-09 20:23:47 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})()
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:55:19 +01:00
|
|
|
func writeColumnGoStruct(w io.Writer, column *dbschema.Column) (err error) {
|
2020-01-09 20:23:47 +00:00
|
|
|
printf := func(format string, args ...interface{}) {
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
_, err = fmt.Fprintf(w, format, args...)
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:55:19 +01:00
|
|
|
printf("{\n")
|
2020-01-09 20:23:47 +00:00
|
|
|
defer printf("},\n")
|
|
|
|
|
|
|
|
printf("Name: %q,\n", column.Name)
|
|
|
|
printf("Type: %q,\n", column.Type)
|
|
|
|
printf("IsNullable: %t,\n", column.IsNullable)
|
|
|
|
if column.Reference != nil {
|
|
|
|
printf("Reference: %#v,\n", column.Reference)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
2022-03-31 08:55:19 +01:00
|
|
|
|
|
|
|
// prettyValue converts to string without the outer type
|
|
|
|
// definition.
|
|
|
|
func prettyValue(v interface{}) string {
|
|
|
|
s := fmt.Sprintf("%#v", v)
|
|
|
|
p := strings.Index(s, "{")
|
|
|
|
return s[p:]
|
|
|
|
}
|