Welcome to mirror list, hosted at ThFree Co, Russian Federation.

write_rockspec.lua « luarocks « src - github.com/torch/luajit-rocks.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 403cbc83b4bc1fa59cc60851baa74e07a60106e7 (plain)
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