14 "github.com/Sirupsen/logrus"
15 "github.com/codegangsta/cli"
16 "github.com/iotbzh/xds-server/lib/crosssdk"
17 "github.com/iotbzh/xds-server/lib/model"
18 "github.com/iotbzh/xds-server/lib/syncthing"
19 "github.com/iotbzh/xds-server/lib/webserver"
20 "github.com/iotbzh/xds-server/lib/xdsconfig"
24 appName = "xds-server"
25 appDescription = "X(cross) Development System Server is a web server that allows to remotely cross build applications."
26 appCopyright = "Apache-2.0"
27 appUsage = "X(cross) Development System Server"
30 var appAuthors = []cli.Author{
31 cli.Author{Name: "Sebastien Douheret", Email: "sebastien@iot.bzh"},
34 // AppVersion is the version of this application
35 var AppVersion = "?.?.?"
37 // AppSubVersion is the git tag id added to version string
38 // Should be set by compilation -ldflags "-X main.AppSubVersion=xxx"
39 var AppSubVersion = "unknown-dev"
41 // Context holds the XDS server context
45 Config *xdsconfig.Config
52 WWWServer *webserver.Server
56 // NewContext Create a new instance of XDS server
57 func NewContext(cliCtx *cli.Context) *Context {
60 // Set logger level and formatter
61 log := cliCtx.App.Metadata["logger"].(*logrus.Logger)
63 logLevel := cliCtx.GlobalString("log")
65 logLevel = "error" // FIXME get from Config DefaultLogLevel
67 if log.Level, err = logrus.ParseLevel(logLevel); err != nil {
68 fmt.Printf("Invalid log level : \"%v\"\n", logLevel)
71 log.Formatter = &logrus.TextFormatter{}
73 // Define default configuration
75 ProgName: cliCtx.App.Name,
78 Exit: make(chan os.Signal, 1),
81 // register handler on SIGTERM / exit
82 signal.Notify(ctx.Exit, os.Interrupt, syscall.SIGTERM)
83 go handlerSigTerm(&ctx)
88 // Handle exit and properly stop/close all stuff
89 func handlerSigTerm(ctx *Context) {
92 ctx.Log.Infof("Stoping Syncthing... (PID %d)", ctx.SThgCmd.Process.Pid)
94 ctx.Log.Infof("Stoping Syncthing-inotify... (PID %d)", ctx.SThgInotCmd.Process.Pid)
95 ctx.SThg.StopInotify()
97 if ctx.WWWServer != nil {
98 ctx.Log.Infof("Stoping Web server...")
104 // XDS Server application main routine
105 func xdsApp(cliCtx *cli.Context) error {
108 // Create XDS server context
109 ctx := NewContext(cliCtx)
112 cfg, err := xdsconfig.Init(ctx.Cli, ctx.Log)
114 return cli.NewExitError(err, 2)
118 // TODO allow to redirect stdout/sterr into logs file
119 //logFilename := filepath.Join(ctx.Config.FileConf.LogsDir + "xds-server.log")
121 // FIXME - add a builder interface and support other builder type (eg. native)
122 builderType := "syncthing"
127 // Start local instance of Syncthing and Syncthing-notify
128 ctx.SThg = st.NewSyncThing(ctx.Config, ctx.Log)
130 ctx.Log.Infof("Starting Syncthing...")
131 ctx.SThgCmd, err = ctx.SThg.Start()
133 return cli.NewExitError(err, 2)
135 fmt.Printf("Syncthing started (PID %d)\n", ctx.SThgCmd.Process.Pid)
137 ctx.Log.Infof("Starting Syncthing-inotify...")
138 ctx.SThgInotCmd, err = ctx.SThg.StartInotify()
140 return cli.NewExitError(err, 2)
142 fmt.Printf("Syncthing-inotify started (PID %d)\n", ctx.SThgInotCmd.Process.Pid)
144 // Establish connection with local Syncthing (retry if connection fail)
145 fmt.Printf("Establishing connection with Syncthing...\n")
146 time.Sleep(2 * time.Second)
151 if err = ctx.SThg.Connect(); err == nil {
154 ctx.Log.Warningf("Establishing connection to Syncthing (retry %d/%d)", retry, maxRetry)
155 time.Sleep(time.Second)
158 if err != nil || retry == 0 {
159 return cli.NewExitError(err, 2)
162 // Retrieve Syncthing config
163 id, err := ctx.SThg.IDGet()
165 return cli.NewExitError(err, 2)
168 if ctx.Config.Builder, err = xdsconfig.NewBuilderConfig(id); err != nil {
169 return cli.NewExitError(err, 2)
172 // Retrieve initial Syncthing config
174 // FIXME: cannot retrieve default SDK, need to save on disk or somewhere
175 // else all config to be able to restore it.
177 stCfg, err := ctx.SThg.ConfigGet()
179 return cli.NewExitError(err, 2)
181 for _, stFld := range stCfg.Folders {
182 relativePath := strings.TrimPrefix(stFld.RawPath, ctx.Config.ShareRootDir)
183 if relativePath == "" {
184 relativePath = stFld.RawPath
187 newFld := xdsconfig.NewFolderConfig(stFld.ID, stFld.Label, ctx.Config.ShareRootDir, strings.TrimRight(relativePath, "/"), defaultSdk)
188 ctx.Config.Folders = ctx.Config.Folders.Update(xdsconfig.FoldersConfig{newFld})
192 ctx.MFolder = model.NewFolder(ctx.Config, ctx.SThg)
195 err = fmt.Errorf("Unsupported builder type")
196 return cli.NewExitError(err, 3)
200 ctx.SDKs, err = crosssdk.Init(ctx.Config, ctx.Log)
202 return cli.NewExitError(err, 2)
205 // Create and start Web Server
206 ctx.WWWServer = webserver.New(ctx.Config, ctx.MFolder, ctx.SDKs, ctx.Log)
207 if err = ctx.WWWServer.Serve(); err != nil {
209 return cli.NewExitError(err, 3)
212 return cli.NewExitError("Program exited ", 4)
218 // Create a new instance of the logger
221 // Create a new App instance
224 app.Description = appDescription
226 app.Version = AppVersion + " (" + AppSubVersion + ")"
227 app.Authors = appAuthors
228 app.Copyright = appCopyright
229 app.Metadata = make(map[string]interface{})
230 app.Metadata["version"] = AppVersion
231 app.Metadata["git-tag"] = AppSubVersion
232 app.Metadata["logger"] = log
234 app.Flags = []cli.Flag{
237 Usage: "JSON config file to use\n\t",
238 EnvVar: "APP_CONFIG",
243 Usage: "logging level (supported levels: panic, fatal, error, warn, info, debug)\n\t",
248 // only one action: Web Server