Improved ResolveEnvVar and add support of tilde (~/...)
[src/xds/xds-server.git] / lib / xdsconfig / fileconfig.go
1 package xdsconfig
2
3 import (
4         "encoding/json"
5         "os"
6         "os/user"
7         "path"
8         "path/filepath"
9         "strings"
10
11         "github.com/iotbzh/xds-server/lib/common"
12 )
13
14 type SyncThingConf struct {
15         BinDir     string `json:"binDir"`
16         Home       string `json:"home"`
17         GuiAddress string `json:"gui-address"`
18         GuiAPIKey  string `json:"gui-apikey"`
19 }
20
21 type FileConfig struct {
22         WebAppDir    string         `json:"webAppDir"`
23         ShareRootDir string         `json:"shareRootDir"`
24         SdkRootDir   string         `json:"sdkRootDir"`
25         HTTPPort     string         `json:"httpPort"`
26         SThgConf     *SyncThingConf `json:"syncthing"`
27         LogsDir      string         `json:"logsDir"`
28 }
29
30 // getConfigFromFile reads configuration from a config file.
31 // Order to determine which config file is used:
32 //  1/ from command line option: "--config myConfig.json"
33 //  2/ $HOME/.xds/config.json file
34 //  3/ <current_dir>/config.json file
35 //  4/ <xds-server executable dir>/config.json file
36
37 func updateConfigFromFile(c *Config, confFile string) error {
38
39         searchIn := make([]string, 0, 3)
40         if confFile != "" {
41                 searchIn = append(searchIn, confFile)
42         }
43         if usr, err := user.Current(); err == nil {
44                 searchIn = append(searchIn, path.Join(usr.HomeDir, ".xds", "config.json"))
45         }
46         cwd, err := os.Getwd()
47         if err == nil {
48                 searchIn = append(searchIn, path.Join(cwd, "config.json"))
49         }
50         exePath, err := filepath.Abs(filepath.Dir(os.Args[0]))
51         if err == nil {
52                 searchIn = append(searchIn, path.Join(exePath, "config.json"))
53         }
54
55         var cFile *string
56         for _, p := range searchIn {
57                 if _, err := os.Stat(p); err == nil {
58                         cFile = &p
59                         break
60                 }
61         }
62         if cFile == nil {
63                 // No config file found
64                 return nil
65         }
66
67         c.Log.Infof("Use config file: %s", *cFile)
68
69         // TODO move on viper package to support comments in JSON and also
70         // bind with flags (command line options)
71         // see https://github.com/spf13/viper#working-with-flags
72
73         fd, _ := os.Open(*cFile)
74         defer fd.Close()
75         fCfg := FileConfig{}
76         if err := json.NewDecoder(fd).Decode(&fCfg); err != nil {
77                 return err
78         }
79         c.FileConf = fCfg
80
81         // Support environment variables (IOW ${MY_ENV_VAR} syntax) in config.json
82         for _, field := range []*string{
83                 &fCfg.WebAppDir,
84                 &fCfg.ShareRootDir,
85                 &fCfg.SdkRootDir,
86                 &fCfg.LogsDir,
87                 &fCfg.SThgConf.Home,
88                 &fCfg.SThgConf.BinDir} {
89
90                 var err error
91                 if *field, err = common.ResolveEnvVar(*field); err != nil {
92                         return err
93                 }
94         }
95
96         // Config file settings overwrite default config
97
98         if fCfg.WebAppDir != "" {
99                 c.WebAppDir = strings.Trim(fCfg.WebAppDir, " ")
100         }
101         // Is it a full path ?
102         if !strings.HasPrefix(c.WebAppDir, "/") && exePath != "" {
103                 // Check first from current directory
104                 for _, rootD := range []string{cwd, exePath} {
105                         ff := path.Join(rootD, c.WebAppDir, "index.html")
106                         if common.Exists(ff) {
107                                 c.WebAppDir = path.Join(rootD, c.WebAppDir)
108                                 break
109                         }
110                 }
111         }
112
113         if fCfg.ShareRootDir != "" {
114                 c.ShareRootDir = fCfg.ShareRootDir
115         }
116
117         if fCfg.HTTPPort != "" {
118                 c.HTTPPort = fCfg.HTTPPort
119         }
120
121         return nil
122 }