summaryrefslogtreecommitdiffstats
path: root/lua
diff options
context:
space:
mode:
authorTed Trask <ttrask01@yahoo.com>2011-08-30 20:13:24 +0000
committerTed Trask <ttrask01@yahoo.com>2011-08-30 20:13:24 +0000
commit42750f022f4b2b9a9df6237c0981fdd479f4532d (patch)
tree219a575c980e5942c2ca9473b426caf289188e15 /lua
parent733a51c96e6b97a725afab9923efd7ef5b509e0b (diff)
downloadacf-core-42750f022f4b2b9a9df6237c0981fdd479f4532d.tar.bz2
acf-core-42750f022f4b2b9a9df6237c0981fdd479f4532d.tar.xz
Moved mvc.lua into /usr/share/lua and cli to /usr/bin/acf_cli
Diffstat (limited to 'lua')
-rw-r--r--lua/Makefile35
-rwxr-xr-xlua/mvc.lua357
2 files changed, 392 insertions, 0 deletions
diff --git a/lua/Makefile b/lua/Makefile
new file mode 100644
index 0000000..c9e7b43
--- /dev/null
+++ b/lua/Makefile
@@ -0,0 +1,35 @@
+include ../config.mk
+
+LUA_DIST=mvc.lua\
+
+EXTRA_DIST=Makefile
+DISTFILES=$(LUA_DIST) $(EXTRA_DIST)
+
+install_dir=$(DESTDIR)/$(luadir)
+dist_dir=$(DISTDIR)/$(notdir $(PWD))
+
+phony+=all
+all:
+
+phony+=clean
+clean:
+
+phony+=distdir
+distdir: $(DISTFILES)
+ mkdir -p "$(dist_dir)"
+ for i in $(DISTFILES); do\
+ dest=`dirname "$(dist_dir)/$$i"`;\
+ mkdir -p "$$dest";\
+ cp "$$i" "$$dest";\
+ done
+
+phony+=install
+install:
+ mkdir -p $(install_dir)
+ for i in $(LUA_DIST); do\
+ dest=`dirname "$(install_dir)/$$i"`;\
+ mkdir -p "$$dest";\
+ cp "$$i" "$$dest";\
+ done
+
+.PHONY: $(phony)
diff --git a/lua/mvc.lua b/lua/mvc.lua
new file mode 100755
index 0000000..41aa9db
--- /dev/null
+++ b/lua/mvc.lua
@@ -0,0 +1,357 @@
+--[[ Basic MVC framework
+ Written for Alpine Configuration Framework (ACF)
+ see www.alpinelinux.org for more information
+ Copyright (C) 2007 Nathan Angelacos
+ Licensed under the terms of GPL2
+ ]]--
+module(..., package.seeall)
+
+require("posix")
+
+mvc = {}
+
+-- the constructor
+--[[ Builds a new MVC object. If "module" is given, then tries to load
+ self.conf.appdir .. module "-controller.lua" in c.worker and
+ self.conf.appdir .. module "-model.lua" in c.model
+
+ The returned .conf table is guaranteed to have the following
+ appdir - where the application lives
+ confdir - where the configuration file is
+ sessiondir - where session data and other temporary stuff goes
+ appname - the name of the application
+ ]]
+
+new = function (self, modname)
+ local model_loaded = true
+ local worker_loaded = true
+ local c = {}
+ c.worker = {}
+ c.model = {}
+
+ -- make defaults if the parent doesn't have them
+ if self.conf == nil then
+ c.conf = { appdir = "", confdir = "",
+ tempdir = "", appname = "" }
+ end
+
+ -- If no clientdata, then clientdata is a null table
+ if self.clientdata == nil then
+ c.clientdata = {}
+ end
+
+ -- If we don't have an application name, use the modname
+ if (self.conf == nil ) or (self.conf.appname == nil) then
+ c.conf.appname = modname
+ end
+
+ -- load the module code here
+ if (modname) then
+ c.worker = self:soft_require( modname .. "-controller")
+ if c.worker == nil then
+ c.worker = {}
+ worker_loaded = false
+ end
+ c.model = self:soft_require( modname .. "-model" )
+ if c.model == nil then
+ c.model = {}
+ model_loaded = false
+ end
+ end
+
+ -- The magic that makes all the metatables point in the correct
+ -- direction. c.model -> c.worker -> parent -> parent.worker ->
+ -- grandparent -> grandparent -> worker (and so on)
+
+ -- The model looks in worker for missing
+ setmetatable (c.model, c.model )
+ c.model.__index = c.worker
+
+ -- the worker looks in the parent table for missing
+ setmetatable (c.worker, c.worker)
+ c.worker.__index = self
+
+ -- the table looks in the worker for missing
+ setmetatable (c, c)
+ c.__index = c.worker
+
+ -- ensure an "mvc" table exists, even if empty
+ if (type(rawget(c.worker, "mvc")) ~= "table") then
+ c.worker.mvc = {}
+ end
+
+ setmetatable (c.worker.mvc, c.worker.mvc)
+ -- If creating a new parent container, then
+ -- we are the top of the chain.
+ if (modname) then
+ c.worker.mvc.__index = self.worker.mvc
+ else
+ c.worker.mvc.__index = self.mvc
+ end
+
+ -- run the worker on_load code
+ if type(rawget(c.worker.mvc, "on_load")) == "function" then
+ c.worker.mvc.on_load(c, self)
+ c.worker.mvc.on_load = nil
+ end
+
+ -- save the new self on the SELF stack
+ if not SELF then SELF = {} end
+ SELF[#SELF + 1] = c
+
+ return c, worker_loaded, model_loaded
+end
+
+destroy = function (self)
+ if type(rawget(self.worker.mvc, "on_unload")) == "function" then
+ self.worker.mvc.on_unload(self)
+ self.worker.mvc.on_unload = nil
+ end
+
+ -- remove the self from the SELF stack (should be at the end, but just in case)
+ if SELF then
+ for i,s in ipairs(SELF) do
+ if s == self then
+ table.remove(SELF, i)
+ break
+ end
+ end
+ end
+
+ -- remove packages from package.loaded
+ if self["_NAME"] then package.loaded[self["_NAME"]] = nil end
+ if self.model and self.model["_NAME"] then package.loaded[self.model["_NAME"]] = nil end
+end
+
+-- This is a sample front controller/dispatch.
+dispatch = function (self, userprefix, userctlr, useraction)
+ local controller = nil
+ local success, err = xpcall ( function ()
+
+ if userprefix == nil then
+ self.conf.prefix, self.conf.controller, self.conf.action =
+ parse_path_info(ENV["PATH_INFO"])
+ else
+ self.conf.prefix = userprefix
+ self.conf.controller = userctlr or ""
+ self.conf.action = useraction or ""
+ end
+
+ -- If they didn't provide a controller, and a default was specified
+ -- use it
+ if self.conf.controller == "" and self.conf.default_controller then
+ self.conf.controller = self.conf.default_controller
+ self.conf.prefix = self.conf.default_prefix or "/"
+ end
+
+ local worker_loaded
+ controller, worker_loaded = self:new(self.conf.prefix .. self.conf.controller)
+
+ if not worker_loaded then
+ self.conf.type = "dispatch"
+ error(self.conf)
+ end
+
+ if controller.conf.action == "" then
+ controller.conf.action = rawget(controller.worker, "default_action") or ""
+ end
+
+ local action = controller.conf.action
+
+ -- Because of the inheritance, normally the
+ -- controller.worker.action will flow up, so that all children have
+ -- actions of all parents. We use rawget to make sure that only
+ -- controller defined actions are used on dispatch
+ -- If the action is missing, raise an error
+ if ( type(rawget(controller.worker, action)) ~= "function") then
+ self.conf.type = "dispatch"
+ error (self.conf)
+ end
+
+ -- run the (first found) pre_exec code, starting at the controller
+ -- and moving up the parents
+ if type(controller.worker.mvc.pre_exec) == "function" then
+ controller.worker.mvc.pre_exec ( controller )
+ end
+
+ -- run the action
+ local viewtable = controller.worker[action](controller)
+
+ -- run the post_exec code
+ if type(controller.worker.mvc.post_exec) == "function" then
+ controller.worker.mvc.post_exec ( controller )
+ end
+
+ local viewfunc = controller:view_resolver()
+
+ -- we're done with the controller, destroy it
+ controller:destroy()
+ controller = nil
+
+ viewfunc (viewtable)
+ end,
+ self:soft_traceback(message)
+ )
+
+ if not success then
+ local handler
+ if controller then
+ handler = controller.worker or controller
+ if handler then handler:exception_handler(err) end
+ controller:destroy()
+ controller = nil
+ end
+ if nil == handler then
+ handler = self.worker or mvc
+ handler:exception_handler(err)
+ end
+ end
+end
+
+-- Tries to see if name exists in the self.conf.appdir, and if so, it loads it.
+-- otherwise, returns nil, but no error
+soft_require = function (self, name )
+ local filename, file
+ for p in string.gmatch(self.conf.appdir, "[^,]+") do
+ filename = p .. name .. ".lua"
+ file = io.open(filename)
+ if file then
+ file:close()
+ local PATH=package.path
+ -- FIXME - this should really try to open the lua file,
+ -- and if it doesnt exist silently fail.
+ -- This version allows things from /usr/local/lua/5.1 to
+ -- be loaded
+ package.path = p .. "/?.lua;" .. package.path
+ local t
+ if posix.dirname(name) == "." then
+ t = require(posix.basename(name))
+ else
+ t = require(posix.basename(posix.dirname(name)).."."..posix.basename(name))
+ end
+ package.path = PATH
+ return t
+ end
+ end
+ return nil
+end
+
+-- look in various places for a config file, and store it in self.conf
+read_config = function( self, appname )
+ appname = appname or self.conf.appname
+ self.conf.appname = self.conf.appname or appname
+
+ local confs = { (ENV["HOME"] or ENV["PWD"] or "") .. "/." ..
+ appname .. "/" .. appname .. ".conf",
+ ( ENV["HOME"] or ENV["PWD"] or "") .. "/" ..
+ appname .. ".conf",
+ ENV["ROOT"] or "" .. "/etc/" .. appname .. "/" ..
+ appname .. ".conf",
+ ENV["ROOT"] or "" .. "/etc/" .. appname .. ".conf"
+ }
+ for i, filename in ipairs (confs) do
+ local file = io.open (filename)
+ if (file) then
+ self.conf.confdir = posix.dirname(filename) .. "/"
+ self.conf.conffile = filename
+ for line in file:lines() do
+ key, value = string.match(line, "^%s*([^[=%s#]*)%s*=%s*(.*)")
+ if key then
+ self.conf[key] = value
+ end
+ end
+ file:close()
+ break
+ end
+ end
+
+ if (#self.conf.confdir) then -- check for an appname-hooks.lua file
+ self.conf.app_hooks = {}
+ setmetatable (self.conf.app_hooks, {__index = _G})
+
+ -- loadfile loads into the global environment
+ -- so we set env 0, not env 1
+ setfenv (0, self.conf.app_hooks)
+ local f = loadfile(self.conf.confdir .. "/" .. appname.. "-hooks.lua")
+ if (f) then f() end
+ setfenv (0, _G)
+ -- setmetatable (self.conf.app_hooks, {})
+ end
+
+end
+
+-- parse a "URI" like string into a prefix, controller and action
+-- return them (or blank strings)
+parse_path_info = function( str )
+ str = str or ""
+ local words = {}
+ str = string.gsub(str, "/+$", "")
+ for x=1,3 do
+ words[#words+1] = string.match(str, "[^/]+$")
+ str = string.gsub(str, "/+[^/]*$", "")
+ end
+ prefix = "/"..(words[#words] or "").."/"
+ if prefix == "//" then prefix = "/" end
+ controller = words[#words-1] or ""
+ action = words[#words-2] or ""
+
+ return prefix, controller, action
+end
+
+-- The view resolver of last resort.
+view_resolver = function(self)
+ return function()
+ if ENV["REQUEST_METHOD"] then
+ io.write ("Content-type: text/plain\n\n")
+ end
+ io.write ("Your controller and application did not specify a view resolver.\n")
+ io.write ("The MVC framework has no view available. sorry.\n")
+ return
+ end
+end
+
+-- Generates a debug.traceback if called with no arguments
+soft_traceback = function (self, message )
+ if message then
+ return message
+ else
+ return debug.traceback
+ end
+end
+
+-- The exception hander of last resort
+exception_handler = function (self, message )
+ if ENV["REQUEST_METHOD"] then
+ print ("Content-Type: text/plain\n\n")
+ end
+ print ("The following unhandled application error occured:\n\n")
+
+ if (type(message) == "table" ) then
+ if (message.type == "dispatch") then
+ print ('controller: "' .. message.controller .. '" does not have a "' ..
+ message.action .. '" action.')
+ else
+ print ("An error of type: '" .. (tostring(message.type) or "nil") .. "' was raised." )
+ end
+ else
+ print (tostring(message))
+ end
+end
+
+-- create a Configuration Framework Entity (cfe)
+-- returns a table with at least "value", "type", and "label"
+cfe = function ( optiontable )
+ optiontable = optiontable or {}
+ me = { value="",
+ type="text",
+ label="" }
+ for key,value in pairs(optiontable) do
+ me[key] = value
+ end
+ return me
+end
+_G.cfe = cfe
+
+logevent = function ( ... )
+ os.execute ( "logger \"ACF: " .. (... or "") .. "\"" )
+end