if not modules then modules = { } end modules ['l-package'] = { version = 1.001, comment = "companion to luat-lib.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } -- Code moved from data-lua and changed into a plug-in. -- We overload the regular loader. We do so because we operate mostly in -- tds and use our own loader code. Alternatively we could use a more -- extensive definition of package.path and package.cpath but even then -- we're not done. Also, we now have better tracing. -- -- -- local mylib = require("libtest") -- -- local mysql = require("luasql.mysql") local type = type local gsub, format, find = string.gsub, string.format, string.find local P, S, Cs, lpegmatch = lpeg.P, lpeg.S, lpeg.Cs, lpeg.match local package = package local searchers = package.searchers or package.loaders -- dummies local filejoin = file and file.join or function(path,name) return path .. "/" .. name end local isreadable = file and file.is_readable or function(name) local f = io.open(name) if f then f:close() return true end end local addsuffix = file and file.addsuffix or function(name,suffix) return name .. "." .. suffix end -- local separator, concatinator, placeholder, pathofexecutable, ignorebefore = string.match(package.config,"(.-)\n(.-)\n(.-)\n(.-)\n(.-)\n") -- -- local config = { -- separator = separator, -- \ or / -- concatinator = concatinator, -- ; -- placeholder = placeholder, -- ? becomes name -- pathofexecutable = pathofexecutable, -- ! becomes executables dir (on windows) -- ignorebefore = ignorebefore, -- - remove all before this when making lua_open -- } local function cleanpath(path) -- hm, don't we have a helper for this? return path end local pattern = Cs((((1-S("\\/"))^0 * (S("\\/")^1/"/"))^0 * (P(".")^1/"/"+P(1))^1) * -1) local function lualibfile(name) return lpegmatch(pattern,name) or name end local offset = luarocks and 1 or 0 -- todo: also check other extras local helpers = package.helpers or { cleanpath = cleanpath, lualibfile = lualibfile, trace = false, report = function(...) print(format(...)) end, builtin = { ["preload table"] = searchers[1+offset], -- special case, built-in libs ["path specification"] = searchers[2+offset], ["cpath specification"] = searchers[3+offset], ["all in one fallback"] = searchers[4+offset], -- special case, combined libs }, methods = { }, sequence = { "already loaded", "preload table", "qualified path", -- beware, lua itself doesn't handle qualified paths (prepends ./) "lua extra list", "lib extra list", "path specification", "cpath specification", "all in one fallback", "not loaded", } } package.helpers = helpers local methods = helpers.methods local builtin = helpers.builtin -- extra tds/ctx paths ... a bit of overhead for efficient tracing local extraluapaths = { } local extralibpaths = { } local luapaths = nil -- delayed local libpaths = nil -- delayed local oldluapath = nil local oldlibpath = nil local nofextralua = -1 local nofextralib = -1 local nofpathlua = -1 local nofpathlib = -1 local function listpaths(what,paths) local nofpaths = #paths if nofpaths > 0 then for i=1,nofpaths do helpers.report("using %s path %i: %s",what,i,paths[i]) end else helpers.report("no %s paths defined",what) end return nofpaths end local function getextraluapaths() if helpers.trace and #extraluapaths ~= nofextralua then nofextralua = listpaths("extra lua",extraluapaths) end return extraluapaths end local function getextralibpaths() if helpers.trace and #extralibpaths ~= nofextralib then nofextralib = listpaths("extra lib",extralibpaths) end return extralibpaths end local function getluapaths() local luapath = package.path or "" if oldluapath ~= luapath then luapaths = file.splitpath(luapath,";") oldluapath = luapath nofpathlua = -1 end if helpers.trace and #luapaths ~= nofpathlua then nofpathlua = listpaths("builtin lua",luapaths) end return luapaths end local function getlibpaths() local libpath = package.cpath or "" if oldlibpath ~= libpath then libpaths = file.splitpath(libpath,";") oldlibpath = libpath nofpathlib = -1 end if helpers.trace and #libpaths ~= nofpathlib then nofpathlib = listpaths("builtin lib",libpaths) end return libpaths end package.luapaths = getluapaths package.libpaths = getlibpaths package.extraluapaths = getextraluapaths package.extralibpaths = getextralibpaths local hashes = { lua = { }, lib = { }, } local function registerpath(tag,what,target,...) local pathlist = { ... } local cleanpath = helpers.cleanpath local trace = helpers.trace local report = helpers.report local hash = hashes[what] -- local function add(path) local path = cleanpath(path) if not hash[path] then target[#target+1] = path hash[path] = true if trace then report("registered %s path %s: %s",tag,#target,path) end else if trace then report("duplicate %s path: %s",tag,path) end end end -- for p=1,#pathlist do local path = pathlist[p] if type(path) == "table" then for i=1,#path do add(path[i]) end else add(path) end end return paths end helpers.registerpath = registerpath function package.extraluapath(...) registerpath("extra lua","lua",extraluapaths,...) end function package.extralibpath(...) registerpath("extra lib","lib",extralibpaths,...) end -- lib loader (used elsewhere) local function loadedaslib(resolved,rawname) -- todo: strip all before first - local base = gsub(rawname,"%.","_") -- so, we can do a require("foo/bar") and initialize bar -- local base = gsub(file.basename(rawname),"%.","_") local init = "luaopen_" .. gsub(base,"%.","_") if helpers.trace then helpers.report("calling loadlib with '%s' with init '%s'",resolved,init) end return package.loadlib(resolved,init) end helpers.loadedaslib = loadedaslib -- wrapped and new loaders local function loadedbypath(name,rawname,paths,islib,what) local trace = helpers.trace for p=1,#paths do local path = paths[p] local resolved = filejoin(path,name) if trace then helpers.report("%s path, identifying '%s' on '%s'",what,name,path) end if isreadable(resolved) then if trace then helpers.report("%s path, '%s' found on '%s'",what,name,resolved) end if islib then return loadedaslib(resolved,rawname) else return loadfile(resolved) end end end end helpers.loadedbypath = loadedbypath local function loadedbyname(name,rawname) if find(name,"^/") or find(name,"^[a-zA-Z]:/") then local trace=helpers.trace if trace then helpers.report("qualified name, identifying '%s'",what,name) end if isreadable(name) then if trace then helpers.report("qualified name, '%s' found",what,name) end return loadfile(name) end end end helpers.loadedbyname = loadedbyname methods["already loaded"] = function(name) return package.loaded[name] end methods["preload table"] = function(name) return builtin["preload table"](name) end methods["qualified path"]=function(name) return loadedbyname(addsuffix(lualibfile(name),"lua"),name) end methods["lua extra list"] = function(name) return loadedbypath(addsuffix(lualibfile(name),"lua"),name,getextraluapaths(),false,"lua") end methods["lib extra list"] = function(name) return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true, "lib") end methods["path specification"] = function(name) getluapaths() -- triggers list building and tracing return builtin["path specification"](name) end methods["cpath specification"] = function(name) getlibpaths() -- triggers list building and tracing return builtin["cpath specification"](name) end methods["all in one fallback"] = function(name) return builtin["all in one fallback"](name) end methods["not loaded"] = function(name) if helpers.trace then helpers.report("unable to locate '%s'",name or "?") end return nil end local level = 0 local used = { } helpers.traceused = false function helpers.loaded(name) local sequence = helpers.sequence level = level + 1 for i=1,#sequence do local method = sequence[i] if helpers.trace then helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name) end local result, rest = methods[method](name) if type(result) == "function" then if helpers.trace then helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name) end if helpers.traceused then used[#used+1] = { level = level, name = name } end level = level - 1 return result, rest end end -- safeguard, we never come here level = level - 1 return nil end function helpers.showused() local n = #used if n > 0 then helpers.report("%s libraries loaded:",n) helpers.report() for i=1,n do local u = used[i] helpers.report("%i %a",u.level,u.name) end helpers.report() end end function helpers.unload(name) if helpers.trace then if package.loaded[name] then helpers.report("unloading, name '%s', %s",name,"done") else helpers.report("unloading, name '%s', %s",name,"not loaded") end end package.loaded[name] = nil end -- overloading require does not work out well so we need to push it in -- front .. table.insert(searchers,1,helpers.loaded)