1
1
package revel
2
2
3
3
import (
4
+ "fmt"
5
+ "github.com/go-stack/stack"
6
+ "github.com/revel/revel/logger"
4
7
"go/build"
5
8
"path/filepath"
6
9
"sort"
7
10
"strings"
8
- "github.com/revel/revel/logger"
9
11
)
10
12
11
13
// Module specific functions
12
14
type Module struct {
13
15
Name , ImportPath , Path string
14
16
ControllerTypeList []* ControllerType
15
- Log logger.MultiLogger
17
+ Log logger.MultiLogger
18
+ initializedModules map [string ]ModuleCallbackInterface
16
19
}
17
20
21
+ // Modules can be called back after they are loaded in revel by using this interface.
22
+ type ModuleCallbackInterface func (* Module )
23
+
18
24
// The namespace separator constant
19
25
const namespaceSeperator = `\` // (note cannot be . or : as this is already used for routes)
20
26
21
27
var (
22
- Modules []* Module // The list of modules in use
23
- anyModule = & Module {} // Wildcard search for controllers for a module (for backward compatible lookups)
24
- appModule = & Module {Name : "App" } // The app module
25
- moduleLogger = RevelLog .New ("section" , "module" )
28
+ Modules []* Module // The list of modules in use
29
+ anyModule = & Module {} // Wildcard search for controllers for a module (for backward compatible lookups)
30
+ appModule = & Module {Name : "App" , initializedModules : map [ string ] ModuleCallbackInterface {}, Log : AppLog } // The app module
31
+ moduleLog = RevelLog .New ("section" , "module" )
26
32
)
27
33
34
+ // Called by a module init() function, caller will receive the *Module object created for that module
35
+ // This would be useful for assigning a logger for logging information in the module (since the module context would be correct)
36
+ func RegisterModuleInit (callback ModuleCallbackInterface ) {
37
+ // Store the module that called this so we can do a callback when the app is initialized
38
+ // The format %+k is from go-stack/Call.Format and returns the package path
39
+ key := fmt .Sprintf ("%+k" , stack .Caller (1 ))
40
+ appModule .initializedModules [key ] = callback
41
+ if Initialized {
42
+ RevelLog .Error ("Application already initialized, initializing using app module" , "key" , key )
43
+ callback (appModule )
44
+ }
45
+
46
+ }
28
47
func init () {
29
48
AddInitEventHandler (func (typeOf int , value interface {}) (responseOf int ) {
30
49
if typeOf == REVEL_BEFORE_MODULES_LOADED {
@@ -117,7 +136,7 @@ func loadModules() {
117
136
// Reorder module order by key name, a poor mans sort but at least it is consistent
118
137
sort .Strings (keys )
119
138
for _ , key := range keys {
120
- moduleLogger .Debug ("Sorted keys" , "keys" , key )
139
+ moduleLog .Debug ("Sorted keys" , "keys" , key )
121
140
122
141
}
123
142
for _ , key := range keys {
@@ -128,7 +147,7 @@ func loadModules() {
128
147
129
148
modulePath , err := ResolveImportPath (moduleImportPath )
130
149
if err != nil {
131
- moduleLogger .Error ("Failed to load module. Import of path failed" , "modulePath" , moduleImportPath , "error" , err )
150
+ moduleLog .Error ("Failed to load module. Import of path failed" , "modulePath" , moduleImportPath , "error" , err )
132
151
}
133
152
// Drop anything between module.???.<name of module>
134
153
subKey := key [len ("module." ):]
@@ -137,32 +156,47 @@ func loadModules() {
137
156
}
138
157
addModule (subKey , moduleImportPath , modulePath )
139
158
}
159
+
160
+ // Modules loaded, now show module path
161
+ for key , callback := range appModule .initializedModules {
162
+ found := false
163
+ for _ , m := range Modules {
164
+ if strings .HasPrefix (key , m .ImportPath ) {
165
+ moduleLog .Debug ("Module called callback" , "moduleKey" , m .ImportPath , "callbackKey" , key )
166
+ callback (m )
167
+ }
168
+ }
169
+ if ! found {
170
+ RevelLog .Error ("Callback for non registered module initializing with application module" ,"modulePath" ,key )
171
+ callback (appModule )
172
+ }
173
+ }
140
174
}
141
175
142
176
//
143
177
func addModule (name , importPath , modulePath string ) {
144
178
if _ , found := ModuleByName (name ); found {
145
- moduleLogger .Panic ("Attempt to import duplicate module %s path %s aborting startup" , "name" , name , "path" , modulePath )
179
+ moduleLog .Panic ("Attempt to import duplicate module %s path %s aborting startup" , "name" , name , "path" , modulePath )
146
180
}
147
- Modules = append (Modules , & Module {Name : name , ImportPath : importPath , Path : modulePath , Log :RootLog .New ("module" , name )})
181
+ Modules = append (Modules , & Module {Name : name , ImportPath : importPath , Path : modulePath , Log : RootLog .New ("module" , name )})
148
182
if codePath := filepath .Join (modulePath , "app" ); DirExists (codePath ) {
149
183
CodePaths = append (CodePaths , codePath )
150
184
if viewsPath := filepath .Join (modulePath , "app" , "views" ); DirExists (viewsPath ) {
151
185
TemplatePaths = append (TemplatePaths , viewsPath )
152
186
}
153
187
}
154
188
155
- moduleLogger .Debug ("Loaded module " , "module" , filepath .Base (modulePath ))
189
+ moduleLog .Debug ("Loaded module " , "module" , filepath .Base (modulePath ))
156
190
157
191
// Hack: There is presently no way for the testrunner module to add the
158
192
// "test" subdirectory to the CodePaths. So this does it instead.
159
193
if importPath == Config .StringDefault ("module.testrunner" , "github.com/revel/modules/testrunner" ) {
160
194
joinedPath := filepath .Join (BasePath , "tests" )
161
- moduleLogger .Debug ("Found testrunner module, adding `tests` path " , "path" , joinedPath )
195
+ moduleLog .Debug ("Found testrunner module, adding `tests` path " , "path" , joinedPath )
162
196
CodePaths = append (CodePaths , joinedPath )
163
197
}
164
198
if testsPath := filepath .Join (modulePath , "tests" ); DirExists (testsPath ) {
165
- moduleLogger .Debug ("Found tests path " , "path" , testsPath )
199
+ moduleLog .Debug ("Found tests path " , "path" , testsPath )
166
200
CodePaths = append (CodePaths , testsPath )
167
201
}
168
202
}
0 commit comments