diff support/casc/platform.lua @ 65:8b8b0bade520

Fixed support for mounts using the new MountJournal and mount IDs (no conversion of old profiles at the moment).
author Jerome Vuarand <jerome.vuarand@gmail.com>
date Thu, 23 Oct 2014 13:44:59 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/support/casc/platform.lua	Thu Oct 23 13:44:59 2014 +0100
@@ -0,0 +1,148 @@
+local M, assert, getenv = {}, assert, os.getenv
+
+local function maybe(m)
+	local ok, v = pcall(require, m)
+	return ok and v
+end
+local lfs = maybe("lfs") -- LuaFileSystem; http://keplerproject.github.io/luafilesystem/
+local zlib = maybe("zlib") -- lzlib; https://github.com/LuaDist/lzlib
+local bit = maybe("bit") -- Lua BitOp; http://bitop.luajit.org
+local socket = maybe("socket.http") -- LuaSocket; http://w3.impa.br/~diego/software/luasocket/home.html
+
+local function shellEscape(s)
+	return '"' .. s:gsub('"', '"\\\\""') .. '"'
+end
+local function readAndDeleteFile(path)
+	local h, err = io.open(path, "rb")
+	if h then
+		local c = h:read("*a")
+		h:close()
+		h, err = c, nil
+	end
+	os.remove(path)
+	return h, err
+end
+
+local dir_sep = package and package.config and package.config:sub(1,1) or "/"
+do -- M.path(a, b, ...)
+	M.path = function(a, b, ...)
+		if a and b then
+			return M.path(a .. (a:sub(-1) ~= dir_sep and dir_sep or "") .. b, ...)
+		end
+		return a
+	end
+end
+M.url = function(a, b, ...)
+	if a and b then
+		return M.url(a .. ((a:sub(-1) == "/" or b:sub(1,1) == "/") and "" or "/") .. b, ...)
+	end
+	return a
+end
+
+M.commands =
+	dir_sep == '/' and {toDevNull=' 2>/dev/null', ls='ls %s', mkdir='mkdir -p %s', gzip='gzip -dcq %s'} or
+	dir_sep == '\\' and {toDevNull=' 2>NUL', ls='(for %%a in (%s) do @echo %%~fa)', mkdir='mkdir %s', gzip='gzip -dcq %s', TMP=os.getenv('TMP') or os.getenv('TEMP')}
+
+M.tmpname = function()
+	local tn = os.tmpname()
+	return (M.commands and M.commands.TMP or "") .. tn
+end
+
+M.decompress = zlib and zlib.decompress or function(compressed)
+	assert(type(compressed) == "string", 'Syntax: casc.platform.decompress("compressed")')
+	assert(M.commands and M.commands.gzip and M.commands.toDevNull, 'unsupported platform')
+	
+	local f, f2 = M.tmpname(), M.tmpname()
+	local h = io.open(f, "wb")
+	h:write('\31\139\8\0\0\0\0\0')
+	h:write(compressed)
+	h:close()
+	
+	os.execute(M.commands.gzip:format(shellEscape(f)) .. " 1>" .. f2 .. " " .. M.commands.toDevNull)
+	os.remove(f)
+	
+	return readAndDeleteFile(f2)
+end
+
+M.mkdir = lfs and lfs.mkdir or function(path)
+	assert(type(path) == 'string', 'Syntax: casc.platform.mkdir("path")')
+	assert(M.commands and M.commands.mkdir, 'unsupported platform')
+	
+	return os.execute(M.commands.mkdir:format(shellEscape(path)))
+end
+
+M.files = lfs and function(dir, glob)
+	assert(type(dir) == "string" and type(glob) == 'string', 'Syntax: casc.platform.files("dir", "glob")')
+	local pat = "^" .. glob:gsub("%.%-%+", "%%%0"):gsub("%*", ".*") .. "$"
+	local t, ni = {}, 1
+	for f in lfs.dir(dir) do
+		if f ~= "." and f ~= ".." and f:match(pat) then
+			t[ni], ni = M.path(dir, f), ni + 1
+		end
+	end
+	return pairs(t)
+end or function(dir, glob)
+	assert(type(dir) == "string" and type(glob) == 'string', 'Syntax: casc.platform.files("dir", "glob")')
+	assert(M.commands and M.commands.ls, 'unsupported platform')
+	
+	local dir, files = glob:match("^(.-)([^" .. dir_sep .. "]+)$")
+	local t, ni, h = {}, 1, io.popen(M.commands.ls:format(shellEscape(dir) .. files), "r")
+	for l in h:lines() do
+		t[ni], ni = l, ni + 1
+	end
+	h:close()
+	return pairs(t)
+end
+
+local floor = math.floor
+M.rol = bit and bit.rol or function(n, b)
+	local n, e2 = n % 2^32, 2^(32-b)
+	return ((n % e2) * 2^b + floor(n/e2)) % 2^32
+end
+
+M.bxor = bit and bit.bxor or function(a, b)
+   local out, m, lm = 0, 1
+	for i=1,32 do
+		m, lm = m+m, m
+		local am, bm = a % m, b % m
+		out, a, b = out + (am == bm and 0 or lm), a-am, b-bm
+		if a == 0 or b == 0 then
+			return (out + b + a) % 2^32
+		end
+	end
+	return out
+end
+
+if socket then
+	socket.USERAGENT, socket.TIMEOUT = "lcasc/1.1", 5
+	local ltn12, RETRIES = require("ltn12"), 3
+	M.http = function(url, h)
+		for i=1,RETRIES do
+			local sink = {}
+			local ok, status, head = socket.request({url=url, sink=ltn12.sink.table(sink), headers=h})
+			if ok then
+				local cnt = table.concat(sink, "")
+				return status >= 200 and status < 300 and cnt, status, head, cnt
+			elseif i == RETRIES then
+				error("HTTP request failed: " .. tostring(status) .. "\nURL: " .. tostring(url))
+			end
+		end
+	end
+else
+	M.http = function(url, h)
+		local c, of = "curl -s -S -A 'luacasc/1.1+curl'", M.tmpname()
+		if type(h) == "table" then
+			for k,v in pairs(h) do
+				c = c .. ' -H ' .. shellEscape(k .. ": " .. v)
+			end
+		end
+		c = c .. ' -o ' .. shellEscape(of)
+		c = c .. ' ' .. shellEscape(url)
+		if os.execute(c) == 0 then
+			return readAndDeleteFile(of)
+		end
+		os.remove(of)
+	end
+end
+
+return M
\ No newline at end of file