@@ -12,12 +12,11 @@ import (
1212 "strconv"
1313 "strings"
1414
15- "charm.land/lipgloss/v2"
1615 "github.com/libops/sitectl/pkg/config"
1716 "github.com/libops/sitectl/pkg/docker"
1817 "github.com/libops/sitectl/pkg/plugin"
18+ "github.com/libops/sitectl/pkg/plugin/debugui"
1919 "github.com/spf13/cobra"
20- "golang.org/x/term"
2120 "gopkg.in/yaml.v3"
2221)
2322
@@ -111,27 +110,6 @@ var drupalCoreModules = map[string]struct{}{
111110 "workspaces" : {},
112111}
113112
114- var (
115- debugPanelStyle = lipgloss .NewStyle ().
116- Background (lipgloss .Color ("#112235" )).
117- Padding (1 , 2 )
118- debugTitleStyle = lipgloss .NewStyle ().
119- Bold (true ).
120- Foreground (lipgloss .Color ("#98C1D9" ))
121- debugSectionDividerStyle = lipgloss .NewStyle ().
122- Foreground (lipgloss .Color ("#29425E" ))
123- debugStatusOKStyle = lipgloss .NewStyle ().
124- Bold (true ).
125- Foreground (lipgloss .Color ("#7BD389" ))
126- debugStatusWarningStyle = lipgloss .NewStyle ().
127- Bold (true ).
128- Foreground (lipgloss .Color ("#F4C95D" ))
129- debugMutedStyle = lipgloss .NewStyle ().
130- Foreground (lipgloss .Color ("#9FB3C8" ))
131- debugRowStyle = lipgloss .NewStyle ().
132- Background (lipgloss .Color ("#112235" ))
133- )
134-
135113var componentExtensionCmd = & cobra.Command {
136114 Use : "__component" ,
137115 Short : "Internal component extension command" ,
@@ -221,11 +199,11 @@ func renderDrupalDebug(runCtx context.Context) (string, error) {
221199 slog .Debug ("resolved drupal root" , "plugin" , "drupal" , "drupal_root" , drupalRoot )
222200 configDir := filepath .Join (drupalRoot , "config" , "sync" )
223201 body := []string {
224- debugDivider (),
202+ debugui . Divider (),
225203 "" ,
226- debugTitleStyle . Render ("General" ),
204+ debugui . Title ("General" ),
227205 "" ,
228- formatDebugRows ([]debugRow {
206+ debugui . FormatRows ([]debugui. Row {
229207 {Label : "Context" , Value : ctx .Name },
230208 {Label : "Project dir" , Value : ctx .ProjectDir },
231209 {Label : "Drupal root" , Value : drupalRoot },
@@ -236,7 +214,7 @@ func renderDrupalDebug(runCtx context.Context) (string, error) {
236214 if strings .TrimSpace (drupalRoot ) == "" {
237215 slog .Debug ("drupal root unavailable; skipping extension scan" , "plugin" , "drupal" )
238216 body = append (body , "" , "Installed modules: unavailable" )
239- return renderDebugPanel ("drupal" , strings .Join (body , "\n " )), nil
217+ return debugui . RenderPanel ("drupal" , strings .Join (body , "\n " )), nil
240218 }
241219
242220 slog .Debug ("reading core.extension.yml" , "plugin" , "drupal" , "path" , filepath .Join (configDir , "core.extension.yml" ))
@@ -256,27 +234,27 @@ func renderDrupalDebug(runCtx context.Context) (string, error) {
256234 slog .Debug ("rendering cache_page summary" , "plugin" , "drupal" )
257235 cachePageSummary , err := renderCachePageSummary (runCtx )
258236 if err != nil {
259- body = append (body , "" , debugDivider (), "" , debugTitleStyle . Render ("Cache Page" ), "" , formatDebugRows ([]debugRow {
260- {Label : "Status" , Value : renderStatus ("warning" )},
237+ body = append (body , "" , debugui . Divider (), "" , debugui . Title ("Cache Page" ), "" , debugui . FormatRows ([]debugui. Row {
238+ {Label : "Status" , Value : debugui . Status ("warning" )},
261239 {Label : "cache_page" , Value : fmt .Sprintf ("unavailable (%v)" , err )},
262240 }))
263241 } else if strings .TrimSpace (cachePageSummary ) != "" {
264- body = append (body , "" , debugDivider (), "" , debugTitleStyle . Render ("Cache Page" ), "" , cachePageSummary )
242+ body = append (body , "" , debugui . Divider (), "" , debugui . Title ("Cache Page" ), "" , cachePageSummary )
265243 }
266244
267245 moduleLines , err := renderModuleList (runCtx , files , drupalRoot , modules , moduleVersionInfo )
268246 if err != nil {
269247 return "" , err
270248 }
271249
272- configLines := []string {debugDivider (), "" , debugTitleStyle . Render ("Installed Extensions" ), "" , fmt .Sprintf ("Installed modules (%d):" , len (modules ))}
250+ configLines := []string {debugui . Divider (), "" , debugui . Title ("Installed Extensions" ), "" , fmt .Sprintf ("Installed modules (%d):" , len (modules ))}
273251 configLines = append (configLines , moduleLines ... )
274252 configLines = append (configLines , "" )
275253 configLines = append (configLines , fmt .Sprintf ("Installed themes (%d):" , len (themes )))
276254 configLines = append (configLines , formatListLines (themes , 3 )... )
277255 body = append (body , "" , strings .Join (configLines , "\n " ))
278256
279- patchLines := []string {debugDivider (), "" , debugTitleStyle . Render ("Composer Patches" ), "" }
257+ patchLines := []string {debugui . Divider (), "" , debugui . Title ("Composer Patches" ), "" }
280258 if strings .TrimSpace (composerPatches ) == "" {
281259 patchLines = append (patchLines , " none" )
282260 } else {
@@ -285,7 +263,7 @@ func renderDrupalDebug(runCtx context.Context) (string, error) {
285263 body = append (body , "" , strings .Join (patchLines , "\n " ))
286264
287265 slog .Debug ("finished plugin debug" , "plugin" , "drupal" )
288- return renderDebugPanel ("drupal" , strings .Join (body , "\n " )), nil
266+ return debugui . RenderPanel ("drupal" , strings .Join (body , "\n " )), nil
289267}
290268
291269func renderCachePageSummary (runCtx context.Context ) (string , error ) {
@@ -304,23 +282,25 @@ func renderCachePageSummary(runCtx context.Context) (string, error) {
304282 return "" , err
305283 }
306284
307- rows := []debugRow {
308- {Label : "Status" , Value : renderStatus ("ok" )},
285+ rows := []debugui. Row {
286+ {Label : "Status" , Value : debugui . Status ("ok" )},
309287 {Label : "cache_page" , Value : humanBytes (cachePageSize )},
310288 {Label : "cache_render" , Value : humanBytes (cacheRenderSize )},
311289 }
312290 if cachePageSize >= cachePageWarningThreshold || cacheRenderSize >= cachePageWarningThreshold {
313- rows [0 ].Value = renderStatus ("warning" )
291+ rows [0 ].Value = debugui . Status ("warning" )
314292 }
315293 if cachePageSize >= cachePageWarningThreshold {
316- rows = append (rows , debugRow {Label : "Recommendation" , Value : pageCacheExclusionURL })
294+ rows = append (rows , debugui. Row {Label : "Recommendation" , Value : pageCacheExclusionURL })
317295 }
318- return formatDebugRows (rows ), nil
296+ return debugui . FormatRows (rows ), nil
319297}
320298
321299func readDrupalCacheTableSize (runCtx context.Context , cli * docker.DockerClient , containerName , containerRoot , tableName string ) (int64 , error ) {
322300 query := fmt .Sprintf ("SELECT COALESCE(data_length + index_length, 0) FROM information_schema.TABLES WHERE table_schema = DATABASE() AND table_name = '%s';" , strings .TrimSpace (tableName ))
323- output , err := execDrupalCommandCapture (runCtx , cli , containerName , containerRoot , []string {"drush" , "sql:query" , query , "--extra=--batch" , "--extra=--skip-column-names" })
301+ cmd := []string {"drush" , "sql:query" , query , "--extra=--batch" , "--extra=--skip-column-names" }
302+ slog .Debug (strings .Join (cmd , " " ), "plugin" , "drupal" , "container" , containerName )
303+ output , err := docker .ExecCapture (runCtx , cli , containerName , containerRoot , cmd )
324304 if err != nil {
325305 return 0 , err
326306 }
@@ -351,37 +331,6 @@ func getDrupalContainerForSDK(runCtx context.Context) (ctx *config.Context, cli
351331 return ctx , cli , containerName , nil
352332}
353333
354- func execDrupalCommandCapture (runCtx context.Context , cli * docker.DockerClient , containerName , containerRoot string , cmd []string ) (string , error ) {
355- slog .Debug (strings .Join (cmd , " " ), "plugin" , "drupal" , "container" , containerName )
356- var stdout bytes.Buffer
357- var stderr bytes.Buffer
358-
359- exitCode , err := cli .Exec (runCtx , docker.ExecOptions {
360- Container : containerName ,
361- Cmd : cmd ,
362- WorkingDir : containerRoot ,
363- AttachStdout : true ,
364- AttachStderr : true ,
365- Stdout : & stdout ,
366- Stderr : & stderr ,
367- })
368- if err != nil {
369- return "" , err
370- }
371- if exitCode != 0 {
372- detail := strings .TrimSpace (stderr .String ())
373- if detail == "" {
374- detail = strings .TrimSpace (stdout .String ())
375- }
376- if detail != "" {
377- return "" , fmt .Errorf ("drupal command failed with exit code %d: %s" , exitCode , detail )
378- }
379- return "" , fmt .Errorf ("drupal command failed with exit code %d" , exitCode )
380- }
381-
382- return strings .TrimSpace (stdout .String ()), nil
383- }
384-
385334func parseFirstInt (output string ) (int64 , error ) {
386335 for _ , line := range strings .Split (output , "\n " ) {
387336 line = strings .TrimSpace (line )
@@ -650,87 +599,3 @@ func formatListLines(values []string, perLine int) []string {
650599 }
651600 return lines
652601}
653-
654- type debugRow struct {
655- Label string
656- Value string
657- }
658-
659- func renderDebugPanel (title , body string ) string {
660- header := debugTitleStyle .Render (strings .TrimSpace (title ))
661- content := header
662- if strings .TrimSpace (body ) != "" {
663- content += "\n \n " + body
664- }
665- return debugPanelStyle .Width (debugPanelWidth ()).Render (content )
666- }
667-
668- func formatDebugRows (rows []debugRow ) string {
669- labelWidth := 0
670- for _ , row := range rows {
671- if width := len (strings .TrimSpace (row .Label )); width > labelWidth {
672- labelWidth = width
673- }
674- }
675- lines := make ([]string , 0 , len (rows ))
676- rowWidth := debugContentWidth ()
677- for _ , row := range rows {
678- label := strings .TrimSpace (row .Label )
679- value := strings .TrimSpace (row .Value )
680- if label == "" {
681- lines = append (lines , renderDebugRow (rowWidth , "" , value ))
682- continue
683- }
684- lines = append (lines , renderDebugRow (rowWidth , fmt .Sprintf ("%-*s" , labelWidth , label ), value ))
685- }
686- return strings .Join (lines , "\n " )
687- }
688-
689- func renderStatus (state string ) string {
690- switch strings .ToLower (strings .TrimSpace (state )) {
691- case "ok" :
692- return debugStatusOKStyle .Render ("OK" )
693- case "warning" :
694- return debugStatusWarningStyle .Render ("WARNING" )
695- default :
696- return debugMutedStyle .Render (strings .ToUpper (strings .TrimSpace (state )))
697- }
698- }
699-
700- func renderDebugRow (width int , label , value string ) string {
701- valueWidth := max (0 , width - lipgloss .Width (label )- 2 )
702- row := label
703- if strings .TrimSpace (label ) != "" {
704- row += " "
705- }
706- row += lipgloss .NewStyle ().
707- Width (valueWidth ).
708- Background (lipgloss .Color ("#112235" )).
709- Render (value )
710- return debugRowStyle .Width (width ).Render (row )
711- }
712-
713- func max (a , b int ) int {
714- if a > b {
715- return a
716- }
717- return b
718- }
719-
720- func debugPanelWidth () int {
721- if columns , err := strconv .Atoi (strings .TrimSpace (os .Getenv ("COLUMNS" ))); err == nil && columns > 0 {
722- return max (40 , columns )
723- }
724- if width , _ , err := term .GetSize (int (os .Stdout .Fd ())); err == nil && width > 0 {
725- return max (40 , width )
726- }
727- return 100
728- }
729-
730- func debugContentWidth () int {
731- return max (20 , debugPanelWidth ()- 4 )
732- }
733-
734- func debugDivider () string {
735- return debugSectionDividerStyle .Width (debugContentWidth ()).Render (strings .Repeat ("─" , debugContentWidth ()))
736- }
0 commit comments