1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
|
--!A cross-platform build utility based on Lua
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-present, Xmake Open Source Community.
--
-- @author ruki
-- @file utils.lua
--
-- define module
local utils = utils or {}
-- load modules
local option = require("base/option")
local colors = require("base/colors")
local string = require("base/string")
local log = require("base/log")
local io = require("base/io")
local dump = require("base/dump")
local text = require("base/text")
-- save original interfaces
utils._bin2c = utils._bin2c or utils.bin2c
-- dump values
function utils.dump(...)
if option.get("quiet") then
return ...
end
local diagnosis = option.get("diagnosis")
-- show caller info
if diagnosis then
local info = debug.getinfo(2)
local line = info.currentline
if not line or line < 0 then line = info.linedefined end
io.write(string.format("dump from %s %s:%s\n", info.name or "<anonymous>", info.source, line))
end
local values = table.pack(...)
if values.n == 0 then
return
end
if values.n == 1 then
dump(values[1], "", diagnosis)
else
for i = 1, values.n do
dump(values[i], string.format("%2d: ", i), diagnosis)
end
end
return table.unpack(values, 1, values.n)
end
-- print string with newline
function utils._print(...)
-- print it if not quiet
if not option.get("quiet") then
local values = {...}
for i, v in ipairs(values) do
-- dump basic type
if type(v) == "string" or type(v) == "boolean" or type(v) == "number" then
io.write(tostring(v))
-- dump table
elseif type(v) == "table" then
dump(v)
else
io.write("<" .. tostring(v) .. ">")
end
if i ~= #values then
io.write(" ")
end
end
io.write('\n')
end
end
-- print string without newline
function utils._iowrite(...)
-- print it if not quiet
if not option.get("quiet") then
io.write(...)
end
end
-- decode errors if errors is encoded table string
function utils._decode_errors(errors)
if not errors then
return
end
local _, pos = errors:find("[@encode(error)]: ", 1, true)
if pos then
-- strip traceback (maybe from coroutine.resume)
local errs = errors:sub(pos + 1)
local stack = nil
local stackpos = errs:find("}\nstack traceback:", 1, true)
if stackpos and stackpos > 1 then
stack = errs:sub(stackpos + 2)
errs = errs:sub(1, stackpos)
end
errors, errs = errs:deserialize()
if not errors then
errors = errs
end
if type(errors) == "table" then
if stack then
errors._stack = stack
end
setmetatable(errors,
{
__tostring = function (self)
local result = self.errors
if not result then
result = string.serialize(self, {strip = true, indent = false})
end
result = result or ""
if self._stack then
result = result .. "\n" .. self._stack
end
return result
end,
__concat = function (self, other)
return tostring(self) .. tostring(other)
end
})
end
return errors
end
end
-- print format string with newline
function utils.print(format, ...)
assert(format)
local message = string.tryformat(format, ...)
utils._print(message)
log:printv(message)
end
-- print format string without newline
function utils.printf(format, ...)
assert(format)
local message = string.tryformat(format, ...)
utils._iowrite(message)
log:write(message)
end
-- print format string and colors with newline
function utils.cprint(format, ...)
assert(format)
local message = string.tryformat(format, ...)
utils._print(colors.translate(message))
if log:file() then
log:printv(colors.ignore(message))
end
end
-- print format string and colors without newline
function utils.cprintf(format, ...)
assert(format)
local message = string.tryformat(format, ...)
utils._iowrite(colors.translate(message))
if log:file() then
log:write(colors.ignore(message))
end
end
-- print the verbose information
function utils.vprint(format, ...)
if (option.get("verbose") or option.get("diagnosis")) and format ~= nil then
utils.print(format, ...)
end
end
-- print the verbose information without newline
function utils.vprintf(format, ...)
if (option.get("verbose") or option.get("diagnosis")) and format ~= nil then
utils.printf(format, ...)
end
end
-- print the error information
function utils.error(format, ...)
if format ~= nil then
local errors = string.tryformat(format, ...)
local decoded_errors = utils._decode_errors(errors)
if decoded_errors then
errors = tostring(decoded_errors)
end
utils.cprint("${bright color.error}${text.error}: ${clear}" .. errors)
log:flush()
end
end
-- add warning message
function utils.warning(format, ...)
if option.get("quiet") then
return
end
-- format message
local args = table.pack(...)
local msg = (args.n > 0 and string.tryformat(format, ...) or format)
-- init warnings
local warnings = utils._WARNINGS
if not warnings then
warnings = {}
utils._WARNINGS = warnings
end
-- add warning msg
table.insert(warnings, msg)
end
-- show warnings
function utils.show_warnings()
local warnings = utils._WARNINGS
if warnings then
for idx, msg in ipairs(table.unique(warnings)) do
if not option.get("verbose") and idx > 1 then
utils.cprint("${bright color.warning}${text.warning}: ${color.warning}add -v for getting more warnings ..")
break
end
utils.cprint("${bright color.warning}${text.warning}: ${color.warning}%s", msg)
end
end
end
-- try to call script
function utils.trycall(script, traceback, ...)
return xpcall(script, function (errors)
-- get traceback
traceback = traceback or debug.traceback
-- decode it if errors is encoded table string
local decoded_errors = utils._decode_errors(errors)
if decoded_errors then
return decoded_errors
end
return traceback(errors)
end, ...)
end
-- get confirm result
--
-- @code
-- if utils.confirm({description = "xmake.lua not found, try generating it", default = true}) then
-- TODO
-- end
-- @endcode
--
function utils.confirm(opt)
-- init options
opt = opt or {}
-- get default
local default = opt.default
if default == nil then
default = false
end
-- get description
local description = opt.description or ""
-- get confirm result
local result = option.get("yes") or option.get("confirm")
if type(result) == "string" then
result = result:lower()
if result == "d" or result == "def" then
result = default
else
result = nil
end
end
-- get user confirm
if result == nil then
-- show tips
if type(description) == "function" then
description()
else
utils.cprint("${bright color.warning}note: ${clear}%s (pass -y or --confirm=y/n/d to skip confirm)?", description)
end
-- get answer
if opt.answer then
result = opt.answer()
else
utils.cprint("please input: ${bright}%s${clear} (y/n)", default and "y" or "n")
io.flush()
result = option.boolean((io.read() or "false"):trim())
if type(result) ~= "boolean" then
result = default
end
end
end
return result
end
function utils.table(data, opt)
utils.printf(text.table(data, opt))
end
function utils.vtable(data, opt)
utils.vprintf(text.table(data, opt))
end
-- generate c/c++ code from the binary file
function utils.bin2c(binaryfile, outputfile, opt)
opt = opt or {}
return utils._bin2c(binaryfile, outputfile, opt.linewidth or 32, opt.nozeroend or false)
end
-- return module
return utils
|