3 if not arg[1] or arg[1]:match("%-%-?help") or arg[1]:match("^[/-]%?$") then
4 print "make_squishy - Generate squishy files for your projects"
6 print(" Usage: "..arg[0].." FILE1 FILE2 FILE...");
8 print "make_squishy will scan the given files for require() calls, and convert the "
9 print "found modules into a squishy file, 'squishy.new'. make_squishy automatically scans "
10 print "the modules it finds, looking for further dependencies. To disable this, use "
11 print "the --no-recursion option."
16 local short_opts = { v = "verbose", vv = "very_verbose", o = "output", q = "quiet", qq = "very_quiet" }
17 local files, opts = {}, {};
18 local scanned_files, modules = {}, {};
20 for _, opt in ipairs(arg) do
21 if opt:match("^%-") then
22 local name = opt:match("^%-%-?([^%s=]+)()")
23 name = (short_opts[name] or name):gsub("%-+", "_");
24 if name:match("^no_") then
25 name = name:sub(4, -1);
28 opts[name] = opt:match("=(.*)$") or true;
31 table.insert(files, opt);
35 if opts.very_verbose then opts.verbose = true; end
36 if opts.very_quiet then opts.quiet = true; end
38 local noprint = function () end
39 local print_err, print_info, print_verbose, print_debug = noprint, noprint, noprint, noprint;
41 if not opts.very_quiet then print_err = print; end
42 if not opts.quiet then print_info = print; end
43 if opts.verbose or opts.very_verbose then print_verbose = print; end
44 if opts.very_verbose then print_debug = print; end
46 local squishy = io.stdout
48 local LUA_DIRSEP = package.config:sub(1,1);
49 local LUA_PATH_MARK = package.config:sub(5,5);
51 local base_path = (files[1]:match("^(.-)"..LUA_DIRSEP.."[^"..LUA_DIRSEP.."]*$") or ".").."/";
53 local package_path = package.path:gsub("[^;]+", function (path)
54 if not path:match("^%"..LUA_DIRSEP) then
55 return base_path..path;
57 end):gsub("/%./", "/");
58 local package_cpath = package.cpath:gsub("[^;]+", function (path)
59 if not path:match("^%"..LUA_DIRSEP) then
60 return base_path..path;
62 end):gsub("/%./", "/");
65 function scan_file(outfile, scanfile)
66 for line in io.lines(scanfile) do
67 for _, module in (" "..line):gmatch("[^%w_]require%s*%(?([\"'])(.-)%1") do
68 if not modules[module] then
70 modules[module] = true;
71 local filename = resolve_module(module, package_path);
72 if false and not filename then
74 filename = resolve_module(module, package_cpath);
77 print_info("Couldn't resolve module '"..module.."' to a file (required in "..scanfile..")");
78 elseif opts.recursion ~= false and not scanned_files[filename] then
79 scanned_files[filename] = true;
80 table.insert(files, filename);
83 outfile:write((binary and "Binary" or ""), string.format([[Module %q %q]], module, filename:gsub("^"..base_path:gsub("%p", "%%%1"), "")), "\n");
91 function resolve_module(name, path)
92 name = name:gsub("%.", LUA_DIRSEP);
93 for c in path:gmatch("[^;]+") do
94 c = c:gsub("%"..LUA_PATH_MARK, name);
95 print_debug("Testing: "..c)
102 return nil; -- not found
105 for _, filename in ipairs(files) do
106 squishy:write(string.format([[Main %q]], filename:gsub("^"..base_path:gsub("%p", "%%%1"), "")), "\n");
109 for _, filename in ipairs(files) do
110 scanned_files[filename] = true;
111 print_verbose("Found:", filename);
112 scan_file(squishy, filename)