summaryrefslogtreecommitdiff
path: root/src/luarocks/rockspecs.lua
blob: 454bab772546b4e587bcb494615106c571d15ee4 (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
local rockspecs = {}

local cfg = require("luarocks.core.cfg")
local dir = require("luarocks.dir")
local path = require("luarocks.path")
local queries = require("luarocks.queries")
local type_rockspec = require("luarocks.type.rockspec")
local util = require("luarocks.util")
local vers = require("luarocks.core.vers")

local vendored_build_type_set = {
   ["builtin"] = true,
   ["cmake"] = true,
   ["command"] = true,
   ["make"] = true,
   ["module"] = true, -- compatibility alias
   ["none"] = true,
}

local rockspec_mt = {}

rockspec_mt.__index = rockspec_mt

function rockspec_mt.type()
   return "rockspec"
end

--- Perform platform-specific overrides on a table.
-- Overrides values of table with the contents of the appropriate
-- subset of its "platforms" field. The "platforms" field should
-- be a table containing subtables keyed with strings representing
-- platform names. Names that match the contents of the global
-- detected platforms setting are used. For example, if
-- platform "unix" is detected, then the fields of
-- tbl.platforms.unix will overwrite those of tbl with the same
-- names. For table values, the operation is performed recursively
-- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of
-- tbl.x are preserved).
-- @param tbl table or nil: Table which may contain a "platforms" field;
-- if it doesn't (or if nil is passed), this function does nothing.
local function platform_overrides(tbl)
   assert(type(tbl) == "table" or not tbl)

   if not tbl then return end

   if tbl.platforms then
      for platform in cfg.each_platform() do
         local platform_tbl = tbl.platforms[platform]
         if platform_tbl then
            util.deep_merge(tbl, platform_tbl)
         end
      end
   end
   tbl.platforms = nil
end

local function convert_dependencies(rockspec, key)
   if rockspec[key] then
      for i = 1, #rockspec[key] do
         local parsed, err = queries.from_dep_string(rockspec[key][i])
         if not parsed then
            return nil, "Parse error processing dependency '"..rockspec[key][i].."': "..tostring(err)
         end
         rockspec[key][i] = parsed
      end
   else
      rockspec[key] = {}
   end
   return true
end

--- Set up path-related variables for a given rock.
-- Create a "variables" table in the rockspec table, containing
-- adjusted variables according to the configuration file.
-- @param rockspec table: The rockspec table.
local function configure_paths(rockspec)
   local vars = {}
   for k,v in pairs(cfg.variables) do
      vars[k] = v
   end
   local name, version = rockspec.name, rockspec.version
   vars.PREFIX = path.install_dir(name, version)
   vars.LUADIR = path.lua_dir(name, version)
   vars.LIBDIR = path.lib_dir(name, version)
   vars.CONFDIR = path.conf_dir(name, version)
   vars.BINDIR = path.bin_dir(name, version)
   vars.DOCDIR = path.doc_dir(name, version)
   rockspec.variables = vars
end

function rockspecs.from_persisted_table(filename, rockspec, globals, quick)
   assert(type(rockspec) == "table")
   assert(type(globals) == "table" or globals == nil)
   assert(type(filename) == "string")
   assert(type(quick) == "boolean" or quick == nil)

   if rockspec.rockspec_format then
      if vers.compare_versions(rockspec.rockspec_format, type_rockspec.rockspec_format) then
         return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks."
      end
   end

   if not quick then
      local ok, err = type_rockspec.check(rockspec, globals or {})
      if not ok then
         return nil, err
      end
   end

   --- Check if rockspec format version satisfies version requirement.
   -- @param rockspec table: The rockspec table.
   -- @param version string: required version.
   -- @return boolean: true if rockspec format matches version or is newer, false otherwise.
   do
      local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0")
      rockspec.format_is_at_least = function(self, version)
         return parsed_format >= vers.parse_version(version)
      end
   end

   platform_overrides(rockspec.build)
   platform_overrides(rockspec.dependencies)
   platform_overrides(rockspec.build_dependencies)
   platform_overrides(rockspec.test_dependencies)
   platform_overrides(rockspec.external_dependencies)
   platform_overrides(rockspec.source)
   platform_overrides(rockspec.hooks)
   platform_overrides(rockspec.test)

   rockspec.name = rockspec.package:lower()

   local protocol, pathname = dir.split_url(rockspec.source.url)
   if dir.is_basic_protocol(protocol) then
      rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url)
   end
   rockspec.source.protocol, rockspec.source.pathname = protocol, pathname

   -- Temporary compatibility
   if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end
   if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end

   rockspec.local_abs_filename = filename
   rockspec.source.dir_set = rockspec.source.dir ~= nil
   rockspec.source.dir = rockspec.source.dir or rockspec.source.module

   rockspec.rocks_provided = util.get_rocks_provided(rockspec)

   for _, key in ipairs({"dependencies", "build_dependencies", "test_dependencies"}) do
      local ok, err = convert_dependencies(rockspec, key)
      if not ok then
         return nil, err
      end
   end

   if rockspec.build
      and rockspec.build.type
      and not vendored_build_type_set[rockspec.build.type] then
      local build_pkg_name = "luarocks-build-" .. rockspec.build.type
      if not rockspec.build_dependencies then
         rockspec.build_dependencies = {}
      end

      local found = false
      for _, dep in ipairs(rockspec.build_dependencies) do
         if dep.name == build_pkg_name then
            found = true
            break
         end
      end

      if not found then
         table.insert(rockspec.build_dependencies, queries.from_dep_string(build_pkg_name))
      end
   end

   if not quick then
      configure_paths(rockspec)
   end

   return setmetatable(rockspec, rockspec_mt)
end

return rockspecs