#!/usr/bin/lua -- --- T2-COPYRIGHT-NOTE-BEGIN --- -- T2 SDE: package/*/sam/sam.lua -- Copyright (C) 2006 - 2022 The T2 SDE Project -- -- This Copyright note is generated by scripts/Create-CopyPatch, -- more information can be found in the files COPYING and README. -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License version 2. -- --- T2-COPYRIGHT-NOTE-END --- -- identification local _NAME = "SAM" local _VERSION = "0.0-devel" local _COPYRIGHT = "Copyright (C) 2006 The T2 SDE Project" local _DESCRIPTION = "System Administration Manager for systems based on T2" -- SAM namespace sam = sam or { command = {} } require "sam.log" -- default options sam.opt = sam.opt or { loglevel = sam.log.DEBUG, -- sam.log.WARN } --[[ DESCRIPTION ] ---------------------------------------------------------- Provided functions: * sam.command["command-name"](args...) * sam.command["command-name"].main(args...) Execute a command (extended by modulues) with given arguments. The only built-in command currently is "help". --]] ------------------------------------------------------------------------ -- fprintf alike helper function local function fprintf(stream, ...) stream:write( string.format(unpack(arg)) ) end -- MODULES ------------------------------------------------------------------ -- load_module(name) -- Load the previously detected module. local function load_module(name) sam.info(_NAME, "Loading module %s (from %s)\n", name, sam.command[name]._module._FILE) -- sanity check for module info if not sam.command[name] or not sam.command[name]._module then sam.error(_NAME, "No such command module '%s', giving up.\n", name) return end -- load and execute the module local module, emsg = loadfile(sam.command[name]._module._FILE) if not module then print(emsg) os.exit(-1) end module = module() -- module sanity check if not module.main or not module._NAME then sam.error(_NAME, "Command module '%s' is probably not a SAM module.\n", name) return end -- copy module data sam.command[name]._NAME = module._NAME sam.command[name]._DESCRIPTION = module._DESCRIPTION sam.command[name]._USAGE = module._USAGE sam.command[name]._module.main = module.main sam.command[name]._load = nil -- set real methods sam.command[name].main = function(self,...) return self._module.main(unpack(arg)) end -- set correct metatable setmetatable(sam.command[name], { __call = function(self, ...) return self._module.main(unpack(arg)) end, }) end -- detect_modules() -- Detect all SAM modules local function detect_modules() local lfs = require("lfs") local moddir = os.getenv("SAM_MODULES") or "/usr/share/sam" for file in lfs.dir( moddir ) do local name local path _,_,name = string.find(file, "^sam_([%a][_%w%a]*).lua") path = moddir .. "/" .. file if name and lfs.attributes(path).mode == "file" and "sam_" .. name .. ".lua" == file then sam.dbg(_NAME, "Found '%s' (%s)\n", name, path) -- preset the module structure of the detected module -- for auto-loading sam.command[name] = { _module = { _NAME = name, _FILE = path, }, _load = function(self,...) load_module(self._module._NAME) end, _NAME = name, _DESCRIPTION = "", _USAGE = "", main = function(self,...) load_module(self._module._NAME) return self:main(unpack(arg)) end, } -- add a metatable so the commands can be used, however, -- it is anly a intermediate metatable, as the module is not -- loaded yet. The module gets loaded (dynamic linker alike) -- once it is called setmetatable(sam.command[name], { __call = function(self, ...) load_module(self._module._NAME) return self:main(unpack(arg)) end, }) end end end -- COMMANDS ----------------------------------------------------------------- local function usage(cmd) fprintf(io.stdout, "%s v%s %s\n\n", _NAME, _VERSION, _COPYRIGHT) if cmd then if sam.command[cmd]._load then sam.command[cmd]:_load() end fprintf(io.stdout, "Usage: sam %s\n", sam.command[cmd]._USAGE) else fprintf(io.stdout, "Usage: sam [command options]\n\n%s\n", [[Commands: help Show command overview (this) help Show command specific usage information]]) for k,_ in pairs(sam.command) do if sam.command[k]._load then sam.command[k]:_load() end fprintf(io.stdout, " %16s %s\n", k, sam.command[k]._DESCRIPTION) end end end -- -------------------------------------------------------------------------- -- INITIALIZE SAM -- -------------------------------------------------------------------------- detect_modules() -- -------------------------------------------------------------------------- -- MAIN -- -------------------------------------------------------------------------- if arg[1] then -- help if arg[1] == "help" then usage(arg[2]) elseif arg[2] == "help" then usage(arg[1]) else -- split command and command arguments local cmd = arg[1] local args = arg ; table.remove(args, 1) sam.command[cmd](unpack(args or {})) end end