forked from convox/rack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.go
135 lines (106 loc) · 2.47 KB
/
run.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"fmt"
"os"
"strings"
"golang.org/x/crypto/ssh/terminal"
"github.com/convox/rack/cmd/convox/stdcli"
"gopkg.in/urfave/cli.v1"
)
func init() {
stdcli.RegisterCommand(cli.Command{
Name: "run",
Description: "run a one-off command in your Convox rack",
Usage: "<process name> <command> [options]",
ArgsUsage: "<process name> <command>",
Action: cmdRun,
Flags: []cli.Flag{
appFlag,
rackFlag,
cli.BoolFlag{
Name: "detach",
Usage: "run in the background",
},
cli.StringFlag{
Name: "release, r",
Usage: "release name (defaults to current release)",
},
},
})
}
func cmdRun(c *cli.Context) error {
stdcli.NeedHelp(c)
stdcli.NeedArg(c, -2)
if c.Bool("detach") {
return cmdRunDetached(c)
}
_, app, err := stdcli.DirApp(c, ".")
if err != nil {
return stdcli.Error(err)
}
ps := c.Args().First()
err = validateProcessId(c, app, ps)
if err != nil {
return stdcli.Error(err)
}
args := strings.Join(c.Args().Tail(), " ")
release := c.String("release")
code, err := runAttached(c, app, ps, args, release)
if err != nil {
return stdcli.Error(err)
}
return cli.NewExitError("", code)
}
func cmdRunDetached(c *cli.Context) error {
stdcli.NeedArg(c, -2)
_, app, err := stdcli.DirApp(c, ".")
if err != nil {
return err
}
ps := c.Args().First()
err = validateProcessId(c, app, ps)
if err != nil {
return stdcli.Error(err)
}
command := strings.Join(c.Args().Tail(), " ")
release := c.String("release")
fmt.Printf("Running `%s` on %s... ", command, ps)
err = rackClient(c).RunProcessDetached(app, ps, command, release)
if err != nil {
return stdcli.Error(err)
}
fmt.Println("OK")
return nil
}
func runAttached(c *cli.Context, app, ps, args, release string) (int, error) {
fd := os.Stdin.Fd()
var w, h int
if terminal.IsTerminal(int(fd)) {
stdinState, err := terminal.GetState(int(fd))
if err != nil {
return -1, err
}
defer terminal.Restore(int(fd), stdinState)
w, h, err = terminal.GetSize(int(fd))
if err != nil {
return -1, err
}
}
code, err := rackClient(c).RunProcessAttached(app, ps, args, release, h, w, os.Stdin, os.Stdout)
if err != nil {
return -1, err
}
return code, nil
}
func validateProcessId(c *cli.Context, app, ps string) error {
formation, err := rackClient(c).ListFormation(app)
if err != nil {
return err
}
for _, f := range formation {
if ps == f.Name {
return nil
}
}
return fmt.Errorf("Unknown process name: %s", ps)
}