group ports to render ranges as ... ranges

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2021-09-21 15:21:28 +02:00 • committed by Nicolas De loof
parent e39ea13002
commit 97a0efd7c3
4 changed files with 104 additions and 17 deletions

View file

@ -147,14 +147,7 @@ SERVICES:
func writter(containers []api.ContainerSummary) func(w io.Writer) {
return func(w io.Writer) {
for _, container := range containers {
var ports []string
for _, p := range container.Publishers {
if p.URL == "" {
ports = append(ports, fmt.Sprintf("%d/%s", p.TargetPort, p.Protocol))
} else {
ports = append(ports, fmt.Sprintf("%s->%d/%s", p.URL, p.TargetPort, p.Protocol))
}
}
ports := DisplayablePorts(container)
status := container.State
if status == "running" && container.Health != "" {
status = fmt.Sprintf("%s (%s)", container.State, container.Health)
@ -162,7 +155,7 @@ func writter(containers []api.ContainerSummary) func(w io.Writer) {
status = fmt.Sprintf("%s (%d)", container.State, container.ExitCode)
}
command := formatter2.Ellipsis(container.Command, 20)
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", container.Name, strconv.Quote(command), container.Service, status, strings.Join(ports, ", "))
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", container.Name, strconv.Quote(command), container.Service, status, ports)
}
}
}
@ -182,3 +175,73 @@ func filterByStatus(containers []api.ContainerSummary, status string) []api.Cont
}
return filtered
}
type portRange struct {
pStart int
pEnd int
tStart int
tEnd int
IP string
protocol string
}
func (pr portRange) String() string {
var (
pub string
tgt string
)
if pr.pEnd > pr.pStart {
pub = fmt.Sprintf("%s:%d-%d->", pr.IP, pr.pStart, pr.pEnd)
} else if pr.pStart > 0 {
pub = fmt.Sprintf("%s:%d->", pr.IP, pr.pStart)
}
if pr.tEnd > pr.tStart {
tgt = fmt.Sprintf("%d-%d", pr.tStart, pr.tEnd)
} else {
tgt = fmt.Sprintf("%d", pr.tStart)
}
return fmt.Sprintf("%s%s/%s", pub, tgt, pr.protocol)
}
// DisplayablePorts is copy pasted from https://github.com/docker/cli/pull/581/files
func DisplayablePorts(c api.ContainerSummary) string {
if c.Publishers == nil {
return ""
}
sort.Sort(c.Publishers)
pr := portRange{}
ports := []string{}
for _, p := range c.Publishers {
prIsRange := pr.tEnd != pr.tStart
tOverlaps := p.TargetPort <= pr.tEnd
// Start a new port-range if:
// - the protocol is different from the current port-range
// - published or target port are not consecutive to the current port-range
// - the current port-range is a _range_, and the target port overlaps with the current range's target-ports
if p.Protocol != pr.protocol || p.URL != pr.IP || p.PublishedPort-pr.pEnd > 1 || p.TargetPort-pr.tEnd > 1 || prIsRange && tOverlaps {
// start a new port-range, and print the previous port-range (if any)
if pr.pStart > 0 {
ports = append(ports, pr.String())
}
pr = portRange{
pStart: p.PublishedPort,
pEnd: p.PublishedPort,
tStart: p.TargetPort,
tEnd: p.TargetPort,
protocol: p.Protocol,
IP: p.URL,
}
continue
}
pr.pEnd = p.PublishedPort
pr.tEnd = p.TargetPort
}
if pr.tStart > 0 {
ports = append(ports, pr.String())
}
return strings.Join(ports, ", ")
}