• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / cli / 15269737294

27 May 2025 07:56AM UTC coverage: 60.208% (-0.01%) from 60.221%
15269737294

Pull #3620

github

web-flow
Merge b325d5413 into 9a2a74005
Pull Request #3620: Update Dockerfile

9027 of 14993 relevant lines covered (60.21%)

509.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.96
/internal/utils/container_output.go
1
package utils
2

3
import (
4
        "bufio"
5
        "bytes"
6
        "encoding/json"
7
        "fmt"
8
        "io"
9
        "os"
10
        "regexp"
11
        "strconv"
12
        "strings"
13

14
        "github.com/docker/docker/pkg/jsonmessage"
15
        "github.com/docker/docker/pkg/stdcopy"
16
        "github.com/go-errors/errors"
17
)
18

19
func ProcessPullOutput(out io.ReadCloser, p Program) error {
1✔
20
        dec := json.NewDecoder(out)
1✔
21

1✔
22
        downloads := make(map[string]struct{ current, total int64 })
1✔
23

1✔
24
        for {
7✔
25
                var progress jsonmessage.JSONMessage
6✔
26

6✔
27
                if err := dec.Decode(&progress); err == io.EOF {
7✔
28
                        break
1✔
29
                } else if err != nil {
5✔
30
                        return err
×
31
                }
×
32

33
                if strings.HasPrefix(progress.Status, "Pulling from") {
6✔
34
                        p.Send(StatusMsg(progress.Status + "..."))
1✔
35
                } else if progress.Status == "Pulling fs layer" || progress.Status == "Waiting" {
7✔
36
                        downloads[progress.ID] = struct{ current, total int64 }{
2✔
37
                                current: 0,
2✔
38
                                total:   0,
2✔
39
                        }
2✔
40
                } else if progress.Status == "Downloading" {
6✔
41
                        downloads[progress.ID] = struct{ current, total int64 }{
2✔
42
                                current: progress.Progress.Current,
2✔
43
                                total:   progress.Progress.Total,
2✔
44
                        }
2✔
45

2✔
46
                        var overallProgress float64
2✔
47
                        for _, percentage := range downloads {
5✔
48
                                if percentage.total > 0 {
6✔
49
                                        progress := float64(percentage.current) / float64(percentage.total)
3✔
50
                                        overallProgress += progress / float64(len(downloads))
3✔
51
                                }
3✔
52
                        }
53

54
                        p.Send(ProgressMsg(&overallProgress))
2✔
55
                }
56
        }
57

58
        p.Send(ProgressMsg(nil))
1✔
59

1✔
60
        return nil
1✔
61
}
62

63
type DiffStream struct {
64
        o bytes.Buffer
65
        r *io.PipeReader
66
        w *io.PipeWriter
67
        p Program
68
}
69

70
func NewDiffStream(p Program) *DiffStream {
×
71
        r, w := io.Pipe()
×
72
        go func() {
×
73
                if err := ProcessDiffProgress(p, r); err != nil {
×
74
                        fmt.Fprintln(os.Stderr, err)
×
75
                }
×
76
        }()
77
        return &DiffStream{r: r, w: w, p: p}
×
78
}
79

80
func (c DiffStream) Stdout() io.Writer {
×
81
        return &c.o
×
82
}
×
83

84
func (c DiffStream) Stderr() io.Writer {
×
85
        return c.w
×
86
}
×
87

88
func (c DiffStream) Collect() ([]byte, error) {
×
89
        if err := c.w.Close(); err != nil {
×
90
                fmt.Fprintln(os.Stderr, "Failed to close stream:", err)
×
91
        }
×
92
        return ProcessDiffOutput(c.o.Bytes())
×
93
}
94

95
func ProcessDiffProgress(p Program, out io.Reader) error {
×
96
        scanner := bufio.NewScanner(out)
×
97
        re := regexp.MustCompile(`(.*)([[:digit:]]{2,3})%`)
×
98
        for scanner.Scan() {
×
99
                line := scanner.Text()
×
100

×
101
                if line == "Starting schema diff..." {
×
102
                        percentage := 0.0
×
103
                        p.Send(ProgressMsg(&percentage))
×
104
                }
×
105

106
                matches := re.FindStringSubmatch(line)
×
107
                if len(matches) != 3 {
×
108
                        // TODO: emit actual error statements
×
109
                        continue
×
110
                }
111

112
                p.Send(StatusMsg(matches[1]))
×
113
                percentage, err := strconv.ParseFloat(matches[2], 64)
×
114
                if err != nil {
×
115
                        continue
×
116
                }
117
                percentage = percentage / 100
×
118
                p.Send(ProgressMsg(&percentage))
×
119
        }
120
        p.Send(ProgressMsg(nil))
×
121
        return scanner.Err()
×
122
}
123

124
type DiffDependencies struct {
125
        Type string `json:"type"`
126
}
127

128
type DiffEntry struct {
129
        Type             string             `json:"type"`
130
        Status           string             `json:"status"`
131
        DiffDdl          string             `json:"diff_ddl"`
132
        GroupName        string             `json:"group_name"`
133
        Dependencies     []DiffDependencies `json:"dependencies"`
134
        SourceSchemaName *string            `json:"source_schema_name"`
135
}
136

137
const diffHeader = `-- This script was generated by the Schema Diff utility in pgAdmin 4
138
-- For the circular dependencies, the order in which Schema Diff writes the objects is not very sophisticated
139
-- and may require manual changes to the script to ensure changes are applied in the correct order.
140
-- Please report an issue for any failure with the reproduction steps.`
141

142
func ProcessDiffOutput(diffBytes []byte) ([]byte, error) {
2✔
143
        // TODO: Remove when https://github.com/supabase/pgadmin4/issues/24 is fixed.
2✔
144
        diffBytes = bytes.TrimPrefix(diffBytes, []byte("NOTE: Configuring authentication for DESKTOP mode.\n"))
2✔
145

2✔
146
        if len(diffBytes) == 0 {
2✔
147
                return diffBytes, nil
×
148
        }
×
149

150
        var diffJson []DiffEntry
2✔
151
        if err := json.Unmarshal(diffBytes, &diffJson); err != nil {
2✔
152
                return nil, err
×
153
        }
×
154

155
        var filteredDiffDdls []string
2✔
156
        for _, diffEntry := range diffJson {
6✔
157
                if diffEntry.Status == "Identical" || diffEntry.DiffDdl == "" {
4✔
158
                        continue
×
159
                }
160

161
                switch diffEntry.Type {
4✔
162
                case "extension", "function", "mview", "table", "trigger_function", "type", "view":
4✔
163
                        // skip
164
                default:
×
165
                        continue
×
166
                }
167

168
                {
4✔
169
                        doContinue := false
4✔
170
                        for _, dep := range diffEntry.Dependencies {
4✔
171
                                if dep.Type == "extension" {
×
172
                                        doContinue = true
×
173
                                        break
×
174
                                }
175
                        }
176

177
                        if doContinue {
4✔
178
                                continue
×
179
                        }
180
                }
181

182
                isSchemaIgnored := func(schema string) bool {
8✔
183
                        for _, s := range InternalSchemas {
68✔
184
                                if s == schema {
66✔
185
                                        return true
2✔
186
                                }
2✔
187
                        }
188
                        return false
2✔
189
                }
190

191
                if isSchemaIgnored(diffEntry.GroupName) ||
4✔
192
                        // Needed at least for trigger_function
4✔
193
                        (diffEntry.SourceSchemaName != nil && isSchemaIgnored(*diffEntry.SourceSchemaName)) {
6✔
194
                        continue
2✔
195
                }
196

197
                trimmed := strings.TrimSpace(diffEntry.DiffDdl)
2✔
198
                if len(trimmed) > 0 {
4✔
199
                        filteredDiffDdls = append(filteredDiffDdls, trimmed)
2✔
200
                }
2✔
201
        }
202

203
        if len(filteredDiffDdls) == 0 {
3✔
204
                return nil, nil
1✔
205
        }
1✔
206
        return []byte(diffHeader + "\n\n" + strings.Join(filteredDiffDdls, "\n\n") + "\n"), nil
1✔
207
}
208

209
func ProcessPsqlOutput(out io.Reader, p Program) error {
2✔
210
        r, w := io.Pipe()
2✔
211
        doneCh := make(chan struct{}, 1)
2✔
212

2✔
213
        go func() {
4✔
214
                scanner := bufio.NewScanner(r)
2✔
215

2✔
216
                for scanner.Scan() {
3✔
217
                        select {
1✔
218
                        case <-doneCh:
×
219
                                return
×
220
                        default:
1✔
221
                        }
222

223
                        line := scanner.Text()
1✔
224
                        p.Send(PsqlMsg(&line))
1✔
225
                }
226
        }()
227

228
        var errBuf bytes.Buffer
2✔
229
        if _, err := stdcopy.StdCopy(w, &errBuf, out); err != nil {
2✔
230
                return err
×
231
        }
×
232
        if errBuf.Len() > 0 {
3✔
233
                return errors.New("Error running SQL: " + errBuf.String())
1✔
234
        }
1✔
235

236
        doneCh <- struct{}{}
1✔
237
        p.Send(PsqlMsg(nil))
1✔
238

1✔
239
        return nil
1✔
240
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc