Merge "Change seba installation for cord 7.0.0"
[iec.git] / src / foundation / api / revel / revel.go
1 // Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
2 // Revel Framework source code and usage is governed by a MIT style
3 // license that can be found in the LICENSE file.
4
5 package revel
6
7 import (
8         "go/build"
9         "log"
10         "path/filepath"
11         "strings"
12
13         "encoding/json"
14         "fmt"
15         "github.com/revel/config"
16         "github.com/revel/revel/logger"
17         "github.com/revel/revel/model"
18 )
19
20 const (
21         // RevelImportPath Revel framework import path
22         RevelImportPath = "github.com/revel/revel"
23 )
24
25 const (
26         TEST_MODE_FLAG   = "testModeFlag"
27         SPECIAL_USE_FLAG = "specialUseFlag"
28 )
29
30 // App details
31 var (
32         RevelConfig *model.RevelContainer
33         AppName    string // e.g. "sample"
34         AppRoot    string // e.g. "/app1"
35         BasePath   string // e.g. "$GOPATH/src/corp/sample"
36         AppPath    string // e.g. "$GOPATH/src/corp/sample/app"
37         ViewsPath  string // e.g. "$GOPATH/src/corp/sample/app/views"
38         ImportPath string // e.g. "corp/sample"
39         SourcePath string // e.g. "$GOPATH/src"
40
41         Config  *config.Context
42         RunMode string // Application-defined (by default, "dev" or "prod")
43         DevMode bool   // if true, RunMode is a development mode.
44
45         // Revel installation details
46         RevelPath string // e.g. "$GOPATH/src/github.com/revel/revel"
47
48         // Where to look for templates
49         // Ordered by priority. (Earlier paths take precedence over later paths.)
50         CodePaths     []string // Code base directories, for modules and app
51         TemplatePaths []string // Template path directories manually added
52
53         // ConfPaths where to look for configurations
54         // Config load order
55         // 1. framework (revel/conf/*)
56         // 2. application (conf/*)
57         // 3. user supplied configs (...) - User configs can override/add any from above
58         ConfPaths []string
59
60         // Server config.
61         //
62         // Alert: This is how the app is configured, which may be different from
63         // the current process reality.  For example, if the app is configured for
64         // port 9000, HTTPPort will always be 9000, even though in dev mode it is
65         // run on a random port and proxied.
66         HTTPPort    int    // e.g. 9000
67         HTTPAddr    string // e.g. "", "127.0.0.1"
68         HTTPSsl     bool   // e.g. true if using ssl
69         HTTPSslCert string // e.g. "/path/to/cert.pem"
70         HTTPSslKey  string // e.g. "/path/to/key.pem"
71
72         // All cookies dropped by the framework begin with this prefix.
73         CookiePrefix string
74         // Cookie domain
75         CookieDomain string
76         // Cookie flags
77         CookieSecure bool
78
79         // Revel request access log, not exposed from package.
80         // However output settings can be controlled from app.conf
81
82         // True when revel engine has been initialized (Init has returned)
83         Initialized bool
84
85         // Private
86         secretKey     []byte             // Key used to sign cookies. An empty key disables signing.
87         packaged      bool               // If true, this is running from a pre-built package.
88         initEventList = []EventHandler{} // Event handler list for receiving events
89 )
90
91 // Init initializes Revel -- it provides paths for getting around the app.
92 //
93 // Params:
94 //   mode - the run mode, which determines which app.conf settings are used.
95 //   importPath - the Go import path of the application.
96 //   srcPath - the path to the source directory, containing Revel and the app.
97 //     If not specified (""), then a functioning Go installation is required.
98 func Init(inputmode, importPath, srcPath string) {
99         RevelConfig = &model.RevelContainer{}
100         // Ignore trailing slashes.
101         ImportPath = strings.TrimRight(importPath, "/")
102         SourcePath = srcPath
103
104         RunMode = updateLog(inputmode)
105
106         // If the SourcePath is not specified, find it using build.Import.
107         var revelSourcePath string // may be different from the app source path
108         if SourcePath == "" {
109                 revelSourcePath, SourcePath = findSrcPaths(importPath)
110         } else {
111                 // If the SourcePath was specified, assume both Revel and the app are within it.
112                 SourcePath = filepath.Clean(SourcePath)
113                 revelSourcePath = SourcePath
114                 packaged = true
115         }
116
117         RevelPath = filepath.Join(revelSourcePath, filepath.FromSlash(RevelImportPath))
118         BasePath = filepath.Join(SourcePath, filepath.FromSlash(importPath))
119         AppPath = filepath.Join(BasePath, "app")
120         ViewsPath = filepath.Join(AppPath, "views")
121
122         CodePaths = []string{AppPath}
123
124         if ConfPaths == nil {
125                 ConfPaths = []string{}
126         }
127
128         // Config load order
129         // 1. framework (revel/conf/*)
130         // 2. application (conf/*)
131         // 3. user supplied configs (...) - User configs can override/add any from above
132         ConfPaths = append(
133                 []string{
134                         filepath.Join(RevelPath, "conf"),
135                         filepath.Join(BasePath, "conf"),
136                 },
137                 ConfPaths...)
138
139         TemplatePaths = []string{
140                 ViewsPath,
141                 filepath.Join(RevelPath, "templates"),
142         }
143
144         // Load app.conf
145         var err error
146         Config, err = config.LoadContext("app.conf", ConfPaths)
147         if err != nil || Config == nil {
148                 RevelLog.Fatal("Failed to load app.conf:", "error", err)
149         }
150
151         // After application config is loaded update the logger
152         updateLog(inputmode)
153
154         // Configure properties from app.conf
155         DevMode = Config.BoolDefault("mode.dev", false)
156         HTTPPort = Config.IntDefault("http.port", 9000)
157         HTTPAddr = Config.StringDefault("http.addr", "")
158         HTTPSsl = Config.BoolDefault("http.ssl", false)
159         HTTPSslCert = Config.StringDefault("http.sslcert", "")
160         HTTPSslKey = Config.StringDefault("http.sslkey", "")
161         if HTTPSsl {
162                 if HTTPSslCert == "" {
163                         RevelLog.Fatal("No http.sslcert provided.")
164                 }
165                 if HTTPSslKey == "" {
166                         RevelLog.Fatal("No http.sslkey provided.")
167                 }
168         }
169
170         AppName = Config.StringDefault("app.name", "(not set)")
171         AppRoot = Config.StringDefault("app.root", "")
172         CookiePrefix = Config.StringDefault("cookie.prefix", "REVEL")
173         CookieDomain = Config.StringDefault("cookie.domain", "")
174         CookieSecure = Config.BoolDefault("cookie.secure", HTTPSsl)
175         if secretStr := Config.StringDefault("app.secret", ""); secretStr != "" {
176                 SetSecretKey([]byte(secretStr))
177         }
178
179         RaiseEvent(REVEL_BEFORE_MODULES_LOADED, nil)
180         loadModules()
181         RaiseEvent(REVEL_AFTER_MODULES_LOADED, nil)
182
183         Initialized = true
184         RevelLog.Info("Initialized Revel", "Version", Version, "BuildDate", BuildDate, "MinimumGoVersion", MinimumGoVersion)
185 }
186
187 // The input mode can be as simple as "prod" or it can be a JSON string like
188 // {"mode":"%s","testModeFlag":true}
189 // When this function is called it returns the true "inputmode" extracted from the parameter
190 // and it sets the log context appropriately
191 func updateLog(inputmode string) (returnMode string) {
192         if inputmode == "" {
193                 returnMode = config.DefaultSection
194                 return
195         } else {
196                 returnMode = inputmode
197         }
198
199         // Check to see if the mode is a json object
200         modemap := map[string]interface{}{}
201
202         var testModeFlag, specialUseFlag bool
203         if err := json.Unmarshal([]byte(inputmode), &modemap); err == nil {
204                 returnMode = modemap["mode"].(string)
205                 if testmode, found := modemap[TEST_MODE_FLAG]; found {
206                         testModeFlag, _ = testmode.(bool)
207                 }
208                 if specialUse, found := modemap[SPECIAL_USE_FLAG]; found {
209                         specialUseFlag, _ = specialUse.(bool)
210                 }
211         }
212
213         var newContext *config.Context
214         // If the Config is nil, set the logger to minimal log messages by adding the option
215         if Config == nil {
216                 newContext = config.NewContext()
217                 newContext.SetOption(TEST_MODE_FLAG, fmt.Sprint(true))
218         } else {
219                 // Ensure that the selected runmode appears in app.conf.
220                 // If empty string is passed as the mode, treat it as "DEFAULT"
221                 if !Config.HasSection(returnMode) {
222                         log.Fatalln("app.conf: No mode found:", returnMode)
223                 }
224                 Config.SetSection(returnMode)
225                 newContext = Config
226         }
227
228         // Only set the testmode flag if it doesnt exist
229         if _, found := newContext.Bool(TEST_MODE_FLAG); !found {
230                 newContext.SetOption(TEST_MODE_FLAG, fmt.Sprint(testModeFlag))
231         }
232         if _, found := newContext.Bool(SPECIAL_USE_FLAG); !found {
233                 newContext.SetOption(SPECIAL_USE_FLAG, fmt.Sprint(specialUseFlag))
234         }
235
236         appHandle := logger.InitializeFromConfig(BasePath, newContext)
237
238         // Set all the log handlers
239         setAppLog(AppLog, appHandle)
240
241         return
242 }
243
244 // Set the secret key
245 func SetSecretKey(newKey []byte) error {
246         secretKey = newKey
247         return nil
248 }
249
250 // ResolveImportPath returns the filesystem path for the given import path.
251 // Returns an error if the import path could not be found.
252 func ResolveImportPath(importPath string) (string, error) {
253         if packaged {
254                 return filepath.Join(SourcePath, importPath), nil
255         }
256
257         modPkg, err := build.Import(importPath, RevelPath, build.FindOnly)
258         if err != nil {
259                 return "", err
260         }
261         return modPkg.Dir, nil
262 }
263
264 // CheckInit method checks `revel.Initialized` if not initialized it panics
265 func CheckInit() {
266         if !Initialized {
267                 RevelLog.Panic("CheckInit: Revel has not been initialized!")
268         }
269 }
270
271 // findSrcPaths uses the "go/build" package to find the source root for Revel
272 // and the app.
273 func findSrcPaths(importPath string) (revelSourcePath, appSourcePath string) {
274         var (
275                 gopaths = filepath.SplitList(build.Default.GOPATH)
276                 goroot  = build.Default.GOROOT
277         )
278
279         if len(gopaths) == 0 {
280                 RevelLog.Fatal("GOPATH environment variable is not set. " +
281                         "Please refer to http://golang.org/doc/code.html to configure your Go environment.")
282         }
283
284         if ContainsString(gopaths, goroot) {
285                 RevelLog.Fatalf("GOPATH (%s) must not include your GOROOT (%s). "+
286                         "Please refer to http://golang.org/doc/code.html to configure your Go environment.",
287                         gopaths, goroot)
288         }
289
290         appPkg, err := build.Import(importPath, "", build.FindOnly)
291         if err != nil {
292                 RevelLog.Panic("Failed to import "+importPath+" with error:", "error", err)
293         }
294
295         revelPkg, err := build.Import(RevelImportPath, appPkg.Dir, build.FindOnly)
296         if err != nil {
297                 RevelLog.Fatal("Failed to find Revel with error:", "error", err)
298         }
299
300         return revelPkg.Dir[:len(revelPkg.Dir)-len(RevelImportPath)], appPkg.SrcRoot
301 }