-
Notifications
You must be signed in to change notification settings - Fork 288
/
sail.go
141 lines (116 loc) · 3.45 KB
/
sail.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
136
137
138
139
140
141
package sail
import (
"context"
"net/http"
"os"
"os/signal"
"syscall"
"time"
http_logrus "github.com/improbable-eng/go-httpwares/logging/logrus"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/windmilleng/tilt/internal/assets"
"github.com/windmilleng/tilt/internal/logger"
"github.com/windmilleng/tilt/internal/model"
"github.com/windmilleng/tilt/internal/network"
"github.com/windmilleng/tilt/internal/sail/server"
"golang.org/x/sync/errgroup"
)
const DefaultWebDevPort = 10451
var webModeFlag model.WebMode = model.DefaultWebMode
var webDevPort = DefaultWebDevPort
var port = model.DefaultSailPort
var log = logrus.WithFields(logrus.Fields{})
func Execute() {
rootCmd := &cobra.Command{
Use: "sail",
Short: "A server to coordinate collaborative coding and debugging with Tilt",
Run: run,
}
rootCmd.Flags().IntVar(&port, "port", model.DefaultSailPort, "Port to listen on")
rootCmd.Flags().Var(&webModeFlag, "web-mode", "Values: local, prod. Controls whether to use prod assets or a local dev server")
rootCmd.Flags().IntVar(&webDevPort, "webdev-port", DefaultWebDevPort, "Port for the Tilt Dev Webpack server. Only applies when using --web-mode=local")
err := rootCmd.Execute()
if err != nil {
log.Fatal(err)
}
}
func contextWithCancel() (context.Context, func()) {
ctx, cancel := context.WithCancel(context.Background())
l := logger.NewLogger(logger.InfoLvl, os.Stderr)
ctx = logger.WithLogger(ctx, l)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
cancel()
// If we get another SIGINT/SIGTERM, OR it takes too long for tilt to
// exit after cancelling context, just exit
select {
case <-sigs:
l.Debugf("force quitting...")
os.Exit(1)
case <-time.After(2 * time.Second):
l.Debugf("Context canceled but app still running; forcibly exiting.")
os.Exit(1)
}
}()
return ctx, cancel
}
func run(cmd *cobra.Command, args []string) {
ctx, cancel := contextWithCancel()
mode, err := provideWebMode()
if err != nil {
log.Fatal(err)
}
assetServ, err := assets.ProvideAssetServer(ctx, mode, model.WebVersion("0.0.0"), provideWebDevPort())
if err != nil {
log.Fatal(err)
}
logrus.SetFormatter(&logrus.JSONFormatter{})
ss := server.ProvideSailServer(assetServ)
httpServer := &http.Server{
Addr: network.AllHostsBindAddr(int(port)),
Handler: http.DefaultServeMux,
}
http.Handle("/", loggingHandler(ss.Router()))
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
defer cancel()
log.Infof("Sail server listening on %d", port)
return httpServer.ListenAndServe()
})
g.Go(func() error {
<-ctx.Done()
return httpServer.Shutdown(context.Background())
})
g.Go(func() error {
defer cancel()
return assetServ.Serve(ctx)
})
g.Go(func() error {
<-ctx.Done()
_ = httpServer.Shutdown(context.Background())
assetServ.TearDown(context.Background())
return nil
})
err = g.Wait()
if err != nil && err != context.Canceled {
log.Fatal(err)
}
}
func loggingHandler(handler http.Handler) http.Handler {
return http_logrus.Middleware(log)(handler)
}
func provideWebMode() (model.WebMode, error) {
switch webModeFlag {
case model.LocalWebMode, model.ProdWebMode, model.PrecompiledWebMode:
return webModeFlag, nil
case model.DefaultWebMode:
return model.LocalWebMode, nil
}
return "", model.UnrecognizedWebModeError(string(webModeFlag))
}
func provideWebDevPort() model.WebDevPort {
return model.WebDevPort(webDevPort)
}