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
334
335
336
337
338
339
340
|
--module("luarocks.write_rockspec", package.seeall)
local write_rockspec = {}
package.loaded["luarocks.write_rockspec"] = write_rockspec
local dir = require("luarocks.dir")
local fetch = require("luarocks.fetch")
local fs = require("luarocks.fs")
local path = require("luarocks.path")
local persist = require("luarocks.persist")
local type_check = require("luarocks.type_check")
local util = require("luarocks.util")
write_rockspec.help_summary = "Write a template for a rockspec file."
write_rockspec.help_arguments = "[--output=<file> ...] [<name>] [<version>] {<url>|<path>}"
write_rockspec.help = [[
This command writes an initial version of a rockspec file,
based on an URL or a local path. You may use a relative path such as '.'.
If a local path is given, name and version arguments are mandatory.
For URLs, LuaRocks will attempt to infer name and version if not given.
If a repository URL is given with no version, it creates an 'scm' rock.
Note that the generated file is a _starting point_ for writing a
rockspec, and is not guaranteed to be complete or correct.
--output=<file> Write the rockspec with the given filename.
If not given, a file is written in the current
directory with a filename based on given name and version.
--license="<string>" A license string, such as "MIT/X11" or "GNU GPL v3".
--summary="<txt>" A short one-line description summary.
--detailed="<txt>" A longer description string.
--homepage=<url> Project homepage.
--lua-version=<ver> Supported Lua versions. Accepted values are "5.1", "5.2",
"5.3", "5.1,5.2", "5.2,5.3", or "5.1,5.2,5.3".
--tag=<tag> Tag to use. Will attempt to extract version number from it.
--lib=<lib>[,<lib>] A comma-separated list of libraries that C files need to
link to.
]]
local function open_file(name)
return io.open(dir.path(fs.current_dir(), name), "r")
end
local function get_url(rockspec)
local file, temp_dir, err_code, err_file, err_temp_dir = fetch.fetch_sources(rockspec, false)
if err_code == "source.dir" then
file, temp_dir = err_file, err_temp_dir
elseif not file then
util.warning("Could not fetch sources - "..temp_dir)
return false
end
util.printout("File successfully downloaded. Making checksum and checking base dir...")
if fetch.is_basic_protocol(rockspec.source.protocol) then
rockspec.source.md5 = fs.get_md5(file)
end
local inferred_dir, found_dir = fetch.find_base_dir(file, temp_dir, rockspec.source.url)
return true, found_dir or inferred_dir, temp_dir
end
local function configure_lua_version(rockspec, luaver)
if luaver == "5.1" then
table.insert(rockspec.dependencies, "lua ~> 5.1")
elseif luaver == "5.2" then
table.insert(rockspec.dependencies, "lua ~> 5.2")
elseif luaver == "5.3" then
table.insert(rockspec.dependencies, "lua ~> 5.3")
elseif luaver == "5.1,5.2" then
table.insert(rockspec.dependencies, "lua >= 5.1, < 5.3")
elseif luaver == "5.2,5.3" then
table.insert(rockspec.dependencies, "lua >= 5.2, < 5.4")
elseif luaver == "5.1,5.2,5.3" then
table.insert(rockspec.dependencies, "lua >= 5.1, < 5.4")
else
util.warning("Please specify supported Lua version with --lua-version=<ver>. "..util.see_help("write_rockspec"))
end
end
local function detect_description(rockspec)
local fd = open_file("README.md") or open_file("README")
if not fd then return end
local data = fd:read("*a")
fd:close()
local paragraph = data:match("\n\n([^%[].-)\n\n")
if not paragraph then paragraph = data:match("\n\n(.*)") end
if paragraph then
if #paragraph < 80 then
rockspec.description.summary = paragraph:gsub("\n", "")
rockspec.description.detailed = paragraph
else
local summary = paragraph:gsub("\n", " "):match("([^.]*%.) ")
if summary then
rockspec.description.summary = summary:gsub("\n", "")
end
rockspec.description.detailed = paragraph
end
end
end
local function detect_mit_license(data)
local strip_copyright = (data:gsub("Copyright [^\n]*\n", ""))
local sum = 0
for i = 1, #strip_copyright do
local num = string.byte(strip_copyright:sub(i,i))
if num > 32 and num <= 128 then
sum = sum + num
end
end
return sum == 78656
end
local function show_license(rockspec)
local fd = open_file("COPYING") or open_file("LICENSE") or open_file("MIT-LICENSE.txt")
if not fd then return nil end
local data = fd:read("*a")
fd:close()
local is_mit = detect_mit_license(data)
util.title("License for "..rockspec.package..":")
util.printout(data)
util.printout()
return is_mit
end
local function get_cmod_name(file)
local fd = open_file(file)
if not fd then return nil end
local data = fd:read("*a")
fd:close()
return (data:match("int%s+luaopen_([a-zA-Z0-9_]+)"))
end
local luamod_blacklist = {
test = true,
tests = true,
}
local function fill_as_builtin(rockspec, libs)
rockspec.build.type = "builtin"
rockspec.build.modules = {}
local prefix = ""
for _, parent in ipairs({"src", "lua"}) do
if fs.is_dir(parent) then
fs.change_dir(parent)
prefix = parent.."/"
break
end
end
local incdirs, libdirs
if libs then
incdirs, libdirs = {}, {}
for _, lib in ipairs(libs) do
local upper = lib:upper()
incdirs[#incdirs+1] = "$("..upper.."_INCDIR)"
libdirs[#libdirs+1] = "$("..upper.."_LIBDIR)"
end
end
for _, file in ipairs(fs.find()) do
local luamod = file:match("(.*)%.lua$")
if luamod and not luamod_blacklist[luamod] then
rockspec.build.modules[path.path_to_module(file)] = prefix..file
else
local cmod = file:match("(.*)%.c$")
if cmod then
local modname = get_cmod_name(file) or path.path_to_module(file:gsub("%.c$", ".lua"))
rockspec.build.modules[modname] = {
sources = prefix..file,
libraries = libs,
incdirs = incdirs,
libdirs = libdirs,
}
end
end
end
for _, directory in ipairs({ "doc", "docs", "samples", "tests" }) do
if fs.is_dir(directory) then
if not rockspec.build.copy_directories then
rockspec.build.copy_directories = {}
end
table.insert(rockspec.build.copy_directories, directory)
end
end
if prefix ~= "" then
fs.pop_dir()
end
end
local function rockspec_cleanup(rockspec)
rockspec.source.file = nil
rockspec.source.protocol = nil
rockspec.variables = nil
rockspec.name = nil
end
function write_rockspec.run(...)
local flags, name, version, url_or_dir = util.parse_flags(...)
if not name then
return nil, "Missing arguments. "..util.see_help("write_rockspec")
end
if name and not version then
url_or_dir = name
name = nil
elseif not url_or_dir then
url_or_dir = version
end
if flags["tag"] == true then
return nil, "Incorrect usage: --tag requires an argument. "..util.see_help("write_rockspec")
end
if flags["tag"] then
if not version then
version = flags["tag"]:gsub("^v", "")
end
end
local protocol, pathname = dir.split_url(url_or_dir)
if not fetch.is_basic_protocol(protocol) then
if not name then
name = dir.base_name(url_or_dir):gsub("%.[^.]+$", "")
end
if not version then
version = "scm"
end
elseif protocol ~= "file" then
local filename = dir.base_name(url_or_dir)
local newname, newversion = filename:match("(.*)-([^-]+)")
if (not name) and newname then
name = newname
end
if (not version) and newversion then
version = newversion:gsub(".[a-z]+$", ""):gsub(".tar$", "")
end
if not (name and version) then
return nil, "Missing name and version arguments. "..util.see_help("write_rockspec")
end
elseif not version then
return nil, "Missing name and version arguments. "..util.see_help("write_rockspec")
end
local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec")
if not flags["homepage"] and url_or_dir:match("^git://github.com") then
flags["homepage"] = "http://"..url_or_dir:match("^[^:]+://(.*)")
end
local rockspec = {
package = name,
name = name:lower(),
version = version.."-1",
source = {
url = "*** please add URL for source tarball, zip or repository here ***",
tag = flags["tag"],
},
description = {
summary = flags["summary"] or "*** please specify description summary ***",
detailed = flags["detailed"] or "*** please enter a detailed description ***",
homepage = flags["homepage"] or "*** please enter a project homepage ***",
license = flags["license"] or "*** please specify a license ***",
},
dependencies = {},
build = {},
}
path.configure_paths(rockspec)
rockspec.source.protocol = protocol
configure_lua_version(rockspec, flags["lua-version"])
local local_dir = url_or_dir
if url_or_dir:match("://") then
rockspec.source.url = url_or_dir
rockspec.source.file = dir.base_name(url_or_dir)
rockspec.source.dir = "dummy"
if not fetch.is_basic_protocol(rockspec.source.protocol) then
if version ~= "scm" then
rockspec.source.tag = flags["tag"] or "v" .. version
end
end
rockspec.source.dir = nil
local ok, base_dir, temp_dir = get_url(rockspec)
if ok then
if base_dir ~= dir.base_name(url_or_dir) then
rockspec.source.dir = base_dir
end
end
if base_dir then
local_dir = dir.path(temp_dir, base_dir)
else
local_dir = nil
end
end
if not local_dir then
local_dir = "."
end
local libs = nil
if flags["lib"] then
libs = {}
rockspec.external_dependencies = {}
for lib in flags["lib"]:gmatch("([^,]+)") do
table.insert(libs, lib)
rockspec.external_dependencies[lib:upper()] = {
library = lib
}
end
end
local ok, err = fs.change_dir(local_dir)
if not ok then return nil, "Failed reaching files from project - error entering directory "..local_dir end
detect_description(rockspec)
local is_mit = show_license(rockspec)
if is_mit and not flags["license"] then
rockspec.description.license = "MIT"
end
fill_as_builtin(rockspec, libs)
rockspec_cleanup(rockspec)
persist.save_from_table(filename, rockspec, type_check.rockspec_order)
util.printout()
util.printout("Wrote template at "..filename.." -- you should now edit and finish it.")
util.printout()
return true
end
return write_rockspec
|