diff --git a/docker/client.go b/docker/client.go index 7bc5165..7b5a7d2 100644 --- a/docker/client.go +++ b/docker/client.go @@ -12,14 +12,6 @@ import ( "gitea.thegux.fr/hmdeploy/models" ) -const ( - appPartsLength = 2 - imagePartsLength = 2 - portPartsLength = 2 - portOutPartsLength = 2 - replicasPartLength = 2 -) - var ( ErrDockerClientSave = errors.New("unable to save image into tar") diff --git a/docker/models.go b/docker/models.go index f82db47..9f41f5c 100644 --- a/docker/models.go +++ b/docker/models.go @@ -131,7 +131,7 @@ func (s *Service) UnmarshalJSON(data []byte) error { Tag string }{ Name: imageName, - Tag: ci.Details[0].Spec.Labels.Tag, + Tag: imageNameParts[1], }, Ports: ci.Details[0].Endpoint.Ports, Replicas: replicas, diff --git a/main.go b/main.go index 7a5be54..4ef7a62 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "os" "os/signal" "path" + "strings" "sync" "gitea.thegux.fr/hmdeploy/deployers" @@ -255,7 +256,62 @@ func getSwarmServicesDetails(hm *models.HMMap) error { return err } - fmt.Println(services) + tb := utils.NewTable( + utils.WithColSeparator(" | "), + utils.WithHeaderBorderStyle("*"), + utils.WithRowSeparator("-"), + utils.WithHeader("App", 20), + utils.WithHeader("Name", 20), + utils.WithHeader("Image", 20), + utils.WithHeader("Tag", 20), + utils.WithHeader("Target-Published", 40), + utils.WithHeader("Replicas", 2), + utils.WithHeader("Status", 10), + ) + + for idx := range services { + columns := []utils.Column{} + columns = append( + columns, + utils.Column{ + Name: "app", + Value: services[idx].App, + }, + utils.Column{ + Name: "name", + Value: services[idx].Name, + }, + utils.Column{ + Name: "image", + Value: services[idx].Image.Name, + }, + utils.Column{ + Name: "tag", + Value: services[idx].Image.Tag, + }, + ) + + ports := []string{} + for idy := range services[idx].Ports { + ports = append( + ports, + fmt.Sprintf( + "%d-%d", + services[idx].Ports[idy].Target, + services[idx].Ports[idy].Published, + ), + ) + } + + columns = append(columns, utils.Column{ + Name: "target-published", + Value: strings.Join(ports, ","), + }) + + tb.AddRow(columns...) + } + tb.Render() + return nil } diff --git a/utils/utils.go b/utils/utils.go index b664604..99b3dc6 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -120,3 +120,153 @@ func CatchAndConvertNumber(value string) (int, error) { return strconv.Atoi(string(buf)) } + +type HeaderColumn struct { + Name string + Length int + pos int +} + +type Header struct { + BorderStyle string + headerMeta map[string]*HeaderColumn + Columns []HeaderColumn +} + +type TableOption func(*Table) + +func WithHeaderBorderStyle(style string) TableOption { + return func(t *Table) { + t.Header.BorderStyle = style + } +} + +func WithRowSeparator(separator string) TableOption { + return func(t *Table) { + t.RowSeparator = separator + } +} + +func WithColSeparator(separator string) TableOption { + return func(t *Table) { + t.ColSeparator = separator + } +} + +func WithHeader(name string, length int) TableOption { + return func(t *Table) { + if t.Header.Columns == nil { + t.Header.Columns = []HeaderColumn{} + } + pos := len(t.Header.Columns) + t.Header.Columns = append( + t.Header.Columns, + HeaderColumn{Name: name, Length: length, pos: pos}, + ) + + if t.Header.headerMeta == nil { + t.Header.headerMeta = map[string]*HeaderColumn{} + } + + t.Header.headerMeta[strings.ToLower(name)] = &t.Header.Columns[pos] + } +} + +type Column struct { + Name string + Value string +} + +type Table struct { + RowSeparator string + ColSeparator string + data [][]string + Header Header + cursor int +} + +func NewTable(options ...TableOption) Table { + table := Table{} + for _, o := range options { + o(&table) + } + + table.data = [][]string{} + + return table +} + +func (t *Table) AddRow(columns ...Column) error { + maxNbCols := len(t.Header.Columns) + if len(columns) > maxNbCols { + return fmt.Errorf("invalid column number, should be %d", maxNbCols) + } + + rowData := make([]string, maxNbCols) + t.data = append(t.data, rowData) + + for idx := range columns { + header, ok := t.Header.headerMeta[strings.ToLower(columns[idx].Name)] + if !ok { + return fmt.Errorf("no corresponding %s column exist", columns[idx].Name) + } + + value := columns[idx].Value + if len(value) > header.Length { + log.Debug(). + Str("column", columns[idx].Name). + Str("value", value). + Msg("col value too long, trimming...") + value = value[:header.Length-3] + "..." + } + + t.data[t.cursor][header.pos] = value + } + t.cursor++ + + return nil +} + +func (t *Table) Render() { + table := []string{} + + // header + headerParts := []string{} + for idx := range t.Header.Columns { + headerParts = append( + headerParts, + fmt.Sprintf("%-*s", t.Header.Columns[idx].Length, t.Header.Columns[idx].Name), + ) + } + + header := strings.Join(headerParts, t.ColSeparator) + border := "" + for i := 0; i < len(header); i++ { + border += t.Header.BorderStyle + } + + rowHr := "" + for i := 0; i < len(header); i++ { + rowHr += t.RowSeparator + } + + table = append(table, border, header, border) + + // data + for idx := range t.data { + lineParts := []string{} + for idy := range t.data[idx] { + lineParts = append(lineParts, fmt.Sprintf( + "%-*s", + t.Header.Columns[idy].Length, + t.data[idx][idy]), + ) + } + + if idx+1 < len(t.data) { + table = append(table, strings.Join(lineParts, t.ColSeparator), rowHr) + } + } + + fmt.Println(strings.Join(table, "\n")) +}