List Dep

lua-users home
wiki

[!] VersionNotice: The below code pertains to an older Lua version, Lua 4. It does not run as is under Lua 5.

This program outputs a list of dependencies between Lua files, such as when one Lua file calls dofile on another Lua file. (This is a CASE tool.)

comment = [[



  ListDep.lua: "List module dependencies"

  Version 1.0 - April, 5, 2002



  This program output a list of dependencies between Lua files,

  such as when one Lua file calls {{dofile}} on another Lua file.

  The output of this program is a graph which can be viewed by the aiSee program.

  Download aiSee at http://www.aisee.com, available for unixes and windows



  To see how to use it, call "lua ListDep.lua" for the usage description.



  Please, send any comments to Luiz Carlos Silveira <luiz@fabricadigital.com.br>



  

  Limitations:

  

    - the "parser" don't have states, so it assumes your code behaves well.

      For example, comment starters inside a string confuses the parser



    - directories are not correctly resolved, so only the module's basename

      is considered. In other words, the dependencies will not be correctly

      listed if there are two modules with the same name.

      

    - dofile's that appear anywhere in the code are considered (except in

      comments), including those that are in strings.



]]







MODULES = {} 

INFO = {} 



function newModule(module_label, module_title) 

    MODULES[module_label] = {label = module_label, title = module_title, 

dofiles={}} 

end 



function connectModules(from, to) 

    if (MODULES[to] == nil) then 

        INFO.HAS_MODULE_NOT_FOUND = 1 

        to = "MODULE_NOT_FOUND" 

    end 

    if (MODULES[to].label == "UNKNOWN_REF") then 

        INFO.HAS_UNKNOWN_REF = 1 

    end 

    tinsert(MODULES[from].dofiles, MODULES[to]) 

end 



function exportGraph(out_file)

local hndOUT

    if (out_file == "-") then

        hndOUT = _STDOUT

    else

        hndOUT = openfile(out_file, "w")

        if (hndOUT == nil) then

            error("Cannot write to "..out_file)

        end

    end

    write(hndOUT, "graph: {manhattanedges: yes\n") 

    for i, module in MODULES do 

        local module_label = module.label 

        local module_title = module.title 

        -- only show MODULE_NOT_FOUD and UNKNOWN_REF if they are connected to someone

        if not (((module_label == "MODULE_NOT_FOUND") and (INFO.HAS_MODULE_NOT_FOUND == nil)) or 

            ((module_label == "UNKNOWN_REF") and (INFO.HAS_UNKNOWN_REF == nil))) then 

            write(hndOUT, 'node: {label: "'..module_label..'" title: "'..module_title..'"}\n') 

        end 

    end 



    for i, module in MODULES do 

        for i = 1, getn(module.dofiles) do 

            local dofile = module.dofiles[i] 

            write(hndOUT, 'edge: {sourcename: "'..module.label..'" targetname: "'..dofile.label..'"}\n') 

        end 

    end 

    write(hndOUT, "}\n") 

    closefile(hndOUT) 

end 





-- returns the 'basename' and the 'basedir' 

function getBases(filename) 

    return  gsub(filename, "(.*/)(.*)", "%2") or filename, 

            gsub(filename, "(.*/)(.*)", "%1") 

end 





-- processes the modules listed in the 'hnd' file

function getReferenceForModules(hnd) 

   local filename 

   local modules = {} 

   local dirname 

   local filename 

   local basedir 

   local basename 



   newModule("UNKNOWN_REF", "UNKNOWN_REF") 

   newModule("MODULE_NOT_FOUND", "MODULE_NOT_FOUND") 



   filename = read(hnd) 

   while (filename) do 

      if (filename ~= '') then 

         basename, basedir = getBases(filename) 

         tinsert(modules, filename) 

         newModule(basename, basename) 

      end 

      filename = read(hnd) 

   end 



   for i = 1, getn(modules) do 

      processFile(modules[i]) 

   end 

end 





-- processes a module

function processFile(filename) 



    local wholefile, result 

    local hndIN 

    local basename, basedir = getBases(filename)





    local execute_function_param = function (param) 

        local n

        local module_name

        local module_basename 

        

        -- detect '' and "" strings

        module_name, n  = gsub(param, ".*([\"'])([^%1]*)%1.*", "%2")

        if (n == 0) then

            -- detect [[]] strings

            module_name, n = gsub(param, ".*%[%[[^%]*]%]%].*", "%1")

        end

        

        if (n ~= 1) then 

            module_basename = "UNKNOWN_REF" 

        else

            module_name = gsub(module_name, "%."..CONFIG.luac_extension, ".lua") 

            module_basename = getBases(module_name)

        end



        connectModules(%basename, module_basename) 

    end







    print("processing file "..filename) 



    hndIN = openfile(filename, "r") 

    if (hndIN == nil) then 

       print("** error opening file "..fname) 

    end 



    wholefile = read(hndIN, "*a")



    -- remove comments (don't work if -- is inside a string)

    wholefile = gsub(wholefile, "%-%-[^\n\r]*", "")



    -- find "dofile"s 

    for i, execute_function in CONFIG.lua_file_execute_functions do 

        -- for beginning of the file 

        gsub(wholefile, "^"..execute_function.."[^0-9A-Za-z_]*(%b())", execute_function_param) 

        -- for the middle and the end of the file 

        gsub(wholefile, "[^0-9A-Za-z_]"..execute_function.."[^0-9A-Za-z_]*(%b())", execute_function_param) 

    end 



   closefile(hndIN) 



end 





-- main 





CONFIG = {

    output = "-",

    exclude_from_path = "",

    luac_extension = "luac",

    lua_file_execute_functions = {"dofile"}, 

} 





if (not list) then 

    print('Usage: lua <list="luafiles.list"|"-"> [output="file"|"-"]')

    print('           [luac_extension="ext"]')

    print('           [lua_file_execute_functions="{\'func1\', ..., \'funcn\'}"]')

    print('           ListDeps.lua"') 

    print()

    print()

    print('  list: A file with the list of lua files to process. One file per line.')

    print('        Use "-" to read from standard input')

    print('        example: find project/lua -name "*.lua" | lua list="-" ListDeps.lua')

    print()

    print('  output: The GDL output file, or "-" to write to the standard output.')

    print()

    print('  exclude_from_path: A gsub pattern to exclude from each lua file path')

    print()

    print('  luac_extension: The lua compiled files extension used in dofiles')

    print()

    print('  lua_file_execute_functions: a table with the functions that do files')

    print()

    print()

    print('Note: it only works over source code files!') 

    exit() 

end



if (output) then

    CONFIG.output = output

    output = nil

end

if (luac_extension ~= nil) then

    CONFIG.luac_extension = luac_extension

    luac_extension = nil

end

if (lua_file_execute_functions ~= nil) then

    CONFIG.lua_file_execute_functions = dostring('return '..lua_file_execute_functions)

    lua_file_execute_functions = nil

end



if (list == "-") then 

   getReferenceForModules(_STDIN) 

else 

   hnd = openfile(list, "r") 

   if (hnd == nil) then 

          print("File "..list.." not found!") 

          exit() 

       end 

   getReferenceForModules(hnd) 

   closefile(hnd) 

end 



exportGraph(CONFIG.output)


RecentChanges · preferences
edit · history
Last edited January 2, 2007 1:45 am GMT (diff)