Created
December 2, 2011 07:35
-
-
Save davidm/1422205 to your computer and use it in GitHub Desktop.
Lua module 'sourcepack' - Extract Lua files from other Lua files.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env lua | |
--[[ FILE README.txt | |
LUA MODULE | |
sourceunpack v$(_VERSION) - Extract Lua files containing other Lua files. | |
SYNOPSIS | |
git clone git://gist.github.com/1325400.git file_slurp | |
cd file_slurp | |
../sourceunpack.lua file_slurp.lua | |
cd out | |
luarocks make | |
DESCRIPTION | |
This provides a mechanism where a single Lua file can contain | |
other files embedded in its comments. These files can be extracted | |
via this tool. | |
The sourceunpack.lua module can itself be extracted: | |
./sourceunpack.lua sourceunpack.lua | |
DOWNLOAD/INSTALL | |
Download <https://raw.github.com/gist/1422205/sourceunpack.lua>. | |
Alternately, if using git: | |
git clone git://gist.github.com/1422205.git lua-sourceunpack | |
Optionally unpack and install in LuaRocks: | |
cd lua-sourceunpack && ./sourceunpack.lua sourceunpack.lua | |
cd out && luarocks make | |
COPYRIGHT | |
(c) 2011-2012 David Manura. Licensed under the same terms as Lua 5.1 (MIT license). | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
THE SOFTWARE. | |
--]]--------------------------------------------------------------------- | |
-- sourceunpack.lua | |
-- (c) 2011-2012 David Manura. Licensed under the same terms as Lua 5.1 (MIT license). | |
-- https://gist.github.com/1325400 | |
package.preload['file_slurp'] = function() | |
-- file_slurp.lua | |
-- (c) 2011-2012 David Manura. Licensed under the same terms as Lua 5.1 (MIT license). | |
local FS = {_TYPE='module', _NAME='file_slurp', _VERSION='0.4.20111129'} | |
local function check_options(options) | |
if not options then return {} end | |
local bad = options:match'[^tTsap]' | |
if bad then error('ASSERT: invalid option '..bad, 3) end | |
local t = {}; for v in options:gmatch'.' do t[v] = true end | |
if t.T and t.t then error('ASSERT: options t and T mutually exclusive', 3) end | |
return t | |
end | |
local function fail(tops, err, code, filename) | |
err = err..' [code '..code..']' | |
err = err..' [filename '..filename..']' -- maybe make option | |
if tops.s then return nil, err else error(err, 3) end | |
end | |
function FS.readfile(filename, options) | |
local tops = check_options(options) | |
local open = tops.p and io.popen or io.open | |
local data, ok | |
local fh, err, code = open(filename, 'r'..((tops.t or tops.p) and '' or 'b')) | |
if fh then | |
data, err, code = fh:read'*a' | |
if data then ok, err, code = fh:close() else fh:close() end | |
end | |
if not ok then return fail(tops, err, code, filename) end | |
if tops.T then data = data:gsub('\r', '') end | |
return data | |
end | |
function FS.writefile(filename, data, options) | |
local tops = check_options(options) | |
local open = tops.p and io.popen or io.open | |
local ok | |
local fh, err, code = open(filename, | |
(tops.a and 'a' or 'w') .. ((tops.t or tops.p) and '' or 'b')) | |
if fh then | |
ok, err, code = fh:write(data) | |
if ok then ok, err, code = fh:close() else fh:close() end | |
end | |
if not ok then return fail(tops, err, code, filename) end | |
return data | |
end | |
function FS.testfile(filename, options) | |
local fh, err, code = io.open(filename, options or 'r') | |
if fh then fh:close(); return true | |
else return false, err .. ' [code '..code..']' end | |
end | |
return FS | |
end | |
------------------------------------------------- | |
local M = {_TYPE='module', _NAME='sourceunpack', _VERSION='0.2.20120121'} | |
local FS = require 'file_slurp' | |
local function expand_rockspec_in(filename, outdir, codefilename, code) | |
local function getvar(V, name) -- lazy eval and cache | |
local val | |
if name == '_VERSION' then | |
for ver in code:gmatch[=[_VERSION *= *['"](.-)['"]]=] do -- last if multiple | |
val = ver | |
end | |
elseif name == 'GITID' and FS.readfile('.git/HEAD', 's') then | |
val = (FS.readfile('git rev-parse HEAD:'..codefilename, 'ps') or ''):match('^([0-9a-f]+)%s*$') or '$(GITID)' | |
elseif name == 'MD5' then | |
val = (FS.readfile('md5sum '..codefilename, 'ps') or ''):match('^([0-9a-f]+)') | |
else | |
return -- ignore | |
end | |
V[name] = val | |
io.write(name, '=', val, '\n') | |
return val | |
end | |
local V = setmetatable({}, {__index = getvar}) | |
local function subst(s) return s:gsub('%$%((.-)%)', V) end | |
local text = FS.readfile(filename, 'T') | |
local packagename = assert(text:match"package *= *'([^']+)'", 'package attribute not found in rockspec.in') | |
local versionname = subst(assert(text:match"version *= *'([^']+)'", 'version attribute not found in rockspec.in')) | |
local outfilename = outdir..'/'..packagename..'-'..versionname..'.rockspec' | |
text = subst(text) | |
FS.writefile(outfilename, text) | |
return outfilename | |
end | |
function M.unpack(codefilename, outdir) | |
outdir = outdir or 'out' | |
local code = FS.readfile(codefilename, 'T') | |
local filenames = {} | |
code = code:gsub('%-*\n*%-%-%[(=*)%[%s*FILE%s+(%S+).-\n\n?(.-)%-%-%]%1%]%-*%s*', | |
function(_, filename, text) | |
filenames[#filenames+1] = filename | |
if not FS.writefile(outdir..'/.test', '', 's') then os.execute('mkdir '..outdir) end | |
os.remove(outdir..'/.test') | |
print('writing '..outdir..'/' .. filename) | |
FS.writefile(outdir..'/' .. filename, text) | |
if filename == 'rockspec.in' then | |
local outfilename = expand_rockspec_in(outdir..'/rockspec.in', outdir, codefilename, code) | |
print('writing '..outfilename) | |
end | |
return '' | |
end) | |
filenames[#filenames+1] = codefilename | |
filenames[#filenames+1] = 'MANIFEST' | |
print('writing '..outdir..'/MANIFEST') | |
FS.writefile(outdir..'/MANIFEST', table.concat(filenames, '\n')..'\n') | |
print('writing '..outdir..'/' .. codefilename) | |
FS.writefile(outdir..'/' .. codefilename, code) | |
print('testing...') | |
local arg0 = arg[0]; arg[0] = nil -- clear | |
dofile(outdir..'/test.lua') | |
arg[0] = arg0 -- restore | |
end | |
if arg[0] and arg[0]:match'sourceunpack%.lua$' then -- called from command line | |
package.loaded['sourceunpack'] = M | |
local SU = require 'sourceunpack' | |
local name = ... | |
if not name then io.stderr:write('usage: sourceunpack <filename>\n'); os.exit(1) end | |
SU.unpack(name) | |
end | |
return M | |
--[[ FILE rockspec.in | |
package = 'lua-sourceunpack' | |
version = '$(_VERSION)-1' | |
source = { | |
url = 'https://raw.github.com/gist/1422205/$(GITID)/sourceunpack.lua', | |
--url = 'https://raw.github.com/gist/1422205/sourceunpack.lua', -- latest raw | |
--url = 'https://gist.github.com/gists/1422205/download', -- latest archive | |
md5 = '$(MD5)' | |
} | |
description = { | |
summary = 'Extract Lua files containing other Lua files.', | |
detailed = | |
'Extract Lua files containing other Lua files.', | |
license = 'MIT/X11', | |
homepage = 'https://gist.github.com/1422205', | |
maintainer = 'David Manura' | |
} | |
dependencies = {} | |
build = { | |
type = 'builtin', | |
modules = { | |
['sourceunpack'] = 'sourceunpack.lua' | |
} | |
} | |
--]]--------------------------------------------------------------------- | |
--[[ FILE test.lua | |
-- test.lua - test suite for sourceunpack.lua | |
local SU = require 'sourceunpack' | |
print 'OK' | |
--]] | |
--[[ FILE CHANGES.txt | |
0.2.20120121 | |
New rockspec.in file indirectly generating .rockspec. | |
0.1.20111203 | |
Initial public release | |
--]] | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment