Mercurial > wow > cyborg-mmo7
comparison 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 |
comparison
equal
deleted
inserted
replaced
64:49ae7191821f | 65:8b8b0bade520 |
---|---|
1 local M, assert, getenv = {}, assert, os.getenv | |
2 | |
3 local function maybe(m) | |
4 local ok, v = pcall(require, m) | |
5 return ok and v | |
6 end | |
7 local lfs = maybe("lfs") -- LuaFileSystem; http://keplerproject.github.io/luafilesystem/ | |
8 local zlib = maybe("zlib") -- lzlib; https://github.com/LuaDist/lzlib | |
9 local bit = maybe("bit") -- Lua BitOp; http://bitop.luajit.org | |
10 local socket = maybe("socket.http") -- LuaSocket; http://w3.impa.br/~diego/software/luasocket/home.html | |
11 | |
12 local function shellEscape(s) | |
13 return '"' .. s:gsub('"', '"\\\\""') .. '"' | |
14 end | |
15 local function readAndDeleteFile(path) | |
16 local h, err = io.open(path, "rb") | |
17 if h then | |
18 local c = h:read("*a") | |
19 h:close() | |
20 h, err = c, nil | |
21 end | |
22 os.remove(path) | |
23 return h, err | |
24 end | |
25 | |
26 local dir_sep = package and package.config and package.config:sub(1,1) or "/" | |
27 do -- M.path(a, b, ...) | |
28 M.path = function(a, b, ...) | |
29 if a and b then | |
30 return M.path(a .. (a:sub(-1) ~= dir_sep and dir_sep or "") .. b, ...) | |
31 end | |
32 return a | |
33 end | |
34 end | |
35 M.url = function(a, b, ...) | |
36 if a and b then | |
37 return M.url(a .. ((a:sub(-1) == "/" or b:sub(1,1) == "/") and "" or "/") .. b, ...) | |
38 end | |
39 return a | |
40 end | |
41 | |
42 M.commands = | |
43 dir_sep == '/' and {toDevNull=' 2>/dev/null', ls='ls %s', mkdir='mkdir -p %s', gzip='gzip -dcq %s'} or | |
44 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')} | |
45 | |
46 M.tmpname = function() | |
47 local tn = os.tmpname() | |
48 return (M.commands and M.commands.TMP or "") .. tn | |
49 end | |
50 | |
51 M.decompress = zlib and zlib.decompress or function(compressed) | |
52 assert(type(compressed) == "string", 'Syntax: casc.platform.decompress("compressed")') | |
53 assert(M.commands and M.commands.gzip and M.commands.toDevNull, 'unsupported platform') | |
54 | |
55 local f, f2 = M.tmpname(), M.tmpname() | |
56 local h = io.open(f, "wb") | |
57 h:write('\31\139\8\0\0\0\0\0') | |
58 h:write(compressed) | |
59 h:close() | |
60 | |
61 os.execute(M.commands.gzip:format(shellEscape(f)) .. " 1>" .. f2 .. " " .. M.commands.toDevNull) | |
62 os.remove(f) | |
63 | |
64 return readAndDeleteFile(f2) | |
65 end | |
66 | |
67 M.mkdir = lfs and lfs.mkdir or function(path) | |
68 assert(type(path) == 'string', 'Syntax: casc.platform.mkdir("path")') | |
69 assert(M.commands and M.commands.mkdir, 'unsupported platform') | |
70 | |
71 return os.execute(M.commands.mkdir:format(shellEscape(path))) | |
72 end | |
73 | |
74 M.files = lfs and function(dir, glob) | |
75 assert(type(dir) == "string" and type(glob) == 'string', 'Syntax: casc.platform.files("dir", "glob")') | |
76 local pat = "^" .. glob:gsub("%.%-%+", "%%%0"):gsub("%*", ".*") .. "$" | |
77 local t, ni = {}, 1 | |
78 for f in lfs.dir(dir) do | |
79 if f ~= "." and f ~= ".." and f:match(pat) then | |
80 t[ni], ni = M.path(dir, f), ni + 1 | |
81 end | |
82 end | |
83 return pairs(t) | |
84 end or function(dir, glob) | |
85 assert(type(dir) == "string" and type(glob) == 'string', 'Syntax: casc.platform.files("dir", "glob")') | |
86 assert(M.commands and M.commands.ls, 'unsupported platform') | |
87 | |
88 local dir, files = glob:match("^(.-)([^" .. dir_sep .. "]+)$") | |
89 local t, ni, h = {}, 1, io.popen(M.commands.ls:format(shellEscape(dir) .. files), "r") | |
90 for l in h:lines() do | |
91 t[ni], ni = l, ni + 1 | |
92 end | |
93 h:close() | |
94 return pairs(t) | |
95 end | |
96 | |
97 local floor = math.floor | |
98 M.rol = bit and bit.rol or function(n, b) | |
99 local n, e2 = n % 2^32, 2^(32-b) | |
100 return ((n % e2) * 2^b + floor(n/e2)) % 2^32 | |
101 end | |
102 | |
103 M.bxor = bit and bit.bxor or function(a, b) | |
104 local out, m, lm = 0, 1 | |
105 for i=1,32 do | |
106 m, lm = m+m, m | |
107 local am, bm = a % m, b % m | |
108 out, a, b = out + (am == bm and 0 or lm), a-am, b-bm | |
109 if a == 0 or b == 0 then | |
110 return (out + b + a) % 2^32 | |
111 end | |
112 end | |
113 return out | |
114 end | |
115 | |
116 if socket then | |
117 socket.USERAGENT, socket.TIMEOUT = "lcasc/1.1", 5 | |
118 local ltn12, RETRIES = require("ltn12"), 3 | |
119 M.http = function(url, h) | |
120 for i=1,RETRIES do | |
121 local sink = {} | |
122 local ok, status, head = socket.request({url=url, sink=ltn12.sink.table(sink), headers=h}) | |
123 if ok then | |
124 local cnt = table.concat(sink, "") | |
125 return status >= 200 and status < 300 and cnt, status, head, cnt | |
126 elseif i == RETRIES then | |
127 error("HTTP request failed: " .. tostring(status) .. "\nURL: " .. tostring(url)) | |
128 end | |
129 end | |
130 end | |
131 else | |
132 M.http = function(url, h) | |
133 local c, of = "curl -s -S -A 'luacasc/1.1+curl'", M.tmpname() | |
134 if type(h) == "table" then | |
135 for k,v in pairs(h) do | |
136 c = c .. ' -H ' .. shellEscape(k .. ": " .. v) | |
137 end | |
138 end | |
139 c = c .. ' -o ' .. shellEscape(of) | |
140 c = c .. ' ' .. shellEscape(url) | |
141 if os.execute(c) == 0 then | |
142 return readAndDeleteFile(of) | |
143 end | |
144 os.remove(of) | |
145 end | |
146 end | |
147 | |
148 return M |