From 392f67d65a950fcf08a08d10d21e80f359160262 Mon Sep 17 00:00:00 2001
From: Hisham Muhammad <hisham@gobolinux.org>
Date: Tue, 19 Jun 2018 00:16:24 -0300
Subject: fs: perform tool detection at runtime (downloader, md5checker)

---
 src/luarocks/fs/lua.lua     |  3 +-
 src/luarocks/fs/tools.lua   | 83 ++++++++++++++++++++++++++++++++-------------
 src/luarocks/upload/api.lua |  2 +-
 3 files changed, 63 insertions(+), 25 deletions(-)

diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua
index ede7884a..b53ef8cc 100644
--- a/src/luarocks/fs/lua.lua
+++ b/src/luarocks/fs/lua.lua
@@ -712,7 +712,8 @@ function fs_lua.download(url, filename, cache)
    end
    if https_err then
       if not downloader_warning then
-         util.warning("falling back to "..cfg.downloader.." - install luasec to get native HTTPS support")
+         local downloader = fs.which_tool("downloader")
+         util.warning("falling back to "..downloader.." - install luasec to get native HTTPS support")
          downloader_warning = true
       end
       return fs.use_downloader(url, filename, cache)
diff --git a/src/luarocks/fs/tools.lua b/src/luarocks/fs/tools.lua
index 8419f7d3..671c7ae1 100644
--- a/src/luarocks/fs/tools.lua
+++ b/src/luarocks/fs/tools.lua
@@ -10,21 +10,54 @@ local vars = cfg.variables
 
 local dir_stack = {}
 
---- Obtain current directory.
--- Uses the module's internal directory stack.
--- @return string: the absolute pathname of the current directory.
-function tools.current_dir()
-   local current = cfg.cache_pwd
-   if not current then
-      local pipe = io.popen(fs.quiet_stderr(fs.Q(vars.PWD)))
-      current = pipe:read("*l")
-      pipe:close()
-      cfg.cache_pwd = current
+do
+   local tool_cache = {}
+   
+   local tool_options = {
+      downloader = {
+         { var = "CURL", name = "curl" },
+         { var = "WGET", name = "wget" },
+      },
+      md5checker = {
+         { var = "MD5SUM", name = "md5sum" },
+         { var = "OPENSSL", name = "openssl" },
+         { var = "MD5", name = "md5", arg = "-v" },
+      },
+   }
+   
+   function tools.which_tool(tooltype)
+      if tool_cache[tooltype] then
+         return tool_cache[tooltype]
+      end
+      
+      for _, opt in ipairs(tool_options[tooltype]) do
+         if fs.is_tool_available(vars[opt.var], opt.name, opt.arg) then
+            tool_cache[tooltype] = opt.name
+            break
+         end
+      end
+      return tool_cache[tooltype]
    end
-   for _, directory in ipairs(dir_stack) do
-      current = fs.absolute_name(directory, current)
+end
+
+do
+   local cache_pwd
+   --- Obtain current directory.
+   -- Uses the module's internal directory stack.
+   -- @return string: the absolute pathname of the current directory.
+   function tools.current_dir()
+      local current = cache_pwd
+      if not current then
+         local pipe = io.popen(fs.quiet_stderr(fs.Q(vars.PWD)))
+         current = pipe:read("*l")
+         pipe:close()
+         cache_pwd = current
+      end
+      for _, directory in ipairs(dir_stack) do
+         current = fs.absolute_name(directory, current)
+      end
+      return current
    end
-   return current
 end
 
 --- Change the current directory.
@@ -101,9 +134,11 @@ function tools.use_downloader(url, filename, cache)
    assert(type(filename) == "string" or not filename)
 
    filename = fs.absolute_name(filename or dir.base_name(url))
+   
+   local downloader = fs.which_tool("downloader")
 
    local ok
-   if cfg.downloader == "wget" then
+   if downloader == "wget" then
       local wget_cmd = fs.Q(vars.WGET).." "..vars.WGETNOCERTFLAG.." --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet "
       if cfg.connection_timeout and cfg.connection_timeout > 0 then
         wget_cmd = wget_cmd .. "--timeout="..tostring(cfg.connection_timeout).." --tries=1 "
@@ -119,7 +154,7 @@ function tools.use_downloader(url, filename, cache)
       else
          ok = fs.execute_quiet(wget_cmd, url)
       end
-   elseif cfg.downloader == "curl" then
+   elseif downloader == "curl" then
       local curl_cmd = fs.Q(vars.CURL).." "..vars.CURLNOCERTFLAG.." -f -L --user-agent \""..cfg.user_agent.." via curl\" "
       if cfg.connection_timeout and cfg.connection_timeout > 0 then
         curl_cmd = curl_cmd .. "--connect-timeout "..tostring(cfg.connection_timeout).." "
@@ -144,15 +179,17 @@ local md5_cmd = {
 -- @param file string: The file to be computed.
 -- @return string: The MD5 checksum or nil + message
 function tools.get_md5(file)
-   local cmd = md5_cmd[cfg.md5checker]
-   if not cmd then return nil, "no MD5 checker command configured" end
-   local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file)))
-   local computed = pipe:read("*l")
-   pipe:close()
-   if computed then
-      computed = computed:match("("..("%x"):rep(32)..")")
+   local md5checker = fs.which_tool("md5checker")
+   if md5checker then
+      local cmd = md5_cmd[md5checker]
+      local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file)))
+      local computed = pipe:read("*l")
+      pipe:close()
+      if computed then
+         computed = computed:match("("..("%x"):rep(32)..")")
+      end
+      if computed then return computed end
    end
-   if computed then return computed end
    return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file))
 end
 
diff --git a/src/luarocks/upload/api.lua b/src/luarocks/upload/api.lua
index f9244258..30857158 100644
--- a/src/luarocks/upload/api.lua
+++ b/src/luarocks/upload/api.lua
@@ -143,7 +143,7 @@ function Api:request(url, params, post_params)
    local json_ok, json = require_json()
    if not json_ok then return nil, "A JSON library is required for this command. "..json end
    
-   if cfg.downloader == "wget" then
+   if fs.which_tool("downloader") == "wget" then
       local curl_ok, err = fs.is_tool_available(vars.CURL, "curl")
       if not curl_ok then
          return nil, err
-- 
cgit v1.2.3-55-g6feb