webmcp

view framework/bin/mcp.lua @ 233:827c44692141

Allow setting certain global variables in autoloader
author jbe
date Sat Feb 28 23:28:41 2015 +0100 (2015-02-28)
parents 82cc171e8510
children 36346c33a020
line source
1 #!/usr/bin/env moonbridge
3 WEBMCP_VERSION = "2.0.0_devel"
5 -- allow control of global environment
6 local _G = _G
7 local global_metatable = {
8 __index = _G,
9 __newindex = function(self, key, value)
10 _G[key] = value
11 end
12 }
13 _ENV = setmetatable({}, global_metatable)
15 -- check if interactive mode
16 if listen then -- defined by moonbridge
17 WEBMCP_MODE = "listen"
18 else
19 WEBMCP_MODE = "interactive"
20 end
22 -- configuration names are provided as 4th, 5th, etc. argument
23 WEBMCP_CONFIG_NAMES = {select(4, ...)}
25 -- determine framework and bath path from command line arguments
26 -- or print usage synopsis (if applicable)
27 do
28 local arg1, arg2, arg3 = ...
29 local helpout
30 if
31 arg1 == "-h" or arg1 == "--help" or
32 arg2 == "-h" or arg2 == "--help" -- if first arg is provided by wrapper
33 then
34 helpout = io.stdout
35 elseif
36 #WEBMCP_CONFIG_NAMES < 1 or
37 (WEBMCP_MODE == "interactive") ~= (arg3 == "INTERACTIVE")
38 then
39 helpout = io.stderr
40 end
41 if helpout then
42 helpout:write("Usage: moonbridge -- <framework path>/bin/mcp.lua <framework path> <app base path> <app name> <config name> [<config name> ...]\n")
43 helpout:write(" or: lua -i <framework path>/bin/mcp.lua <framework path> <app base path> INTERACTIVE <config name> [<config name> ...]\n")
44 if helpout == io.stderr then
45 return 1
46 else
47 return 0
48 end
49 end
50 local function append_trailing_slash(str)
51 return string.gsub(str, "([^/])$", function(last) return last .. "/" end)
52 end
53 WEBMCP_FRAMEWORK_PATH = append_trailing_slash(arg1)
54 WEBMCP_BASE_PATH = append_trailing_slash(arg2)
55 if WEBMCP_MODE == "listen" then
56 WEBMCP_APP_NAME = arg3
57 end
58 end
60 -- setup search paths for libraries
61 do
62 if string.match(package.path, "^[^;]") then
63 package.path = ";" .. package.path
64 end
65 package.path = WEBMCP_FRAMEWORK_PATH .. "lib/?.lua" .. package.path
66 -- find out which file name extension shared libraries have
67 local slib_exts = {}
68 for ext in string.gmatch(package.cpath, "%?%.([A-Za-z0-9_-]+)") do
69 if not slib_exts[ext] then
70 slib_exts[#slib_exts+1] = ext
71 slib_exts[ext] = true
72 end
73 end
74 local paths = {}
75 for i, ext in ipairs(slib_exts) do
76 paths[#paths+1] = WEBMCP_FRAMEWORK_PATH .. "accelerator/?." .. ext
77 end
78 for i, ext in ipairs(slib_exts) do
79 paths[#paths+1] = WEBMCP_FRAMEWORK_PATH .. "lib/?." .. ext
80 end
81 paths[#paths+1] = package.cpath
82 package.cpath = table.concat(paths, ";")
83 end
85 -- autoloader system for WebMCP environment "$WEBMCP_FRAMEWORK_PATH/env/",
86 -- application environment extensions "$WEBMCP_BASE_PATH/env/"
87 -- and models "$WEBMCP_BASE_PATH/model/"
88 do
89 local weakkey_mt = { __mode = "k" }
90 local autoloader_category = setmetatable({}, weakkey_mt)
91 local autoloader_path = setmetatable({}, weakkey_mt)
92 local autoloader_mt = {}
93 local function install_autoloader(self, category, path_fragment)
94 autoloader_category[self] = category
95 autoloader_path[self] = path_fragment
96 setmetatable(self, autoloader_mt)
97 end
98 local function try_exec(filename)
99 local file = io.open(filename, "r")
100 if file then
101 local filedata = file:read("*a")
102 io.close(file)
103 local func, errmsg = load(filedata, "=" .. filename, nil, _ENV)
104 if func then
105 func()
106 return true
107 else
108 error(errmsg, 0)
109 end
110 else
111 return false
112 end
113 end
114 function autoloader_mt.__index(self, key)
115 local category, base_path, merge_base_path, file_key
116 local merge = false
117 if
118 string.find(key, "^[a-z_][A-Za-z0-9_]*$") and
119 not string.find(key, "^__")
120 then
121 category = "env"
122 base_path = WEBMCP_FRAMEWORK_PATH .. "env/"
123 merge = true
124 merge_base_path = WEBMCP_BASE_PATH .. "env/"
125 file_key = key
126 elseif string.find(key, "^[A-Z][A-Za-z0-9]*$") then
127 category = "model"
128 base_path = WEBMCP_BASE_PATH .. "model/"
129 local first = true
130 file_key = string.gsub(key, "[A-Z]",
131 function(c)
132 if first then
133 first = false
134 return string.lower(c)
135 else
136 return "_" .. string.lower(c)
137 end
138 end
139 )
140 else
141 return
142 end
143 local required_category = autoloader_category[self]
144 if required_category and required_category ~= category then return end
145 local path_fragment = autoloader_path[self]
146 local path = base_path .. path_fragment .. file_key
147 local merge_path
148 if merge then
149 merge_path = merge_base_path .. path_fragment .. file_key
150 end
151 local function try_dir(dirname)
152 local dir = io.open(dirname)
153 if dir then
154 io.close(dir)
155 local obj = {}
156 install_autoloader(obj, category, path_fragment .. file_key .. "/")
157 rawset(self, key, obj)
158 try_exec(path .. "/__init.lua")
159 if merge then try_exec(merge_path .. "/__init.lua") end
160 return true
161 else
162 return false
163 end
164 end
165 if self == _ENV then
166 _G[key] = false -- allow writing global variable
167 end
168 if merge and try_exec(merge_path .. ".lua") then
169 elseif merge and try_dir(merge_path .. "/") then
170 elseif try_exec(path .. ".lua") then
171 elseif try_dir(path .. "/") then
172 else end
173 local value = rawget(self, key)
174 if self == _ENV and value == false then
175 _G[key] = nil
176 return nil
177 else
178 return value
179 end
180 end
181 install_autoloader(_G, nil, "")
182 try_exec(WEBMCP_FRAMEWORK_PATH .. "env/__init.lua")
183 try_exec(WEBMCP_BASE_PATH .. "env/__init.lua")
184 end
186 -- replace Moonbridge listen function
187 local moonbridge_listen = listen
188 local listeners = {}
189 function listen(args)
190 listeners[#listeners+1] = args
191 end
193 -- prohibit (unintended) definition of new global variables
194 function global_metatable.__newindex()
195 error("Setting of global variable prohibited")
196 end
198 -- execute configurations and pre-fork initializers
199 for i, config_name in ipairs(WEBMCP_CONFIG_NAMES) do
200 execute.config(config_name)
201 end
202 execute.prefork_initializers()
204 -- interactive console mode
205 if WEBMCP_MODE == "interactive" then
206 _G.multirand = require "multirand" -- TODO: cleaner solution
207 execute.postfork_initializers()
208 trace.disable() -- avoids memory leakage (TODO: needs general solution for moonbridge?)
209 end
211 -- invoke moonbridge
212 if WEBMCP_MODE == "listen" then
213 local http = require("moonbridge_http")
214 for i, listener in ipairs(listeners) do
215 --listener.prepare = execute.postfork_initializers
216 listener.prepare = function()
217 _G.multirand = require "multirand"
218 execute.postfork_initializers()
219 end
220 listener.connect = http.generate_handler(
221 request.handler,
222 request.get_http_options()
223 )
224 listener.finish = execute.finalizers
225 moonbridge_listen(listener)
226 end
227 end

Impressum / About Us