Skip to content

Commit 93237bf

Browse files
committed
debug
1 parent 6a437b3 commit 93237bf

6 files changed

Lines changed: 222 additions & 23 deletions

File tree

cmd/backup.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cmd
22

33
import (
4-
"context"
54
"fmt"
65
"time"
76

@@ -58,7 +57,7 @@ Example:
5857
cmdArgs = append(cmdArgs, extraFlag)
5958
}
6059

61-
exitCode, err := sdk.ExecInContainerInteractive(context.Background(), containerName, cmdArgs)
60+
exitCode, err := cli.ExecInteractive(cmd.Context(), containerName, cmdArgs)
6261
if err != nil {
6362
return err
6463
}

cmd/drush.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cmd
22

33
import (
4-
"context"
54
"fmt"
65

76
"github.com/kballard/go-shellquote"
@@ -41,7 +40,7 @@ Examples:
4140
drushCmd := []string{"bash", "-c", fmt.Sprintf("drush %s", shellquote.Join(filteredArgs...))}
4241

4342
// Execute the command interactively using SDK helper
44-
exitCode, err := sdk.ExecInContainerInteractive(context.Background(), containerName, drushCmd)
43+
exitCode, err := cli.ExecInteractive(cmd.Context(), containerName, drushCmd)
4544
if err != nil {
4645
return err
4746
}

cmd/extensions.go

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import (
44
"bytes"
55
"context"
66
"fmt"
7+
"log/slog"
78
"os"
89
"path/filepath"
910
"sort"
1011
"strconv"
1112
"strings"
1213

1314
"charm.land/lipgloss/v2"
15+
"github.com/kballard/go-shellquote"
1416
"github.com/libops/sitectl/pkg/config"
1517
"github.com/libops/sitectl/pkg/docker"
1618
"github.com/libops/sitectl/pkg/plugin"
@@ -91,7 +93,7 @@ var debugExtensionCmd = &cobra.Command{
9193
Short: "Internal debug extension command",
9294
Hidden: true,
9395
RunE: func(cmd *cobra.Command, args []string) error {
94-
rendered, err := renderDrupalDebug()
96+
rendered, err := renderDrupalDebug(cmd.Context())
9597
if err != nil {
9698
return err
9799
}
@@ -111,21 +113,26 @@ func init() {
111113
debugExtensionCmd.Flags().StringVar(&drupalRootfsPath, "drupal-rootfs", "drupal/rootfs/var/www/drupal", "Drupal rootfs path override")
112114
}
113115

114-
func renderDrupalDebug() (string, error) {
116+
func renderDrupalDebug(runCtx context.Context) (string, error) {
117+
slog.Debug("starting plugin debug", "plugin", "drupal")
115118
if sdk == nil {
116119
return "", fmt.Errorf("plugin sdk is not initialized")
117120
}
118121
ctx, err := sdk.GetContext()
119122
if err != nil {
120123
return "", err
121124
}
122-
files, err := plugin.NewFileAccessor(ctx)
125+
slog.Debug("resolved plugin context", "plugin", "drupal", "context", ctx.Name, "project_dir", ctx.ProjectDir)
126+
slog.Debug("creating file accessor", "plugin", "drupal")
127+
files, err := sdk.GetFileAccessor()
123128
if err != nil {
124129
return "", err
125130
}
126131
defer files.Close()
127132

133+
slog.Debug("resolving drupal root", "plugin", "drupal", "rootfs", drupalRootfsPath)
128134
drupalRoot := resolveDrupalRoot(files, ctx.ProjectDir, drupalRootfsPath)
135+
slog.Debug("resolved drupal root", "plugin", "drupal", "drupal_root", drupalRoot)
129136
configDir := filepath.Join(drupalRoot, "config", "sync")
130137
body := []string{
131138
debugDivider(),
@@ -141,15 +148,19 @@ func renderDrupalDebug() (string, error) {
141148
}
142149

143150
if strings.TrimSpace(drupalRoot) == "" {
151+
slog.Debug("drupal root unavailable; skipping extension scan", "plugin", "drupal")
144152
body = append(body, "", "Installed modules: unavailable")
145153
return renderDebugPanel("drupal", strings.Join(body, "\n")), nil
146154
}
147155

148-
modules, themes, err := readCoreExtension(files, filepath.Join(configDir, "core.extension.yml"))
156+
slog.Debug("reading core.extension.yml", "plugin", "drupal", "path", filepath.Join(configDir, "core.extension.yml"))
157+
modules, themes, err := readCoreExtension(runCtx, files, filepath.Join(configDir, "core.extension.yml"))
149158
if err != nil {
150159
return "", err
151160
}
152-
cachePageSummary, err := renderCachePageSummary()
161+
slog.Debug("read installed extensions", "plugin", "drupal", "modules", len(modules), "themes", len(themes))
162+
slog.Debug("rendering cache_page summary", "plugin", "drupal")
163+
cachePageSummary, err := renderCachePageSummary(runCtx)
153164
if err != nil {
154165
body = append(body, "", debugDivider(), "", debugTitleStyle.Render("Cache Page"), "", formatDebugRows([]debugRow{
155166
{Label: "Status", Value: renderStatus("warning")},
@@ -166,18 +177,19 @@ func renderDrupalDebug() (string, error) {
166177
configLines = append(configLines, formatListLines(themes, 3)...)
167178
body = append(body, "", strings.Join(configLines, "\n"))
168179

180+
slog.Debug("finished plugin debug", "plugin", "drupal")
169181
return renderDebugPanel("drupal", strings.Join(body, "\n")), nil
170182
}
171183

172-
func renderCachePageSummary() (string, error) {
173-
_, cli, containerName, err := getDrupalContainerForSDK()
184+
func renderCachePageSummary(runCtx context.Context) (string, error) {
185+
_, cli, containerName, err := getDrupalContainerForSDK(runCtx)
174186
if err != nil {
175187
return "", err
176188
}
177189
defer cli.Close()
178190

179191
query := "SELECT COALESCE(data_length + index_length, 0) FROM information_schema.TABLES WHERE table_schema = DATABASE() AND table_name = 'cache_page';"
180-
output, err := execDrupalCommandCapture(cli, containerName, []string{"drush", "sql:query", query, "--extra=--batch --skip-column-names"})
192+
output, err := execDrupalCommandCapture(runCtx, cli, containerName, []string{"drush", "sql:query", query, "--extra=--batch", "--extra=--skip-column-names"})
181193
if err != nil {
182194
return "", err
183195
}
@@ -198,7 +210,7 @@ func renderCachePageSummary() (string, error) {
198210
return formatDebugRows(rows), nil
199211
}
200212

201-
func getDrupalContainerForSDK() (ctx *config.Context, cli *docker.DockerClient, containerName string, err error) {
213+
func getDrupalContainerForSDK(runCtx context.Context) (ctx *config.Context, cli *docker.DockerClient, containerName string, err error) {
202214
if sdk == nil {
203215
return nil, nil, "", fmt.Errorf("plugin sdk is not initialized")
204216
}
@@ -213,7 +225,7 @@ func getDrupalContainerForSDK() (ctx *config.Context, cli *docker.DockerClient,
213225
return nil, nil, "", err
214226
}
215227

216-
containerName, err = cli.GetContainerName(ctx, *drupalServiceName)
228+
containerName, err = cli.GetContainerNameContext(runCtx, ctx, *drupalServiceName)
217229
if err != nil {
218230
cli.Close()
219231
return nil, nil, "", err
@@ -222,13 +234,17 @@ func getDrupalContainerForSDK() (ctx *config.Context, cli *docker.DockerClient,
222234
return ctx, cli, containerName, nil
223235
}
224236

225-
func execDrupalCommandCapture(cli *docker.DockerClient, containerName string, cmd []string) (string, error) {
237+
func execDrupalCommandCapture(runCtx context.Context, cli *docker.DockerClient, containerName string, cmd []string) (string, error) {
238+
slog.Debug(strings.Join(cmd, " "), "plugin", "drupal", "container", containerName)
226239
var stdout bytes.Buffer
227240
var stderr bytes.Buffer
228241

229-
exitCode, err := cli.Exec(context.Background(), docker.ExecOptions{
242+
wrappedCmd := []string{"bash", "-lc", fmt.Sprintf("cd /var/www/drupal && %s", shellquote.Join(cmd...))}
243+
244+
exitCode, err := cli.Exec(runCtx, docker.ExecOptions{
230245
Container: containerName,
231-
Cmd: cmd,
246+
Cmd: wrappedCmd,
247+
WorkingDir: "/var/www/drupal",
232248
AttachStdout: true,
233249
AttachStderr: true,
234250
Stdout: &stdout,
@@ -295,8 +311,8 @@ func resolveDrupalRoot(files *plugin.FileAccessor, projectDir, drupalRootPath st
295311
return ""
296312
}
297313

298-
func readCoreExtension(files *plugin.FileAccessor, path string) ([]string, []string, error) {
299-
data, err := files.ReadFile(path)
314+
func readCoreExtension(runCtx context.Context, files *plugin.FileAccessor, path string) ([]string, []string, error) {
315+
data, err := files.ReadFileContext(runCtx, path)
300316
if err != nil {
301317
if os.IsNotExist(err) {
302318
return nil, nil, nil

cmd/extensions_test.go

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"os"
6+
"path/filepath"
7+
"reflect"
8+
"strings"
9+
"testing"
10+
11+
"github.com/libops/sitectl/pkg/config"
12+
"github.com/libops/sitectl/pkg/plugin"
13+
)
14+
15+
func TestReadCoreExtensionParsesModulesAndThemes(t *testing.T) {
16+
root := t.TempDir()
17+
path := filepath.Join(root, "core.extension.yml")
18+
data := `_core:
19+
default_config_hash: abc
20+
module:
21+
views: 10
22+
pathauto: 1
23+
system: 0
24+
theme:
25+
claro: 0
26+
olivero: 0
27+
`
28+
if err := os.WriteFile(path, []byte(data), 0o644); err != nil {
29+
t.Fatalf("WriteFile() error = %v", err)
30+
}
31+
32+
files, err := plugin.NewFileAccessor(&config.Context{DockerHostType: config.ContextLocal})
33+
if err != nil {
34+
t.Fatalf("NewFileAccessor() error = %v", err)
35+
}
36+
defer files.Close()
37+
38+
modules, themes, err := readCoreExtension(context.Background(), files, path)
39+
if err != nil {
40+
t.Fatalf("readCoreExtension() error = %v", err)
41+
}
42+
43+
wantModules := []string{"pathauto", "system", "views"}
44+
if !reflect.DeepEqual(modules, wantModules) {
45+
t.Fatalf("modules = %v, want %v", modules, wantModules)
46+
}
47+
48+
wantThemes := []string{"claro", "olivero"}
49+
if !reflect.DeepEqual(themes, wantThemes) {
50+
t.Fatalf("themes = %v, want %v", themes, wantThemes)
51+
}
52+
}
53+
54+
func TestReadCoreExtensionMissingFileReturnsNilSlices(t *testing.T) {
55+
files, err := plugin.NewFileAccessor(&config.Context{DockerHostType: config.ContextLocal})
56+
if err != nil {
57+
t.Fatalf("NewFileAccessor() error = %v", err)
58+
}
59+
defer files.Close()
60+
61+
modules, themes, err := readCoreExtension(context.Background(), files, filepath.Join(t.TempDir(), "missing.yml"))
62+
if err != nil {
63+
t.Fatalf("readCoreExtension() error = %v", err)
64+
}
65+
if modules != nil {
66+
t.Fatalf("expected nil modules, got %v", modules)
67+
}
68+
if themes != nil {
69+
t.Fatalf("expected nil themes, got %v", themes)
70+
}
71+
}
72+
73+
func TestResolveDrupalRootFindsConfiguredRootfs(t *testing.T) {
74+
projectDir := t.TempDir()
75+
drupalRoot := filepath.Join(projectDir, "drupal", "rootfs", "var", "www", "drupal")
76+
configDir := filepath.Join(drupalRoot, "config", "sync")
77+
if err := os.MkdirAll(configDir, 0o755); err != nil {
78+
t.Fatalf("MkdirAll() error = %v", err)
79+
}
80+
if err := os.WriteFile(filepath.Join(configDir, "core.extension.yml"), []byte("module: {}\ntheme: {}\n"), 0o644); err != nil {
81+
t.Fatalf("WriteFile() error = %v", err)
82+
}
83+
84+
files, err := plugin.NewFileAccessor(&config.Context{DockerHostType: config.ContextLocal})
85+
if err != nil {
86+
t.Fatalf("NewFileAccessor() error = %v", err)
87+
}
88+
defer files.Close()
89+
90+
got := resolveDrupalRoot(files, projectDir, "drupal/rootfs/var/www/drupal")
91+
if got != drupalRoot {
92+
t.Fatalf("resolveDrupalRoot() = %q, want %q", got, drupalRoot)
93+
}
94+
}
95+
96+
func TestResolveDrupalRootFallsBackToProjectDir(t *testing.T) {
97+
projectDir := t.TempDir()
98+
configDir := filepath.Join(projectDir, "config", "sync")
99+
if err := os.MkdirAll(configDir, 0o755); err != nil {
100+
t.Fatalf("MkdirAll() error = %v", err)
101+
}
102+
if err := os.WriteFile(filepath.Join(configDir, "core.extension.yml"), []byte("module: {}\ntheme: {}\n"), 0o644); err != nil {
103+
t.Fatalf("WriteFile() error = %v", err)
104+
}
105+
106+
files, err := plugin.NewFileAccessor(&config.Context{DockerHostType: config.ContextLocal})
107+
if err != nil {
108+
t.Fatalf("NewFileAccessor() error = %v", err)
109+
}
110+
defer files.Close()
111+
112+
got := resolveDrupalRoot(files, projectDir, "drupal/rootfs/var/www/drupal")
113+
if got != projectDir {
114+
t.Fatalf("resolveDrupalRoot() = %q, want %q", got, projectDir)
115+
}
116+
}
117+
118+
func TestFormatListLinesWrapsThreePerLine(t *testing.T) {
119+
values := []string{"action", "admin_toolbar", "big_pipe", "views", "pathauto", "token", "media"}
120+
121+
got := formatListLines(values, 3)
122+
want := []string{
123+
" action, admin_toolbar, big_pipe",
124+
" views, pathauto, token",
125+
" media",
126+
}
127+
if !reflect.DeepEqual(got, want) {
128+
t.Fatalf("formatListLines() = %v, want %v", got, want)
129+
}
130+
}
131+
132+
func TestFormatListLinesEmptyReturnsNone(t *testing.T) {
133+
got := formatListLines(nil, 3)
134+
want := []string{" none"}
135+
if !reflect.DeepEqual(got, want) {
136+
t.Fatalf("formatListLines() = %v, want %v", got, want)
137+
}
138+
}
139+
140+
func TestParseFirstIntReadsFirstNonEmptyLine(t *testing.T) {
141+
got, err := parseFirstInt("\n 1024 \nignored\n")
142+
if err != nil {
143+
t.Fatalf("parseFirstInt() error = %v", err)
144+
}
145+
if got != 1024 {
146+
t.Fatalf("parseFirstInt() = %d, want 1024", got)
147+
}
148+
}
149+
150+
func TestParseFirstIntErrorsWhenMissingNumber(t *testing.T) {
151+
_, err := parseFirstInt("\n \n")
152+
if err == nil {
153+
t.Fatal("expected parseFirstInt() error")
154+
}
155+
if !strings.Contains(err.Error(), "no numeric output returned") {
156+
t.Fatalf("unexpected error: %v", err)
157+
}
158+
}
159+
160+
func TestGetDrupalContainerForSDKRequiresSDK(t *testing.T) {
161+
original := sdk
162+
sdk = nil
163+
defer func() { sdk = original }()
164+
165+
_, _, _, err := getDrupalContainerForSDK(context.Background())
166+
if err == nil {
167+
t.Fatal("expected getDrupalContainerForSDK() error")
168+
}
169+
if !strings.Contains(err.Error(), "plugin sdk is not initialized") {
170+
t.Fatalf("unexpected error: %v", err)
171+
}
172+
}
173+
174+
func TestRenderDrupalDebugRequiresSDK(t *testing.T) {
175+
original := sdk
176+
sdk = nil
177+
defer func() { sdk = original }()
178+
179+
_, err := renderDrupalDebug(context.Background())
180+
if err == nil {
181+
t.Fatal("expected renderDrupalDebug() error")
182+
}
183+
if !strings.Contains(err.Error(), "plugin sdk is not initialized") {
184+
t.Fatalf("unexpected error: %v", err)
185+
}
186+
}

cmd/helpers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func getDrupalContainer(cmd *cobra.Command, args []string) (filteredArgs []strin
3333
}
3434

3535
// Get the Drupal container name
36-
containerName, err = cli.GetContainerName(ctx, *drupalServiceName)
36+
containerName, err = cli.GetContainerNameContext(cmd.Context(), ctx, *drupalServiceName)
3737
if err != nil {
3838
cli.Close()
3939
return nil, nil, nil, "", err
@@ -68,7 +68,7 @@ func getDrupalContainerFromFlags(cmd *cobra.Command) (ctx *config.Context, cli *
6868
}
6969

7070
// Get the Drupal container name
71-
containerName, err = cli.GetContainerName(ctx, *drupalServiceName)
71+
containerName, err = cli.GetContainerNameContext(cmd.Context(), ctx, *drupalServiceName)
7272
if err != nil {
7373
cli.Close()
7474
return nil, nil, "", err

0 commit comments

Comments
 (0)