Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Sep 2005 01:45:28 GMT
From:      soc-andrew <soc-andrew@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 84408 for review
Message-ID:  <200509280145.j8S1jSok066806@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=84408

Change 84408 by soc-andrew@soc-andrew_serv on 2005/09/28 01:44:54

	Update the Lua backend to a new version from today
	Rename uses of POSIX to posix as POSIX is boolean
	Install more needed parts (still more to come)

Affected files ...

.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/backend/lua/lib/package.lua#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/backend/lua/lib/uinav.lua#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/app/Makefile#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/app/app.lua#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/dfui/Makefile#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/dfui/common.c#3 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/dfui/dfui.c#3 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/dfui/dfui.lua#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/dfui/progress.c#3 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/filename/Makefile#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/filename/filename.lua#3 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/pty/Makefile#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/pty/pty.c#3 edit
.. //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/pty/pty.lua#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/etc/mtree/BSD.usr.dist#4 edit
.. //depot/projects/soc2005/bsdinstaller/src/lib/bsdinstaller/lua/Makefile.inc1#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/lib/bsdinstaller/lua/dfui/Makefile#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/libexec/bsdinstaller/Makefile#2 edit
.. //depot/projects/soc2005/bsdinstaller/src/libexec/bsdinstaller/lib/Makefile#1 add

Differences ...

==== //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/backend/lua/lib/package.lua#2 (text+ko) ====

@@ -160,7 +160,7 @@
 			pkg_tmp = tab.tmp_dir
 		else
 			local tmp_dir = App.dir.root .. ts:get_base() .. "tmp"
-			local link = POSIX.readlink(tmp_dir)
+			local link = posix.readlink(tmp_dir)
 			if link ~= nil then
 				pkg_tmp = FileName.remove_leading_slash(real_tmp_dir)
 			elseif FileName.is_dir(tmp_dir) then
@@ -358,7 +358,7 @@
 	method.enumerate_installed_on = function(ps, ts)
 		local i, filename, list, dir
 
-		dir = POSIX.dir(
+		dir = posix.dir(
 		    App.expand("${root}${base}var/db/pkg", {
 			base = ts:get_base()
 		    })

==== //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/backend/lua/lib/uinav.lua#2 (text+ko) ====

@@ -233,7 +233,7 @@
 			from_dir = FileName.dirname(App.current_script)
 		end
 
-		filenames = POSIX.dir(from_dir)
+		filenames = posix.dir(from_dir)
 		table.sort(filenames)
 
 		for i, filename in ipairs(filenames) do

==== //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/app/Makefile#2 (text+ko) ====

@@ -1,10 +1,14 @@
-# $Id: Makefile,v 1.4 2005/04/05 20:53:46 cpressey Exp $
-# Dummy makefile.
+# $Id: Makefile,v 1.6 2005/08/27 02:11:33 cpressey Exp $
+
+BASE?=../../..
+include ${BASE}/Config
 
 all:
-	@echo "No building required."
-
-in_cvs: all
+	@echo "Nothing to build."
 
 clean:
 	@echo "No cleaning required."
+
+distribution:
+	mkdir -p ${DESTDIR}/share/lua/5.0/
+	cp app.lua ${DESTDIR}/share/lua/5.0/

==== //depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/lib/lua/app/app.lua#2 (text+ko) ====

@@ -1,6 +1,36 @@
--- app.lua
--- $Id: app.lua,v 1.54 2005/04/22 05:03:07 cpressey Exp $
--- Lua-based Application Environment static object.
+-- $Id: app.lua,v 1.70 2005/09/13 19:25:29 cpressey Exp $
+-- Lua-based Application Environment.
+
+--
+-- Copyright (c)2005 Chris Pressey.  All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- 1. Redistributions of source code must retain the above copyright
+--    notices, this list of conditions and the following disclaimer.
+-- 2. Redistributions in binary form must reproduce the above copyright
+--    notices, this list of conditions, and the following disclaimer in
+--    the documentation and/or other materials provided with the
+--    distribution.
+-- 3. Neither the names of the copyright holders nor the names of their
+--    contributors may be used to endorse or promote products derived
+--    from this software without specific prior written permission. 
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+-- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+-- FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+-- COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+-- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+-- ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+-- POSSIBILITY OF SUCH DAMAGE.
+--
 
 -- BEGIN app.lua --
 
@@ -14,247 +44,166 @@
 --[[ App ]]--
 --[[-----]]--
 
--- Application Environment - roughly equivalent to
--- InstallerContext (or i_fn_args in the C version,) but:
+--
+-- Application Environment.
 --
--- *  this version is written purely in Lua, and
--- *  this version is not specific to the Installer - it could just as well
---    be used for any application that needs:
+-- This package provides a global environment or framework for an
+-- application written in Lua.  It was written for the BSD Installer,
+-- but should be general enough to be suitable for many applications
+-- which require some or all of the following:
 --
---   o  user interface facilities (highly abstracted)
---   o  configuration, possibly loaded from config files
---      - locations of directories (root dir, temp dir, etc)
+--   o  highly abstracted user interface facilities
+--   o  configuration, either loaded from configuration files,
+--      or read from the command-line arguments, including:
+--      - locations of directories (cmd root dir, temp dir, etc)
 --      - names of system commands
 --      - etc
---   o  application-wide options
 --   o  application-wide state
 --   o  logging
 --   o  temporary files
 --
--- For simplicity, we consider this to be a singleton or
--- "static object" (with a single global "instance" called App.)
+-- Although App superficially resembles a class, it cannot be instantiated.
+-- Hence it can be considered a "package", or a "singleton class" or
+-- "static object", with a single global "instance".
+--
+
+--
+-- Container.
+--
 
 App = {}
 
 --
--- Initialize global stuff.
+-- Private data.
 --
 
-App.init = function()
-	App.defaults = {
-	    name	= "Unnamed Application",
-	    logfile	= "unnamed.log",
-	    dir = {
-		root	= "/",
-		tmp	= "/tmp/"
-	    },
-	    transport	= "tcp",
-	    rendezvous	= "9999"
-	}
-	
-	App.last_log_time = -1
-	App.conf_path = ""
-	App.current_script = arg[0]
-	
-	App.config = {}
-	App.option = {}
-	App.state = {}
+local last_log_time = -1
+local current_script = nil
 
-	App.add_pkg_path("./lib")
-	App.add_pkg_path(FileName.dirname(App.current_script) .. "lib")
-	App.add_conf_path("./conf")
-	App.add_conf_path(FileName.dirname(App.current_script) .. "conf")
+--
+-- Private functions.
+--
 
-	arg = App.process_cmdline(arg)
+--
+-- Add a directory to package.path (used by compat-5.1.)
+--
+local add_pkg_path = function(dir)
+	if package and package.path then
+		if package.path ~= "" then
+			package.path = package.path .. ";"
+		end
+		package.path = package.path .. tostring(dir) .. "/?.lua"
+	end
 end
 
 --
--- Startup and shutdown.
+-- Public static methods.
 --
 
-App.start = function(opt)
-	local k, v
+-----------------------------------------------------------------------
+-------------------------- Startup and Shutdown -----------------------
+-----------------------------------------------------------------------
 
+--
+-- Application startup.
+--
+App.start = function(arg)
 	--
-	-- Private function to create a dummy user interface adapter
-	-- if the App was started without one.
+	-- Begin setting up the App.
+	-- Initialize the global application containers.
+	-- Make the configuration table "see through" so that
+	-- the configuration files have access to all Lua functions.
 	--
-	local new_dummy_ui = function()
-		local method = {}
-	
-		method.start = function(method)
-			App.log("Dummy user interface started")
-			return true
-		end
-	
-		method.stop = function(method)
-			App.log("Dummy user interface stopped")
-			return true
-		end
-	
-		method.present = function(method, tab)
-			App.dump_table(tab)
-			return {
-			    action_id = tab.actions[1].id,
-			    datasets = tab.datasets
-			}
-		end
-	
-		method.inform = function(method, msg)
-			App.log("INFORM: %s", msg)
-			return { action_id = "ok", datasets = {} }
-		end
-		
-		method.confirm = function(method, msg)
-			App.log("CONFIRM: %s", msg)
-			return true
-		end
-	
-		method.select = function(method, msg, map)
-			local k, v
-			App.log("SELECT: %s", msg)
-			for k, v in map do
-				return v
-			end
-		end
-	
-		method.select_file = function(method, tab)
-			App.log("SELECT FILE: %s", tab.title or "Select File")
-			return "cancel"
-		end
-	
-		--
-		-- Constructor within a constructor, here...
-		--
-		method.new_progress_bar = function(method, tab)
-			local method = {}
-	
-			method.start = function(method)
-				App.log("START PROGRESS BAR")
-				return true
-			end
-	
-			method.set_amount = function(method, new_amount)
-				App.log("SET PROGRESS AMOUNT: %d", new_amount)
-				return true
-			end
-	
-			method.set_short_desc = function(method, new_short_desc)
-				App.log("SET PROGRESS DESC: %d", new_short_desc)
-				return true
-			end
-	
-			method.update = function(method)
-				App.log("PROGRESS UPDATE: %d", new_amount)
-				return true
-			end
-	
-			method.stop = function(method)
-				App.log("STOP PROGRESS BAR")
-				return true
-			end
-	
-			return method
-		end
-	
-		return method
-	end
+	App.conf = setmetatable({}, { __index = _G })
+	App.state = {}
 
 	--
-	-- Begin setting up the App.
+	-- Set the current script to the script that was invoked, as it was
+	-- recorded as the first command-line argument.
 	--
+	current_script = assert(arg[0], "Missing script name")
 
-	-- Set up defaults.
-	if not opt then
-		opt = {}
-	end
+	--
+	-- Set up the default search path, based on the current script.
+	--
+	add_pkg_path(FileName.dirname(current_script) .. "lib")
 
-	App.merge_tables(opt, App.defaults, function(key, dest_val, src_val)
-		if not dest_val then
-			return src_val
+	--
+	-- Process each command-line argument in turn.
+	--
+	local argn = 1
+	while arg[argn] do
+		if arg[argn] == "-L" then
+			argn = argn + 1
+			add_pkg_path(arg[argn])
+		elseif arg[argn] == "-t" then -- obsolete dfui transport
+			argn = argn + 1
+			App.set_property("ui.transport=" .. arg[argn])
+		elseif arg[argn] == "-r" then -- obsolete dfui rendezvous
+			argn = argn + 1
+			App.set_property("ui.rendezvous=" .. arg[argn])
+		elseif string.find(arg[argn], "=") then
+			App.set_property(arg[argn])
 		else
-			return dest_val
+			App.load_conf(arg[argn])
 		end
-	end)
 
-	-- Set name of application.
-	App.name = opt.name
-	App.log_filename = opt.logfile
-
-	-- Set up directories, and make sure each ends with a slash.
-	App.dir = opt.dir
-	for k, v in App.dir do
-		if string.sub(v, -1) ~= "/" then
-			App.dir[k] = v .. "/"
-		end
+		argn = argn + 1
 	end
 
-	-- Determine the operating system.
-	App.os = {}
-	App.os.name = App.determine_os_name()
-	-- App.os.version = App.determine_os_version()
+	--
+	-- Fix up configuration:
+	--
 
-	-- Open our logfile.
-	App.open_log(App.dir.tmp .. App.log_filename)
-	App.log(App.name .. " started")
+	--
+	-- Set the product name to the OS name, if not given.
+	--
+	App.conf.product.name =
+	    App.conf.product.name or App.conf.os.name
+	App.conf.product.version =
+	    App.conf.product.version or App.conf.os.version
 
-	-- Load command names, if available.
-	App.cmd_names = App.load_conf("cmdnames")
+	--
+	-- Make sure each directory in App.conf.dir ends with a slash.
+	--
+	local name, dir
+	for name, dir in App.conf.dir do
+		App.conf.dir[name] = FileName.add_trailing_slash(dir)
+	end
 
-	-- Set up the ${}-expansion function.
-	App.expand = function(str, ...)
-		local ltables = arg or {}
-		local gtables = {App.cmd_names, App.dir}
+	--
+	-- Open our logfile.
+	--
+	App.open_log(App.conf.dir.tmp .. App.conf.log_filename)
+	App.log("%s started", App.conf.app_name)
 
-		local result = string.gsub(str, "%$%{([%w_]+)%}", function(key)
-			local i, tab, value
-
-			if table.getn(ltables) > 0 then
-				for i, tab in ipairs(ltables) do
-					value = tab[key]
-					if value then
-						return value
-					end
-				end
-			end
-
-			if table.getn(gtables) > 0 then
-				for i, tab in ipairs(gtables) do
-					value = tab[key]
-					if value then
-						return value
-					end
-				end
-			end
-
-			App.log_warn("Could not expand `${%s}'", key)
-			return "${" .. key .. "}"
-		end)
-
-		return result
-	end
-
+	--
 	-- Set up temporary files.
+	--
 	App.tmpfile = {}
-	
-	-- Set up application-specific containers:
-	--	config:	application configuration
-	--	option:	application-wide options
-	--	state:	application-wide state
-	App.config = opt.config or App.config
-	App.option = opt.option or App.option
-	App.state = opt.state or App.state
 
+	--
 	-- Seed the random-number generator.
+	--
 	math.randomseed(os.time())
+end
 
-	-- Set up the App's UI adapter.
-	App.ui = opt.ui or new_dummy_ui()
+--
+-- Start the user interface.  XXX this interface is a bit ugly now.
+--
+App.start_ui = function(ui)
+	--
+	-- Set up the App's UI bridge.
+	--
+	App.ui = ui or App.UIBridge.new(App.DummyUI)
 	if not App.ui:start() then
 		App.log_fatal("Could not start user interface")
 	end
 end
 
+--
+-- Application shutdown.
+--
 App.stop = function()
 	App.clean_tmpfiles()
 	App.ui:stop()
@@ -262,90 +211,18 @@
 	App.close_log()
 end
 
-App.process_cmdline = function(arg)
-	local argn = 1
-	local remaining_arg = {}
-
-	while arg[argn] do
-		if arg[argn] == "-C" then
-			argn = argn + 1
-			App.add_conf_path(arg[argn])
-		elseif arg[argn] == "-L" then
-			argn = argn + 1
-			App.add_pkg_path(arg[argn])
-		elseif arg[argn] == "-R" then
-			argn = argn + 1
-			local script_name = App.find_script(arg[argn]) or arg[argn]
-			local ok, result = App.run(script_name)
-			if not ok then
-				io.stderr:write("warning: could not run `" ..
-				    tostring(script_name) .. "':\n")
-				io.stderr:write(result .. "\n")
-			end
-		elseif string.find(arg[argn], "=") then
-			App.set_property(arg[argn])
-		else
-			table.insert(remaining_arg, arg[argn])
-		end
-
-		argn = argn + 1
-	end
+-----------------------------------------------------------------------
+----------------- Locating and Running Scriptlets ---------------------
+-----------------------------------------------------------------------
 
-	return remaining_arg
-end
-
 --
--- Given a string in the form "foo.bar=baz", set the member "bar" of the
--- subtable "foo" of the App object to "baz".
+-- Determine the name of the currently running script.
 --
-App.set_property = function(expr)
-	local found, len, k, v, c, r, i, t
-
-	t = App.defaults
-	r = {}
-	found, len, k, v = string.find(expr, "^(.*)=(.*)$")
-	for c in string.gfind(k, "[^%.]+") do
-		table.insert(r, c)
-	end
-	for i, c in r do
-		if i == table.getn(r) then
-			t[c] = v
-		else
-			if not t[c] then
-				t[c] = {}
-			end
-			if type(t[c]) == "table" then
-				t = t[c]
-			else
-				App.log_warn("%s: not a table", tostring(c))
-			end
-		end
-	end
+App.get_current_script = function()
+	return current_script
 end
 
 --
--- Add a directory to package.path (used by compat-5.1.)
---
-App.add_pkg_path = function(dir)
-	if package and package.path then
-		if package.path ~= "" then
-			package.path = package.path .. ";"
-		end
-		package.path = package.path .. tostring(dir) .. "/?.lua"
-	end
-end
-
---
--- Add a directory to App.conf_path (used by App.load_conf().)
---
-App.add_conf_path = function(dir)
-	if App.conf_path ~= "" then
-		App.conf_path = App.conf_path .. ";"
-	end
-	App.conf_path = App.conf_path .. tostring(dir) .. "/?.lua"
-end
-
---
 -- Run a Lua script.
 -- Note that the script name must be either relative to the
 -- current working directory, or fully-qualified.
@@ -356,11 +233,11 @@
 --    if false, the second is an error message string.
 --
 App.run = function(script_name, ...)
-	local save_script = App.current_script
+	local save_script = current_script
 	local save_args = ARG
 	local ok, result, fun, errmsg
 
-	if App.option.fatal_errors then
+	if App.conf.fatal_errors then
 		assert(script_name and type(script_name) == "string",
 		       "bad filename " .. tostring(script_name))
 	end
@@ -368,21 +245,18 @@
 		return false, "bad filename " .. tostring(script_name)
 	end
 
-	App.add_pkg_path(FileName.dirname(script_name) .. "lib")
-	App.add_conf_path(FileName.dirname(script_name) .. "conf")
-
 	fun, errmsg = loadfile(script_name)
 
-	if App.option.fatal_errors then
+	if App.conf.fatal_errors then
 		assert(fun, errmsg)
 	end
 	if not fun then
 		return false, errmsg
 	end
 
-	App.current_script = script_name
+	current_script = script_name
 	ARG = arg
-	if App.option.fatal_errors then
+	if App.conf.fatal_errors then
 		ok = true
 		result = fun()
 	else
@@ -391,7 +265,7 @@
 					 end)
 	end
 	ARG = save_args
-	App.current_script = save_script
+	current_script = save_script
 
 	return ok, result
 end
@@ -400,7 +274,7 @@
 -- Find a Lua script.
 --
 App.find_script = function(script_name)
-	script_name = FileName.dirname(App.current_script) .. script_name
+	script_name = FileName.dirname(current_script) .. script_name
 
 	if FileName.is_dir(script_name) then
 		if string.sub(script_name, -1, -1) ~= "/" then
@@ -422,64 +296,6 @@
 end
 
 --
--- Dump the contents of the given table to stdout,
--- primarily intended for debugging.
---
-App.dump_table = function(tab, indent)
-	local k, v
-
-	if not indent then
-		indent = ""
-	end
-
-	for k, v in tab do
-		if type(v) == "table" then
-			print(indent .. tostring(k) .. "=")
-			App.dump_table(v, indent .. "\t")
-		else
-			print(indent .. tostring(k) .. "=" .. tostring(v))
-		end
-	end
-end
-
---
--- Merge two tables by looking at each item from the second (src)
--- table and putting a value into the first (dest) table based on
--- the result of a provided callback function which receives the
--- key and bother values, and returns the resulting value.
---
--- An 'overriding' merge can be accomplished with:
---	function(key, dest_val, src_val)
---		return src_val
---	end
---
--- A 'non-overriding' merge can be accomplished with:
---	function(key, dest_val, src_val)
---		if dest_val == nil then
---			return src_val
---		else
---			return dest_val
---		end
---	end
---
-App.merge_tables = function(dest, src, fun)
-	local k, v
-
-	for k, v in src do
-		if type(v) == "table" then
-			if not dest[k] then
-				dest[k] = {}
-			end
-			if type(dest[k]) == "table" then
-				App.merge_tables(dest[k], v, fun)
-			end
-		else
-			dest[k] = fun(k, dest[k], v)
-		end
-	end
-end
-
---
 -- Run a script.  Expects the full filename (will not search.)
 -- Displays a nice dialog box if the script contained errors.
 --
@@ -518,83 +334,64 @@
 	return App.run_script(App.find_script(script_name), unpack(arg))
 end
 
+-----------------------------------------------------------------------
+-------------- Locating and Loading Configuration Files ---------------
+-----------------------------------------------------------------------
+
 --
--- Wait for a condition to come true.
--- Display a (cancellable) progress bar while we wait.
--- Returns two values: whether the condition eventually
--- did come true, and roughly how long it took (if it
--- timed out, this value will be greater than the timeout.)
+-- A metatable that overloads the '+' operator on tables, so that
+-- 'a + b' results in an overriding merge of b's pairs into a.
 --
-App.wait_for = function(tab)
-	local predicate = tab.predicate
-	local timeout = tab.timeout or 30
-	local frequency = tab.frequency or 2
-	local title = tab.title or "Please wait..."
-	local short_desc = tab.short_desc or title
-	local pr
-	local time_elapsed = 0
-	local cancelled = false
-
-	assert(type(predicate) == "function")
-
-	if predicate() then
-		return true
+local overload_mt = {
+	__add = function(a, b)
+		App.merge_tables(a, b, function(key, dest_val, src_val)
+			return src_val
+		end)
+		return a
 	end
+}
 
-	pr = App.ui:new_progress_bar{
-	    title = title,
-	    short_desc = short_desc
-	}
-	pr:start()
-	
-	while time_elapsed < timeout and not cancelled and not result do
-		POSIX.nanosleep(frequency)
-		time_elapsed = time_elapsed + frequency
-		if predicate() then
-			return true, time_elapsed
-		end
-		pr:set_amount((time_elapsed * 100) / timeout)
-		cancelled = not pr:update()
-	end
-
-	pr:stop()
-
-	return false, time_elapsed
-end
-
 --
--- Configuration file loading.
+-- Load a configuration file, given its name.
 --
+App.load_conf = function(filename)
+	App.log("Loading configuration file '%s'...", filename)
 
-App.locate_conf = function(name)
-	local comp
+	--
+	-- Load and configuration file and compile it into a
+	-- function.  Give the function the App.conf table
+	-- as its global context.  Run the function, and all
+	-- of the values it has set will go into App.conf.
+	--
+	local conf_func, err = loadfile(filename)
+	if not conf_func then
+		App.log_fatal("Could not load configuration file '%s': %s",
+		    name, err)
+	end
+	setfenv(conf_func, App.conf)
+	conf_func()
 
-	for comp in string.gfind(App.conf_path, "[^;]+") do
-		comp = string.gsub(comp, "?", name)
-		if FileName.is_file(comp) then
-			return comp
+	--
+	-- Make all the tables in the configuration extendable with
+	-- the '+' operator, for future conf files that may be loaded.
+	--
+	local name, value
+	for name, value in App.conf do
+		if type(value) == "table" then
+			setmetatable(value, overload_mt)
 		end
 	end
-	
-	return nil
 end
 
-App.load_conf = function(name)
-	local filename = App.locate_conf(name)
 
-	if filename ~= nil then
-		App.log("Loading configuration file '%s'...", filename)
-		return App.run_script(filename)
-	else
-		App.log_warn("Could not locate configuration file '%s'!", name)
-		return nil
-	end
-end
+-----------------------------------------------------------------------
+----------------------------- Logging ---------------------------------
+-----------------------------------------------------------------------
 
 --
--- Logging.
+-- Open the log.
+-- XXX This doesn't really need to be public, does it?
 --
-
 App.open_log = function(filename, mode)
 	if App.log_file then
 		return
@@ -611,6 +408,17 @@
 	end
 end
 
+--
+-- Reopen the log with the same filename as it was opened with,
+-- after (temporarily) closing it.
+--
+App.reopen_log = function()
+	return App.open_log(App.conf.dir.tmp .. App.conf.log_filename, "a")
+end
+
+--
+-- Close the log.
+--
 App.close_log = function()
 	if App.log_file then
 		App.log_file:close()
@@ -618,48 +426,72 @@
 	end
 end
 
+--
+-- Write a line to the log.
+--
 App.log = function(str, ...)
 	local stamp = math.floor(os.time())
-	local line = ""
-	local i, a
 
 	local write_log = function(s)
 		s = s .. "\n"
-		io.stderr:write(s)
+		io.stdout:write(s)
+		io.stdout:flush()
 		if App.log_file then
 			App.log_file:write(s)
 			App.log_file:flush()
 		end
 	end
 
-	if stamp > App.last_log_time then
-		App.last_log_time = stamp
+	if stamp > last_log_time then
+		last_log_time = stamp
 		write_log("[" .. os.date() .. "]")
 	end
+	write_log(App.format(str, unpack(arg)))
+end
 
+App.format = function(str, ...)
 	str = string.gsub(str, "%%%a", "%%s")
-	for i, a in ipairs(arg) do
-		arg[i] = tostring(a)
+
+        local i
+	for i = 1, table.getn(arg) do
+		arg[i] = tostring(arg[i])
 	end
-	write_log(string.format(str, unpack(arg)))
+
+	return string.format(str, unpack(arg))
+end
+
+--
+-- Write a plain string to the log (no formatting.)
+--
+App.log_string = function(str)
+	App.log("%s", str)
 end
 
+--
+-- Write a warning to the log.
+--
 App.log_warn = function(str, ...)
 	App.log("WARNING: " .. str, unpack(arg))
 end
 
+--
+-- Write an error to the log.
+--
 App.log_fatal = function(str, ...)
 	App.log(str, unpack(arg))
-	error(str)
+	error(App.format(str, unpack(arg)))
 end
 
+--
+-- Display the log in the abstract user interface.
+--
 App.view_log = function()
 	local contents = ""
 	local fh
 
 	App.close_log()
 
-	fh = io.open(App.dir.tmp .. App.log_filename, "r")
+	fh = io.open(App.conf.dir.tmp .. App.conf.log_filename, "r")
 	for line in fh:lines() do
 		contents = contents .. line .. "\n"
 	end
@@ -667,7 +499,7 @@
 
 	App.ui:present({
 		id = "app_log",
-		name = App.name .. ": Log",
+		name = App.conf.app_name .. ": Log",
 		short_desc = contents,
 		role = "informative",
 		minimum_width = "72",
@@ -677,40 +509,64 @@
 		}
 	})
 	
-	App.open_log(App.dir.tmp .. App.log_filename, "a")
+	App.open_log(App.conf.dir.tmp .. App.conf.log_filename, "a")
 end
 
 --
--- Temporary file handling.
+-- Install logging wrappers around every method in a class/object.
+-- This is more useful for debugging purposes than for everyday use.
 --
+App.log_methods = function(obj_method_table)
+	local k, v
+	for k, v in pairs(obj_method_table) do
+		local method_name, orig_fun = k, method[k]
+		method[k] = function(...)
+			App.log("ENTERING: %s", method_name)
+			orig_fun(unpack(arg))
+			App.log("EXITED: %s", method_name)
+		end
+	end
+end
 
+-----------------------------------------------------------------------
+------------------------- Temporary Files -----------------------------
+-----------------------------------------------------------------------
+
+--
+-- Delete all known temporary files.
+--
 App.clean_tmpfiles = function()
 	local filename, unused
 
 	for filename, unused in App.tmpfile do
 		App.log("Deleting tmpfile: " .. filename)
-		os.remove(App.dir.tmp .. filename)
+		os.remove(App.conf.dir.tmp .. filename)
 	end
 end
 
--- Registers that the given file (which resides in App.dir.tmp)
+--
+-- Register that the given file (which resides in App.conf.dir.tmp)
 -- is a temporary file, and may be deleted when upon exit.
+--
 App.register_tmpfile = function(filename)
 	App.tmpfile[filename] = 1
 end
 
--- Creates and opens a new temporary file (in App.dir.tmp).
+--
+-- Create and open a new temporary file (in App.conf.dir.tmp).
 -- If the filename is omitted, one is chosen using the mkstemp
 -- system call.  If the mode is omitted, updating ("w+") is
 -- assumed.  The file object and the file name are returned.
+--

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200509280145.j8S1jSok066806>