From 07ca14e35c362d74412f45704c3324ba8374d636 Mon Sep 17 00:00:00 2001 From: Wouter R Date: Sun, 28 Jul 2013 05:01:58 +0200 Subject: [PATCH] Add doxify.sh to generate HTML code documentation using ldoc; update documentation in several utility files. --- .gitignore | 1 + README | 4 -- README.md | 12 ++++++ doxify.sh | 18 +++++++++ src/conf_defaults.lua | 7 ++-- src/util/logger.lua | 41 +++++++++++++------ src/util/settings.lua | 91 ++++++++++++++++++++++++++++++++++--------- src/util/utils.lua | 13 ++++++- 8 files changed, 150 insertions(+), 37 deletions(-) delete mode 100644 README create mode 100644 README.md create mode 100755 doxify.sh diff --git a/.gitignore b/.gitignore index b8752e7..7c71a02 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +docs misc diff --git a/README b/README deleted file mode 100644 index 3e7086a..0000000 --- a/README +++ /dev/null @@ -1,4 +0,0 @@ -WiFi box OpenWRT firmware package -================================= - -Documentation can be found in the source code and on the wiki: . diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e39e7c --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +WiFi box OpenWRT firmware package +================================= + +General documentation can be found on the wiki: . Source code documentation can be generated, see below. + +Documentation +------------- + +The script 'doxify.sh' generates HTML documentation of the source code in the directory 'docs'. +Make sure the 'ldoc' program is installed on your machine and the LDOC variable in the script points there. + +On OSX, this can be accomplished by installing it through luarocks (run `sudo luarocks install ldoc`). Luarocks can be installed using [MacPorts](http://www.macports.org/). After installing that, the command would be `sudo port install luarocks`. diff --git a/doxify.sh b/doxify.sh new file mode 100755 index 0000000..5465787 --- /dev/null +++ b/doxify.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# Generate Lua source code documentation using ldoc. Change LDOC to the path of your luadoc executable and change WIFIBOX_BASE_DIR to the location of your wifibox source tree, or "." if you really want a relative output directory. +# All given options are forwarded to ldoc, -a is already being passed by default. + +LDOC=/opt/local/share/luarocks/bin/ldoc +WIFIBOX_BASE_DIR=~/Files/_devel/eclipse-workspace/wifibox + +HTML_PATH=$WIFIBOX_BASE_DIR/docs +SRC_DIR=$WIFIBOX_BASE_DIR/src +FILESPEC=$WIFIBOX_BASE_DIR/src #replace by config.ld so we can also specify README.md? + +$LDOC -d $HTML_PATH $FILESPEC -a -f markdown $@ + +if [ $? -eq 127 ]; then + echo "$0: It looks like the ldoc program could not be found, please configure the LDOC variable correctly and make sure ldoc is installed on your system." + echo "$0: By default, this script expects ldoc has been installed with luarocks on OSX, which in turn is installed with macports." +fi diff --git a/src/conf_defaults.lua b/src/conf_defaults.lua index 7dec701..7e3c809 100644 --- a/src/conf_defaults.lua +++ b/src/conf_defaults.lua @@ -1,4 +1,5 @@ ---[[ +--[[-- + TODO: finish documentation This file contains all valid configuration keys, their default values and optional constraints. The table names are used as configuration key names, where underscores ('_') may be used to denote semi-categories. The settings interface replaces periods ('.') by underscores so for instance 'network.ap.address' will @@ -105,13 +106,13 @@ M.printer_useSubLayers = { M.printer_firstLayerSlow = { default = true, - type = 'float', + type = 'bool', description = 'Print the first layer slowly to get a more stable start', } M.printer_autoWarmUp = { default = true, - type = 'float', + type = 'bool', description = '', } diff --git a/src/util/logger.lua b/src/util/logger.lua index e37c6fb..6e15465 100644 --- a/src/util/logger.lua +++ b/src/util/logger.lua @@ -1,26 +1,30 @@ +--[[-- + TODO: ldoc: @{} ref in init() tformat + TODO: use macros/type definitions to document rest modules (to auto-match things like 'M._NAME%')? + TODO: finish documentation +]] + local utils = require('util.utils') local M = {} + local logLevel, logVerbose, logStream -M.LEVEL = {'debug', 'info', 'warn', 'error', 'fatal'} +--- Available log levels. +M.LEVEL = { + 'debug', -- for debug messages + 'info', -- for informational messages + 'warn', -- for warnings (something is wrong/fishy but not neccesarily problematic) + 'error', -- for recoverable errors + 'fatal' -- for unrecoverable errors +} -- M.LEVEL already has idx=>name entries, now create name=>idx entries for i,v in ipairs(M.LEVEL) do M.LEVEL[v] = i end -function M:init(level, verbose) - logLevel = level or M.LEVEL.warn - logVerbose = verbose or false - logStream = stream or io.stdout -end - --- pass nil as stream to reset to stdout -function M:setStream(stream) - logStream = stream or io.stdout -end local function log(level, msg, verbose) if level >= logLevel then @@ -36,6 +40,21 @@ local function log(level, msg, verbose) end end + +--- Initializes the logger. +-- @tparam @{util.logger.LEVEL} level Minimum level of messages to log. +-- @tparam bool verbose Write verbose log messages (include file/line inforomation). +function M:init(level, verbose) + logLevel = level or M.LEVEL.warn + logVerbose = verbose or false + logStream = stream or io.stdout +end + +-- pass nil as stream to reset to stdout +function M:setStream(stream) + logStream = stream or io.stdout +end + function M:debug(msg, verbose) log(M.LEVEL.debug, msg, verbose); return true end function M:info(msg, verbose) log(M.LEVEL.info, msg, verbose); return true end function M:warn(msg, verbose) log(M.LEVEL.warn, msg, verbose); return true end diff --git a/src/util/settings.lua b/src/util/settings.lua index 311b14a..8e67cd2 100644 --- a/src/util/settings.lua +++ b/src/util/settings.lua @@ -1,29 +1,39 @@ ---[[ - The settings interface reads and writes its configuration using UCI. - The corresponding config file is /etc/config/wifibox. To have an initial - set of reasonable settings (and allow users to easily return to them), - any key not found in the UCI configuration is looked up in the (immutable) - 'base configuration' (base_config.lua). This file also contains constraints - to check if newly set values are valid. +--[[-- + The settings interface reads and writes configuration keys using UCI. + All keys have pre-defined defaults in @{conf_defaults} which will be used + if no value is stored in the UCI config. The UCI config file is + '/etc/config/wifibox'. + The default values guarantee there will always be a set of reasonable settings + to use and provide a clear overview of all existing configuration keys as well. - By the way, returning correct values in get()/fromUciValue() for booleans has been fixed at a - relatively convenient time purely thanks to the unit tests...just to indicate they are useful. :) -]]-- + By the way, returning correct values in get()/fromUciValue() for booleans has + been fixed at a relatively convenient time purely thanks to the unit tests... + just to indicate how useful they are. :) +]] +local uci = require('uci').cursor() local utils = require('util.utils') local baseconfig = require('conf_defaults') -local uci = require('uci').cursor() local M = {} -local UCI_CONFIG_NAME = 'wifibox' -- the file under /etc/config + +--- UCI config name (i.e. file under /etc/config) +local UCI_CONFIG_NAME = 'wifibox' + +--- Absolute path to the UCI config file local UCI_CONFIG_FILE = '/etc/config/' .. UCI_CONFIG_NAME -local UCI_CONFIG_TYPE = 'settings' -- the section type that will be used in UCI_CONFIG_FILE -local UCI_CONFIG_SECTION = 'general' -- the section name that will be used in UCI_CONFIG_FILE + +--- Section type that will be used in UCI\_CONFIG\_FILE +local UCI_CONFIG_TYPE = 'settings' + +--- Section name that will be used in UCI\_CONFIG\_FILE +local UCI_CONFIG_SECTION = 'general' + local ERR_NO_SUCH_KEY = "key does not exist" ---- Returns the given key with all periods ('.') replaced by underscores ('_'). --- @param key The key for which to substitute dots. +--- Returns a key with all periods ('.') replaced by underscores ('_'). +-- @tparam string key The key for which to substitute dots. -- @return The substituted key, or the key parameter itself if it is not of type 'string'. local function replaceDots(key) if type(key) ~= 'string' then return key end @@ -31,18 +41,33 @@ local function replaceDots(key) return r end --- The inverse of replaceDots() +--- Returns a key with all underscores ('_') replaced by periods ('.'). +-- @tparam string key The key for which to substitute underscores. +-- @return The substituted key, or the key parameter itself if it is not of type 'string'. local function replaceUnderscores(key) if type(key) ~= 'string' then return key end local r = key:gsub('_', '%.') return r end +--- Converts a lua value to equivalent representation for UCI. +-- Boolean values are converted to '1' and '0', everything else is converted to a string. +-- +-- @param v The value to convert. +-- @param vType The type of the given value. +-- @return A value usable to write to UCI. local function toUciValue(v, vType) if vType == 'bool' then return v and '1' or '0' end return tostring(v) end +--- Converts a value read from UCI to a correctly typed lua value. +-- For boolean, '1' is converted to true and everything else to false. Floats +-- and ints are converted to numbers and everything else will be returned as is. +-- +-- @param v The value to convert. +-- @param vType The type of the given value. +-- @return A lua value typed correctly with regard to the vType parameter. local function fromUciValue(v, vType) if v == nil then return nil end @@ -56,6 +81,10 @@ local function fromUciValue(v, vType) end +--- Reports whether a value is valid given the constraints specified in a base table. +-- @param value The value to test. +-- @tparam table baseTable The base table to use constraint data from (min,max,regex). +-- @treturn bool Returns true if the value is valid, false if it is not. local function isValid(value, baseTable) local varType, min, max, regex = baseTable.type, baseTable.min, baseTable.max, baseTable.regex @@ -81,6 +110,9 @@ local function isValid(value, baseTable) return true end +--- Looks up the table in conf_defaults.lua corresponding to a key. +-- @tparam string key The key for which to return the base table. +-- @treturn table The base table for key, or nil if it does not exist. local function getBaseKeyTable(key) local base = baseconfig[key] return type(base) == 'table' and base.default ~= nil and base or nil @@ -105,6 +137,8 @@ function M.get(key) return actualV end +--- Returns all configuration keys with their current values. +-- @treturn table A table containing a key/value pair for each configuration key. function M.getAll() local result = {} for k,_ in pairs(baseconfig) do @@ -116,18 +150,32 @@ function M.getAll() return result end +--- Reports whether or not a key exists. +-- @tparam string key The key to find. +-- @treturn bool True if the key exists, false if not. function M.exists(key) key = replaceDots(key) return getBaseKeyTable(key) ~= nil end +--- Reports whether or not a key is at its default value. +-- 'Default' in this regard means that no UCI value is defined. This means that +-- if for instance, the default is 'abc', and UCI contains a configured value of +-- 'abc' as well, that key is _not_ a default value. +-- +-- @tparam string key The key to report about. +-- @treturn bool True if the key is currently at its default value, false if not. function M.isDefault(key) key = replaceDots(key) if not M.exists(key) then return nil,ERR_NO_SUCH_KEY end return uci:get(UCI_CONFIG_NAME, UCI_CONFIG_SECTION, key) == nil end --- pass nil as value to restore default +--- Sets a key to a new value or reverts it to the default value. +-- @tparam string key The key to set. +-- @param value The value or set, or nil to revert key to its default value. +-- @treturn bool|nil True if everything went well, nil in case of error. +-- @treturn ?string Error message in case first return value is nil (invalid key). function M.set(key, value) key = replaceDots(key) local r = utils.create(UCI_CONFIG_FILE) @@ -139,6 +187,13 @@ function M.set(key, value) if M.isDefault(key) and value == nil then return true end -- key is default already local current = uci:get(UCI_CONFIG_NAME, UCI_CONFIG_SECTION, key) + +-- TODO: test if this fixes setting bools (and does not break settings the other types) +-- if base.type == 'bool' then +-- value = utils.toboolean(value) +-- elseif base.type == 'int' or base.type == 'float' then +-- value = tonumber(value) +-- end if fromUciValue(current, base.type) == value then return true end diff --git a/src/util/utils.lua b/src/util/utils.lua index 40d22a8..32dd1ef 100644 --- a/src/util/utils.lua +++ b/src/util/utils.lua @@ -1,7 +1,11 @@ -local uci = require('uci').cursor() +--[[-- + TODO: finish documentation + The unavoidable collection of utility functions. +]] local M = {} + function string:split(div) local div, pos, arr = div or ':', 0, {} for st,sp in function() return self:find(div, pos, true) end do @@ -42,7 +46,14 @@ function M.dump(o) end end +--- Returns the name of a section in a UCI config. +-- This name is necessary to be able to refer to the corresponding section and +-- the UCI library does not provide a way to look it up. +-- @tparam string config Name of the UCI config to search through. +-- @tparam string type UCI type of the section to find. +-- @treturn string Name of the section matching the parameters, or nil if it could not be found. function M.getUciSectionName(config, type) + local uci = require('uci').cursor() local sname = nil uci:foreach(config, type, function(s) sname = s['.name'] end) return sname