From 370a2943c09e70154862f382fe3de7f486a4a1c6 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Wed, 13 Nov 2013 09:33:10 +0100 Subject: fixes LR install in location with spaces, quoting LR commands NOTE: seems to be broken now, bug not found yet --- src/luarocks/fs.lua | 19 +++++++++++++++++++ src/luarocks/fs/lua.lua | 8 ++++++-- src/luarocks/fs/win32/tools.lua | 36 ++++++++++++++++++------------------ 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/luarocks/fs.lua b/src/luarocks/fs.lua index 467b1943..e002c7ba 100644 --- a/src/luarocks/fs.lua +++ b/src/luarocks/fs.lua @@ -38,3 +38,22 @@ load_fns(fs_lua) local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools") if ok and fs_plat_tools then load_fns(fs_plat_tools) end +-- uncomment below for further debugging than 'verbose=true' in config file +-- code below will also catch commands outside of fs.execute() +-- especially uses of io.popen(). +--[[ +old_exec = os.execute +os.execute = function(cmd) + print("os.execute: ", cmd) + return old_exec(cmd) +end +old_popen = io.popen +io.popen = function(one, two) + if two == nil then + print("io.popen: ", one) + else + print("io.popen: ", one, "Mode:", two) + end + return old_popen(one, two) +end +--]] diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua index d477d88f..51cbee03 100644 --- a/src/luarocks/fs/lua.lua +++ b/src/luarocks/fs/lua.lua @@ -108,12 +108,16 @@ end -- The command is executed in the current directory in the dir stack. -- @param command string: The command to be executed. No quoting/escaping -- is applied. --- @param ... Strings containing additional arguments, which are quoted. +-- @param ... Strings containing additional arguments, which will be quoted. -- @return boolean: true if command succeeds (status code 0), false -- otherwise. function execute_quiet(command, ...) assert(type(command) == "string") - return fs.execute_string(fs.quiet(quote_args(command, ...))) + if cfg.verbose then + return fs.execute_string(quote_args(command, ...)) + else + return fs.execute_string(fs.quiet(quote_args(command, ...))) + end end --- Check the MD5 checksum for a file. diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua index 979aaff4..9aa76851 100644 --- a/src/luarocks/fs/win32/tools.lua +++ b/src/luarocks/fs/win32/tools.lua @@ -112,7 +112,7 @@ end function make_dir(directory) assert(directory) directory = dir.normalize(directory) - fs.execute_quiet(vars.MKDIR.." -p ", directory) + fs.execute_quiet(fs.Q(vars.MKDIR).." -p ", directory) if not fs.is_dir(directory) then return false, "failed making directory "..directory end @@ -125,7 +125,7 @@ end -- @param directory string: pathname of directory to remove. function remove_dir_if_empty(directory) assert(directory) - fs.execute_quiet(vars.RMDIR, directory) + fs.execute_quiet(fs.Q(vars.RMDIR), directory) end --- Remove a directory if it is empty. @@ -134,7 +134,7 @@ end -- @param directory string: pathname of directory to remove. function remove_dir_tree_if_empty(directory) assert(directory) - fs.execute_quiet(vars.RMDIR, directory) + fs.execute_quiet(fs.Q(vars.RMDIR), directory) end --- Copy a file. @@ -145,7 +145,7 @@ end function copy(src, dest) assert(src and dest) if dest:match("[/\\]$") then dest = dest:sub(1, -2) end - local ok = fs.execute(vars.CP, src, dest) + local ok = fs.execute(fs.Q(vars.CP), src, dest) if ok then return true else @@ -160,7 +160,7 @@ end -- plus an error message. function copy_contents(src, dest) assert(src and dest) - if fs.execute_quiet(vars.CP.." -dR "..src.."\\*.* "..fs.Q(dest)) then + if fs.execute_quiet(fs.Q(vars.CP).." -dR "..src.."\\*.* "..fs.Q(dest)) then return true else return false, "Failed copying "..src.." to "..dest @@ -191,7 +191,7 @@ function list_dir(at) return {} end local result = {} - local pipe = io.popen(command_at(at, vars.LS)) + local pipe = io.popen(command_at(at, fs.Q(vars.LS))) for file in pipe:lines() do table.insert(result, file) end @@ -214,7 +214,7 @@ function find(at) return {} end local result = {} - local pipe = io.popen(command_at(at, vars.FIND.." 2> NUL")) + local pipe = io.popen(command_at(at, fs.Q(vars.FIND).." 2> NUL")) for file in pipe:lines() do -- Windows find is a bit different local first_two = file:sub(1,2) @@ -233,7 +233,7 @@ end -- additional arguments. -- @return boolean: true on success, false on failure. function zip(zipfile, ...) - return fs.execute_quiet(vars.SEVENZ.." -aoa a -tzip", zipfile, ...) + return fs.execute_quiet(fs.Q(vars.SEVENZ).." -aoa a -tzip", zipfile, ...) end --- Uncompress files from a .zip archive. @@ -241,7 +241,7 @@ end -- @return boolean: true on success, false on failure. function unzip(zipfile) assert(zipfile) - return fs.execute_quiet(vars.SEVENZ.." -aoa x", zipfile) + return fs.execute_quiet(fs.Q(vars.SEVENZ).." -aoa x", zipfile) end --- Test is pathname is a directory. @@ -257,7 +257,7 @@ end -- @return boolean: true if it is a regular file, false otherwise. function is_file(file) assert(file) - return fs.execute(vars.TEST.." -f", file) + return fs.execute(fs.Q(vars.TEST).." -f", file) end --- Download a remote file. @@ -276,7 +276,7 @@ function download(url, filename, cache) local ok if cfg.downloader == "wget" then - local wget_cmd = vars.WGET.." --no-check-certificate --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet " + local wget_cmd = fs.Q(vars.WGET).." --no-check-certificate --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet " if cache then -- --timestamping is incompatible with --output-document, -- but that's not a problem for our use cases. @@ -289,7 +289,7 @@ function download(url, filename, cache) ok = fs.execute(wget_cmd..fs.Q(url).." 2> NUL 1> NUL") end elseif cfg.downloader == "curl" then - ok = fs.execute_string(vars.CURL.." -L --user-agent \""..cfg.user_agent.." via curl\" "..fs.Q(url).." 2> NUL 1> "..fs.Q(filename)) + ok = fs.execute_string(fs.Q(vars.CURL).." -L --user-agent \""..cfg.user_agent.." via curl\" "..fs.Q(url).." 2> NUL 1> "..fs.Q(filename)) end if ok then return true, filename @@ -302,7 +302,7 @@ end -- @param archive string: Filename of archive. -- @return boolean : success status local function gunzip(archive) - return fs.execute_quiet(vars.SEVENZ.." -aoa x", archive) + return fs.execute_quiet(fs.Q(vars.SEVENZ).." -aoa x", archive) end --- Unpack an archive. @@ -314,7 +314,7 @@ function unpack_archive(archive) assert(type(archive) == "string") local ok - local sevenzx = vars.SEVENZ.." -aoa x" + local sevenzx = fs.Q(vars.SEVENZ).." -aoa x" if archive:match("%.tar%.gz$") then ok = gunzip(archive) if ok then @@ -346,9 +346,9 @@ function unpack_archive(archive) end local md5_cmd = { - md5sum = vars.MD5SUM, - openssl = vars.OPENSSL.." md5", - md5 = vars.MD5, + md5sum = fs.Q(vars.MD5SUM), + openssl = fs.Q(vars.OPENSSL).." md5", + md5 = fs.Q(vars.MD5), } --- Get the MD5 checksum for a file. @@ -357,7 +357,7 @@ local md5_cmd = { function get_md5(file) local cmd = md5_cmd[cfg.md5checker] if not cmd then return nil end - local pipe = io.popen(cmd.." "..fs.absolute_name(file)) + local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file))) local computed = pipe:read("*a") pipe:close() if not computed then return nil end -- cgit v1.2.3-55-g6feb From 217a43551fae3bff78e6fabef8f29919e252ac15 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Wed, 13 Nov 2013 15:29:31 +0100 Subject: update get_md5() and check_md5() to also return an error message if it fails unquoted arguments of get_md5 command to prevent failure, needs further updating --- src/luarocks/fs/lua.lua | 15 ++++++++------- src/luarocks/fs/unix/tools.lua | 7 +++++-- src/luarocks/fs/win32/tools.lua | 11 +++++++---- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua index 51cbee03..f9ec43ba 100644 --- a/src/luarocks/fs/lua.lua +++ b/src/luarocks/fs/lua.lua @@ -123,18 +123,18 @@ end --- Check the MD5 checksum for a file. -- @param file string: The file to be checked. -- @param md5sum string: The string with the expected MD5 checksum. --- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false if not +-- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false + msg if not -- or if it could not perform the check for any reason. function check_md5(file, md5sum) file = dir.normalize(file) - local computed = fs.get_md5(file) + local computed, msg = fs.get_md5(file) if not computed then - return false + return false, msg end if computed:match("^"..md5sum) then return true else - return false + return false, "Mismatch MD5 hash for file "..file end end @@ -648,14 +648,15 @@ if md5_ok then --- Get the MD5 checksum for a file. -- @param file string: The file to be computed. --- @return string: The MD5 checksum +-- @return string: The MD5 checksum or nil + error function get_md5(file) file = fs.absolute_name(file) local file = io.open(file, "rb") - if not file then return false end + if not file then return nil, "Failed to compute MD5 hash for file "..file end local computed = md5.sumhexa(file:read("*a")) file:close() - return computed + if computed then return computed end + return nil, "Failed to compute MD5 hash for file "..file end end diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua index e3468ab4..c857b093 100644 --- a/src/luarocks/fs/unix/tools.lua +++ b/src/luarocks/fs/unix/tools.lua @@ -328,8 +328,11 @@ function get_md5(file) local pipe = io.popen(cmd.." "..fs.absolute_name(file)) local computed = pipe:read("*a") pipe:close() - if not computed then return nil end - return computed:match("("..("%x"):rep(32)..")") + if computed then + computed = computed:match("("..("%x"):rep(32)..")") + end + if computed then return computed end + return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file)) end function get_permissions(filename) diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua index 9aa76851..1c0131c7 100644 --- a/src/luarocks/fs/win32/tools.lua +++ b/src/luarocks/fs/win32/tools.lua @@ -353,15 +353,18 @@ local md5_cmd = { --- Get the MD5 checksum for a file. -- @param file string: The file to be computed. --- @return string: The MD5 checksum +-- @return string: The MD5 checksum or nil + message function get_md5(file) local cmd = md5_cmd[cfg.md5checker] if not cmd then return nil end - local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file))) + local pipe = io.popen(cmd.." "..fs.absolute_name(file)) -- should be in fs.Q() local computed = pipe:read("*a") pipe:close() - if not computed then return nil end - return computed:match("("..("%x"):rep(32)..")") + if computed then + computed = computed:match("("..("%x"):rep(32)..")") + end + if computed then return computed end + return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file)) end --- Test for existance of a file. -- cgit v1.2.3-55-g6feb From 579ad25c0c89e3844bd729ff909db5680fbbbe80 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Mon, 18 Nov 2013 09:41:20 +0100 Subject: fixed type. Fixes #185 --- src/luarocks/cfg.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/luarocks/cfg.lua b/src/luarocks/cfg.lua index e3d924fb..f66ad1d9 100644 --- a/src/luarocks/cfg.lua +++ b/src/luarocks/cfg.lua @@ -322,7 +322,7 @@ if detected.windows then local localappdata = os.getenv("LOCALAPPDATA") if not localappdata then -- for Windows versions below Vista - localappdata = os.getenv("USER_PROFILE").."/Local Settings/Application Data" + localappdata = os.getenv("USERPROFILE").."/Local Settings/Application Data" end defaults.local_cache = localappdata.."/LuaRocks/Cache" end -- cgit v1.2.3-55-g6feb From 722c03ae8b059cba8039e8066dd1a82e7c3ddcb3 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Tue, 19 Nov 2013 11:52:08 +0100 Subject: fixed double quotes in io.popen commands --- src/luarocks/fs/win32.lua | 9 +++++++++ src/luarocks/fs/win32/tools.lua | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua index 0280b3f0..9f85ac05 100644 --- a/src/luarocks/fs/win32.lua +++ b/src/luarocks/fs/win32.lua @@ -9,6 +9,15 @@ local cfg = require("luarocks.cfg") local dir = require("luarocks.dir") local util = require("luarocks.util") +-- Monkey patch io.popen and os.execute to make sure quoting +-- works as expected. +-- See http://lua-users.org/lists/lua-l/2013-11/msg00367.html +local _prefix = "type NUL && " +local _popen, _execute = io.popen, os.execute +io.popen = function(cmd, ...) return _popen(_prefix..cmd, ...) end +os.execute = function(cmd, ...) return _execute(_prefix..cmd, ...) end + + --- Annotate command string for quiet execution. -- @param cmd string: A command-line string. -- @return string: The command-line, with silencing annotation. diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua index 1c0131c7..1d302288 100644 --- a/src/luarocks/fs/win32/tools.lua +++ b/src/luarocks/fs/win32/tools.lua @@ -357,7 +357,7 @@ local md5_cmd = { function get_md5(file) local cmd = md5_cmd[cfg.md5checker] if not cmd then return nil end - local pipe = io.popen(cmd.." "..fs.absolute_name(file)) -- should be in fs.Q() + local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file))) local computed = pipe:read("*a") pipe:close() if computed then -- cgit v1.2.3-55-g6feb From 4c650b92ab48b0f50b41f26fbc9e895f34a4fc53 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Thu, 28 Nov 2013 21:06:40 +0100 Subject: fixes permission checks on Windows with VirtualStore redirection --- src/luarocks/fs/win32.lua | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua index 0280b3f0..b6ea25e4 100644 --- a/src/luarocks/fs/win32.lua +++ b/src/luarocks/fs/win32.lua @@ -9,6 +9,15 @@ local cfg = require("luarocks.cfg") local dir = require("luarocks.dir") local util = require("luarocks.util") +-- Monkey patch io.popen and os.execute to make sure quoting +-- works as expected. +-- See http://lua-users.org/lists/lua-l/2013-11/msg00367.html +local _prefix = "type NUL && " +local _popen, _execute = io.popen, os.execute +io.popen = function(cmd, ...) return _popen(_prefix..cmd, ...) end +os.execute = function(cmd, ...) return _execute(_prefix..cmd, ...) end + + --- Annotate command string for quiet execution. -- @param cmd string: A command-line string. -- @return string: The command-line, with silencing annotation. @@ -173,3 +182,36 @@ function replace_file(old_file, new_file) return os.rename(new_file, old_file) end +--- Test is file/dir is writable. +-- Warning: testing if a file/dir is writable does not guarantee +-- that it will remain writable and therefore it is no replacement +-- for checking the result of subsequent operations. +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function is_writable(file) + assert(file) + file = dir.normalize(file) + local result + local tmpname = 'tmpluarockstestwritable.deleteme' + if fs.is_dir(file) then + local file2 = dir.path(file, tmpname) + local fh = io.open(file2, 'wb') + result = fh ~= nil + if fh then fh:close() end + if result then + -- the above test might give a false positive when writing to + -- c:\program files\ because of VirtualStore redirection on Vista and up + -- So get a directory listing and check whether it's really there + local pipe = io.popen("dir "..fs.Q(file)) + local dir_list = pipe:read("*a") + pipe:close() + result = (nil ~= string.find(dir_list, tmpname, 1, true)) + end + os.remove(file2) + else + local fh = io.open(file, 'r+b') + result = fh ~= nil + if fh then fh:close() end + end + return result +end -- cgit v1.2.3-55-g6feb From 45c234241dfb0789aa331e460b0d38f75981f0e9 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Thu, 28 Nov 2013 21:12:14 +0100 Subject: removed unintended code --- src/luarocks/fs/win32.lua | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua index b6ea25e4..6f7ba140 100644 --- a/src/luarocks/fs/win32.lua +++ b/src/luarocks/fs/win32.lua @@ -9,15 +9,6 @@ local cfg = require("luarocks.cfg") local dir = require("luarocks.dir") local util = require("luarocks.util") --- Monkey patch io.popen and os.execute to make sure quoting --- works as expected. --- See http://lua-users.org/lists/lua-l/2013-11/msg00367.html -local _prefix = "type NUL && " -local _popen, _execute = io.popen, os.execute -io.popen = function(cmd, ...) return _popen(_prefix..cmd, ...) end -os.execute = function(cmd, ...) return _execute(_prefix..cmd, ...) end - - --- Annotate command string for quiet execution. -- @param cmd string: A command-line string. -- @return string: The command-line, with silencing annotation. -- cgit v1.2.3-55-g6feb From aeed3edc86962fe21fb2b2553e91fadbec878a3d Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Fri, 29 Nov 2013 23:44:59 +0100 Subject: The installer will automatically request admin priviledges to allow proper installation in protected locations. A new switch /NOADMIN is added to explicitly prevent this, and allow installation in unprotected locations when the user doesn't have admin rights. --- install.bat | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/install.bat b/install.bat index a4257be6..26255502 100644 --- a/install.bat +++ b/install.bat @@ -27,6 +27,7 @@ local FORCE_CONFIG = false local INSTALL_LUA = false local USE_MINGW = false local REGISTRY = false +local NOADMIN = false --- -- Some helpers @@ -82,6 +83,12 @@ local function mkdir (dir) return exec([[.\bin\bin\mkdir -p "]]..dir..[[" >NUL]]) end +-- does the current user have admin priviledges ( = elevated) +local function permission() + return exec("net session >nul 2>&1") -- fails if not admin +end + + -- interpolate string with values from 'vars' table local function S (tmpl) return (tmpl:gsub('%$([%a_][%w_]*)', vars)) @@ -136,6 +143,11 @@ Other options: /F Remove installation directory if it already exists. /R Load registry information to register '.rockspec' extension with LuaRocks commands (right-click). +/NOADMIN The installer requires admin priviledges. If not + available it will elevate a new process. Use this + switch to prevent elevation, but make sure the + destination paths are all accessible for the current + user. ]]) end @@ -180,6 +192,8 @@ local function parse_options(args) FORCE = true elseif name == "/R" then REGISTRY = true + elseif name == "/NOADMIN" then + NOADMIN = true else die("Unrecognized option: " .. name) end @@ -427,6 +441,7 @@ local with_arg = { -- options followed by an argument, others are flags } -- reconstruct argument values with spaces and double quotes -- this will be damaged by the batch construction at the start of this file +local oarg = arg -- retain old table if #arg > 0 then farg = table.concat(arg, " ") .. " " arg = {} @@ -448,6 +463,9 @@ if #arg > 0 then while farg:sub(1,1) == " " do farg = farg:sub(2,-1) end -- remove prefix spaces end end +for k,v in pairs(oarg) do if k < 1 then arg[k] = v end end -- copy 0 and negative indexes +oarg = nil + local i = 1 while i <= #arg do @@ -470,6 +488,29 @@ print(S"LuaRocks $VERSION.x installer.\n") parse_options(config) check_flags() +if not permission() then + if not NOADMIN then + -- must elevate the process with admin priviledges + print("Need admin priviledges, now elevating a new process to continue installing...") + local runner = os.getenv("TEMP").."\\".."LuaRocks_Installer.bat" + local f = io.open(runner, "w") + f:write("@echo off\n") + f:write("CHDIR /D "..arg[0]:match("(.+)%\\.-$").."\n") -- return to current die, elevation changes current path + f:write('"'..arg[-1]..'" "'..table.concat(arg, '" "', 0)..'"\n') + f:write("ECHO Press any key to close this window...\n") + f:write("PAUSE > NUL\n") + f:close() + -- run the created temp batch file in elevated mode + exec("PowerShell -Command (New-Object -com 'Shell.Application').ShellExecute('"..runner.."', '', '', 'runas')\n") + print("Now exiting unpriviledged installer") + os.exit() -- exit here, the newly created elevated process will do the installing + else + print("Attempting to install without admin priviledges...") + end +else + print("Admin priviledges available for installing") +end + vars.FULL_PREFIX = S"$PREFIX\\$VERSION" vars.BINDIR = vars.FULL_PREFIX vars.LIBDIR = vars.FULL_PREFIX -- cgit v1.2.3-55-g6feb From 5d8a42b6667248e6c0fea881ffb9863d1374a68a Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Sun, 1 Dec 2013 09:06:50 +0100 Subject: simplified priviledge test on Windows --- src/luarocks/fs/win32.lua | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua index b6ea25e4..a3f0663b 100644 --- a/src/luarocks/fs/win32.lua +++ b/src/luarocks/fs/win32.lua @@ -201,11 +201,8 @@ function is_writable(file) if result then -- the above test might give a false positive when writing to -- c:\program files\ because of VirtualStore redirection on Vista and up - -- So get a directory listing and check whether it's really there - local pipe = io.popen("dir "..fs.Q(file)) - local dir_list = pipe:read("*a") - pipe:close() - result = (nil ~= string.find(dir_list, tmpname, 1, true)) + -- So check whether it's really there + result = fs.exists(file2) end os.remove(file2) else -- cgit v1.2.3-55-g6feb From 03cc9208fbeec8065365cbd5d5c124a327b47a4a Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Sun, 1 Dec 2013 10:02:57 +0100 Subject: refactored debug output. Now all is set by using `verbose = true` in the config file instead of manually uncommenting code. Also moved to platform independent code, from Windows only --- install.bat | 1 + src/luarocks/fs.lua | 45 ++++++++++++++++++++++++----------------- src/luarocks/fs/lua.lua | 4 ++-- src/luarocks/fs/win32/tools.lua | 16 ++------------- 4 files changed, 31 insertions(+), 35 deletions(-) diff --git a/install.bat b/install.bat index 26255502..22f72e13 100644 --- a/install.bat +++ b/install.bat @@ -709,6 +709,7 @@ rocks_trees = { end f:write(S" LUALIB = '$LUA_LIBNAME'\n") f:write("}\n") + f:write("verbose = false -- set to 'true' to enable verbose output\n") f:close() print(S"Created LuaRocks config file: $CONFIG_FILE") else diff --git a/src/luarocks/fs.lua b/src/luarocks/fs.lua index e002c7ba..2d799da2 100644 --- a/src/luarocks/fs.lua +++ b/src/luarocks/fs.lua @@ -11,6 +11,32 @@ module("luarocks.fs", package.seeall) local cfg = require("luarocks.cfg") +local pack = table.pack or function(...) return { n = select("#", ...), ... } end +local unpack = table.unpack or unpack + +if cfg.verbose then -- patch io.popen and os.execute to display commands in verbose mode + old_popen = io.popen + io.popen = function(one, two) + if two == nil then + print("\nio.popen: ", one) + else + print("\nio.popen: ", one, "Mode:", two) + end + return old_popen(one, two) + end + + old_exec = os.execute + os.execute = function(cmd) + print("\nos.execute: ", cmd) + local code = pack(old_exec(cmd)) + print("Results: "..tostring(code.n)) + for i = 1,code.n do + print(" "..tostring(i).." ("..type(code[i]).."): "..tostring(code[i])) + end + return unpack(code, 1, code.n) + end +end + local function load_fns(fs_table) for name, fn in pairs(fs_table) do if not _M[name] then @@ -38,22 +64,3 @@ load_fns(fs_lua) local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools") if ok and fs_plat_tools then load_fns(fs_plat_tools) end --- uncomment below for further debugging than 'verbose=true' in config file --- code below will also catch commands outside of fs.execute() --- especially uses of io.popen(). ---[[ -old_exec = os.execute -os.execute = function(cmd) - print("os.execute: ", cmd) - return old_exec(cmd) -end -old_popen = io.popen -io.popen = function(one, two) - if two == nil then - print("io.popen: ", one) - else - print("io.popen: ", one, "Mode:", two) - end - return old_popen(one, two) -end ---]] diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua index f9ec43ba..5f7d6c37 100644 --- a/src/luarocks/fs/lua.lua +++ b/src/luarocks/fs/lua.lua @@ -106,6 +106,7 @@ end --- Run the given command, quoting its arguments, silencing its output. -- The command is executed in the current directory in the dir stack. +-- Silencing is omitted if 'verbose' mode is enabled. -- @param command string: The command to be executed. No quoting/escaping -- is applied. -- @param ... Strings containing additional arguments, which will be quoted. @@ -113,7 +114,7 @@ end -- otherwise. function execute_quiet(command, ...) assert(type(command) == "string") - if cfg.verbose then + if cfg.verbose then -- omit silencing output return fs.execute_string(quote_args(command, ...)) else return fs.execute_string(fs.quiet(quote_args(command, ...))) @@ -150,7 +151,6 @@ if lfs_ok then -- @return boolean: true if command succeeds (status code 0), false -- otherwise. function execute_string(cmd) - if cfg.verbose then print("Executing: "..cmd) end local code = os.execute(cmd) return (code == 0 or code == true) end diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua index 1d302288..0ec46314 100644 --- a/src/luarocks/fs/win32/tools.lua +++ b/src/luarocks/fs/win32/tools.lua @@ -12,10 +12,6 @@ local dir_stack = {} local vars = cfg.variables -local function pack(...) - return { n = select("#", ...), ... } -end - --- Strip the last extension of a filename. -- Example: "foo.tar.gz" becomes "foo.tar". -- If filename has no dots, returns it unchanged. @@ -60,16 +56,8 @@ end -- otherwise. function execute_string(cmd) cmd = command_at(fs.current_dir(), cmd) - if cfg.verbose then print("Executing: "..tostring(cmd)) end - local code = pack(os.execute(cmd)) - if cfg.verbose then - print("Results: "..tostring(code.n)) - for i = 1,code.n do - print(" "..tostring(i).." ("..type(code[i]).."): "..tostring(code[i])) - end - print() - end - if code[1] == 0 or code[1] == true then + local code = os.execute(cmd) + if code == 0 or code == true then return true else return false -- cgit v1.2.3-55-g6feb From 948a07074fc9edb5d0cc822a141b9f29381c1a4b Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Sun, 1 Dec 2013 10:21:53 +0100 Subject: If PowerShell is not available, a proper message is now displayed when installing on Windows without admin priviledges --- install.bat | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/install.bat b/install.bat index 22f72e13..11558f7f 100644 --- a/install.bat +++ b/install.bat @@ -491,6 +491,10 @@ check_flags() if not permission() then if not NOADMIN then -- must elevate the process with admin priviledges + if not exec("PowerShell /? >NUL 2>&1") then + -- powershell is not available, so error out + die("No administrative priviledges detected and cannot auto-elevate. Please run with admin priviledges or use the /NOADMIN switch") + end print("Need admin priviledges, now elevating a new process to continue installing...") local runner = os.getenv("TEMP").."\\".."LuaRocks_Installer.bat" local f = io.open(runner, "w") -- cgit v1.2.3-55-g6feb From aeff1458076fdefccea990a6d62139084ee605e2 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Mon, 2 Dec 2013 09:35:57 +0100 Subject: Windows installer required /P argument to be first or would overwrite other values cleanup temp batch file in case of elevation --- install.bat | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/install.bat b/install.bat index 11558f7f..1e4763fc 100644 --- a/install.bat +++ b/install.bat @@ -6,8 +6,8 @@ local vars = {} vars.PREFIX = [[C:\LuaRocks]] vars.VERSION = "2.1" -vars.SYSCONFDIR = [[C:\LuaRocks]] -vars.ROCKS_TREE = [[C:\LuaRocks]] +vars.SYSCONFDIR = nil +vars.ROCKS_TREE = nil vars.SCRIPTS_DIR = nil vars.LUA_INTERPRETER = nil vars.LUA_PREFIX = nil @@ -163,8 +163,6 @@ local function parse_options(args) os.exit(0) elseif name == "/P" then vars.PREFIX = option.value - vars.SYSCONFDIR = option.value - vars.ROCKS_TREE = option.value P_SET = true elseif name == "/CONFIG" then vars.SYSCONFDIR = option.value @@ -425,7 +423,11 @@ local function look_for_lua_install () return false end ---- + +-- *********************************************************** +-- Installer script start +-- *********************************************************** + -- Poor man's command-line parsing local config = {} local with_arg = { -- options followed by an argument, others are flags @@ -466,7 +468,7 @@ end for k,v in pairs(oarg) do if k < 1 then arg[k] = v end end -- copy 0 and negative indexes oarg = nil - +-- build config option table with name and value elements local i = 1 while i <= #arg do local opt = arg[i] @@ -499,10 +501,11 @@ if not permission() then local runner = os.getenv("TEMP").."\\".."LuaRocks_Installer.bat" local f = io.open(runner, "w") f:write("@echo off\n") - f:write("CHDIR /D "..arg[0]:match("(.+)%\\.-$").."\n") -- return to current die, elevation changes current path + f:write("CHDIR /D "..arg[0]:match("(.+)%\\.-$").."\n") -- return to current dir, elevation changes current path f:write('"'..arg[-1]..'" "'..table.concat(arg, '" "', 0)..'"\n') f:write("ECHO Press any key to close this window...\n") f:write("PAUSE > NUL\n") + f:write('DEL "'..runner..'"') -- temp batch file deletes itself f:close() -- run the created temp batch file in elevated mode exec("PowerShell -Command (New-Object -com 'Shell.Application').ShellExecute('"..runner.."', '', '', 'runas')\n") @@ -515,6 +518,8 @@ else print("Admin priviledges available for installing") end +vars.SYSCONFDIR = vars.SYSCONFDIR or vars.PREFIX +vars.ROCKS_TREE = vars.ROCKS_TREE or vars.PREFIX vars.FULL_PREFIX = S"$PREFIX\\$VERSION" vars.BINDIR = vars.FULL_PREFIX vars.LIBDIR = vars.FULL_PREFIX @@ -644,8 +649,13 @@ else end +-- *********************************************************** +-- Configure LuaRocks +-- *********************************************************** + print() print("Configuring LuaRocks...") + -- Create a site-config file if exists(S[[$LUADIR\luarocks\site_config.lua]]) then exec(S[[RENAME "$LUADIR\luarocks\site_config.lua" site_config.lua.bak]]) -- cgit v1.2.3-55-g6feb From 52b6e37e53c7f99134f3b2aa9c07595221c1f7b2 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Mon, 2 Dec 2013 14:09:35 +0100 Subject: Commandline options where silently ignored if config.lua already existed. Now a backup is made and the options are written. Additional paths to the local tree are now listed after installing --- install.bat | 98 ++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 34 deletions(-) diff --git a/install.bat b/install.bat index 1e4763fc..8373f856 100644 --- a/install.bat +++ b/install.bat @@ -88,6 +88,19 @@ local function permission() return exec("net session >nul 2>&1") -- fails if not admin end +-- rename file (full path) to backup (name only), appending number if required +-- returns the new name (name only) +local function backup(filename, backupname) + local path = filename:match("(.+)%\\.-$").."\\" + local nname = backupname + local i = 0 + while exists(path..nname) do + i = i + 1 + nname = backupname..tostring(i) + end + exec([[REN "]]..filename..[[" "]]..nname..[[" > NUL]]) + return nname +end -- interpolate string with values from 'vars' table local function S (tmpl) @@ -699,51 +712,56 @@ vars.CONFIG_FILE = vars.SYSCONFDIR.."\\config.lua" if not exists(vars.SYSCONFDIR) then mkdir(vars.SYSCONFDIR) end -if not exists(vars.CONFIG_FILE) then - local f = io.open(vars.CONFIG_FILE, "w") - f:write([=[ +if exists(vars.CONFIG_FILE) then + local nname = backup(vars.CONFIG_FILE, "config.bak") + print("***************") + print(S"*** WARNING *** LuaRocks config file already exists: '$CONFIG_FILE'. The old file has been renamed to '"..nname.."'") + print("***************") +end +local f = io.open(vars.CONFIG_FILE, "w") +f:write([=[ rocks_servers = { [[http://luarocks.org/repositories/rocks]] } rocks_trees = { ]=]) - if FORCE_CONFIG then - f:write(" home..[[/luarocks]],\n") - end - f:write(S" [[$ROCKS_TREE]]\n") - f:write("}\n") - if vars.SCRIPTS_DIR then - f:write(S"scripts_dir=[[$SCRIPTS_DIR]]\n") - end - f:write("variables = {\n") - if USE_MINGW and vars.LUA_RUNTIME == "MSVCRT" then - f:write(" MSVCRT = 'm', -- make MinGW use MSVCRT.DLL as runtime\n") - else - f:write(" MSVCRT = '"..vars.LUA_RUNTIME.."',\n") - end - f:write(S" LUALIB = '$LUA_LIBNAME'\n") - f:write("}\n") - f:write("verbose = false -- set to 'true' to enable verbose output\n") - f:close() - print(S"Created LuaRocks config file: $CONFIG_FILE") +if FORCE_CONFIG then + f:write(" home..[[/luarocks]],\n") +end +f:write(S" [[$ROCKS_TREE]]\n") +f:write("}\n") +if vars.SCRIPTS_DIR then + f:write(S"scripts_dir=[[$SCRIPTS_DIR]]\n") +end +f:write("variables = {\n") +if USE_MINGW and vars.LUA_RUNTIME == "MSVCRT" then + f:write(" MSVCRT = 'm', -- make MinGW use MSVCRT.DLL as runtime\n") else - print(S"LuaRocks config file already exists: $CONFIG_FILE") + f:write(" MSVCRT = '"..vars.LUA_RUNTIME.."',\n") end +f:write(S" LUALIB = '$LUA_LIBNAME'\n") +f:write("}\n") +f:write("verbose = false -- set to 'true' to enable verbose output\n") +f:close() + +print(S"Created LuaRocks config file: $CONFIG_FILE") + print() print("Creating rocktrees...") if not exists(vars.ROCKS_TREE) then mkdir(vars.ROCKS_TREE) - print(S[[Created rocktree: "$ROCKS_TREE"]]) + print(S[[Created system rocktree : "$ROCKS_TREE"]]) else - print(S[[Rocktree exists: "$ROCKS_TREE"]]) + print(S[[System rocktree exists : "$ROCKS_TREE"]]) end -local APPDATA = os.getenv("APPDATA") -if not exists(APPDATA.."\\luarocks") then - mkdir(APPDATA.."\\luarocks") - print([[Created rocktree: "]]..APPDATA..[[\luarocks"]]) + +vars.LOCAL_TREE = os.getenv("APPDATA")..[[\LuaRocks]] +if not exists(vars.LOCAL_TREE) then + mkdir(vars.LOCAL_TREE) + print(S[[Created local user rocktree: "$LOCAL_TREE"]]) else - print([[Rocktree exists: "]]..APPDATA..[[\luarocks"]]) + print(S[[Local user rocktree exists : "$LOCAL_TREE"]]) end -- Load registry information @@ -768,12 +786,24 @@ exec( S[[del "$FULL_PREFIX\pe-parser.lua" > nul]] ) -- *********************************************************** print(S[[ + *** LuaRocks is installed! *** - You may want to add the following elements to your paths; -PATH : $LUA_BINDIR;$FULL_PREFIX -LUA_PATH : $ROCKS_TREE\share\lua\$LUA_VERSION\?.lua;$ROCKS_TREE\share\lua\$LUA_VERSION\?\init.lua -LUA_CPATH: $ROCKS_TREE\lib\lua\$LUA_VERSION\?.dll +You may want to add the following elements to your paths; +Lua interpreter; + PATH : $LUA_BINDIR + PATHEXT : .LUA +LuaRocks; + PATH : $FULL_PREFIX + LUA_PATH : $FULL_PREFIX\lua\?.lua;$FULL_PREFIX\lua\?\init.lua +Local user rocktree (Note: %APPDATA% is user dependent); + PATH : %APPDATA%\LuaRock\bin + LUA_PATH : %APPDATA%\LuaRocks\share\lua\$LUA_VERSION\?.lua;%APPDATA%\LuaRocks\share\lua\$LUA_VERSION\?\init.lua + LUA_CPATH: %APPDATA%\LuaRocks\lib\lua\$LUA_VERSION\?.dll +System rocktree + PATH : $ROCKS_TREE\bin + LUA_PATH : $ROCKS_TREE\share\lua\$LUA_VERSION\?.lua;$ROCKS_TREE\share\lua\$LUA_VERSION\?\init.lua + LUA_CPATH: $ROCKS_TREE\lib\lua\$LUA_VERSION\?.dll ]]) os.exit(0) -- cgit v1.2.3-55-g6feb From 716a8a5b44baebe1ec057410046fb467dc920c83 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Tue, 3 Dec 2013 14:45:56 +0100 Subject: bugfix: unquoted path --- install.bat | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install.bat b/install.bat index 8373f856..43a2b34f 100644 --- a/install.bat +++ b/install.bat @@ -401,7 +401,7 @@ local function look_for_lua_install () then if get_runtime() then print("Runtime check completed, now testing interpreter...") - if exec(S[[$LUA_BINDIR\$LUA_INTERPRETER -v 2>NUL]]) then + if exec(S[["$LUA_BINDIR\$LUA_INTERPRETER" -v 2>NUL]]) then print(" Ok") return true end @@ -422,7 +422,7 @@ local function look_for_lua_install () print("Headers found, checking runtime to use...") if get_runtime() then print("Runtime check completed, now testing interpreter...") - if exec(S[[$LUA_BINDIR\$LUA_INTERPRETER -v 2>NUL]]) then + if exec(S[["$LUA_BINDIR\$LUA_INTERPRETER" -v 2>NUL]]) then print(" Ok") return true end @@ -797,7 +797,7 @@ LuaRocks; PATH : $FULL_PREFIX LUA_PATH : $FULL_PREFIX\lua\?.lua;$FULL_PREFIX\lua\?\init.lua Local user rocktree (Note: %APPDATA% is user dependent); - PATH : %APPDATA%\LuaRock\bin + PATH : %APPDATA%\LuaRocks\bin LUA_PATH : %APPDATA%\LuaRocks\share\lua\$LUA_VERSION\?.lua;%APPDATA%\LuaRocks\share\lua\$LUA_VERSION\?\init.lua LUA_CPATH: %APPDATA%\LuaRocks\lib\lua\$LUA_VERSION\?.dll System rocktree -- cgit v1.2.3-55-g6feb