Skip to content
This repository was archived by the owner on Dec 23, 2021. It is now read-only.

Commit 075f434

Browse files
authored
Merge pull request #34 from skanehira/develop
Added features of container attach and asynchronous operation
2 parents 5aa2455 + 6a4834c commit 075f434

File tree

11 files changed

+394
-270
lines changed

11 files changed

+394
-270
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ docui can do thises.
1414
- start/stop
1515
- export/commit
1616
- inspect/rename/filtering
17+
- attach
1718

1819
- volume
1920
- create/remove/prune

common/common.go

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ import (
1111
"strings"
1212
"time"
1313

14+
"github.com/davecgh/go-spew/spew"
1415
docker "github.com/fsouza/go-dockerclient"
1516
"github.com/jroimartin/gocui"
1617
)
1718

19+
var cutNewlineReplacer = strings.NewReplacer("\r", "", "\n", "")
20+
1821
func StructToJson(i interface{}) string {
1922
j, err := json.Marshal(i)
2023
if err != nil {
@@ -55,15 +58,27 @@ func OutputFormatedLine(v *gocui.View, i interface{}) {
5558
parseLength := func(cw int, str string) (int, int) {
5659
minMax := strings.Split(str, " ")
5760

61+
if len(minMax) < 2 {
62+
return -1, -1
63+
}
64+
5865
min, _ := strconv.ParseFloat(strings.Split(minMax[0], ":")[1], 64)
5966
max, _ := strconv.ParseFloat(strings.Split(minMax[1], ":")[1], 64)
6067
return int(float64(cw) * min), int(float64(cw) * max)
6168
}
6269

6370
for i := 0; i < size; i++ {
64-
value := elem.Field(i).Interface().(string)
71+
value, ok := elem.Field(i).Interface().(string)
72+
if !ok {
73+
continue
74+
}
6575
max, min := parseLength(cw, elem.Type().Field(i).Tag.Get("len"))
6676

77+
// skip if can not get the tag
78+
if max == -1 && min == -1 {
79+
continue
80+
}
81+
6782
if max < min {
6883
max = min
6984
}
@@ -92,7 +107,9 @@ func OutputFormatedHeader(v *gocui.View, i interface{}) {
92107
tag := field.Tag.Get("tag")
93108
name := field.Name
94109

95-
elem.FieldByName(name).SetString(tag)
110+
if field.Type.Kind() == reflect.String {
111+
elem.FieldByName(name).SetString(tag)
112+
}
96113
}
97114

98115
OutputFormatedLine(v, i)
@@ -137,3 +154,20 @@ func ParseLabels(labels map[string]string) string {
137154

138155
return result
139156
}
157+
158+
func DateNow() string {
159+
return time.Now().Format("2006/01/02 15:04:05")
160+
}
161+
162+
func CutNewline(i string) string {
163+
return cutNewlineReplacer.Replace(i)
164+
}
165+
166+
func DebugOutput(i interface{}) {
167+
file, err := os.OpenFile("/tmp/docui.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
168+
if err != nil {
169+
return
170+
}
171+
defer file.Close()
172+
fmt.Fprintln(file, spew.Sdump(i))
173+
}

main.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
package main
22

33
import (
4+
"os"
5+
46
"github.com/skanehira/docui/panel"
57

68
"github.com/jroimartin/gocui"
79
)
810

911
func main() {
10-
gui := panel.New(gocui.Output256)
11-
defer gui.Close()
12+
for {
13+
gui := panel.New(gocui.Output256)
14+
err := gui.MainLoop()
1215

13-
if err := gui.MainLoop(); err != nil && err != gocui.ErrQuit {
14-
panic(err)
16+
switch err {
17+
case gocui.ErrQuit:
18+
gui.Close()
19+
os.Exit(0)
20+
case panel.AttachFlag:
21+
gui.Close()
22+
gui.Panels[panel.ContainerListPanel].(*panel.ContainerList).Attach()
23+
}
1524
}
1625
}

panel/containerPanel.go

Lines changed: 71 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package panel
33
import (
44
"fmt"
55
"os"
6+
"os/exec"
67
"strings"
78
"time"
89

@@ -147,6 +148,9 @@ func (c *ContainerList) SetKeyBinding() {
147148
if err := c.SetKeybinding(c.name, 'f', gocui.ModNone, c.Filter); err != nil {
148149
panic(err)
149150
}
151+
if err := c.SetKeybinding(c.name, 'a', gocui.ModNone, c.AttachContainer); err != nil {
152+
panic(err)
153+
}
150154
}
151155

152156
func (c *ContainerList) selected() (*Container, error) {
@@ -220,24 +224,11 @@ func (c *ContainerList) StartContainer(g *gocui.Gui, v *gocui.View) error {
220224
return nil
221225
}
222226

223-
g.Update(func(g *gocui.Gui) error {
224-
c.StateMessage("container starting...")
225-
226-
g.Update(func(g *gocui.Gui) error {
227-
defer c.Refresh(g, v)
228-
defer c.CloseStateMessage()
229-
230-
if err := c.Docker.StartContainerWithID(container.ID); err != nil {
231-
c.ErrMessage(err.Error(), c.name)
232-
return nil
233-
}
234-
235-
c.SwitchPanel(c.name)
236-
237-
return nil
238-
})
239-
240-
return nil
227+
c.AddTask(fmt.Sprintf("Start container %s", container.Name), func() error {
228+
if err := c.Docker.StartContainerWithID(container.ID); err != nil {
229+
return err
230+
}
231+
return c.Refresh(g, v)
241232
})
242233

243234
return nil
@@ -250,24 +241,11 @@ func (c *ContainerList) StopContainer(g *gocui.Gui, v *gocui.View) error {
250241
return nil
251242
}
252243

253-
g.Update(func(g *gocui.Gui) error {
254-
c.StateMessage("container stopping...")
255-
256-
g.Update(func(g *gocui.Gui) error {
257-
defer c.CloseStateMessage()
258-
defer c.Refresh(g, v)
259-
260-
if err := c.Docker.StopContainerWithID(container.ID); err != nil {
261-
c.ErrMessage(err.Error(), c.name)
262-
return nil
263-
}
264-
265-
c.SwitchPanel(c.name)
266-
267-
return nil
268-
})
269-
270-
return nil
244+
c.AddTask(fmt.Sprintf("Stop container %s", container.Name), func() error {
245+
if err := c.Docker.StopContainerWithID(container.ID); err != nil {
246+
return err
247+
}
248+
return c.Refresh(g, v)
271249
})
272250

273251
return nil
@@ -320,37 +298,23 @@ func (c *ContainerList) ExportContainer(g *gocui.Gui, v *gocui.View) error {
320298
}
321299

322300
data := c.form.GetFieldTexts()
301+
container := data["Container"]
302+
path := data["Path"]
323303

324-
g.Update(func(g *gocui.Gui) error {
325-
c.form.Close(g, v)
326-
c.StateMessage("container exporting...")
327-
328-
g.Update(func(g *gocui.Gui) error {
329-
defer c.CloseStateMessage()
330-
331-
file, err := os.OpenFile(data["Path"], os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
332-
if err != nil {
333-
c.ErrMessage(err.Error(), c.name)
334-
return nil
335-
}
336-
defer file.Close()
337-
338-
options := docker.ExportContainerOptions{
339-
ID: data["Container"],
340-
OutputStream: file,
341-
}
342-
343-
if err := c.Docker.ExportContainerWithOptions(options); err != nil {
344-
c.ErrMessage(err.Error(), c.name)
345-
return nil
346-
}
304+
c.form.Close(g, v)
347305

348-
c.SwitchPanel(c.name)
349-
350-
return nil
306+
c.AddTask(fmt.Sprintf("Export container %s to %s", container, path), func() error {
307+
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
308+
if err != nil {
309+
return err
310+
}
311+
defer file.Close()
351312

352-
})
353-
return nil
313+
options := docker.ExportContainerOptions{
314+
ID: container,
315+
OutputStream: file,
316+
}
317+
return c.Docker.ExportContainerWithOptions(options)
354318
})
355319

356320
return nil
@@ -408,32 +372,23 @@ func (c *ContainerList) CommitContainer(g *gocui.Gui, v *gocui.View) error {
408372
data["Tag"] = "latest"
409373
}
410374

375+
container := data["Container"]
376+
repository := data["Repository"]
377+
tag := data["Tag"]
378+
411379
options := docker.CommitContainerOptions{
412-
Container: data["Container"],
413-
Repository: data["Repository"],
414-
Tag: data["Tag"],
380+
Container: container,
381+
Repository: repository,
382+
Tag: tag,
415383
}
416384

417-
g.Update(func(g *gocui.Gui) error {
418-
c.form.Close(g, v)
419-
c.StateMessage("container committing...")
420-
421-
g.Update(func(g *gocui.Gui) error {
422-
defer c.CloseStateMessage()
385+
c.form.Close(g, v)
423386

424-
if err := c.Docker.CommitContainerWithOptions(options); err != nil {
425-
c.ErrMessage(err.Error(), c.name)
426-
return nil
427-
}
428-
429-
c.Panels[ImageListPanel].Refresh(g, v)
430-
c.SwitchPanel(c.name)
431-
432-
return nil
433-
434-
})
435-
436-
return nil
387+
c.AddTask(fmt.Sprintf("Commit container %s to %s", container, repository+":"+tag), func() error {
388+
if err := c.Docker.CommitContainerWithOptions(options); err != nil {
389+
return err
390+
}
391+
return c.Refresh(g, v)
437392
})
438393

439394
return nil
@@ -485,32 +440,21 @@ func (c *ContainerList) RenameContainer(g *gocui.Gui, v *gocui.View) error {
485440
}
486441

487442
data := c.form.GetFieldTexts()
443+
oldName := data["Container"]
444+
name := data["NewName"]
488445

489446
options := docker.RenameContainerOptions{
490-
ID: data["Container"],
491-
Name: data["NewName"],
447+
ID: oldName,
448+
Name: name,
492449
}
493450

494-
g.Update(func(g *gocui.Gui) error {
495-
c.form.Close(g, v)
496-
c.StateMessage("container renaming...")
497-
498-
g.Update(func(g *gocui.Gui) error {
499-
defer c.CloseStateMessage()
500-
501-
if err := c.Docker.RenameContainerWithOptions(options); err != nil {
502-
c.ErrMessage(err.Error(), c.name)
503-
return nil
504-
}
451+
c.form.Close(g, v)
505452

506-
c.Refresh(g, v)
507-
c.SwitchPanel(c.name)
508-
509-
return nil
510-
511-
})
512-
513-
return nil
453+
c.AddTask(fmt.Sprintf("Rename container %s to %s", oldName, name), func() error {
454+
if err := c.Docker.RenameContainerWithOptions(options); err != nil {
455+
return err
456+
}
457+
return c.Refresh(g, v)
514458
})
515459

516460
return nil
@@ -597,3 +541,23 @@ func (c *ContainerList) Filter(g *gocui.Gui, lv *gocui.View) error {
597541

598542
return nil
599543
}
544+
545+
func (c *ContainerList) AttachContainer(g *gocui.Gui, v *gocui.View) error {
546+
return AttachFlag
547+
}
548+
549+
func (c *ContainerList) Attach() error {
550+
selected, err := c.selected()
551+
if err != nil {
552+
return err
553+
}
554+
555+
cmd := exec.Command("docker", "attach", selected.ID)
556+
557+
cmd.Stdin = os.Stdin
558+
cmd.Stdout = os.Stdout
559+
cmd.Stderr = os.Stderr
560+
cmd.Run()
561+
562+
return nil
563+
}

0 commit comments

Comments
 (0)