squish, because libraries don't have to be tricky to package!

Sat, 25 Jul 2009 03:04:25 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Sat, 25 Jul 2009 03:04:25 +0100
changeset 0
b119b560ca3d
child 1
2d9fe676e684

squish, because libraries don't have to be tricky to package!

squish.lua file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/squish.lua	Sat Jul 25 03:04:25 2009 +0100
@@ -0,0 +1,173 @@
+#!/usr/bin/env lua
+
+local short_opts = { v = "verbose", vv = "very_verbose", o = "output", q = "quiet", qq = "very_quiet" }
+opts = {};
+
+for _, opt in ipairs(arg) do
+	if opt:match("^%-") then
+		local name = opt:match("^%-%-?([^%s=]+)()")
+		name = (short_opts[name] or name):gsub("%-+", "_");
+		if name:match("^no_") then
+			name = name:sub(4, -1);
+			opts[name] = false;
+		else
+			opts[name] = opt:match("=(.*)$") or true;
+		end
+	else
+		base_path = opt;
+	end
+end
+
+if opts.very_verbose then opts.verbose = true; end
+if opts.very_quiet then opts.quiet = true; end
+
+local noprint = function () end
+local print_err, print_info, print_verbose, print_debug = noprint, noprint, noprint, noprint;
+
+if not opts.very_quiet then print_err = print; end
+if not opts.quiet then print_info = print; end
+if opts.verbose or opts.very_verbose then print_verbose = print; end
+if opts.very_verbose then print_debug = print; end
+
+local enable_debug = true;
+
+local modules, main_files = {}, {};
+
+--  Functions to be called from squishy file  --
+
+function Module(name)
+	local i = #modules+1;
+	modules[i] = { name = name, url = ___fetch_url };
+	return function (path)
+		modules[i].path = path;
+	end
+end
+
+function AutoFetchURL(url)
+	___fetch_url = url;
+end
+
+function Main(fn)
+	table.insert(main_files, fn);
+end
+
+function Output(fn)
+	out_fn = fn;
+end
+
+function Option(name)
+	if opts[name] == nil then
+		opts[name] = true;
+		return function (value)
+			opts[name] = value;
+		end
+	else
+		return function () end;
+	end
+end
+
+-- -- -- -- -- -- -- --- -- -- -- -- -- -- -- --
+
+base_path = (base_path or "."):gsub("/$", "").."/"
+squishy_file = base_path .. "squishy";
+out_fn = opts.output or "squished.out.lua";
+
+local ok, err = pcall(dofile, squishy_file);
+
+if not ok then
+	print_err("Couldn't read squishy file: "..err);
+	os.exit(1);
+end
+
+local fetch = {};
+function fetch.filesystem(path)
+	local f, err = io.open(path);
+	if not f then return false, err; end
+	
+	local data = f:read("*a");
+	f:close();
+	
+	return data;
+end
+
+function fetch.http(url)
+	local http = require "socket.http";
+	
+	local body, status = http.request(url);
+	if status == 200 then
+		return body;
+	end
+	return false, "HTTP status code: "..tostring(status);
+end
+
+print_info("Writing "..out_fn.."...");
+local f = io.open(out_fn, "w+");
+
+if opts.executable then
+	f:write("#!/usr/bin/env lua\n");
+end
+
+if enable_debug then
+	f:write [[
+	local function ___rename_chunk(chunk, name)
+		if type(chunk) == "function" then
+			chunk = string.dump(chunk);
+		end
+		local intsize = chunk:sub(8,8):byte();
+		local b = { chunk:sub(13, 13+intsize-1):byte(1, intsize) };
+		local oldlen = 0;
+		for i = 1, #b do 
+			oldlen = oldlen + b[i] * 2^((i-1)*8);
+		end
+		
+		local newname = name.."\0";
+		local newlen = #newname;
+		
+		local b = { };
+		for i=1,intsize do
+			b[i] = string.char(math.floor(newlen / 2^((i-1)*8)) % (2^(i*8)));
+		end
+		
+		return loadstring(chunk:sub(1, 12)..table.concat(b)..newname
+			..chunk:sub(13+intsize+oldlen, -1));
+	end
+	]];
+end
+
+for _, module in ipairs(modules) do
+	local modulename, path = module.name, base_path..module.path;
+	print_verbose("Packing "..modulename.." ("..path..")...");
+	local data, err = fetch.filesystem(path);
+	if (not data) and module.url then
+		print_debug("Fetching: ".. module.url:gsub("%?", module.path))
+		data, err = fetch.http(module.url:gsub("%?", module.path));
+	end
+	if data then
+		f:write("package.preload['", modulename, "'] = (function ()\n");
+		f:write(data);
+		f:write("end)\n");
+		if enable_debug then
+			f:write(string.format("package.preload[%q] = ___rename_chunk(package.preload[%q], %q);\n\n", 
+				modulename, modulename, "@"..path));
+		end
+	else
+		print_err("Couldn't pack module '"..modulename.."': "..err);
+		os.exit(1);
+	end
+end
+
+print_debug("Finalising...")
+for _, fn in pairs(main_files) do
+	local fin, err = io.open(base_path..fn);
+	if not fin then
+		print_err("Failed to open "..fn..": "..err);
+		os.exit(1);
+	else
+		f:write((fin:read("*a"):gsub("^#.-\n", "")));
+		fin:close();
+	end
+end
+
+f:close();
+
+print_info("OK!");

mercurial