-
Notifications
You must be signed in to change notification settings - Fork 235
/
Copy pathlist.go
140 lines (128 loc) · 3.88 KB
/
list.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package list
import (
"context"
"fmt"
"math"
"strconv"
"strings"
"github.com/charmbracelet/glamour"
"github.com/go-errors/errors"
"github.com/jackc/pgconn"
"github.com/jackc/pgx/v4"
"github.com/spf13/afero"
"github.com/supabase/cli/internal/utils"
"github.com/supabase/cli/pkg/migration"
)
func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
remoteVersions, err := loadRemoteVersions(ctx, config, options...)
if err != nil {
return err
}
localVersions, err := LoadLocalVersions(fsys)
if err != nil {
return err
}
table := makeTable(remoteVersions, localVersions)
return RenderTable(table)
}
func loadRemoteVersions(ctx context.Context, config pgconn.Config, options ...func(*pgx.ConnConfig)) ([]string, error) {
conn, err := utils.ConnectByConfig(ctx, config, options...)
if err != nil {
return nil, err
}
defer conn.Close(context.Background())
return migration.ListRemoteMigrations(ctx, conn)
}
func makeTable(remoteMigrations, localMigrations []string) string {
var err error
table := "|Local|Remote|Time (UTC)|\n|-|-|-|\n"
for i, j := 0, 0; i < len(remoteMigrations) || j < len(localMigrations); {
remoteTimestamp := math.MaxInt
if i < len(remoteMigrations) {
if remoteTimestamp, err = strconv.Atoi(remoteMigrations[i]); err != nil {
i++
continue
}
}
localTimestamp := math.MaxInt
if j < len(localMigrations) {
if localTimestamp, err = strconv.Atoi(localMigrations[j]); err != nil {
j++
continue
}
}
// Top to bottom chronological order
if localTimestamp < remoteTimestamp {
table += fmt.Sprintf("|`%s`|` `|`%s`|\n", localMigrations[j], utils.FormatTimestampVersion(localMigrations[j]))
j++
} else if remoteTimestamp < localTimestamp {
table += fmt.Sprintf("|` `|`%s`|`%s`|\n", remoteMigrations[i], utils.FormatTimestampVersion(remoteMigrations[i]))
i++
} else {
table += fmt.Sprintf("|`%s`|`%s`|`%s`|\n", localMigrations[j], remoteMigrations[i], utils.FormatTimestampVersion(remoteMigrations[i]))
i++
j++
}
}
for i, j := 0, 0; i < len(remoteMigrations) || j < len(localMigrations); {
if i < len(remoteMigrations) && !strings.HasPrefix(remoteMigrations[i], "r_") {
i++
continue
}
if j < len(localMigrations) && !strings.HasPrefix(localMigrations[j], "r_") {
j++
continue
}
// Append repeatable migrations to table
if i >= len(remoteMigrations) {
table += fmt.Sprintf("|`%s`|` `|` `|\n", localMigrations[j])
j++
} else if j >= len(localMigrations) {
table += fmt.Sprintf("|` `|`%s`|` `|\n", remoteMigrations[i])
i++
} else {
if localMigrations[j] < remoteMigrations[i] {
table += fmt.Sprintf("|`%s`|` `|` `|\n", localMigrations[j])
j++
} else if remoteMigrations[i] < localMigrations[j] {
table += fmt.Sprintf("|` `|`%s`|` `|\n", remoteMigrations[i])
i++
} else {
table += fmt.Sprintf("|`%s`|`%s`|` `|\n", localMigrations[j], remoteMigrations[i])
i++
j++
}
}
}
return table
}
func RenderTable(markdown string) error {
r, err := glamour.NewTermRenderer(
glamour.WithAutoStyle(),
glamour.WithWordWrap(-1),
)
if err != nil {
return errors.Errorf("failed to initialise terminal renderer: %w", err)
}
out, err := r.Render(markdown)
if err != nil {
return errors.Errorf("failed to render markdown: %w", err)
}
fmt.Print(out)
return nil
}
func LoadLocalVersions(fsys afero.Fs) ([]string, error) {
var versions []string
filter := func(v string) bool {
versions = append(versions, v)
return true
}
_, err := migration.ListLocalMigrations(utils.MigrationsDir, afero.NewIOFS(fsys), filter)
return versions, err
}
func LoadPartialMigrations(version string, fsys afero.Fs) ([]string, error) {
filter := func(v string) bool {
return version == "" || strings.HasPrefix(version, "r_") || v <= version
}
return migration.ListLocalMigrations(utils.MigrationsDir, afero.NewIOFS(fsys), filter)
}