aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhilipp Janda <siffiejoe@gmx.net>2014-05-27 02:45:06 +0200
committerPhilipp Janda <siffiejoe@gmx.net>2014-05-27 02:45:06 +0200
commitdbb63f8248eca42da4fad45c718fe7d70ec8eacc (patch)
tree80ac9c7bcb19a237c667b5f1b7ec6adfaa5a0ae7 /src
parent64eea52bca48ba979ec8f485859f449983c056c5 (diff)
parentdc9d2daf9deaf867b6caaf88ab1bb088e2b4622d (diff)
downloadluarocks-dbb63f8248eca42da4fad45c718fe7d70ec8eacc.tar.gz
luarocks-dbb63f8248eca42da4fad45c718fe7d70ec8eacc.tar.bz2
luarocks-dbb63f8248eca42da4fad45c718fe7d70ec8eacc.zip
Merge remote-tracking branch 'upstream/master' into staticlibs
Diffstat (limited to 'src')
-rwxr-xr-xsrc/bin/luarocks1
-rw-r--r--src/luarocks/cfg.lua15
-rw-r--r--src/luarocks/pack.lua4
-rw-r--r--src/luarocks/upload.lua88
-rw-r--r--src/luarocks/upload/api.lua182
-rw-r--r--src/luarocks/upload/multipart.lua107
6 files changed, 389 insertions, 8 deletions
diff --git a/src/bin/luarocks b/src/bin/luarocks
index b85fbc7c..3c9e1b74 100755
--- a/src/bin/luarocks
+++ b/src/bin/luarocks
@@ -23,6 +23,7 @@ commands = {
23 write_rockspec = "luarocks.write_rockspec", 23 write_rockspec = "luarocks.write_rockspec",
24 purge = "luarocks.purge", 24 purge = "luarocks.purge",
25 doc = "luarocks.doc", 25 doc = "luarocks.doc",
26 upload = "luarocks.upload",
26} 27}
27 28
28command_line.run_command(...) 29command_line.run_command(...)
diff --git a/src/luarocks/cfg.lua b/src/luarocks/cfg.lua
index 5e891b06..8f73bec1 100644
--- a/src/luarocks/cfg.lua
+++ b/src/luarocks/cfg.lua
@@ -32,7 +32,7 @@ end
32 32
33cfg.site_config = site_config 33cfg.site_config = site_config
34 34
35cfg.program_version = "2.1.2" 35cfg.program_version = "2.2.0beta1"
36cfg.major_version = cfg.program_version:match("([^.]%.[^.])") 36cfg.major_version = cfg.program_version:match("([^.]%.[^.])")
37 37
38local persist = require("luarocks.persist") 38local persist = require("luarocks.persist")
@@ -214,14 +214,17 @@ local defaults = {
214 214
215 rocks_servers = { 215 rocks_servers = {
216 { 216 {
217 "http://www.luarocks.org/repositories/rocks", 217 "http://rocks.moonscript.org",
218 "http://luarocks.giga.puc-rio.br/", 218 "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/",
219 "http://luafr.org/luarocks/rocks",
220 "http://liblua.so/luarocks/repositories/rocks",
221 "http://luarocks.logiceditor.com/rocks",
222 } 219 }
223 }, 220 },
224 disabled_servers = {}, 221 disabled_servers = {},
222
223 upload = {
224 server = "rocks.moonscript.org",
225 tool_version = "0.0.1",
226 api_version = "1",
227 },
225 228
226 lua_extension = "lua", 229 lua_extension = "lua",
227 lua_interpreter = site_config.LUA_INTERPRETER or "lua", 230 lua_interpreter = site_config.LUA_INTERPRETER or "lua",
diff --git a/src/luarocks/pack.lua b/src/luarocks/pack.lua
index d8b3ad9b..c73d66ab 100644
--- a/src/luarocks/pack.lua
+++ b/src/luarocks/pack.lua
@@ -33,7 +33,7 @@ argument.
33-- @param rockspec_file string: An URL or pathname for a rockspec file. 33-- @param rockspec_file string: An URL or pathname for a rockspec file.
34-- @return string or (nil, string): The filename of the resulting 34-- @return string or (nil, string): The filename of the resulting
35-- .src.rock file; or nil and an error message. 35-- .src.rock file; or nil and an error message.
36local function pack_source_rock(rockspec_file) 36function pack.pack_source_rock(rockspec_file)
37 assert(type(rockspec_file) == "string") 37 assert(type(rockspec_file) == "string")
38 38
39 local rockspec, err = fetch.load_rockspec(rockspec_file) 39 local rockspec, err = fetch.load_rockspec(rockspec_file)
@@ -201,7 +201,7 @@ function pack.run(...)
201 201
202 local file, err 202 local file, err
203 if arg:match(".*%.rockspec") then 203 if arg:match(".*%.rockspec") then
204 file, err = pack_source_rock(arg) 204 file, err = pack.pack_source_rock(arg)
205 else 205 else
206 file, err = do_pack_binary_rock(arg, version) 206 file, err = do_pack_binary_rock(arg, version)
207 end 207 end
diff --git a/src/luarocks/upload.lua b/src/luarocks/upload.lua
new file mode 100644
index 00000000..018e702d
--- /dev/null
+++ b/src/luarocks/upload.lua
@@ -0,0 +1,88 @@
1
2local upload = {}
3
4local util = require("luarocks.util")
5local fetch = require("luarocks.fetch")
6local pack = require("luarocks.pack")
7local Api = require("luarocks.upload.api")
8
9upload.help_summary = "Upload a rockspec to the public rocks repository."
10upload.help_arguments = "[--skip-pack] [--api-key=<key>] [--force] <rockspec>"
11upload.help = [[
12<rockspec> Pack a source rock file (.src.rock extension),
13 upload rockspec and source rock to server.
14--skip-pack Do not pack and send source rock.
15--api-key=<key> Give it an API key. It will be stored for subsequent uses.
16--force Replace existing rockspec if the same revision of
17 a module already exists. This should be used only
18 in case of upload mistakes: when updating a rockspec,
19 increment the revision number instead.
20]]
21
22function upload.run(...)
23 local flags, fname = util.parse_flags(...)
24 if not fname then
25 return nil, "Missing rockspec. "..util.see_help("upload")
26 end
27
28 local api, err = Api.new(flags)
29 if not api then
30 return nil, err
31 end
32
33 local rockspec, err, errcode = fetch.load_rockspec(fname)
34 if err then
35 return nil, err, errcode
36 end
37
38 util.printout("Sending " .. tostring(fname) .. " ...")
39 local res, err = api:method("check_rockspec", {
40 package = rockspec.package,
41 version = rockspec.version
42 })
43 if not res then return nil, err end
44
45 if not res.module then
46 util.printout("Will create new module (" .. tostring(rockspec.package) .. ")")
47 end
48 if res.version and not flags["force"] then
49 return nil, "Revision "..rockspec.version.." already exists on the server. "..util.see_help("upload")
50 end
51
52 local rock_fname
53 if not flags["skip-pack"] then
54 util.printout("Packing " .. tostring(rockspec.package))
55 rock_fname, err = pack.pack_source_rock(fname)
56 if not rock_fname then
57 return nil, err
58 end
59 end
60
61 local multipart = require("luarocks.upload.multipart")
62
63 res, err = api:method("upload", nil, {
64 rockspec_file = multipart.new_file(fname)
65 })
66 if not res then return nil, err end
67
68 if res.is_new and #res.manifests == 0 then
69 util.printerr("Warning: module not added to root manifest due to name taken.")
70 end
71
72 local module_url = res.module_url
73
74 if rock_fname then
75 util.printout(("Sending " .. tostring(rock_fname) .. " ..."))
76 res, err = api:method("upload_rock/" .. tostring(res.version.id), nil, {
77 rock_file = multipart.new_file(rock_fname)
78 })
79 if not res then return nil, err end
80 end
81
82 util.printout()
83 util.printout("Done: " .. tostring(module_url))
84 util.printout()
85 return true
86end
87
88return upload
diff --git a/src/luarocks/upload/api.lua b/src/luarocks/upload/api.lua
new file mode 100644
index 00000000..818d293e
--- /dev/null
+++ b/src/luarocks/upload/api.lua
@@ -0,0 +1,182 @@
1
2local api = {}
3
4local cfg = require("luarocks.cfg")
5local fs = require("luarocks.fs")
6local util = require("luarocks.util")
7local persist = require("luarocks.persist")
8
9local Api = {}
10
11local function upload_config_file()
12 local _, _, home_conf, home_ok = cfg.which_config()
13 if not home_conf then
14 return nil
15 end
16 return (home_conf:gsub("/[^/]+$", "/upload_config.lua"))
17end
18
19function Api:load_config()
20 local upload_conf = upload_config_file()
21 print(upload_conf)
22 if not upload_conf then return nil end
23 local cfg, err = persist.load_into_table(upload_conf)
24 return cfg
25end
26
27function Api:save_config()
28 -- Test configuration before saving it.
29 local res, err = self:raw_method("status")
30 if not res then
31 return nil, err
32 end
33 if res.errors then
34 util.printerr("Server says: " .. tostring(res.errors[1]))
35 return
36 end
37 local upload_conf = upload_config_file()
38 if not upload_conf then return nil end
39 persist.save_from_table(upload_conf, self.config)
40 fs.chmod(upload_conf, "0600")
41end
42
43function Api:check_version()
44 if not self._server_tool_version then
45 local tool_version = cfg.upload.tool_version
46 local res, err = self:request("http://" .. tostring(self.config.server) .. "/api/tool_version", {
47 current = tool_version
48 })
49 if not res then
50 return nil, err
51 end
52 if not res.version then
53 return nil, "failed to fetch tool version"
54 end
55 self._server_tool_version = res.version
56 if res.force_update then
57 return nil, "Your upload client is too out of date to continue, please upgrade LuaRocks."
58 end
59 if res.version ~= tool_version then
60 util.printerr("Warning: Your LuaRocks is out of date, consider upgrading.")
61 end
62 end
63 return true
64end
65
66function Api:method(...)
67 local res, err = self:raw_method(...)
68 if not res then
69 return nil, err
70 end
71 if res.errors then
72 if res.errors[1] == "Invalid key" then
73 return nil, res.errors[1] .. " (use the --api-key flag to change)"
74 end
75 local msg = table.concat(res.errors, ", ")
76 return nil, "API Failed: " .. msg
77 end
78 return res
79end
80
81function Api:raw_method(path, ...)
82 self:check_version()
83 local url = "http://" .. tostring(self.config.server) .. "/api/" .. tostring(cfg.upload.api_version) .. "/" .. tostring(self.config.key) .. "/" .. tostring(path)
84 return self:request(url, ...)
85end
86
87local function encode_query_string(t, sep)
88 local url = require("socket.url")
89 if sep == nil then
90 sep = "&"
91 end
92 local i = 0
93 local buf = { }
94 for k, v in pairs(t) do
95 if type(k) == "number" and type(v) == "table" then
96 k, v = v[1], v[2]
97 end
98 buf[i + 1] = url.escape(k)
99 buf[i + 2] = "="
100 buf[i + 3] = url.escape(v)
101 buf[i + 4] = sep
102 i = i + 4
103 end
104 buf[i] = nil
105 return table.concat(buf)
106end
107
108-- An ode to the multitude of JSON libraries out there...
109local function require_json()
110 for _, lib in ipairs({ "cjson", "dkjson", "json" }) do
111 local json_ok, json = pcall(require, lib)
112 if json_ok then
113 return json_ok, json
114 end
115 end
116 return nil
117end
118
119function Api:request(url, params, post_params)
120 local http_ok, http = pcall(require, "socket.http")
121 local ltn12_ok, ltn12 = pcall(require, "ltn12")
122 local json_ok, json = require_json()
123 if not http_ok then return nil, "LuaSocket is required for this command." end
124 if not json_ok then return nil, "A JSON library is required for this command." end
125
126 if not self.config.key then
127 return nil, "Must have API key before performing any actions."
128 end
129 local body
130 local headers = {}
131 if params and next(params) then
132 url = url .. ("?" .. encode_query_string(params))
133 end
134 if post_params then
135 local multipart = require("luarocks.upload.multipart")
136 local boundary
137 body, boundary = multipart.encode(post_params)
138 headers["Content-length"] = #body
139 headers["Content-type"] = "multipart/form-data; boundary=" .. tostring(boundary)
140 end
141 local method = post_params and "POST" or "GET"
142 if self.debug then
143 util.printout("[" .. tostring(method) .. "] " .. tostring(url) .. " ... ")
144 end
145 local out = {}
146 local _, status = http.request({
147 url = url,
148 headers = headers,
149 method = method,
150 sink = ltn12.sink.table(out),
151 source = body and ltn12.source.string(body)
152 })
153 if self.debug then
154 util.printout(tostring(status))
155 end
156 if status ~= 200 then
157 return nil, "API returned " .. tostring(status) .. " - " .. tostring(url)
158 end
159 return json.decode(table.concat(out))
160end
161
162function api.new(flags, name)
163 local self = {}
164 setmetatable(self, { __index = Api })
165 self.config = self:load_config() or {}
166 self.config.server = flags["server"] or self.config.server or cfg.upload.server
167 self.config.version = self.config.version or cfg.upload.version
168 self.config.key = flags["api-key"] or self.config.key
169 self.debug = flags["debug"]
170 if not self.config.key then
171 return nil, "You need an API key to upload rocks.\n" ..
172 "Navigate to http://"..self.config.server.."/settings to get a key\n" ..
173 "and then pass it through the --api-key=<key> flag."
174 end
175 if flags["api-key"] then
176 self:save_config()
177 end
178 return self
179end
180
181return api
182
diff --git a/src/luarocks/upload/multipart.lua b/src/luarocks/upload/multipart.lua
new file mode 100644
index 00000000..95afe1b3
--- /dev/null
+++ b/src/luarocks/upload/multipart.lua
@@ -0,0 +1,107 @@
1
2local multipart = {}
3
4local url = require("socket.url")
5
6local File = {}
7
8local unpack = unpack or table.unpack
9
10math.randomseed(os.time())
11
12function File:mime()
13 if not self.mimetype then
14 local mimetypes_ok, mimetypes = pcall(require, "mimetypes")
15 if mimetypes_ok then
16 self.mimetype = mimetypes.guess(self.fname)
17 else
18 self.mimetype = "application/octet-stream"
19 end
20 end
21 return self.mimetype
22end
23
24function File:content()
25 local fd = io.open(self.fname)
26 if not fd then
27 return nil, "Failed to open file: "..self.fname
28 end
29 local data = fd:read("*a")
30 fd:close()
31 return data
32end
33
34local function rand_string(len)
35 local shuffled = {}
36 for i = 1, len do
37 local r = math.random(97, 122)
38 if math.random() >= 0.5 then
39 r = r - 32
40 end
41 shuffled[i] = r
42 end
43 return string.char(unpack(shuffled))
44end
45
46-- multipart encodes params
47-- returns encoded string,boundary
48-- params is an a table of tuple tables:
49-- params = {
50-- {key1, value2},
51-- {key2, value2},
52-- key3: value3
53-- }
54function multipart.encode(params)
55 local tuples = { }
56 for i = 1, #params do
57 tuples[i] = params[i]
58 end
59 for k,v in pairs(params) do
60 if type(k) == "string" then
61 table.insert(tuples, {k, v})
62 end
63 end
64 local chunks = {}
65 for _, tuple in ipairs(tuples) do
66 local k,v = unpack(tuple)
67 k = url.escape(k)
68 local buffer = { 'Content-Disposition: form-data; name="' .. k .. '"' }
69 local content
70 if type(v) == "table" and v.__class == File then
71 buffer[1] = buffer[1] .. ('; filename="' .. v.fname:gsub(".*/", "") .. '"')
72 table.insert(buffer, "Content-type: " .. v:mime())
73 content = v:content()
74 else
75 content = v
76 end
77 table.insert(buffer, "")
78 table.insert(buffer, content)
79 table.insert(chunks, table.concat(buffer, "\r\n"))
80 end
81 local boundary
82 while not boundary do
83 boundary = "Boundary" .. rand_string(16)
84 for _, chunk in ipairs(chunks) do
85 if chunk:find(boundary) then
86 boundary = nil
87 break
88 end
89 end
90 end
91 local inner = "\r\n--" .. boundary .. "\r\n"
92 return table.concat({ "--", boundary, "\r\n",
93 table.concat(chunks, inner),
94 "\r\n", "--", boundary, "--", "\r\n" }), boundary
95end
96
97function multipart.new_file(fname, mime)
98 local self = {}
99 setmetatable(self, { __index = File })
100 self.__class = File
101 self.fname = fname
102 self.mimetype = mime
103 return self
104end
105
106return multipart
107