|
1 #!/usr/bin/env lua |
|
2 |
|
3 local short_opts = { v = "verbose", vv = "very_verbose", o = "output", q = "quiet", qq = "very_quiet" } |
|
4 opts = {}; |
|
5 |
|
6 for _, opt in ipairs(arg) do |
|
7 if opt:match("^%-") then |
|
8 local name = opt:match("^%-%-?([^%s=]+)()") |
|
9 name = (short_opts[name] or name):gsub("%-+", "_"); |
|
10 if name:match("^no_") then |
|
11 name = name:sub(4, -1); |
|
12 opts[name] = false; |
|
13 else |
|
14 opts[name] = opt:match("=(.*)$") or true; |
|
15 end |
|
16 else |
|
17 base_path = opt; |
|
18 end |
|
19 end |
|
20 |
|
21 if opts.very_verbose then opts.verbose = true; end |
|
22 if opts.very_quiet then opts.quiet = true; end |
|
23 |
|
24 local noprint = function () end |
|
25 local print_err, print_info, print_verbose, print_debug = noprint, noprint, noprint, noprint; |
|
26 |
|
27 if not opts.very_quiet then print_err = print; end |
|
28 if not opts.quiet then print_info = print; end |
|
29 if opts.verbose or opts.very_verbose then print_verbose = print; end |
|
30 if opts.very_verbose then print_debug = print; end |
|
31 |
|
32 local enable_debug = true; |
|
33 |
|
34 local modules, main_files = {}, {}; |
|
35 |
|
36 -- Functions to be called from squishy file -- |
|
37 |
|
38 function Module(name) |
|
39 local i = #modules+1; |
|
40 modules[i] = { name = name, url = ___fetch_url }; |
|
41 return function (path) |
|
42 modules[i].path = path; |
|
43 end |
|
44 end |
|
45 |
|
46 function AutoFetchURL(url) |
|
47 ___fetch_url = url; |
|
48 end |
|
49 |
|
50 function Main(fn) |
|
51 table.insert(main_files, fn); |
|
52 end |
|
53 |
|
54 function Output(fn) |
|
55 out_fn = fn; |
|
56 end |
|
57 |
|
58 function Option(name) |
|
59 if opts[name] == nil then |
|
60 opts[name] = true; |
|
61 return function (value) |
|
62 opts[name] = value; |
|
63 end |
|
64 else |
|
65 return function () end; |
|
66 end |
|
67 end |
|
68 |
|
69 -- -- -- -- -- -- -- --- -- -- -- -- -- -- -- -- |
|
70 |
|
71 base_path = (base_path or "."):gsub("/$", "").."/" |
|
72 squishy_file = base_path .. "squishy"; |
|
73 out_fn = opts.output or "squished.out.lua"; |
|
74 |
|
75 local ok, err = pcall(dofile, squishy_file); |
|
76 |
|
77 if not ok then |
|
78 print_err("Couldn't read squishy file: "..err); |
|
79 os.exit(1); |
|
80 end |
|
81 |
|
82 local fetch = {}; |
|
83 function fetch.filesystem(path) |
|
84 local f, err = io.open(path); |
|
85 if not f then return false, err; end |
|
86 |
|
87 local data = f:read("*a"); |
|
88 f:close(); |
|
89 |
|
90 return data; |
|
91 end |
|
92 |
|
93 function fetch.http(url) |
|
94 local http = require "socket.http"; |
|
95 |
|
96 local body, status = http.request(url); |
|
97 if status == 200 then |
|
98 return body; |
|
99 end |
|
100 return false, "HTTP status code: "..tostring(status); |
|
101 end |
|
102 |
|
103 print_info("Writing "..out_fn.."..."); |
|
104 local f = io.open(out_fn, "w+"); |
|
105 |
|
106 if opts.executable then |
|
107 f:write("#!/usr/bin/env lua\n"); |
|
108 end |
|
109 |
|
110 if enable_debug then |
|
111 f:write [[ |
|
112 local function ___rename_chunk(chunk, name) |
|
113 if type(chunk) == "function" then |
|
114 chunk = string.dump(chunk); |
|
115 end |
|
116 local intsize = chunk:sub(8,8):byte(); |
|
117 local b = { chunk:sub(13, 13+intsize-1):byte(1, intsize) }; |
|
118 local oldlen = 0; |
|
119 for i = 1, #b do |
|
120 oldlen = oldlen + b[i] * 2^((i-1)*8); |
|
121 end |
|
122 |
|
123 local newname = name.."\0"; |
|
124 local newlen = #newname; |
|
125 |
|
126 local b = { }; |
|
127 for i=1,intsize do |
|
128 b[i] = string.char(math.floor(newlen / 2^((i-1)*8)) % (2^(i*8))); |
|
129 end |
|
130 |
|
131 return loadstring(chunk:sub(1, 12)..table.concat(b)..newname |
|
132 ..chunk:sub(13+intsize+oldlen, -1)); |
|
133 end |
|
134 ]]; |
|
135 end |
|
136 |
|
137 for _, module in ipairs(modules) do |
|
138 local modulename, path = module.name, base_path..module.path; |
|
139 print_verbose("Packing "..modulename.." ("..path..")..."); |
|
140 local data, err = fetch.filesystem(path); |
|
141 if (not data) and module.url then |
|
142 print_debug("Fetching: ".. module.url:gsub("%?", module.path)) |
|
143 data, err = fetch.http(module.url:gsub("%?", module.path)); |
|
144 end |
|
145 if data then |
|
146 f:write("package.preload['", modulename, "'] = (function ()\n"); |
|
147 f:write(data); |
|
148 f:write("end)\n"); |
|
149 if enable_debug then |
|
150 f:write(string.format("package.preload[%q] = ___rename_chunk(package.preload[%q], %q);\n\n", |
|
151 modulename, modulename, "@"..path)); |
|
152 end |
|
153 else |
|
154 print_err("Couldn't pack module '"..modulename.."': "..err); |
|
155 os.exit(1); |
|
156 end |
|
157 end |
|
158 |
|
159 print_debug("Finalising...") |
|
160 for _, fn in pairs(main_files) do |
|
161 local fin, err = io.open(base_path..fn); |
|
162 if not fin then |
|
163 print_err("Failed to open "..fn..": "..err); |
|
164 os.exit(1); |
|
165 else |
|
166 f:write((fin:read("*a"):gsub("^#.-\n", ""))); |
|
167 fin:close(); |
|
168 end |
|
169 end |
|
170 |
|
171 f:close(); |
|
172 |
|
173 print_info("OK!"); |