14 "github.com/Sirupsen/logrus"
15 "github.com/codegangsta/cli"
16 "github.com/iotbzh/xds-server/lib/model"
17 "github.com/iotbzh/xds-server/lib/syncthing"
18 "github.com/iotbzh/xds-server/lib/webserver"
19 "github.com/iotbzh/xds-server/lib/xdsconfig"
23 appName = "xds-server"
24 appDescription = "X(cross) Development System Server is a web server that allows to remotely cross build applications."
25 appCopyright = "Apache-2.0"
26 appUsage = "X(cross) Development System Server"
29 var appAuthors = []cli.Author{
30 cli.Author{Name: "Sebastien Douheret", Email: "sebastien@iot.bzh"},
33 // AppVersion is the version of this application
34 var AppVersion = "?.?.?"
36 // AppSubVersion is the git tag id added to version string
37 // Should be set by compilation -ldflags "-X main.AppSubVersion=xxx"
38 var AppSubVersion = "unknown-dev"
40 // Context holds the XDS server context
44 Config *xdsconfig.Config
49 WWWServer *webserver.ServerService
53 // NewContext Create a new instance of XDS server
54 func NewContext(cliCtx *cli.Context) *Context {
57 // Set logger level and formatter
58 log := cliCtx.App.Metadata["logger"].(*logrus.Logger)
60 logLevel := cliCtx.GlobalString("log")
62 logLevel = "error" // FIXME get from Config DefaultLogLevel
64 if log.Level, err = logrus.ParseLevel(logLevel); err != nil {
65 fmt.Printf("Invalid log level : \"%v\"\n", logLevel)
68 log.Formatter = &logrus.TextFormatter{}
70 // Define default configuration
72 ProgName: cliCtx.App.Name,
75 Exit: make(chan os.Signal, 1),
78 // register handler on SIGTERM / exit
79 signal.Notify(ctx.Exit, os.Interrupt, syscall.SIGTERM)
80 go handlerSigTerm(&ctx)
85 // Handle exit and properly stop/close all stuff
86 func handlerSigTerm(ctx *Context) {
89 ctx.Log.Infof("Stopping Syncthing... (PID %d)",
90 ctx.SThgCmd.Process.Pid)
93 if ctx.WWWServer != nil {
94 ctx.Log.Infof("Stoping Web server...")
100 // xdsServer main routine
101 func xdsApp(cliCtx *cli.Context) error {
104 // Create XDS server context
105 ctx := NewContext(cliCtx)
108 cfg, err := xdsconfig.Init(ctx.Cli, ctx.Log)
110 return cli.NewExitError(err, 2)
114 // TODO allow to redirect stdout/sterr into logs file
115 //logFilename := filepath.Join(ctx.Config.FileConf.LogsDir + "xds-server.log")
117 // FIXME - add a builder interface and support other builder type (eg. native)
118 builderType := "syncthing"
123 // Start local instance of Syncthing and Syncthing-notify
124 ctx.SThg = st.NewSyncThing(ctx.Config, ctx.Log)
126 ctx.Log.Infof("Starting Syncthing...")
127 ctx.SThgCmd, err = ctx.SThg.Start()
129 return cli.NewExitError(err, 2)
131 ctx.Log.Infof("Syncthing started (PID %d)", ctx.SThgCmd.Process.Pid)
133 // Establish connection with local Syncthing (retry if connection fail)
137 if err = ctx.SThg.Connect(); err == nil {
140 ctx.Log.Warningf("Establishing connection to Syncthing (retry %d/10)", retry)
141 time.Sleep(time.Second)
144 if err != nil || retry == 0 {
145 return cli.NewExitError(err, 2)
148 // Retrieve Syncthing config
149 id, err := ctx.SThg.IDGet()
151 return cli.NewExitError(err, 2)
154 if ctx.Config.Builder, err = xdsconfig.NewBuilderConfig(id); err != nil {
155 return cli.NewExitError(err, 2)
158 // Retrieve initial Syncthing config
159 stCfg, err := ctx.SThg.ConfigGet()
161 return cli.NewExitError(err, 2)
163 for _, stFld := range stCfg.Folders {
164 relativePath := strings.TrimPrefix(stFld.RawPath, ctx.Config.ShareRootDir)
165 if relativePath == "" {
166 relativePath = stFld.RawPath
168 newFld := xdsconfig.NewFolderConfig(stFld.ID, stFld.Label, ctx.Config.ShareRootDir, strings.Trim(relativePath, "/"))
169 ctx.Config.Folders = ctx.Config.Folders.Update(xdsconfig.FoldersConfig{newFld})
173 ctx.MFolder = model.NewFolder(ctx.Config, ctx.SThg)
176 err = fmt.Errorf("Unsupported builder type")
177 return cli.NewExitError(err, 3)
180 // Create and start Web Server
181 ctx.WWWServer = webserver.NewServer(ctx.Config, ctx.MFolder, ctx.Log)
182 if err = ctx.WWWServer.Serve(); err != nil {
184 return cli.NewExitError(err, 3)
187 return cli.NewExitError("Program exited ", 4)
193 // Create a new instance of the logger
196 // Create a new App instance
199 app.Description = appDescription
201 app.Version = AppVersion + " (" + AppSubVersion + ")"
202 app.Authors = appAuthors
203 app.Copyright = appCopyright
204 app.Metadata = make(map[string]interface{})
205 app.Metadata["version"] = AppVersion
206 app.Metadata["git-tag"] = AppSubVersion
207 app.Metadata["logger"] = log
209 app.Flags = []cli.Flag{
212 Usage: "JSON config file to use\n\t",
213 EnvVar: "APP_CONFIG",
218 Usage: "logging level (supported levels: panic, fatal, error, warn, info, debug)\n\t",
223 // only one action: Web Server