// Package docker — lapisan tipis di atas Docker SDK untuk core tia. // Bebas UI: dipakai bersama oleh TUI dan CLI (F-028). package docker import ( "context" "fmt" "strings" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" ) // Client — pembungkus Docker SDK dengan negosiasi versi API // (mendukung Docker Engine 20.10+, PRD §9). type Client struct { cli *client.Client } // New membaca konfigurasi dari env (DOCKER_HOST dll) atau default socket. func New() (*Client, error) { cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { return nil, fmt.Errorf("docker: create client: %w", err) } return &Client{cli: cli}, nil } func (c *Client) Close() error { return c.cli.Close() } // Info — ringkasan daemon untuk dashboard, doctor, dan status bar. type Info struct { ServerVersion string APIVersion string Containers int Running int Images int MemoryTotal int64 CPUs int } func (c *Client) Info(ctx context.Context) (Info, error) { i, err := c.cli.Info(ctx) if err != nil { return Info{}, fmt.Errorf("docker: info: %w", err) } return Info{ ServerVersion: i.ServerVersion, APIVersion: c.cli.ClientVersion(), // hasil negosiasi API Containers: i.Containers, Running: i.ContainersRunning, Images: i.Images, MemoryTotal: i.MemTotal, CPUs: i.NCPU, }, nil } // Ping — cek daemon hidup (dipakai doctor). func (c *Client) Ping(ctx context.Context) error { if _, err := c.cli.Ping(ctx); err != nil { return fmt.Errorf("docker: ping: %w", err) } return nil } // Container — ringkasan kontainer untuk sidebar/dashboard. type Container struct { ID string Name string Image string State string // running, exited, paused, restarting, created, dead Status string // "Up 2 hours (healthy)" } // ListContainers mengembalikan semua kontainer (termasuk yang berhenti). func (c *Client) ListContainers(ctx context.Context) ([]Container, error) { list, err := c.cli.ContainerList(ctx, container.ListOptions{All: true}) if err != nil { return nil, fmt.Errorf("docker: container list: %w", err) } out := make([]Container, 0, len(list)) for _, ct := range list { name := "" if len(ct.Names) > 0 { name = strings.TrimPrefix(ct.Names[0], "/") } id := ct.ID if len(id) > 12 { id = id[:12] } out = append(out, Container{ ID: id, Name: name, Image: ct.Image, State: ct.State, Status: ct.Status, }) } return out, nil }