New Upstream Release - luarocks

Ready changes

Summary

Merged new upstream version: 3.9.2+dfsg1 (was: 3.8.0+dfsg1).

Resulting package

Built on 2023-02-25T15:48 (took 3m45s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases luarocks

Lintian Result

Diff

diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 85b3c46..0000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-name: Bugs
-about: Bugs and unintented behaviour
-labels: 'bug'
-
----
-
-### Please read the following before submitting:
-- Please do NOT submit bug reports for questions. Ask questions in the [Gitter
-  chat-room](https://gitter.im/luarocks/luarocks).
-- Please do NOT submit duplicate bug reports. Look through the [issue
-  tracker](https://github.com/luarocks/luarocks/issues) before submitting.
-
-### Please fill out the following:
-- **Platform:**
-  - Windows/Linux/MacOS.
-
-- **LuaRocks version:**
-  - `luarocks --version`
-
-- **Configuration file:**
-  - Please try to produce with the default configuration.
-  - If you cannot reproduce with the default configuration, please try to find
-    the minimal configuration to reproduce.
-  - Upload the config to a pastebin such as gist.github.com.
-
-- **LuaRocks output from when the issue occurred:**
-  - Use the `--verbose` flag.
-
-- **Description:**
-  - The steps you took in plain English to reproduce the problem.
diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md
deleted file mode 100644
index fb03b0f..0000000
--- a/.github/ISSUE_TEMPLATE/enhancement.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-name: Enhancements
-about: New functionality
-labels: 'enhancement'
-
----
-
-### Please fill out the following:
-- **Description:**
-  - Please describe in plain English what the enhancement is and what the use case
-    is.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cf18a00..2748fe6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,58 @@
+## What's new in LuaRocks 3.9.1
+
+* Fixed error message when Lua library is not found
+* Fixed build of Windows binary
+* A couple of minor feature additions:
+  * API: `loader.which` has a new mode for searching `package.path/cpath`
+    * Adds a new second argument, `where`, a string which indicates places
+      to search for the module. If `where` contains `"l"`, it will search
+      using the LuaRocks loader; if it contains `"p"`, it will look in the
+      filesystem using `package.path` and `package.cpath`. You can use both
+      at the same time.
+  * `--no-project` flag can be used to override `.luarocks` project directory
+    detection
+
+## What's new in LuaRocks 3.9.0
+
+* `builtin` build mode now always respects CC, CFLAGS and LDFLAGS
+* Check that lua.h version matches the desired Lua version
+* Check that the version of the Lua C library matches the desired Lua version
+* Fixed deployment of non-wrapped binaries
+* Fixed crash when `--lua-version` option is malformed
+* Fixed help message for `--pin` option
+* Unix: use native methods and don't always rely on $USER to determine user
+* Windows: use native CLI tooling more
+* macOS: support .tbd extension when checking for libraries
+* macOS: add XCode SDK path to search paths
+* macOS: add best-effort heuristic for library search using Homebrew paths
+* macOS: avoid quoting issues with LIBFLAG
+* macOS: deployment target is now 11.0 on macOS 11+
+* added DragonFly BSD support
+* LuaRocks test suite now runs on Lua 5.4 and LuaJIT
+* Internal dependencies of standalone LuaRocks executable were bumped
+
+## What's new in LuaRocks 3.8.0
+
+* Support GitHub's protocol security changes transparently.
+  * The raw git:// protocol will stop working on GitHub. LuaRocks already
+    supports git+https:// as an alternative, but to avoid having to update
+    every rockspec in the repository that uses git://github.com, which would
+    require a large coordinated effort, LuaRocks now auto-converts github.com
+    and www.github.com URLs that use git:// to git+https://
+* `luarocks test` has a new flag `--prepare` that checks, downloads and
+  installs the tool requirements and rockspec dependencies but does not
+  run the test suite for the rockspec being tested.
+* Code tweaks so that LuaRocks can run on a Lua interpreter built without
+  the `debug` library.
+* `luarocks upload` supports uploading pre-packaged `.src.rock` files.
+* Configuration fixes for OpenBSD.
+* Respect the existing value for the `variables.LUALIB` configuration
+  variable if given explicitly by the user in the config file, rather
+  than trying to override it with auto-detection.
+* Windows fixes for setting file permissions:
+  * Revert the use of `Everyone` back to `*S-1-1-0`
+  * Quote the use of the `%USERNAME%` variable to support names with spaces
+
 ## What's new in LuaRocks 3.7.0
 
 * Improved connectivity resiliency
diff --git a/COPYING b/COPYING
index ad12fa1..1d1ed74 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,5 @@
-Copyright 2007-2018 Kepler Project.
+Copyright 2007-2011, Kepler Project.
+Copyright 2011-2022, the LuaRocks project authors.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/GNUmakefile b/GNUmakefile
index f4a6015..cbb4799 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -14,9 +14,10 @@ luadir = $(datarootdir)/lua/$(LUA_VERSION)
 builddir = ./build
 buildbinarydir = ./build-binary
 
-
 LUAROCKS_FILES = $(shell find src/luarocks/ -type f -name '*.lua')
 
+LUA_ENV_VARS = LUA_PATH LUA_PATH_5_2 LUA_PATH_5_3 LUA_PATH_5_4 LUA_CPATH LUA_CPATH_5_2 LUA_CPATH_5_3 LUA_CPATH_5_4
+
 all: build
 
 # ----------------------------------------
@@ -51,7 +52,7 @@ luarocks: config.unix $(builddir)/config-$(LUA_VERSION).lua
 	cp $(builddir)/config-$(LUA_VERSION).lua .luarocks/config-$(LUA_VERSION).lua
 	rm -f src/luarocks/core/hardcoded.lua
 	echo "#!/bin/sh" > luarocks
-	echo "unset LUA_PATH LUA_PATH_5_2 LUA_PATH_5_3 LUA_PATH_5_4 LUA_CPATH LUA_CPATH_5_2 LUA_CPATH_5_3 LUA_CPATH_5_4" >> luarocks
+	echo "unset $(LUA_ENV_VARS)" >> luarocks
 	echo 'LUAROCKS_SYSCONFDIR="$(luarocksconfdir)" LUA_PATH="$(CURDIR)/src/?.lua;;" exec "$(LUA)" "$(CURDIR)/src/bin/luarocks" --project-tree="$(CURDIR)/lua_modules" "$$@"' >> luarocks
 	chmod +rx ./luarocks
 	./luarocks init
@@ -59,7 +60,7 @@ luarocks: config.unix $(builddir)/config-$(LUA_VERSION).lua
 luarocks-admin: config.unix
 	rm -f src/luarocks/core/hardcoded.lua
 	echo "#!/bin/sh" > luarocks-admin
-	echo "unset LUA_PATH LUA_PATH_5_2 LUA_PATH_5_3 LUA_PATH_5_4 LUA_CPATH LUA_CPATH_5_2 LUA_CPATH_5_3 LUA_CPATH_5_4" >> luarocks-admin
+	echo "unset $(LUA_ENV_VARS)" >> luarocks-admin
 	echo 'LUAROCKS_SYSCONFDIR="$(luarocksconfdir)" LUA_PATH="$(CURDIR)/src/?.lua;;" exec "$(LUA)" "$(CURDIR)/src/bin/luarocks-admin" --project-tree="$(CURDIR)/lua_modules" "$$@"' >> luarocks-admin
 	chmod +rx ./luarocks-admin
 
diff --git a/README.md b/README.md
index ce8dc29..4a74822 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,8 @@
 
 A package manager for Lua modules.
 
-[![Build Status](https://travis-ci.com/luarocks/luarocks.svg?branch=master)](https://travis-ci.com/luarocks/luarocks)
+[![Build Status](https://github.com/luarocks/luarocks/actions/workflows/test.yml/badge.svg)](https://github.com/luarocks/luarocks/actions)
+[![Luacheck](https://github.com/luarocks/luarocks/actions/workflows/luacheck.yml/badge.svg)](https://github.com/luarocks/luarocks/actions/workflows/luacheck.yml)
 [![Build Status](https://ci.appveyor.com/api/projects/status/4x4630tcf64da48i/branch/master?svg=true)](https://ci.appveyor.com/project/hishamhm/luarocks/branch/master)
 [![Coverage Status](https://codecov.io/gh/luarocks/luarocks/coverage.svg?branch=master)](https://codecov.io/gh/luarocks/luarocks/branch/master)
 [![Join the chat at https://gitter.im/luarocks/luarocks](https://badges.gitter.im/luarocks/luarocks.svg)](https://gitter.im/luarocks/luarocks)
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..de2b983
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,21 @@
+# Security Policy
+
+## Supported Versions
+
+The LuaRocks project supports the _latest version_ of the tool
+for bugfixes and security updates. In other words, if an
+issue is reported and we produce a fix, it will appear in a subsequent
+patch version (x.y.Z) of the tool, but we do not backport fixes
+to previous minor (x.Y.z) or major (X.y.z) versions.
+
+## Reporting a Vulnerability
+
+To report a vulnerability on the LuaRocks CLI tool, email 
+Hisham Muhammad at hisham@luarocks.org.
+
+To report a vulnerability on the https://luarocks.org website,
+email Leaf Corcoran at leafot@gmail.com.
+
+We will acknowledge your contact as soon as the message is
+received, then assess the vulnerability and get back to you
+with further feedback once analysis on our end is done.
diff --git a/configure b/configure
index 09cb27a..a8bf880 100755
--- a/configure
+++ b/configure
@@ -320,7 +320,7 @@ do
 done
 
 echo
-BLUE "Configuring LuaRocks version 3.8.0..."
+BLUE "Configuring LuaRocks version 3.9.2..."
 echo
 echo
 
diff --git a/debian/changelog b/debian/changelog
index 068a0b8..cae654c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+luarocks (3.9.2+dfsg1-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sat, 25 Feb 2023 15:45:36 -0000
+
 luarocks (3.8.0+dfsg1-1) unstable; urgency=medium
 
   * New upstream version 3.8.0+dfsg1
diff --git a/luarocks-3.8.0-1.rockspec b/luarocks-3.9.2-1.rockspec
similarity index 77%
rename from luarocks-3.8.0-1.rockspec
rename to luarocks-3.9.2-1.rockspec
index 9cedd54..c4fe644 100644
--- a/luarocks-3.8.0-1.rockspec
+++ b/luarocks-3.9.2-1.rockspec
@@ -1,9 +1,9 @@
 rockspec_format = "3.0"
 package = "luarocks"
-version = "3.8.0-1"
+version = "3.9.2-1"
 source = {
    url = "git+https://github.com/luarocks/luarocks",
-   tag = "v3.8.0"
+   tag = "v3.9.2"
 }
 description = {
    summary = "A package manager for Lua modules.",
@@ -14,7 +14,7 @@ description = {
       so that when one rock is requested all rocks it depends on are
       installed as well, and at run time, so that when a module is
       required, the correct version is loaded. LuaRocks supports both
-      local and remote repositories, and multiple local rocks trees. 
+      local and remote repositories, and multiple local rocks trees.
    ]],
    homepage = "http://www.luarocks.org",
    issues_url = "https://github.com/luarocks/luarocks/issues",
@@ -29,10 +29,10 @@ test = {
    type = "busted",
    platforms = {
       windows = {
-         flags = { "--exclude-tags=ssh,git,unix" }
+         flags = { "--exclude-tags=ssh,git,unix", "-Xhelper", "lua_dir=$(LUA_DIR)", "-Xhelper", "lua_interpreter=$(LUA)" }
       },
       unix = {
-         flags = { "--exclude-tags=ssh,git" }
+         flags = { "--exclude-tags=ssh,git", "-Xhelper", "lua_dir=$(LUA_DIR)", "-Xhelper", "lua_interpreter=$(LUA)" }
       }
    }
 }
diff --git a/spec/README.md b/spec/README.md
index 46372b1..b55550e 100644
--- a/spec/README.md
+++ b/spec/README.md
@@ -3,14 +3,14 @@
 
 ## Overview
 
-Test suite for LuaRocks project with Busted unit testing framework(http://olivinelabs.com/busted/). 
+Test suite for LuaRocks project with Busted unit testing framework(http://olivinelabs.com/busted/).
 
 * Contains unit & integration tests
 * Easy setup for your purpose on command line or from configuration file
 
 ## Dependencies
 
-* Lua >= 5.1 
+* Lua >= 5.1
 * Busted with dependencies
 
 ## Usage
@@ -26,8 +26,8 @@ LuaRocks folder or specify with *-C* flag.
 env=<type>,       (default:"minimal") type what kind of environment to use ["minimal", "full"]
 noreset,          Don't reset environment after each test
 clean,            remove existing testing environment
-appveyor,         add just if running on TravisCI
-travis,           add just if running on TravisCI
+appveyor,         add just if running on Appveyor
+ci,               add just if running on Unix CI
 os=<version>,     type your OS ["linux", "os x", "windows"]
 ```
 ---------------------------------------------------------------------------------------------
diff --git a/spec/add_spec.lua b/spec/add_spec.lua
index ea6274b..b17cada 100644
--- a/spec/add_spec.lua
+++ b/spec/add_spec.lua
@@ -5,8 +5,8 @@ local testing_paths = test_env.testing_paths
 test_env.unload_luarocks()
 
 local extra_rocks = {
-   "/luasocket-3.0rc1-2.src.rock",
-   "/luasocket-3.0rc1-2.rockspec"
+   "/luasocket-${LUASOCKET}.src.rock",
+   "/luasocket-${LUASOCKET}.rockspec"
 }
 
 describe("LuaRocks add tests #integration", function()
@@ -25,20 +25,20 @@ describe("LuaRocks add tests #integration", function()
       end)
 
       it("invalid server", function()
-         assert.is_false(run.luarocks_admin_bool("--server=invalid add " .. testing_paths.testing_server .. "/luasocket-3.0rc1-2.src.rock"))
+         assert.is_false(run.luarocks_admin_bool("--server=invalid add " .. testing_paths.testing_server .. "/luasocket-${LUASOCKET}.src.rock"))
       end)
 
       it("invalid server #ssh", function()
-         assert.is_true(run.luarocks_admin_bool("--server=testing add " .. testing_paths.testing_server .. "/luasocket-3.0rc1-2.src.rock"))
+         assert.is_true(run.luarocks_admin_bool("--server=testing add " .. testing_paths.testing_server .. "/luasocket-${LUASOCKET}.src.rock"))
       end)
 
       --TODO This test fails, sftp support not yet implemented
       it("invalid server", function()
-         assert.is_false(run.luarocks_admin_bool("--server=testing add luasocket-3.0rc1-2.src.rock", { LUAROCKS_CONFIG = testing_paths.testrun_dir .. "/testing_config_sftp.lua" } ))
+         assert.is_false(run.luarocks_admin_bool("--server=testing add luasocket-${LUASOCKET}.src.rock", { LUAROCKS_CONFIG = testing_paths.testrun_dir .. "/testing_config_sftp.lua" } ))
       end)
 
       it("split server url", function()
-         assert.is_false(run.luarocks_admin_bool("--server=\"localhost@/tmp/luarocks_testing\" add " .. testing_paths.testing_server .. "/luasocket-3.0rc1-2.src.rock"))
+         assert.is_false(run.luarocks_admin_bool("--server=\"localhost@/tmp/luarocks_testing\" add " .. testing_paths.testing_server .. "/luasocket-${LUASOCKET}.src.rock"))
       end)
    end)
 end)
diff --git a/spec/build_spec.lua b/spec/build_spec.lua
index b78d3ff..653f216 100644
--- a/spec/build_spec.lua
+++ b/spec/build_spec.lua
@@ -19,11 +19,9 @@ local extra_rocks = {
    "/lmathx-20150505-1.rockspec",
    "/lpeg-1.0.0-1.rockspec",
    "/lpeg-1.0.0-1.src.rock",
-   "/luafilesystem-1.6.3-1.src.rock",
-   "/luasocket-3.0rc1-2.src.rock",
-   "/luasocket-3.0rc1-2.rockspec",
-   "/stdlib-41.0.0-1.src.rock",
-   "/validate-args-1.5.4-1.rockspec",
+   "/luafilesystem-${LUAFILESYSTEM}.src.rock",
+   "/luasocket-${LUASOCKET}.src.rock",
+   "/luasocket-${LUASOCKET}.rockspec",
    "spec/fixtures/a_rock-1.0-1.src.rock",
    "/busted-2.0.0-1.rockspec",
    "/busted-2.0.rc13-0.rockspec",
@@ -138,13 +136,8 @@ describe("LuaRocks build #integration", function()
 
    describe("basic builds", function()
       it("luacov diff version", function()
-         assert.is_true(run.luarocks_bool("build luacov 0.15.0-1"))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/luacov/0.15.0-1/luacov-0.15.0-1.rockspec"))
-      end)
-
-      it("command stdlib", function()
-         assert.is_true(run.luarocks_bool("build stdlib"))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/stdlib/41.0.0-1/stdlib-41.0.0-1.rockspec"))
+         assert.is_true(run.luarocks_bool("build luacov ${LUACOV}"))
+         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/luacov/${LUACOV}/luacov-${LUACOV}.rockspec"))
       end)
 
       it("fails if the current platform is not supported", function()
@@ -274,13 +267,14 @@ describe("LuaRocks build #integration", function()
       end)
 
       it("lmathx deps partial match", function()
-         assert.is_true(run.luarocks_bool("build lmathx"))
-
          if test_env.LUA_V == "5.1" or test_env.LUAJIT_V then
+            assert.is_true(run.luarocks_bool("build lmathx"))
             assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lmathx/20120430.51-1/lmathx-20120430.51-1.rockspec"))
          elseif test_env.LUA_V == "5.2" then
+            assert.is_true(run.luarocks_bool("build lmathx"))
             assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lmathx/20120430.52-1/lmathx-20120430.52-1.rockspec"))
          elseif test_env.LUA_V == "5.3" then
+            assert.is_true(run.luarocks_bool("build lmathx"))
             assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lmathx/20150505-1/lmathx-20150505-1.rockspec"))
          end
       end)
diff --git a/spec/cmd_spec.lua b/spec/cmd_spec.lua
index d28acdf..fe27ab1 100644
--- a/spec/cmd_spec.lua
+++ b/spec/cmd_spec.lua
@@ -53,6 +53,11 @@ describe("LuaRocks command line #integration", function()
    end)
 
    describe("--lua-version", function()
+      it("fails if given something that is not a number", function()
+         local output = run.luarocks("--lua-version=bozo")
+         assert.match("malformed", output, 1, true)
+      end)
+
       it("warns but continues if given an invalid version", function()
          local output = run.luarocks("--lua-version=1.0")
          assert.match("Warning: Lua 1.0 interpreter not found", output, 1, true)
diff --git a/spec/deps_spec.lua b/spec/deps_spec.lua
index 35fd8be..b006429 100644
--- a/spec/deps_spec.lua
+++ b/spec/deps_spec.lua
@@ -6,11 +6,11 @@ local testing_paths = test_env.testing_paths
 test_env.unload_luarocks()
 
 local extra_rocks = {
-   "/lxsh-0.8.6-2.src.rock",
-   "/lxsh-0.8.6-2.rockspec",
-   "/luasocket-3.0rc1-2.src.rock",
-   "/luasocket-3.0rc1-2.rockspec",
-   "/lpeg-1.0.0-1.src.rock",
+   "/lxsh-${LXSH}.src.rock",
+   "/lxsh-${LXSH}.rockspec",
+   "/luasocket-${LUASOCKET}.src.rock",
+   "/luasocket-${LUASOCKET}.rockspec",
+   "/lpeg-${LPEG}.src.rock",
 }
 
 describe("LuaRocks deps-mode #integration", function()
@@ -23,92 +23,96 @@ describe("LuaRocks deps-mode #integration", function()
       assert.is_true(run.luarocks_bool("build --tree=system lpeg"))
       assert.is_true(run.luarocks_bool("build --deps-mode=one --tree=" .. testing_paths.testing_tree .. " lxsh"))
 
-      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
    end)
 
    it("order", function()
       assert.is_true(run.luarocks_bool("build --tree=system lpeg"))
       assert.is_true(run.luarocks_bool("build --deps-mode=order --tree=" .. testing_paths.testing_tree .. " lxsh"))
 
-      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
    end)
 
    it("order sys", function()
       assert.is_true(run.luarocks_bool("build --tree=" .. testing_paths.testing_tree .. " lpeg"))
       assert.is_true(run.luarocks_bool("build --deps-mode=order --tree=" .. testing_paths.testing_sys_tree .. " lxsh"))
 
-      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
    end)
 
    it("all sys", function()
       assert.is_true(run.luarocks_bool("build --tree=" .. testing_paths.testing_tree .. " lpeg"))
       assert.is_true(run.luarocks_bool("build --deps-mode=all --tree=" .. testing_paths.testing_sys_tree .. " lxsh"))
 
-      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
    end)
 
    it("none", function()
       assert.is_true(run.luarocks_bool("build --tree=" .. testing_paths.testing_tree .. " lpeg"))
       assert.is_true(run.luarocks_bool("build --deps-mode=none lxsh"))
 
-      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
    end)
 
    it("LuaRocks nodeps alias", function()
       assert.is_true(run.luarocks_bool("build --tree=" .. testing_paths.testing_tree .. " --nodeps lxsh"))
 
-      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
    end)
 
    it("make order", function()
       assert.is_true(run.luarocks_bool("build --tree=" .. testing_paths.testing_sys_tree .. " lpeg"))
-      assert.is_true(run.luarocks_bool("download --source lxsh 0.8.6"))
-      assert.is_true(run.luarocks_bool("unpack lxsh-0.8.6-2.src.rock"))
-      lfs.chdir("lxsh-0.8.6-2/lxsh-0.8.6-1/")
+      assert.is_true(run.luarocks_bool("download --source lxsh ${LXSH_V}"))
+      assert.is_true(run.luarocks_bool("unpack lxsh-${LXSH}.src.rock"))
+      lfs.chdir("lxsh-${LXSH}/lxsh-${LXSH_V}-1/")
       assert.is_true(run.luarocks_bool("make --tree=" .. testing_paths.testing_tree .. " --deps-mode=order"))
 
-      lfs.chdir(testing_paths.testrun_dir)
-      test_env.remove_dir("lxsh-0.8.6-2")
-      assert.is_true(os.remove("lxsh-0.8.6-2.src.rock"))
+      finally(function()
+         lfs.chdir(testing_paths.testrun_dir)
+         test_env.remove_dir("lxsh-${LXSH}")
+         assert.is_true(os.remove("lxsh-${LXSH}.src.rock"))
+      end)
 
-      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
    end)
 
    it("make order sys", function()
       assert.is_true(run.luarocks_bool("build --tree=" .. testing_paths.testing_tree .. " lpeg"))
-      assert.is_true(run.luarocks_bool("download --source lxsh 0.8.6"))
-      assert.is_true(run.luarocks_bool("unpack lxsh-0.8.6-2.src.rock"))
-      lfs.chdir("lxsh-0.8.6-2/lxsh-0.8.6-1/")
+      assert.is_true(run.luarocks_bool("download --source lxsh ${LXSH_V}"))
+      assert.is_true(run.luarocks_bool("unpack lxsh-${LXSH}.src.rock"))
+      lfs.chdir("lxsh-${LXSH}/lxsh-${LXSH_V}-1/")
       assert.is_true(run.luarocks_bool("make --tree=" .. testing_paths.testing_sys_tree .. " --deps-mode=order"))
 
-      lfs.chdir(testing_paths.testrun_dir)
-      test_env.remove_dir("lxsh-0.8.6-2")
-      assert.is_true(os.remove("lxsh-0.8.6-2.src.rock"))
+      finally(function()
+         lfs.chdir(testing_paths.testrun_dir)
+         test_env.remove_dir("lxsh-${LXSH}")
+         assert.is_true(os.remove("lxsh-${LXSH}.src.rock"))
+      end)
 
-      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/1.0.0-1/lpeg-1.0.0-1.rockspec"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lpeg/${LPEG}/lpeg-${LPEG}.rockspec"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
    end)
 end)
diff --git a/spec/download_spec.lua b/spec/download_spec.lua
index 823e154..66b12d6 100644
--- a/spec/download_spec.lua
+++ b/spec/download_spec.lua
@@ -6,7 +6,7 @@ local testing_paths = test_env.testing_paths
 test_env.unload_luarocks()
 
 local extra_rocks = {
-   "/validate-args-1.5.4-1.rockspec"
+   "/say-1.3-1.rockspec",
 }
 
 describe("luarocks download #integration", function()
@@ -24,15 +24,15 @@ describe("luarocks download #integration", function()
    end)
 
    it("all with delete downloaded files", function() --TODO maybe download --all more rocks
-      assert.is_true(run.luarocks_bool("download --all validate-args"))
-      assert.is.truthy(lfs.attributes("validate-args-1.5.4-1.rockspec"))
-      test_env.remove_files(lfs.currentdir(), "validate--args--")
+      assert.is_true(run.luarocks_bool("download --all say"))
+      assert.is.truthy(lfs.attributes("say-1.3-1.rockspec"))
+      test_env.remove_files(lfs.currentdir(), "say--")
    end)
 
    it("rockspec version", function()
-      assert.is_true(run.luarocks_bool("download --rockspec validate-args 1.5.4-1"))
-      assert.is.truthy(lfs.attributes("validate-args-1.5.4-1.rockspec"))
-      test_env.remove_files(lfs.currentdir(), "validate--args--")
+      assert.is_true(run.luarocks_bool("download --rockspec say 1.3-1"))
+      assert.is.truthy(lfs.attributes("say-1.3-1.rockspec"))
+      test_env.remove_files(lfs.currentdir(), "say--")
    end)
 
    describe("#namespaces", function()
diff --git a/spec/fetch_spec.lua b/spec/fetch_spec.lua
index 008a91c..046d7b7 100644
--- a/spec/fetch_spec.lua
+++ b/spec/fetch_spec.lua
@@ -39,7 +39,8 @@ describe("luarocks fetch #unit #mock", function()
    describe("fetch.fetch_url", function()
 
       it("fetches the url argument and returns the absolute path of the fetched file", function()
-         local fetchedfile = fetch.fetch_url("http://localhost:8080/file/a_rock.lua")
+         local fetchedfile, err = fetch.fetch_url("http://localhost:8080/file/a_rock.lua")
+         assert(fetchedfile, err)
          assert.truthy(are_same_files(fetchedfile, lfs.currentdir() .. "/a_rock.lua"))
          local fd = assert(io.open(fetchedfile, "r"))
          local fetchedcontent = assert(fd:read("*a"))
@@ -109,6 +110,7 @@ describe("luarocks fetch #unit #mock", function()
 
       it("returns true and fetches the url into a temporary dir", function()
          local fetchedfile, tmpdir = fetch.fetch_url_at_temp_dir("http://localhost:8080/file/a_rock.lua", "test")
+         assert(fetchedfile, tmpdir)
          assert.truthy(are_same_files(fetchedfile, tmpdir .. "/a_rock.lua"))
          local fd = assert(io.open(fetchedfile, "r"))
          local fetchedcontent = assert(fd:read("*a"))
@@ -121,6 +123,7 @@ describe("luarocks fetch #unit #mock", function()
 
       it("returns true and fetches the url into a temporary dir with custom filename", function()
          local fetchedfile, tmpdir = fetch.fetch_url_at_temp_dir("http://localhost:8080/file/a_rock.lua", "test", "my_a_rock.lua")
+         assert(fetchedfile, tmpdir)
          assert.truthy(are_same_files(fetchedfile, tmpdir .. "/my_a_rock.lua"))
          assert.truthy(string.find(tmpdir, "test"))
          local fd = assert(io.open(fetchedfile, "r"))
@@ -274,7 +277,7 @@ describe("luarocks fetch #unit #mock", function()
       end)
 
       it("returns false if the rockspec in invalid", function()
-         assert.falsy(fetch.load_local_rockspec(testing_paths.fixtures_dir .. "/invalid_validate-args-1.5.4-1.rockspec"))
+         assert.falsy(fetch.load_local_rockspec(testing_paths.fixtures_dir .. "/invalid_say-1.3-1.rockspec"))
       end)
 
       it("returns false if the rockspec version is not supported", function()
diff --git a/spec/fixtures/a_repo/manifest b/spec/fixtures/a_repo/manifest
index 5ab87d2..a5f770a 100644
--- a/spec/fixtures/a_repo/manifest
+++ b/spec/fixtures/a_repo/manifest
@@ -68,5 +68,23 @@ repository = {
             arch = "src"
          }
       }
+   },
+   non_lua_file = {
+      ["1.0-1"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      },
+      ["1.0-2"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      }
    }
 }
diff --git a/spec/fixtures/a_repo/manifest-5.1 b/spec/fixtures/a_repo/manifest-5.1
index 5ab87d2..a5f770a 100644
--- a/spec/fixtures/a_repo/manifest-5.1
+++ b/spec/fixtures/a_repo/manifest-5.1
@@ -68,5 +68,23 @@ repository = {
             arch = "src"
          }
       }
+   },
+   non_lua_file = {
+      ["1.0-1"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      },
+      ["1.0-2"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      }
    }
 }
diff --git a/spec/fixtures/a_repo/manifest-5.1.zip b/spec/fixtures/a_repo/manifest-5.1.zip
index 65e316d..e63d6f1 100644
Binary files a/spec/fixtures/a_repo/manifest-5.1.zip and b/spec/fixtures/a_repo/manifest-5.1.zip differ
diff --git a/spec/fixtures/a_repo/manifest-5.2 b/spec/fixtures/a_repo/manifest-5.2
index 5ab87d2..a5f770a 100644
--- a/spec/fixtures/a_repo/manifest-5.2
+++ b/spec/fixtures/a_repo/manifest-5.2
@@ -68,5 +68,23 @@ repository = {
             arch = "src"
          }
       }
+   },
+   non_lua_file = {
+      ["1.0-1"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      },
+      ["1.0-2"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      }
    }
 }
diff --git a/spec/fixtures/a_repo/manifest-5.2.zip b/spec/fixtures/a_repo/manifest-5.2.zip
index b4334a6..cec28c0 100644
Binary files a/spec/fixtures/a_repo/manifest-5.2.zip and b/spec/fixtures/a_repo/manifest-5.2.zip differ
diff --git a/spec/fixtures/a_repo/manifest-5.3 b/spec/fixtures/a_repo/manifest-5.3
index 5ab87d2..a5f770a 100644
--- a/spec/fixtures/a_repo/manifest-5.3
+++ b/spec/fixtures/a_repo/manifest-5.3
@@ -68,5 +68,23 @@ repository = {
             arch = "src"
          }
       }
+   },
+   non_lua_file = {
+      ["1.0-1"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      },
+      ["1.0-2"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      }
    }
 }
diff --git a/spec/fixtures/a_repo/manifest-5.3.zip b/spec/fixtures/a_repo/manifest-5.3.zip
index bab1571..23df5c3 100644
Binary files a/spec/fixtures/a_repo/manifest-5.3.zip and b/spec/fixtures/a_repo/manifest-5.3.zip differ
diff --git a/spec/fixtures/a_repo/manifest-5.4 b/spec/fixtures/a_repo/manifest-5.4
new file mode 100644
index 0000000..a5f770a
--- /dev/null
+++ b/spec/fixtures/a_repo/manifest-5.4
@@ -0,0 +1,90 @@
+commands = {}
+modules = {}
+repository = {
+   a_build_dep = {
+      ["1.0-1"] = {
+         {
+            arch = "src"
+         },
+         {
+            arch = "rockspec"
+         }
+      }
+   },
+   a_rock = {
+      ["1.0-1"] = {
+         {
+            arch = "src"
+         },
+         {
+            arch = "rockspec"
+         }
+      },
+      ["2.0-1"] = {
+         {
+            arch = "src"
+         }
+      }
+   },
+   busted_project = {
+      ["0.1-1"] = {
+         {
+            arch = "src"
+         },
+         {
+            arch = "rockspec"
+         }
+      }
+   },
+   has_another_namespaced_dep = {
+      ["1.0-1"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      }
+   },
+   has_build_dep = {
+      ["1.0-1"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         },
+         {
+            arch = "all"
+         }
+      }
+   },
+   has_namespaced_dep = {
+      ["1.0-1"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      }
+   },
+   non_lua_file = {
+      ["1.0-1"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      },
+      ["1.0-2"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      }
+   }
+}
diff --git a/spec/fixtures/a_repo/manifest-5.4.zip b/spec/fixtures/a_repo/manifest-5.4.zip
new file mode 100644
index 0000000..14b5621
Binary files /dev/null and b/spec/fixtures/a_repo/manifest-5.4.zip differ
diff --git a/spec/fixtures/a_repo/manifests/a_user/manifest-5.4 b/spec/fixtures/a_repo/manifests/a_user/manifest-5.4
new file mode 100644
index 0000000..74b0c61
--- /dev/null
+++ b/spec/fixtures/a_repo/manifests/a_user/manifest-5.4
@@ -0,0 +1,14 @@
+commands = {}
+modules = {}
+repository = {
+   a_rock = {
+      ["2.0-1"] = {
+         {
+            arch = "rockspec"
+         },
+         {
+            arch = "src"
+         }
+      }
+   }
+}
diff --git a/spec/fixtures/a_repo/manifests/another_user/manifest-5.4 b/spec/fixtures/a_repo/manifests/another_user/manifest-5.4
new file mode 100644
index 0000000..185aed0
--- /dev/null
+++ b/spec/fixtures/a_repo/manifests/another_user/manifest-5.4
@@ -0,0 +1,14 @@
+commands = {}
+modules = {}
+repository = {
+   a_rock = {
+      ["3.0-1"] = {
+         {
+            arch = "src"
+         },
+         {
+            arch = "rockspec"
+         }
+      }
+   }
+}
diff --git a/spec/fixtures/a_repo/non_lua_file-1.0-1.rockspec b/spec/fixtures/a_repo/non_lua_file-1.0-1.rockspec
new file mode 100644
index 0000000..51ef42e
--- /dev/null
+++ b/spec/fixtures/a_repo/non_lua_file-1.0-1.rockspec
@@ -0,0 +1,22 @@
+-- regression test for sailorproject/sailor#138
+rockspec_format = "3.0"
+package = "non_lua_file"
+version = "1.0-1"
+source = {
+   url = "file://../upstream/non_lua_file-1.0.tar.gz"
+}
+description = {
+   summary = "An example rockspec that has a script.",
+}
+dependencies = {
+   "lua >= 5.1",
+}
+build = {
+   type = "builtin",
+   modules = {},
+   install = {
+      lua = {
+         ["sailor.blank-app.htaccess"] = "src/sailor/blank-app/.htaccess",
+      }
+   }
+}
diff --git a/spec/fixtures/a_repo/non_lua_file-1.0-1.src.rock b/spec/fixtures/a_repo/non_lua_file-1.0-1.src.rock
new file mode 100644
index 0000000..148f703
Binary files /dev/null and b/spec/fixtures/a_repo/non_lua_file-1.0-1.src.rock differ
diff --git a/spec/fixtures/a_repo/non_lua_file-1.0-2.rockspec b/spec/fixtures/a_repo/non_lua_file-1.0-2.rockspec
new file mode 100644
index 0000000..f9d2e2c
--- /dev/null
+++ b/spec/fixtures/a_repo/non_lua_file-1.0-2.rockspec
@@ -0,0 +1,22 @@
+-- regression test for sailorproject/sailor#138
+rockspec_format = "3.0"
+package = "non_lua_file"
+version = "1.0-2"
+source = {
+   url = "file://../upstream/non_lua_file-1.0.tar.gz"
+}
+description = {
+   summary = "An example rockspec that has a script.",
+}
+dependencies = {
+   "lua >= 5.1",
+}
+build = {
+   type = "builtin",
+   modules = {},
+   install = {
+      lua = {
+         ["sailor.blank-app.htaccess"] = "src/sailor/blank-app/.htaccess",
+      }
+   }
+}
diff --git a/spec/fixtures/a_repo/non_lua_file-1.0-2.src.rock b/spec/fixtures/a_repo/non_lua_file-1.0-2.src.rock
new file mode 100644
index 0000000..06eb9ac
Binary files /dev/null and b/spec/fixtures/a_repo/non_lua_file-1.0-2.src.rock differ
diff --git a/spec/fixtures/invalid_say-1.3-1.rockspec b/spec/fixtures/invalid_say-1.3-1.rockspec
new file mode 100644
index 0000000..890b4db
--- /dev/null
+++ b/spec/fixtures/invalid_say-1.3-1.rockspec
@@ -0,0 +1,23 @@
+package = "say"
+version = "1.3-1"
+source = {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{++{
+  url = "https://github.com/Olivine-Labs/say/archive/v1.3-1.tar.gz",
+  dir = "say-1.3-1"
+}
+description = {
+  summary = "Lua String Hashing/Indexing Library",
+  detailed = [[
+    Useful for internationalization.
+  ]],
+  homepage = "http://olivinelabs.com/busted/",
+  license = "MIT <http://opensource.org/licenses/MIT>"
+}
+dependencies = {
+  "lua >= 5.1"
+}
+build = {
+  type = "builtin",
+  modules = {
+    ["say.init"] = "src/init.lua"
+  }
+}
diff --git a/spec/fixtures/invalid_validate-args-1.5.4-1.rockspec b/spec/fixtures/invalid_validate-args-1.5.4-1.rockspec
deleted file mode 100644
index 0b4d807..0000000
--- a/spec/fixtures/invalid_validate-args-1.5.4-1.rockspec
+++ /dev/null
@@ -1,35 +0,0 @@
-package = 'validate-args'
-version = '1.5.4-1'
-source = {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{++{
-  url = "https://bitbucket.org/djerius/validate.args/downloads/validate-args-1.5.4.tar.gz"
-}
-
-description = {
-   summary = "Function argument validation",
-   detailed = [[
-	 validate.args is a Lua module that provides a framework for
-	 validation of arguments to Lua functions as well as complex data
-	 structures. The included validate.inplace module provides "live"
-	 validation during assignment of values to elements in tables. ]],
-   license = "GPL-3",
-
-}
-
-dependencies = {
-   "lua >= 5.1"
-}
-
-build = {
-
-   type = "builtin",
-
-   modules = {
-      ["validate.args"] = "validate/args.lua",
-      ["validate.inplace"] = "validate/inplace.lua",
-   },
-
-   copy_directories = {
-   "doc", "tests"
-   }
-
-}
diff --git a/spec/fs_spec.lua b/spec/fs_spec.lua
index 5410cff..cd6e5c1 100644
--- a/spec/fs_spec.lua
+++ b/spec/fs_spec.lua
@@ -1476,9 +1476,9 @@ describe("luarocks.fs #unit", function()
       it("produces a wrapper for a Lua script", function()
          write_file("my_script", "io.write('Hello ' .. arg[1])", finally)
          path.use_tree(testing_paths.testing_tree)
-         local wrapper_name = fs.absolute_name("wrapper")
+         local wrapper_name = fs.absolute_name("wrapper") .. test_env.wrapper_extension
          fs.wrap_script("my_script", wrapper_name, "one", nil, nil, "World")
-         local pd = assert(io.popen(wrapper_name .. test_env.wrapper_extension))
+         local pd = assert(io.popen(wrapper_name))
          local data = pd:read("*a")
          pd:close()
          assert.same("Hello World", data)
diff --git a/spec/init_spec.lua b/spec/init_spec.lua
index 3bde313..dadeb30 100644
--- a/spec/init_spec.lua
+++ b/spec/init_spec.lua
@@ -92,13 +92,13 @@ describe("luarocks init #integration", function()
          lfs.mkdir(myproject)
          lfs.chdir(myproject)
 
-         assert(run.luarocks("init --lua-versions=5.1,5.2,5.3"))
+         assert(run.luarocks("init --lua-versions=5.1,5.2,5.3,5.4"))
          local rockspec_name = myproject .. "/myproject-dev-1.rockspec"
          assert.truthy(lfs.attributes(rockspec_name))
          local fd = assert(io.open(rockspec_name, "rb"))
          local data = fd:read("*a")
          fd:close()
-         assert.truthy(data:find("lua >= 5.1, < 5.4", 1, true))
+         assert.truthy(data:find("lua >= 5.1, < 5.5", 1, true))
       end, finally)
    end)
 
diff --git a/spec/install_spec.lua b/spec/install_spec.lua
index 9bc94eb..d410ca9 100644
--- a/spec/install_spec.lua
+++ b/spec/install_spec.lua
@@ -5,28 +5,29 @@ local testing_paths = test_env.testing_paths
 local env_variables = test_env.env_variables
 local write_file = test_env.write_file
 local git_repo = require("spec.util.git_repo")
+local V = test_env.V
 
 test_env.unload_luarocks()
 
 local extra_rocks = {
-   "/cprint-0.1-2.src.rock",
-   "/cprint-0.1-2.rockspec",
-   "/lpeg-0.12-1.src.rock",
+   "/cprint-${CPRINT}.src.rock",
+   "/cprint-${CPRINT}.rockspec",
+   "/lpeg-${LPEG}.src.rock",
    "/luassert-1.7.0-1.src.rock",
-   "/luasocket-3.0rc1-2.src.rock",
-   "/luasocket-3.0rc1-2.rockspec",
-   "/lxsh-0.8.6-2.src.rock",
-   "/lxsh-0.8.6-2.rockspec",
+   "/luasocket-${LUASOCKET}.src.rock",
+   "/luasocket-${LUASOCKET}.rockspec",
+   "/lxsh-${LXSH}.src.rock",
+   "/lxsh-${LXSH}.rockspec",
    "/say-1.2-1.src.rock",
    "/say-1.0-1.src.rock",
    "/wsapi-1.6-1.src.rock",
-   "/luafilesystem-1.6.3-2.src.rock",
-   "/luafilesystem-1.6.3-1.src.rock",
-   "/sailor-0.5-3.src.rock",
-   "/sailor-0.5-4.src.rock",
+   "/luafilesystem-${LUAFILESYSTEM}.src.rock",
+   "/luafilesystem-${LUAFILESYSTEM_OLD}.src.rock",
    "spec/fixtures/a_repo/has_build_dep-1.0-1.all.rock",
    "spec/fixtures/a_repo/a_build_dep-1.0-1.all.rock",
    "spec/fixtures/a_repo/a_rock-1.0-1.src.rock",
+   "spec/fixtures/a_repo/non_lua_file-1.0-1.src.rock",
+   "spec/fixtures/a_repo/non_lua_file-1.0-2.src.rock",
 }
 
 describe("luarocks install #integration", function()
@@ -53,7 +54,9 @@ describe("luarocks install #integration", function()
       end)
 
       it("fails with local flag as root #unix", function()
-         assert.is_false(run.luarocks_bool("install --local luasocket ", { USER = "root" } ))
+         if test_env.TYPE_TEST_ENV ~= "full" then
+            assert.is_false(run.luarocks_bool("install --local luasocket ", { USER = "root" } ))
+         end
       end)
 
       it("fails with no downloader", function()
@@ -78,7 +81,7 @@ describe("luarocks install #integration", function()
       end)
 
       it("only-deps of lxsh show there is no lxsh", function()
-         assert.is_true(run.luarocks_bool("install lxsh 0.8.6-2 --only-deps"))
+         assert.is_true(run.luarocks_bool("install lxsh ${LXSH} --only-deps"))
          assert.is_false(run.luarocks_bool("show lxsh"))
       end)
 
@@ -170,87 +173,93 @@ describe("luarocks install #integration", function()
       end)
 
       it('handle versioned modules when installing another version with --keep #268', function()
+         local libdir = testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION
+
          assert.is_true(run.luarocks_bool("install luafilesystem"))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension))
+         assert.is.truthy(lfs.attributes(libdir .."/lfs."..test_env.lib_extension))
 
-         assert.is_true(run.luarocks_bool("install luafilesystem 1.6.3-1 --keep"))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/luafilesystem_1_6_3_1-lfs."..test_env.lib_extension))
+         local suffix = (V"${LUAFILESYSTEM_OLD}"):gsub("[%.%-]", "_")
+
+         assert.is_true(run.luarocks_bool("install luafilesystem ${LUAFILESYSTEM_OLD} --keep"))
+         assert.is.truthy(lfs.attributes(libdir .. "/lfs."..test_env.lib_extension))
+         assert.is.truthy(lfs.attributes(libdir .. "/luafilesystem_"..suffix.."-lfs."..test_env.lib_extension))
 
          assert.is_true(run.luarocks_bool("install luafilesystem"))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension))
-         assert.is.falsy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/luafilesystem_1_6_3_1-lfs."..test_env.lib_extension))
+         assert.is.truthy(lfs.attributes(libdir .. "/lfs."..test_env.lib_extension))
+         assert.is.falsy(lfs.attributes(libdir .. "/luafilesystem_"..suffix.."-lfs."..test_env.lib_extension))
       end)
 
       it('handle non-Lua files in build.install.lua when upgrading sailorproject/sailor#138', function()
-         assert.is_true(run.luarocks_bool("install sailor 0.5-3 --deps-mode=none"))
+         assert.is_true(run.luarocks_bool("install non_lua_file 1.0-1 --deps-mode=none"))
          assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/share/lua/"..env_variables.LUA_VERSION.."/sailor/blank-app/.htaccess"))
          assert.is.falsy(lfs.attributes(testing_paths.testing_sys_tree .. "/share/lua/"..env_variables.LUA_VERSION.."/sailor/blank-app/.htaccess~"))
 
-         assert.is_true(run.luarocks_bool("install sailor 0.5-4 --deps-mode=none"))
+         assert.is_true(run.luarocks_bool("install non_lua_file 1.0-2 --deps-mode=none"))
          assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/share/lua/"..env_variables.LUA_VERSION.."/sailor/blank-app/.htaccess"))
          assert.is.falsy(lfs.attributes(testing_paths.testing_sys_tree .. "/share/lua/"..env_variables.LUA_VERSION.."/sailor/blank-app/.htaccess~"))
       end)
 
       it("only-deps of luasocket packed rock", function()
-         assert.is_true(run.luarocks_bool("build --pack-binary-rock luasocket 3.0rc1-2"))
-         local output = run.luarocks("install --only-deps " .. "luasocket-3.0rc1-2." .. test_env.platform .. ".rock")
-         assert.match("Successfully installed dependencies for luasocket 3.0rc1-2", output, 1, true)
-         assert.is_true(os.remove("luasocket-3.0rc1-2." .. test_env.platform .. ".rock"))
+         assert.is_true(run.luarocks_bool("build --pack-binary-rock luasocket ${LUASOCKET}"))
+         local output = run.luarocks("install --only-deps " .. "luasocket-${LUASOCKET}." .. test_env.platform .. ".rock")
+         assert.match(V"Successfully installed dependencies for luasocket ${LUASOCKET}", output, 1, true)
+         assert.is_true(os.remove("luasocket-${LUASOCKET}." .. test_env.platform .. ".rock"))
       end)
 
       it("reinstall", function()
-         assert.is_true(run.luarocks_bool("build --pack-binary-rock luasocket 3.0rc1-2"))
-         assert.is_true(run.luarocks_bool("install " .. "luasocket-3.0rc1-2." .. test_env.platform .. ".rock"))
-         assert.is_true(run.luarocks_bool("install --deps-mode=none " .. "luasocket-3.0rc1-2." .. test_env.platform .. ".rock"))
-         assert.is_true(os.remove("luasocket-3.0rc1-2." .. test_env.platform .. ".rock"))
+         assert.is_true(run.luarocks_bool("build --pack-binary-rock luasocket ${LUASOCKET}"))
+         assert.is_true(run.luarocks_bool("install " .. "luasocket-${LUASOCKET}." .. test_env.platform .. ".rock"))
+         assert.is_true(run.luarocks_bool("install --deps-mode=none " .. "luasocket-${LUASOCKET}." .. test_env.platform .. ".rock"))
+         assert.is_true(os.remove("luasocket-${LUASOCKET}." .. test_env.platform .. ".rock"))
       end)
 
       it("installation rolls back on failure", function()
-         assert.is_true(run.luarocks_bool("build --pack-binary-rock luasocket 3.0rc1-2"))
-         local luadir = testing_paths.testing_sys_tree .. "/share/lua/"..env_variables.LUA_VERSION
-         lfs.mkdir(luadir)
+         if test_env.TYPE_TEST_ENV ~= "full" then
+            assert.is_true(run.luarocks_bool("build --pack-binary-rock luasocket ${LUASOCKET}"))
+            local luadir = testing_paths.testing_sys_tree .. "/share/lua/"..env_variables.LUA_VERSION
+            lfs.mkdir(luadir)
 
-         run.luarocks_bool("remove " .. "luasocket")
+            run.luarocks_bool("remove " .. "luasocket")
 
-         -- create a file where a folder should be
-         local fd = io.open(luadir .. "/socket", "w")
-         fd:write("\n")
-         fd:close()
+            -- create a file where a folder should be
+            local fd = io.open(luadir .. "/socket", "w")
+            fd:write("\n")
+            fd:close()
 
-         -- try to install and fail
-         assert.is_false(run.luarocks_bool("install " .. "luasocket-3.0rc1-2." .. test_env.platform .. ".rock"))
+            -- try to install and fail
+            assert.is_false(run.luarocks_bool("install " .. "luasocket-${LUASOCKET}." .. test_env.platform .. ".rock"))
 
-         -- file is still there
-         assert.is.truthy(lfs.attributes(luadir .. "/socket"))
-         -- no left overs from failed installation
-         assert.is.falsy(lfs.attributes(luadir .. "/mime.lua"))
+            -- file is still there
+            assert.is.truthy(lfs.attributes(luadir .. "/socket"))
+            -- no left overs from failed installation
+            assert.is.falsy(lfs.attributes(luadir .. "/mime.lua"))
 
-         -- remove file
-         assert.is_true(os.remove(luadir .. "/socket"))
+            -- remove file
+            assert.is_true(os.remove(luadir .. "/socket"))
 
-         -- try again and succeed
-         assert.is_true(run.luarocks_bool("install " .. "luasocket-3.0rc1-2." .. test_env.platform .. ".rock"))
+            -- try again and succeed
+            assert.is_true(run.luarocks_bool("install " .. "luasocket-${LUASOCKET}." .. test_env.platform .. ".rock"))
 
-         -- files installed successfully
-         assert.is.truthy(lfs.attributes(luadir .. "/socket/ftp.lua"))
-         assert.is.truthy(lfs.attributes(luadir .. "/mime.lua"))
+            -- files installed successfully
+            assert.is.truthy(lfs.attributes(luadir .. "/socket/ftp.lua"))
+            assert.is.truthy(lfs.attributes(luadir .. "/mime.lua"))
 
-         assert.is_true(os.remove("luasocket-3.0rc1-2." .. test_env.platform .. ".rock"))
+            assert.is_true(os.remove("luasocket-${LUASOCKET}." .. test_env.platform .. ".rock"))
+         end
       end)
 
       it("binary rock of cprint", function()
          assert.is_true(run.luarocks_bool("build --pack-binary-rock cprint"))
-         assert.is_true(run.luarocks_bool("install cprint-0.1-2." .. test_env.platform .. ".rock"))
-         assert.is_true(os.remove("cprint-0.1-2." .. test_env.platform .. ".rock"))
+         assert.is_true(run.luarocks_bool("install cprint-${CPRINT}." .. test_env.platform .. ".rock"))
+         assert.is_true(os.remove("cprint-${CPRINT}." .. test_env.platform .. ".rock"))
       end)
 
       it("accepts --no-manifest flag", function()
-         assert.is_true(run.luarocks_bool("install lxsh 0.8.6-2"))
+         assert.is_true(run.luarocks_bool("install lxsh ${LXSH}"))
          assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/manifest"))
          assert.is.truthy(os.remove(testing_paths.testing_sys_rocks .. "/manifest"))
 
-         assert.is_true(run.luarocks_bool("install --no-manifest lxsh 0.8.6-2"))
+         assert.is_true(run.luarocks_bool("install --no-manifest lxsh ${LXSH}"))
          assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/manifest"))
       end)
    end)
@@ -281,7 +290,7 @@ describe("luarocks install #integration", function()
 
    describe("#build_dependencies", function()
       it("install does not install a build dependency", function()
-         assert(run.luarocks_bool("install has_build_dep --server=" .. testing_paths.fixtures_dir .. "/a_repo" ))
+         assert(run.luarocks_bool("install has_build_dep"))
          assert(run.luarocks_bool("show has_build_dep 1.0"))
          assert.falsy(run.luarocks_bool("show a_build_dep 1.0"))
       end)
diff --git a/spec/lint_spec.lua b/spec/lint_spec.lua
index ff7a03e..b205cc5 100644
--- a/spec/lint_spec.lua
+++ b/spec/lint_spec.lua
@@ -7,7 +7,7 @@ test_env.unload_luarocks()
 local lfs = require("lfs")
 
 local extra_rocks = {
-   "/validate-args-1.5.4-1.rockspec"
+   "/say-1.3-1.rockspec"
 }
 
 describe("luarocks lint #integration", function()
@@ -25,10 +25,10 @@ describe("luarocks lint #integration", function()
    end)
 
    it("OK", function()
-      assert.is_true(run.luarocks_bool("download --rockspec validate-args 1.5.4-1"))
-      local output = run.luarocks("lint validate-args-1.5.4-1.rockspec")
+      assert.is_true(run.luarocks_bool("download --rockspec say 1.3-1"))
+      local output = run.luarocks("lint say-1.3-1.rockspec")
       assert.are.same(output, "")
-      assert.is_true(os.remove("validate-args-1.5.4-1.rockspec"))
+      assert.is_true(os.remove("say-1.3-1.rockspec"))
    end)
 
    describe("mismatch set", function()
diff --git a/spec/list_spec.lua b/spec/list_spec.lua
index 875d72a..54c63be 100644
--- a/spec/list_spec.lua
+++ b/spec/list_spec.lua
@@ -1,4 +1,5 @@
 local test_env = require("spec.util.test_env")
+local V = test_env.V
 local run = test_env.run
 local testing_paths = test_env.testing_paths
 
@@ -22,13 +23,13 @@ describe("luarocks list #integration", function()
 
    it("--porcelain", function()
       local output = run.luarocks("list --porcelain")
-      assert.is.truthy(output:find("luacov\t0.15.0-1\tinstalled\t" .. testing_paths.testing_sys_rocks, 1, true))
+      assert.is.truthy(output:find(V"luacov\t${LUACOV}\tinstalled\t" .. testing_paths.testing_sys_rocks, 1, true))
    end)
 
    it("shows version number", function()
       local output = run.luarocks("list")
       assert.is.truthy(output:find("luacov"))
-      assert.matches("0.15.0-1", output, 1, true)
+      assert.matches(V"${LUACOV}", output, 1, true)
    end)
 
    it("LuaRocks install outdated and list it", function()
diff --git a/spec/loader_spec.lua b/spec/loader_spec.lua
index 3517908..c852611 100644
--- a/spec/loader_spec.lua
+++ b/spec/loader_spec.lua
@@ -4,10 +4,21 @@ local testing_paths = test_env.testing_paths
 local write_file = test_env.write_file
 
 describe("luarocks.loader", function()
+
+   before_each(function()
+      test_env.setup_specs()
+   end)
+
    describe("#unit", function()
       it("starts", function()
          assert(run.lua_bool([[-e "require 'luarocks.loader'; print(package.loaded['luarocks.loaded'])"]]))
       end)
+
+      describe("which", function()
+         it("finds modules using package.path", function()
+            assert(run.lua_bool([[-e "loader = require 'luarocks.loader'; local x,y,z,p = loader.which('luarocks.loader', 'p'); assert(p == 'p')"]]))
+         end)
+      end)
    end)
 
    describe("#integration", function()
@@ -21,13 +32,13 @@ describe("luarocks.loader", function()
                   url = "file://]] .. tmpdir:gsub("\\", "/") .. [[/rock_b_01.lua"
                }
                build = {
-                  type = "builtin", 
+                  type = "builtin",
                   modules = {
                      rock_b = "rock_b_01.lua"
                   }
                }
             ]], finally)
-   
+
             write_file("rock_b_10.lua", "print('ROCK B 1.0'); return {}", finally)
             write_file("rock_b-1.0-1.rockspec", [[
                package = "rock_b"
@@ -36,13 +47,13 @@ describe("luarocks.loader", function()
                   url = "file://]] .. tmpdir:gsub("\\", "/") .. [[/rock_b_10.lua"
                }
                build = {
-                  type = "builtin", 
+                  type = "builtin",
                   modules = {
                      rock_b = "rock_b_10.lua"
                   }
                }
             ]], finally)
-   
+
             write_file("rock_a.lua", "require('rock_b'); return {}", finally)
             write_file("rock_a-2.0-1.rockspec", [[
                package = "rock_a"
@@ -54,7 +65,7 @@ describe("luarocks.loader", function()
                   "rock_b < 1.0",
                }
                build = {
-                  type = "builtin", 
+                  type = "builtin",
                   modules = {
                      rock_a = "rock_a.lua"
                   }
@@ -64,9 +75,9 @@ describe("luarocks.loader", function()
             print(run.luarocks("make --server=" .. testing_paths.fixtures_dir .. "/a_repo --tree=" .. testing_paths.testing_tree .. " ./rock_b-0.1-1.rockspec"))
             print(run.luarocks("make --server=" .. testing_paths.fixtures_dir .. "/a_repo --tree=" .. testing_paths.testing_tree .. " ./rock_b-1.0-1.rockspec --keep"))
             print(run.luarocks("make --server=" .. testing_paths.fixtures_dir .. "/a_repo --tree=" .. testing_paths.testing_tree .. " ./rock_a-2.0-1.rockspec"))
-   
+
             local output = run.lua([[-e "require 'luarocks.loader'; require('rock_a')"]])
-   
+
             assert.matches("ROCK B 0.1", output, 1, true)
          end)
       end)
diff --git a/spec/make_spec.lua b/spec/make_spec.lua
index e14eb66..626d84d 100644
--- a/spec/make_spec.lua
+++ b/spec/make_spec.lua
@@ -8,11 +8,11 @@ local write_file = test_env.write_file
 test_env.unload_luarocks()
 
 local extra_rocks = {
-   "/luasocket-3.0rc1-2.src.rock",
-   "/luasocket-3.0rc1-2.rockspec",
-   "/lpeg-0.12-1.src.rock",
-   "/lxsh-0.8.6-2.src.rock",
-   "/lxsh-0.8.6-2.rockspec"
+   "/luasocket-${LUASOCKET}.src.rock",
+   "/luasocket-${LUASOCKET}.rockspec",
+   "/lpeg-${LPEG}.src.rock",
+   "/lxsh-${LXSH}.src.rock",
+   "/lxsh-${LXSH}.rockspec"
 }
 
 describe("luarocks make #integration", function()
@@ -35,35 +35,35 @@ describe("luarocks make #integration", function()
       finally(function()
          -- delete downloaded and unpacked files
          lfs.chdir(testing_paths.testrun_dir)
-         test_env.remove_dir("luasocket-3.0rc1-2")
-         os.remove("luasocket-3.0rc1-2.src.rock")
+         test_env.remove_dir("luasocket-${LUASOCKET}")
+         os.remove("luasocket-${LUASOCKET}.src.rock")
       end)
 
       -- make luasocket
-      assert.is_true(run.luarocks_bool("download --source luasocket 3.0rc1-2"))
-      assert.is_true(run.luarocks_bool("unpack luasocket-3.0rc1-2.src.rock"))
-      lfs.chdir("luasocket-3.0rc1-2/luasocket-3.0-rc1/")
-      assert.is_true(run.luarocks_bool("make luasocket-3.0rc1-2.rockspec"))
+      assert.is_true(run.luarocks_bool("download --source luasocket ${LUASOCKET}"))
+      assert.is_true(run.luarocks_bool("unpack luasocket-${LUASOCKET}.src.rock"))
+      lfs.chdir("luasocket-${LUASOCKET}/luasocket/")
+      assert.is_true(run.luarocks_bool("make luasocket-${LUASOCKET}.rockspec"))
 
       -- test it
       assert.is_true(run.luarocks_bool("show luasocket"))
-      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/luasocket/3.0rc1-2/luasocket-3.0rc1-2.rockspec"))
+      assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/luasocket/${LUASOCKET}/luasocket-${LUASOCKET}.rockspec"))
    end)
 
    it("--no-doc", function()
       finally(function()
          lfs.chdir(testing_paths.testrun_dir)
-         test_env.remove_dir("luasocket-3.0rc1-2")
-         os.remove("luasocket-3.0rc1-2.src.rock")
+         test_env.remove_dir("luasocket-${LUASOCKET}")
+         os.remove("luasocket-${LUASOCKET}.src.rock")
       end)
 
-      assert.is_true(run.luarocks_bool("download --source luasocket 3.0rc1-2"))
-      assert.is_true(run.luarocks_bool("unpack luasocket-3.0rc1-2.src.rock"))
-      lfs.chdir("luasocket-3.0rc1-2/luasocket-3.0-rc1/")
-      assert.is_true(run.luarocks_bool("make --no-doc luasocket-3.0rc1-2.rockspec"))
+      assert.is_true(run.luarocks_bool("download --source luasocket ${LUASOCKET}"))
+      assert.is_true(run.luarocks_bool("unpack luasocket-${LUASOCKET}.src.rock"))
+      lfs.chdir("luasocket-${LUASOCKET}/luasocket")
+      assert.is_true(run.luarocks_bool("make --no-doc luasocket-${LUASOCKET}.rockspec"))
 
       assert.is_true(run.luarocks_bool("show luasocket"))
-      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/luasocket/3.0rc1-2/doc"))
+      assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/luasocket/${LUASOCKET}/doc"))
    end)
 
    it("--only-deps", function()
@@ -82,24 +82,24 @@ describe("luarocks make #integration", function()
    describe("LuaRocks making rockspecs (using lxsh)", function()
       --download lxsh and unpack it
       before_each(function()
-         assert.is_true(run.luarocks_bool("download --source lxsh 0.8.6-2"))
-         assert.is_true(run.luarocks_bool("unpack lxsh-0.8.6-2.src.rock"))
-         assert.is_true(lfs.chdir("lxsh-0.8.6-2/lxsh-0.8.6-1/"))
+         assert.is_true(run.luarocks_bool("download --source lxsh ${LXSH}"))
+         assert.is_true(run.luarocks_bool("unpack lxsh-${LXSH}.src.rock"))
+         assert.is_true(lfs.chdir("lxsh-${LXSH}/lxsh-${LXSH_V}-1/"))
       end)
 
       -- delete downloaded and unpacked files
       after_each(function()
          assert(lfs.chdir(testing_paths.testrun_dir))
-         test_env.remove_dir("lxsh-0.8.6-2")
-         assert.is_true(os.remove("lxsh-0.8.6-2.src.rock"))
+         test_env.remove_dir("lxsh-${LXSH}")
+         assert.is_true(os.remove("lxsh-${LXSH}.src.rock"))
       end)
 
       it("default rockspec", function()
-         assert.is_true(run.luarocks_bool("new_version lxsh-0.8.6-2.rockspec"))
+         assert.is_true(run.luarocks_bool("new_version lxsh-${LXSH}.rockspec"))
          assert.is_true(run.luarocks_bool("make"))
 
          assert.is_true(run.luarocks_bool("show lxsh"))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-3/lxsh-0.8.6-3.rockspec"))
+         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH_V}-3/lxsh-${LXSH_V}-3.rockspec"))
       end)
 
       it("unnamed rockspec", function()
@@ -107,35 +107,35 @@ describe("luarocks make #integration", function()
             os.remove("rockspec")
          end)
 
-         test_env.copy("lxsh-0.8.6-2.rockspec", "rockspec")
+         test_env.copy("lxsh-${LXSH}.rockspec", "rockspec")
          assert.is_true(run.luarocks_bool("make"))
 
          assert.is_true(run.luarocks_bool("show lxsh"))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
       end)
 
       it("ambiguous rockspec", function()
-         assert.is.truthy(os.rename("lxsh-0.8.6-2.rockspec", "lxsh2-0.8.6-2.rockspec"))
+         assert.is.truthy(os.rename("lxsh-${LXSH}.rockspec", "lxsh2-${LXSH}.rockspec"))
          local output = run.luarocks("make")
          assert.is.truthy(output:match("Error: Inconsistency between rockspec filename"))
 
          assert.is_false(run.luarocks_bool("show lxsh"))
-         assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+         assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
       end)
 
       it("ambiguous unnamed rockspec", function()
-         assert.is.truthy(os.rename("lxsh-0.8.6-2.rockspec", "1_rockspec"))
+         assert.is.truthy(os.rename("lxsh-${LXSH}.rockspec", "1_rockspec"))
          test_env.copy("1_rockspec", "2_rockspec")
          local output = run.luarocks("make")
          assert.is.truthy(output:match("Error: Please specify which rockspec file to use"))
 
          assert.is_false(run.luarocks_bool("show lxsh"))
-         assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/0.8.6-2/lxsh-0.8.6-2.rockspec"))
+         assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/lxsh/${LXSH}/lxsh-${LXSH}.rockspec"))
       end)
 
       it("pack binary rock", function()
          assert.is_true(run.luarocks_bool("make --deps-mode=none --pack-binary-rock"))
-         assert.is.truthy(lfs.attributes("lxsh-0.8.6-2.all.rock"))
+         assert.is.truthy(lfs.attributes("lxsh-${LXSH}.all.rock"))
       end)
    end)
 
diff --git a/spec/new_version_spec.lua b/spec/new_version_spec.lua
index f8795db..d47cfd0 100644
--- a/spec/new_version_spec.lua
+++ b/spec/new_version_spec.lua
@@ -7,7 +7,7 @@ test_env.unload_luarocks()
 
 local extra_rocks = {
    "/abelhas-1.1-1.rockspec",
-   "/lpeg-0.12-1.rockspec"
+   "/lpeg-${LPEG}.rockspec"
 }
 
 describe("luarocks new_version #integration", function()
@@ -41,8 +41,8 @@ describe("luarocks new_version #integration", function()
 
    describe("more complex tests", function()
       it("of luacov", function()
-         assert.is_true(run.luarocks_bool("download --rockspec luacov 0.15.0"))
-         assert.is_true(run.luarocks_bool("new_version luacov-0.15.0-1.rockspec 0.2"))
+         assert.is_true(run.luarocks_bool("download --rockspec luacov ${LUACOV_V}"))
+         assert.is_true(run.luarocks_bool("new_version luacov-${LUACOV}.rockspec 0.2"))
          assert.is.truthy(lfs.attributes("luacov-0.2-1.rockspec"))
          test_env.remove_files(lfs.currentdir(), "luacov%-")
       end)
@@ -55,15 +55,15 @@ describe("luarocks new_version #integration", function()
       end)
 
       it("of luacov with tag", function()
-         assert.is_true(run.luarocks_bool("download --rockspec luacov 0.15.0"))
-         assert.is_true(run.luarocks_bool("new_version luacov-0.15.0-1.rockspec --tag v0.3"))
+         assert.is_true(run.luarocks_bool("download --rockspec luacov ${LUACOV_V}"))
+         assert.is_true(run.luarocks_bool("new_version luacov-${LUACOV}.rockspec --tag v0.3"))
          assert.is.truthy(lfs.attributes("luacov-0.3-1.rockspec"))
          test_env.remove_files(lfs.currentdir(), "luacov%-")
       end)
 
       it("updating md5", function()
-         assert.is_true(run.luarocks_bool("download --rockspec lpeg 0.12"))
-         assert.is_true(run.luarocks_bool("new_version lpeg-0.12-1.rockspec 0.2 https://luarocks.org/manifests/gvvaughan/lpeg-1.0.0-1.rockspec"))
+         assert.is_true(run.luarocks_bool("download --rockspec lpeg ${LPEG_V}"))
+         assert.is_true(run.luarocks_bool("new_version lpeg-${LPEG}.rockspec 0.2 https://luarocks.org/manifests/gvvaughan/lpeg-1.0.0-1.rockspec"))
          test_env.remove_files(lfs.currentdir(), "lpeg%-")
       end)
    end)
diff --git a/spec/pack_spec.lua b/spec/pack_spec.lua
index beab7e8..0a4e0d8 100644
--- a/spec/pack_spec.lua
+++ b/spec/pack_spec.lua
@@ -8,8 +8,8 @@ test_env.unload_luarocks()
 
 local extra_rocks = {
    "/luassert-1.7.0-1.src.rock",
-   "/luasocket-3.0rc1-2.src.rock",
-   "/luasocket-3.0rc1-2.rockspec",
+   "/luasocket-${LUASOCKET}.src.rock",
+   "/luasocket-${LUASOCKET}.rockspec",
    "/say-1.2-1.src.rock",
    "/say-1.0-1.src.rock"
 }
@@ -30,7 +30,7 @@ describe("luarocks pack #integration", function()
    end)
 
    it("invalid rockspec", function()
-      assert.is_false(run.luarocks_bool("pack " .. testing_paths.fixtures_dir .. "/invalid_validate-args-1.5.4-1.rockspec"))
+      assert.is_false(run.luarocks_bool("pack " .. testing_paths.fixtures_dir .. "/invalid_say-1.3-1.rockspec"))
    end)
 
    it("not installed rock", function()
diff --git a/spec/remove_spec.lua b/spec/remove_spec.lua
index 21a3969..a67db59 100644
--- a/spec/remove_spec.lua
+++ b/spec/remove_spec.lua
@@ -3,16 +3,17 @@ local lfs = require("lfs")
 local run = test_env.run
 local testing_paths = test_env.testing_paths
 local env_variables = test_env.env_variables
+local V = test_env.V
 
 test_env.unload_luarocks()
 
 local extra_rocks = {
    "/abelhas-1.1-1.src.rock",
-   "/copas-2.0.1-1.src.rock",
+   "/copas-${COPAS}.src.rock",
    "/coxpcall-1.16.0-1.src.rock",
    "/coxpcall-1.16.0-1.rockspec",
-   "/luafilesystem-1.7.0-1.src.rock",
-   "/luafilesystem-1.6.3-2.src.rock",
+   "/luafilesystem-${LUAFILESYSTEM}.src.rock",
+   "/luafilesystem-${LUAFILESYSTEM_OLD}.src.rock",
 }
 
 describe("luarocks remove #integration", function()
@@ -85,31 +86,35 @@ describe("luarocks remove #integration", function()
       end)
 
       it("restores old versions", function()
-         assert.is_true(run.luarocks_bool("install luafilesystem 1.6.3"))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension))
+         local libdir = testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION
+
+         assert.is_true(run.luarocks_bool("install luafilesystem ${LUAFILESYSTEM_OLD_V}"))
+         assert.is.truthy(lfs.attributes(libdir.."/lfs."..test_env.lib_extension))
 
          if test_env.TEST_TARGET_OS ~= "windows" then
-            local fd = io.open(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension, "r")
-            assert(fd:read("*a"):match("LuaFileSystem 1.6.3", 1, true))
+            local fd = io.open(libdir.."/lfs."..test_env.lib_extension, "r")
+            assert(fd:read("*a"):match(V"LuaFileSystem ${LUAFILESYSTEM_OLD_V}", 1, true))
             fd:close()
          end
 
-         assert.is_true(run.luarocks_bool("install luafilesystem 1.7.0 --keep"))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/luafilesystem_1_6_3_2-lfs."..test_env.lib_extension))
+         local suffix = (V"${LUAFILESYSTEM_OLD}"):gsub("[%.%-]", "_")
+
+         assert.is_true(run.luarocks_bool("install luafilesystem ${LUAFILESYSTEM_V} --keep"))
+         assert.is.truthy(lfs.attributes(libdir.."/lfs."..test_env.lib_extension))
+         assert.is.truthy(lfs.attributes(libdir.."/luafilesystem_"..suffix.."-lfs."..test_env.lib_extension))
 
          if test_env.TEST_TARGET_OS ~= "windows" then
-            local fd = io.open(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension, "r")
-            assert(fd:read("*a"):match("LuaFileSystem 1.7.0", 1, true))
+            local fd = io.open(libdir.."/lfs."..test_env.lib_extension, "r")
+            assert(fd:read("*a"):match(V"LuaFileSystem ${LUAFILESYSTEM_V}", 1, true))
             fd:close()
          end
 
-         assert.is_true(run.luarocks_bool("remove luafilesystem 1.7.0"))
-         assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension))
+         assert.is_true(run.luarocks_bool("remove luafilesystem ${LUAFILESYSTEM_V}"))
+         assert.is.truthy(lfs.attributes(libdir.."/lfs."..test_env.lib_extension))
 
          if test_env.TEST_TARGET_OS ~= "windows" then
-            local fd = io.open(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension, "r")
-            assert(fd:read("*a"):match("LuaFileSystem 1.6.3", 1, true))
+            local fd = io.open(libdir.."/lfs."..test_env.lib_extension, "r")
+            assert(fd:read("*a"):match(V"LuaFileSystem ${LUAFILESYSTEM_OLD_V}", 1, true))
             fd:close()
          end
       end)
diff --git a/spec/sysdetect_spec.lua b/spec/sysdetect_spec.lua
index 7f9cf1b..6ec6f6b 100644
--- a/spec/sysdetect_spec.lua
+++ b/spec/sysdetect_spec.lua
@@ -55,6 +55,8 @@ describe("luarocks.core.sysdetect #unix #unit", function()
       ["elf-Haiku-GCC2-ls"] = {"haiku", "x86"},
       ["elf-Haiku-GCC7-WebPositive"] = {"haiku", "x86"},
       ["pe-cygwin-ls.exe"] = {"cygwin", "x86"},
+      ["elf-DragonFly-x86_64-less"] = {"dragonfly", "x86_64"},
+
    }
 
    describe("detect_file", function()
diff --git a/spec/test_spec.lua b/spec/test_spec.lua
index 943d0e4..4be0567 100644
--- a/spec/test_spec.lua
+++ b/spec/test_spec.lua
@@ -10,9 +10,9 @@ test_env.unload_luarocks()
 local extra_rocks = {
    "/busted-2.0.0-1.rockspec",
    "/lua_cliargs-3.0-1.src.rock",
-   "/luafilesystem-1.7.0-2.src.rock",
+   "/luafilesystem-${LUAFILESYSTEM}.src.rock",
    "/luasystem-0.2.1-0.src.rock",
-   "/dkjson-2.5-2.src.rock",
+   "/dkjson-${DKJSON}.src.rock",
    "/say-1.3-1.rockspec",
    "/luassert-1.8.0-0.rockspec",
    "/lua-term-0.7-1.rockspec",
@@ -41,6 +41,7 @@ describe("luarocks test #integration", function()
       lazy_setup(function()
          -- Try to cache rocks from the host system to speed up test
          for _, r in ipairs(extra_rocks) do
+            r = test_env.V(r)
             local n, v = r:match("^/(.*)%-([^%-]+)%-%d+%.[^%-]+$")
             os.execute("luarocks pack " .. n .. " " .. v)
          end
@@ -84,17 +85,26 @@ describe("luarocks test #integration", function()
          assert.is_true(run.luarocks_bool("unpack busted_project-0.1-1.src.rock"))
          lfs.chdir("busted_project-0.1-1/busted_project")
          assert.is_true(run.luarocks_bool("make"))
-         
+
          run.luarocks_bool("remove busted")
          local prepareOutput = run.luarocks_bool("test --prepare")
          assert.is_true(run.luarocks_bool("show busted"))
-          
+
          -- Assert that "test --prepare" run successfully
          assert.is_true(prepareOutput)
 
          local output = run.luarocks("test")
          assert.not_match(tostring(prepareOutput), output)
-         
+
+      end)
+   end)
+
+   describe("command backend", function()
+      describe("prepare", function()
+         it("works with non-busted rocks", function()
+            write_file("test.lua", "", finally)
+            assert.is_true(run.luarocks_bool("test --prepare " .. testing_paths.fixtures_dir .. "/a_rock-1.0-1.rockspec"))
+         end)
       end)
    end)
 end)
diff --git a/spec/unpack_spec.lua b/spec/unpack_spec.lua
index 9b1e2b9..00d6781 100644
--- a/spec/unpack_spec.lua
+++ b/spec/unpack_spec.lua
@@ -1,12 +1,13 @@
 local test_env = require("spec.util.test_env")
+local lfs = require("lfs")
 local run = test_env.run
 local testing_paths = test_env.testing_paths
 
 test_env.unload_luarocks()
 
 local extra_rocks = {
-   "/cprint-0.1-2.src.rock",
-   "/cprint-0.1-2.rockspec",
+   "/cprint-${CPRINT}.src.rock",
+   "/cprint-${CPRINT}.rockspec",
    "/luazip-1.2.4-1.rockspec"
 }
 
@@ -33,22 +34,22 @@ describe("luarocks unpack #integration", function()
    describe("more complex tests", function()
       it("download", function()
          assert.is_true(run.luarocks_bool("unpack cprint"))
-         test_env.remove_dir("cprint-0.1-2")
+         test_env.remove_dir("cprint-${CPRINT}")
       end)
 
       it("src", function()
          assert.is_true(run.luarocks_bool("download --source cprint"))
-         assert.is_true(run.luarocks_bool("unpack cprint-0.1-2.src.rock"))
-         os.remove("cprint-0.1-2.src.rock")
-         test_env.remove_dir("cprint-0.1-2")
+         assert.is_true(run.luarocks_bool("unpack cprint-${CPRINT}.src.rock"))
+         os.remove("cprint-${CPRINT}.src.rock")
+         test_env.remove_dir("cprint-${CPRINT}")
       end)
 
       it("src", function()
          assert.is_true(run.luarocks_bool("download --rockspec cprint"))
-         assert.is_true(run.luarocks_bool("unpack cprint-0.1-2.rockspec"))
-         os.remove("cprint-0.1-2.rockspec")
+         assert.is_true(run.luarocks_bool("unpack cprint-${CPRINT}.rockspec"))
+         os.remove("cprint-${CPRINT}.rockspec")
          os.remove("lua-cprint")
-         test_env.remove_dir("cprint-0.1-2")
+         test_env.remove_dir("cprint-${CPRINT}")
       end)
 
       -- #595 luarocks unpack of a git:// rockspec fails to copy the rockspec
@@ -62,9 +63,9 @@ describe("luarocks unpack #integration", function()
       it("binary", function()
          assert.is_true(run.luarocks_bool("build cprint"))
          assert.is_true(run.luarocks_bool("pack cprint"))
-         assert.is_true(run.luarocks_bool("unpack cprint-0.1-2." .. test_env.platform .. ".rock"))
-         test_env.remove_dir("cprint-0.1-2")
-         os.remove("cprint-0.1-2." .. test_env.platform .. ".rock")
+         assert.is_true(run.luarocks_bool("unpack cprint-${CPRINT}." .. test_env.platform .. ".rock"))
+         test_env.remove_dir("cprint-${CPRINT}")
+         os.remove("cprint-${CPRINT}." .. test_env.platform .. ".rock")
       end)
    end)
 end)
diff --git a/spec/upload_spec.lua b/spec/upload_spec.lua
index 7377599..73f26cd 100644
--- a/spec/upload_spec.lua
+++ b/spec/upload_spec.lua
@@ -23,12 +23,12 @@ describe("luarocks upload #integration", function()
    end)
 
    it("api key invalid and skip-pack", function()
-      assert.is_false(run.luarocks_bool("upload --api-key=\"invalid\" --skip-pack " .. testing_paths.testing_server .. "/luasocket-3.0rc1-2.rockspec"))
+      assert.is_false(run.luarocks_bool("upload --api-key=\"invalid\" --skip-pack " .. testing_paths.testing_server .. "/luasocket-${LUASOCKET}.rockspec"))
    end)
 
    it("force #unix", function()
       assert.is_true(test_env.need_rock("dkjson"))
-      assert.is_false(run.luarocks_bool("upload --api-key=\"invalid\" --force " .. testing_paths.testing_server .. "/luasocket-3.0rc1-2.rockspec"))
+      assert.is_false(run.luarocks_bool("upload --api-key=\"invalid\" --force " .. testing_paths.testing_server .. "/luasocket-${LUASOCKET}.rockspec"))
    end)
 
    describe("tests with Xavante server #mock", function()
diff --git a/spec/util/test_env.lua b/spec/util/test_env.lua
index 35c27dc..8705a69 100644
--- a/spec/util/test_env.lua
+++ b/spec/util/test_env.lua
@@ -1,6 +1,7 @@
 local test_env = {}
 
 local lfs = require("lfs")
+local versions = require("spec.util.versions")
 
 local help_message = [[
 LuaRocks test-suite
@@ -17,7 +18,7 @@ ARGUMENTS
                           default: "minimal").
    noreset                Don't reset environment after each test
    clean                  Remove existing testing environment.
-   travis                 Add if running on TravisCI.
+   ci                     Add if running on Unix CI.
    appveyor               Add if running on Appveyor.
    os=<type>              Set OS ("linux", "osx", or "windows").
    lua_dir=<path>         Path of Lua installation (default "/usr/local")
@@ -36,14 +37,6 @@ local function title(str)
    print(("-"):rep(#str))
 end
 
-function test_env.exists(path)
-   return lfs.attributes(path, "mode") ~= nil
-end
-
-function test_env.file_if_exists(path)
-   return lfs.attributes(path, "mode") and path
-end
-
 --- Quote argument for shell processing. Fixes paths on Windows.
 -- Adds double quotes and escapes. Based on function in fs/win32.lua.
 -- @param arg string: Unquoted argument.
@@ -66,6 +59,62 @@ local function Q(arg)
    end
 end
 
+local function V(str)
+   return (str:gsub("${([^}]-)}", function(name)
+      name = name:lower()
+      local prefix, suffix = name:match("^(.*)_(.)$")
+      if suffix then
+         name = prefix
+         local d = assert(versions[name])
+         local v, r = d:match("^([^-]*)%-(%d*)$")
+         if suffix == "d" then
+            return d
+         elseif suffix == "v" then
+            return v
+         elseif suffix == "r" then
+            return v
+         else
+            print("Test error: invalid suffix " .. suffix .. " in variable " .. name)
+            os.exit(1)
+         end
+      else
+         if not versions[name] then
+            print("Test error: no version definition for " .. name)
+            os.exit(1)
+         end
+         return versions[name]
+      end
+   end))
+end
+
+local os_remove = os.remove
+os.remove = function(f) -- luacheck: ignore
+   return os_remove(V(f))
+end
+
+local os_rename = os.rename
+os.rename = function(a, b) -- luacheck: ignore
+   return os_rename(V(a), V(b))
+end
+
+local lfs_chdir = lfs.chdir
+lfs.chdir = function(d) -- luacheck: ignore
+   return lfs_chdir(V(d))
+end
+
+local lfs_attributes = lfs.attributes
+lfs.attributes = function(f, ...) -- luacheck: ignore
+   return lfs_attributes(V(f), ...)
+end
+
+function test_env.exists(path)
+   return lfs.attributes(path, "mode") ~= nil
+end
+
+function test_env.file_if_exists(path)
+   return lfs.attributes(path, "mode") and path
+end
+
 function test_env.quiet(command)
    if not test_env.VERBOSE then
       if test_env.TEST_TARGET_OS == "windows" then
@@ -79,6 +128,9 @@ function test_env.quiet(command)
 end
 
 function test_env.copy(source, destination)
+   source = V(source)
+   destination = V(destination)
+
    local r_source, err = io.open(source, "r")
    local r_destination, err = io.open(destination, "w")
 
@@ -238,8 +290,8 @@ function test_env.set_args()
          test_env.TEST_ENV_CLEAN = true
       elseif argument == "verbose" then
          test_env.VERBOSE = true
-      elseif argument == "travis" then
-         test_env.TRAVIS = true
+      elseif argument == "ci" then
+         test_env.CI = true
       elseif argument == "appveyor" then
          test_env.APPVEYOR = true
       elseif argument:find("^os=") then
@@ -273,13 +325,13 @@ function test_env.set_args()
          local system = execute_output("uname -s")
          if system == "Linux" then
             test_env.TEST_TARGET_OS = "linux"
-            if test_env.TRAVIS then
+            if test_env.CI then
                test_env.OPENSSL_INCDIR = "/usr/include"
                test_env.OPENSSL_LIBDIR = "/usr/lib/x86_64-linux-gnu"
             end
          elseif system == "Darwin" then
             test_env.TEST_TARGET_OS = "osx"
-            if test_env.TRAVIS then
+            if test_env.CI then
                test_env.OPENSSL_INCDIR = "/usr/local/opt/openssl/include"
                test_env.OPENSSL_LIBDIR = "/usr/local/opt/openssl/lib"
             end
@@ -303,6 +355,9 @@ function test_env.set_args()
 end
 
 function test_env.copy_dir(source_path, target_path)
+   source_path = V(source_path)
+   target_path = V(target_path)
+
    local testing_paths = test_env.testing_paths
    if test_env.TEST_TARGET_OS == "windows" then
       execute_bool(testing_paths.win_tools .. "/cp -R ".. source_path .. "/. " .. target_path)
@@ -314,6 +369,8 @@ end
 --- Remove directory recursively
 -- @param path string: directory path to delete
 function test_env.remove_dir(path)
+   path = V(path)
+
    if test_env.exists(path) then
       for file in lfs.dir(path) do
          if file ~= "." and file ~= ".." then
@@ -334,6 +391,8 @@ end
 -- @param path string: path to directory
 -- @param pattern string: pattern matching basenames of subdirectories to be removed
 function test_env.remove_subdirs(path, pattern)
+   path = V(path)
+
    if test_env.exists(path) then
       for file in lfs.dir(path) do
          if file ~= "." and file ~= ".." then
@@ -352,6 +411,8 @@ end
 -- @param pattern string: pattern matching basenames of files to be deleted
 -- @return result_check boolean: true if one or more files deleted
 function test_env.remove_files(path, pattern)
+   path = V(path)
+
    local result_check = false
    if test_env.exists(path) then
       for file in lfs.dir(path) do
@@ -378,12 +439,14 @@ local function download_rocks(urls, save_path)
    local to_download = {}
    local fixtures = {}
    for _, url in ipairs(urls) do
+      url = V(url)
+
       if url:match("^spec/fixtures") then
          table.insert(fixtures, (url:gsub("^spec/fixtures", test_env.testing_paths.fixtures_dir)))
       else
          -- check if already downloaded
          if not test_env.exists(save_path .. "/" .. url) then
-            table.insert(to_download, luarocks_repo .. url)
+            table.insert(to_download, ((luarocks_repo .. url):gsub("org//", "org/")))
          end
       end
    end
@@ -399,7 +462,10 @@ local function download_rocks(urls, save_path)
       else
          cmd = "wget -cP " .. save_path
       end
-      assert(execute_bool(cmd.." "..table.concat(to_download, " ")))
+      local ok = execute_bool(cmd.." "..table.concat(to_download, " "))
+      if not ok then
+         os.exit(1)
+      end
    end
 
    return (#fixtures > 0) or (#to_download > 0)
@@ -409,6 +475,8 @@ end
 -- @param pathname string: path to file.
 -- @param str string: content of the file.
 function test_env.write_file(pathname, str, finally)
+   pathname = V(pathname)
+
    local file = assert(io.open(pathname, "w"))
    file:write(str)
    file:close()
@@ -487,6 +555,7 @@ local function make_run_function(cmd_name, exec_function, with_coverage, do_prin
    end
 
    return function(cmd, new_vars)
+      cmd = V(cmd)
       local temp_vars = {}
       for k, v in pairs(test_env.env_variables) do
          temp_vars[k] = v
@@ -519,7 +588,11 @@ local function move_file(src, dst)
    if test_env.TEST_TARGET_OS == "windows" then
       execute_bool(test_env.testing_paths.win_tools .. "/mv " .. src .. " " .. dst)
    else
-      execute_bool("mv " .. src .. " " .. dst)
+      local ok = execute_bool("mv " .. src .. " " .. dst)
+      if not ok then
+         print(debug.traceback())
+         os.exit(1)
+      end
    end
 end
 
@@ -541,9 +614,9 @@ local function build_environment(rocks, env_variables)
    test_env.run.luarocks_admin_nocov("make_manifest " .. Q(testing_paths.testing_cache))
 
    for _, rock in ipairs(rocks) do
-      if not test_env.run.luarocks_nocov("install --only-server=" .. testing_paths.testing_cache .. " --tree=" .. testing_paths.testing_sys_tree .. " " .. Q(rock), env_variables) then
-         test_env.run.luarocks_nocov("build --tree=" .. Q(testing_paths.testing_sys_tree) .. " " .. Q(rock), env_variables)
-         test_env.run.luarocks_nocov("pack --tree=" .. Q(testing_paths.testing_sys_tree) .. " " .. Q(rock), env_variables)
+      if not test_env.run.luarocks_nocov(test_env.quiet("install --only-server=" .. testing_paths.testing_cache .. " --tree=" .. testing_paths.testing_sys_tree .. " " .. Q(rock), env_variables)) then
+         assert(test_env.run.luarocks_nocov("build --tree=" .. Q(testing_paths.testing_sys_tree) .. " " .. Q(rock), env_variables))
+         assert(test_env.run.luarocks_nocov("pack --tree=" .. Q(testing_paths.testing_sys_tree) .. " " .. Q(rock), env_variables))
          move_file(rock .. "-*.rock", testing_paths.testing_cache)
       end
    end
@@ -581,15 +654,20 @@ local function create_paths(luaversion_full)
       testing_paths.lua_interpreter = test_env.LUA_INTERPRETER or "lua"
    end
 
-   local bindirs = {
-      testing_paths.luadir .. "/bin",
-      testing_paths.luadir,
-   }
-   for _, bindir in ipairs(bindirs) do
-      local lua = bindir .. "/" .. testing_paths.lua_interpreter
-      if test_env.exists(lua) then
-         testing_paths.lua_bindir = bindir
-         testing_paths.lua = lua
+   local locations
+   if testing_paths.lua_interpreter:match("[/\\]") then
+      locations = { testing_paths.lua_interpreter }
+   else
+      locations = {
+         testing_paths.luadir .. "/bin/" .. testing_paths.lua_interpreter,
+         testing_paths.luadir .. "/" .. testing_paths.lua_interpreter,
+      }
+   end
+
+   for _, location in ipairs(locations) do
+      if test_env.exists(location) then
+         testing_paths.lua_bindir = location:match("(.*)[/\\][^/\\]*$")
+         testing_paths.lua = location
          break
       end
    end
@@ -643,7 +721,7 @@ end
 function test_env.setup_specs(extra_rocks)
    -- if global variable about successful creation of testing environment doesn't exist, build environment
    if not test_env.setup_done then
-      if test_env.TRAVIS then
+      if test_env.CI then
          if not test_env.exists(os.getenv("HOME") .. "/.ssh/id_rsa.pub") then
             execute_bool("ssh-keygen -t rsa -P \"\" -f ~/.ssh/id_rsa")
             execute_bool("cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys")
@@ -685,6 +763,8 @@ end
 -- Return `true` if the rock is already installed or has been installed successfully,
 -- `false` if installation failed.
 function test_env.need_rock(rock)
+   rock = V(rock)
+
    print("Check if " .. rock .. " is installed")
    if test_env.run.luarocks_noprint_nocov(test_env.quiet("show " .. rock)) then
       return true
@@ -836,28 +916,40 @@ local function setup_luarocks()
    print("LuaRocks set up correctly!")
 end
 
+local function mock_api_call(path)
+   if test_env.TEST_TARGET_OS == "windows" then
+      return test_env.execute(Q(test_env.testing_paths.win_tools .. "/wget") .. " --quiet --timeout=5 --tries=1 localhost:8080" .. path)
+   else
+      return test_env.execute("curl -s localhost:8080" .. path)
+   end
+end
+
 function test_env.mock_server_init()
    local testing_paths = test_env.testing_paths
    assert(test_env.need_rock("restserver-xavante"))
-   local final_command
-   local sleep_command
+
    if test_env.TEST_TARGET_OS == "windows" then
-      final_command = test_env.execute_helper("start /b \"\" " .. Q(testing_paths.lua) .. " " .. Q(testing_paths.util_dir .. "/mock-server.lua") .. " " .. Q(testing_paths.fixtures_dir), true, test_env.env_variables)
-      sleep_command = "timeout 1 > NUL"
+      os.execute(test_env.execute_helper("start /b \"\" " .. Q(testing_paths.lua) .. " " .. Q(testing_paths.util_dir .. "/mock-server.lua") .. " " .. Q(testing_paths.fixtures_dir), true, test_env.env_variables))
    else
-      final_command = test_env.execute_helper(testing_paths.lua .. " " .. testing_paths.util_dir .. "/mock-server.lua " .. testing_paths.fixtures_dir .. " &", true, test_env.env_variables)
-      sleep_command = "sleep 1"
+      os.execute(test_env.execute_helper(testing_paths.lua .. " " .. testing_paths.util_dir .. "/mock-server.lua " .. testing_paths.fixtures_dir .. " &", true, test_env.env_variables))
    end
-   os.execute(final_command)
-   os.execute(sleep_command)
+
+   for _ = 1, 10 do
+      if mock_api_call("/api/tool_version") then
+         break
+      end
+
+      if test_env.TEST_TARGET_OS == "windows" then
+         os.execute("timeout 1 > NUL")
+      else
+         os.execute("sleep 1")
+      end
+   end
+
 end
 
 function test_env.mock_server_done()
-   if test_env.TEST_TARGET_OS == "windows" then
-      os.execute(Q(test_env.testing_paths.win_tools .. "/wget") .. " --quiet --timeout=5 --tries=1 localhost:8080/shutdown")
-   else
-      os.execute("curl localhost:8080/shutdown")
-   end
+   mock_api_call("/shutdown")
 end
 
 local function find_binary_rock(src_rock, dir)
@@ -875,20 +967,23 @@ local function prepare_mock_server_binary_rocks()
 
    local rocks = {
       -- rocks needed for mock-server
-      "luasocket-3.0rc1-2.src.rock",
+      "luasocket-${LUASOCKET}.src.rock",
       "coxpcall-1.16.0-1.src.rock",
-      "copas-2.0.1-1.src.rock",
-      "luafilesystem-1.7.0-2.src.rock",
+      "binaryheap-${BINARYHEAP}.src.rock",
+      "timerwheel-${TIMERWHEEL}.src.rock",
+      "copas-${COPAS}.src.rock",
+      "luafilesystem-${LUAFILESYSTEM}.src.rock",
       "xavante-2.4.0-1.src.rock",
       "wsapi-1.6.1-1.src.rock",
       "rings-1.3.0-1.src.rock",
       "wsapi-xavante-1.6.1-1.src.rock",
-      "dkjson-2.5-2.src.rock",
+      "dkjson-${DKJSON}.src.rock",
       "restserver-0.1-1.src.rock",
       "restserver-xavante-0.2-1.src.rock",
    }
    local make_manifest = download_rocks(rocks, testing_paths.testing_server)
    for _, rock in ipairs(rocks) do
+      rock = V(rock)
       local rockname = rock:gsub("%-[^-]+%-%d+%.[%a.]+$", "")
       if not find_binary_rock(rock, testing_paths.testing_server) then
          test_env.run.luarocks_nocov("build " .. Q(testing_paths.testing_server .. "/" .. rock) .. " --tree=" .. testing_paths.testing_cache)
@@ -924,26 +1019,36 @@ function test_env.main()
    local rocks = {} -- names of rocks, required for building environment
    local urls = {}  -- names of rock and rockspec files to be downloaded
 
+   local env_vars = {
+      LUAROCKS_CONFIG = test_env.testing_paths.testrun_dir .. "/testing_config.lua"
+   }
+
    if test_env.TYPE_TEST_ENV == "full" then
-      table.insert(urls, "/luafilesystem-1.6.3-1.src.rock")
-      table.insert(urls, "/luasocket-3.0rc1-1.src.rock")
-      table.insert(urls, "/luasocket-3.0rc1-1.rockspec")
+      table.insert(urls, "/luafilesystem-${LUAFILESYSTEM}.src.rock")
+      table.insert(urls, "/luasocket-${LUASOCKET}.src.rock")
+      table.insert(urls, "/luasocket-${LUASOCKET}.rockspec")
+      table.insert(urls, "/luasec-${LUASEC}.src.rock")
       table.insert(urls, "/md5-1.2-1.src.rock")
-      --table.insert(urls, "/lzlib-0.4.1.53-1.src.rock")
-      table.insert(urls, "/lua-zlib-1.2-0.src.rock")
-      table.insert(urls, "/lua-bz2-0.1.0-1.src.rock")
-      rocks = {"luafilesystem", "luasocket", "md5", "lua-zlib", "lua-bz2"}
+      table.insert(urls, "/manifests/hisham/lua-zlib-1.2-0.src.rock")
+      table.insert(urls, "/manifests/hisham/lua-bz2-0.2.1.1-1.src.rock")
+      rocks = {"luafilesystem", "luasocket", "luasec", "md5", "lua-zlib", "lua-bz2"}
       if test_env.TEST_TARGET_OS ~= "windows" then
-         table.insert(urls, "/luaposix-33.2.1-1.src.rock")
+         if test_env.lua_version == "5.1" then
+            table.insert(urls, "/bit32-${BIT32}.src.rock")
+            table.insert(rocks, "bit32")
+         end
+         table.insert(urls, "/luaposix-${LUAPOSIX}.src.rock")
          table.insert(rocks, "luaposix")
       end
+      assert(test_env.run.luarocks_nocov("config variables.OPENSSL_INCDIR " .. Q(test_env.OPENSSL_INCDIR), env_vars))
+      assert(test_env.run.luarocks_nocov("config variables.OPENSSL_LIBDIR " .. Q(test_env.OPENSSL_LIBDIR), env_vars))
    end
 
    -- luacov is needed for both minimal or full environment
-   table.insert(urls, "/luacov-0.15.0-1.rockspec")
-   table.insert(urls, "/luacov-0.15.0-1.src.rock")
-   table.insert(urls, "/cluacov-0.1.1-1.rockspec")
-   table.insert(urls, "/cluacov-0.1.1-1.src.rock")
+   table.insert(urls, "/luacov-${LUACOV}.rockspec")
+   table.insert(urls, "/luacov-${LUACOV}.src.rock")
+   table.insert(urls, "/cluacov-${CLUACOV}.rockspec")
+   table.insert(urls, "/cluacov-${CLUACOV}.src.rock")
    table.insert(rocks, "luacov")
    table.insert(rocks, "cluacov")
 
@@ -951,10 +1056,6 @@ function test_env.main()
    lfs.mkdir(testing_paths.testing_server)
    download_rocks(urls, testing_paths.testing_server)
 
-   local env_vars = {
-      LUAROCKS_CONFIG = test_env.testing_paths.testrun_dir .. "/testing_config.lua"
-   }
-
    build_environment(rocks, env_vars)
 
    prepare_mock_server_binary_rocks()
@@ -965,5 +1066,6 @@ test_env.set_args()
 test_env.testing_paths = create_paths(test_env.LUA_V or test_env.LUAJIT_V)
 test_env.env_variables = create_env(test_env.testing_paths)
 test_env.run = make_run_functions()
+test_env.V = V
 
 return test_env
diff --git a/spec/util/versions.lua b/spec/util/versions.lua
new file mode 100644
index 0000000..1b227e4
--- /dev/null
+++ b/spec/util/versions.lua
@@ -0,0 +1,17 @@
+return {
+   binaryheap = "0.4-1", -- dependency for copas
+   bit32 = "5.3.5.1-1", -- dependency for luaposix on Lua 5.1
+   cluacov = "0.1.2-1",
+   copas = "3.0.0-2",
+   cprint = "0.2-1",
+   dkjson = "2.6-1",
+   lpeg = "1.0.0-1",
+   luacov = "0.15.0-1",
+   luafilesystem = "1.8.0-1",
+   luafilesystem_old = "1.6.3-2",
+   luaposix = "35.1-1",
+   luasocket = "3.0.0-1",
+   luasec = "1.2.0-1",
+   lxsh = "0.8.6-2",
+   timerwheel = "0.2.0-2", -- dependency for copas
+}
diff --git a/spec/util_spec.lua b/spec/util_spec.lua
index 5aa49b4..0c2d620 100644
--- a/spec/util_spec.lua
+++ b/spec/util_spec.lua
@@ -72,6 +72,31 @@ describe("luarocks.util #unit", function()
       runner.shutdown()
    end)
 
+   describe("util.variable_substitutions", function()
+      it("replaces variables", function()
+         local t = {
+            ["hello"] = "$(KIND) world",
+         }
+         util.variable_substitutions(t, {
+            ["KIND"] = "happy",
+         })
+         assert.are.same({
+            ["hello"] = "happy world",
+         }, t)
+      end)
+
+      it("missing variables are empty", function()
+         local t = {
+            ["hello"] = "$(KIND) world",
+         }
+         util.variable_substitutions(t, {
+         })
+         assert.are.same({
+            ["hello"] = " world",
+         }, t)
+      end)
+   end)
+
    describe("util.sortedpairs", function()
       local function collect(iter, state, var)
          local collected = {}
diff --git a/src/luarocks/build/builtin.lua b/src/luarocks/build/builtin.lua
index 98db29d..cd4d448 100644
--- a/src/luarocks/build/builtin.lua
+++ b/src/luarocks/build/builtin.lua
@@ -157,6 +157,10 @@ function builtin.run(rockspec, no_install)
    local variables = rockspec.variables
    local checked_lua_h = false
 
+   for _, var in ipairs{ "CC", "CFLAGS", "LDFLAGS" } do
+      variables[var] = variables[var] or os.getenv(var) or ""
+   end
+
    local function add_flags(extras, flag, flags)
       if flags then
          if type(flags) ~= "table" then
@@ -176,13 +180,21 @@ function builtin.run(rockspec, no_install)
          add_flags(extras, "-I%s", incdirs)
          return execute(variables.CC.." "..variables.CFLAGS, "-c", "-o", object, "-I"..variables.LUA_INCDIR, source, unpack(extras))
       end
-      compile_library = function(library, objects, libraries, libdirs)
+      compile_library = function(library, objects, libraries, libdirs, name)
          local extras = { unpack(objects) }
          add_flags(extras, "-L%s", libdirs)
          add_flags(extras, "-l%s", libraries)
          extras[#extras+1] = dir.path(variables.LUA_LIBDIR, variables.LUALIB)
-         extras[#extras+1] = "-l" .. (variables.MSVCRT or "m")
-         local ok = execute(variables.LD.." "..variables.LIBFLAG, "-o", library, unpack(extras))
+
+         if variables.CC == "clang" or variables.CC == "clang-cl" then
+            local exported_name = name:gsub("%.", "_")
+            exported_name = exported_name:match('^[^%-]+%-(.+)$') or exported_name
+            extras[#extras+1] = string.format("-Wl,-export:luaopen_%s", exported_name)
+         else
+            extras[#extras+1] = "-l" .. (variables.MSVCRT or "m")
+         end
+
+         local ok = execute(variables.LD.." "..variables.LDFLAGS.." "..variables.LIBFLAG, "-o", library, unpack(extras))
          return ok
       end
       --[[ TODO disable static libs until we fix the conflict in the manifest, which will take extending the manifest format.
@@ -250,7 +262,7 @@ function builtin.run(rockspec, no_install)
             extras[#extras+1] = "-L"..variables.LUA_LIBDIR
             extras[#extras+1] = "-llua"
          end
-         return execute(variables.LD.." "..variables.LIBFLAG, "-o", library, unpack(extras))
+         return execute(variables.LD.." "..variables.LDFLAGS.." "..variables.LIBFLAG, "-o", library, unpack(extras))
       end
       compile_static_library = function(library, objects, libraries, libdirs, name)  -- luacheck: ignore 211
          local ok = execute(variables.AR, "rc", library, unpack(objects))
diff --git a/src/luarocks/cmd.lua b/src/luarocks/cmd.lua
index 233bb1b..f1446df 100644
--- a/src/luarocks/cmd.lua
+++ b/src/luarocks/cmd.lua
@@ -293,7 +293,11 @@ do
       end
 
       detect_config_via_args = function(args)
-         local project_dir, given = find_project_dir(args.project_tree)
+         local project_dir, given
+         if not args.no_project then
+            project_dir, given = find_project_dir(args.project_tree)
+         end
+
          local detected = detect_lua_via_args(args, project_dir)
          if args.lua_version then
             detected.given_lua_version = args.lua_version
@@ -346,9 +350,9 @@ local function get_config_text(cfg)  -- luacheck: ignore 431
 
    local libdir_ok = deps.check_lua_libdir(cfg.variables)
    local incdir_ok = deps.check_lua_incdir(cfg.variables)
-   local bindir_ok = fs.exists(cfg.variables.LUA_BINDIR)
-   local luadir_ok = fs.exists(cfg.variables.LUA_DIR)
-   local lua_ok = fs.exists(cfg.variables.LUA)
+   local bindir_ok = cfg.variables.LUA_BINDIR and fs.exists(cfg.variables.LUA_BINDIR)
+   local luadir_ok = cfg.variables.LUA_DIR and fs.exists(cfg.variables.LUA_DIR)
+   local lua_ok = cfg.variables.LUA and fs.exists(cfg.variables.LUA)
 
    local buf = "Configuration:\n"
    buf = buf.."   Lua:\n"
@@ -463,11 +467,13 @@ Enabling completion for Fish:
       :argname("<prefix>")
    parser:option("--lua-version", "Which Lua version to use.")
       :argname("<ver>")
+      :convert(function(s) return (s:match("^%d+%.%d+$")) end)
    parser:option("--tree", "Which tree to operate on.")
       :hidden_name("--to")
    parser:flag("--local", "Use the tree in the user's home directory.\n"..
       "To enable it, see '"..program.." help path'.")
    parser:flag("--global", "Use the system tree when `local_by_default` is `true`.")
+   parser:flag("--no-project", "Do not use project tree even if running from a project folder.")
    parser:flag("--verbose", "Display verbose output of commands executed.")
    parser:option("--timeout", "Timeout on network operations, in seconds.\n"..
       "0 means no timeout (wait forever). Default is "..
diff --git a/src/luarocks/cmd/build.lua b/src/luarocks/cmd/build.lua
index 002c723..56f0e75 100644
--- a/src/luarocks/cmd/build.lua
+++ b/src/luarocks/cmd/build.lua
@@ -36,7 +36,7 @@ function cmd_build.add_to_parser(parser)
       "rockspec. Allows to specify a different branch to fetch. Particularly "..
       'for "dev" rocks.')
       :argname("<name>")
-   parser:flag("--pin", "Create a luarocks.lock file listing the exact "..
+   cmd:flag("--pin", "Create a luarocks.lock file listing the exact "..
       "versions of each dependency found for this rock (recursively), "..
       "and store it in the rock's directory. "..
       "Ignores any existing luarocks.lock file in the rock's sources.")
diff --git a/src/luarocks/cmd/init.lua b/src/luarocks/cmd/init.lua
index af88760..8bccb23 100644
--- a/src/luarocks/cmd/init.lua
+++ b/src/luarocks/cmd/init.lua
@@ -145,7 +145,7 @@ function init.command(args)
    luarocks_wrapper = dir.path(".", luarocks_wrapper)
    if not fs.exists(luarocks_wrapper) then
       util.printout("Preparing " .. luarocks_wrapper .. " ...")
-      fs.wrap_script(arg[0], "luarocks", "none", nil, nil, "--project-tree", tree)
+      fs.wrap_script(arg[0], luarocks_wrapper, "none", nil, nil, "--project-tree", tree)
    else
       util.printout(luarocks_wrapper .. " already exists. Not overwriting it!")
    end
@@ -164,7 +164,7 @@ function init.command(args)
       if util.check_lua_version(interp, cfg.lua_version) then
          util.printout("Preparing " .. lua_wrapper .. " for version " .. cfg.lua_version .. "...")
          path.use_tree(tree)
-         fs.wrap_script(nil, "lua", "all")
+         fs.wrap_script(nil, lua_wrapper, "all")
       else
          util.warning("No Lua interpreter detected for version " .. cfg.lua_version .. ". Not creating " .. lua_wrapper)
       end
diff --git a/src/luarocks/cmd/install.lua b/src/luarocks/cmd/install.lua
index 0d6ad63..c2e947b 100644
--- a/src/luarocks/cmd/install.lua
+++ b/src/luarocks/cmd/install.lua
@@ -43,6 +43,10 @@ function install.add_to_parser(parser)
       "and report if it is available for another Lua version.")
    util.deps_mode_option(cmd)
    cmd:flag("--no-manifest", "Skip creating/updating the manifest")
+   cmd:flag("--pin", "If the installed rock is a Lua module, create a "..
+      "luarocks.lock file listing the exact versions of each dependency found for "..
+      "this rock (recursively), and store it in the rock's directory. "..
+      "Ignores any existing luarocks.lock file in the rock's sources.")
    -- luarocks build options
    parser:flag("--pack-binary-rock"):hidden(true)
    parser:option("--branch"):hidden(true)
diff --git a/src/luarocks/cmd/test.lua b/src/luarocks/cmd/test.lua
index be9a5df..b353bd8 100644
--- a/src/luarocks/cmd/test.lua
+++ b/src/luarocks/cmd/test.lua
@@ -24,7 +24,7 @@ to separate LuaRocks arguments from test suite arguments.]],
    cmd:argument("args", "Test suite arguments.")
       :args("*")
    cmd:flag("--prepare", "Only install dependencies needed for testing only, but do not run the test")
-   
+
    cmd:option("--test-type", "Specify the test suite type manually if it was "..
       "not specified in the rockspec and it could not be auto-detected.")
       :argname("<type>")
@@ -41,7 +41,7 @@ function cmd_test.command(args)
    if not rockspec then
       return nil, err
    end
-   
+
    return test.run_test_suite(rockspec, args.test_type, args.args, args.prepare)
 end
 
diff --git a/src/luarocks/cmd/which.lua b/src/luarocks/cmd/which.lua
index 7503df0..f50a43c 100644
--- a/src/luarocks/cmd/which.lua
+++ b/src/luarocks/cmd/which.lua
@@ -6,7 +6,6 @@ local which_cmd = {}
 local loader = require("luarocks.loader")
 local cfg = require("luarocks.core.cfg")
 local util = require("luarocks.util")
-local fs = require("luarocks.fs")
 
 function which_cmd.add_to_parser(parser)
    local cmd = parser:command("which", 'Given a module name like "foo.bar", '..
@@ -21,24 +20,17 @@ end
 --- Driver function for "which" command.
 -- @return boolean This function terminates the interpreter.
 function which_cmd.command(args)
-   local pathname, rock_name, rock_version = loader.which(args.modname)
+   local pathname, rock_name, rock_version, where = loader.which(args.modname, "lp")
 
    if pathname then
       util.printout(pathname)
-      util.printout("(provided by " .. tostring(rock_name) .. " " .. tostring(rock_version) .. ")")
-      return true
-   end
-
-   local modpath = args.modname:gsub("%.", "/")
-   for _, v in ipairs({"path", "cpath"}) do
-      for p in package[v]:gmatch("([^;]+)") do
-         local pathname = p:gsub("%?", modpath)  -- luacheck: ignore 421
-         if fs.exists(pathname) then
-            util.printout(pathname)
-            util.printout("(found directly via package." .. v .. " -- not installed as a rock?)")
-            return true
-         end
+      if where == "l" then
+         util.printout("(provided by " .. tostring(rock_name) .. " " .. tostring(rock_version) .. ")")
+      else
+         local key = rock_name
+         util.printout("(found directly via package." .. key.. " -- not installed as a rock?)")
       end
+      return true
    end
 
    return nil, "Module '" .. args.modname .. "' not found."
diff --git a/src/luarocks/core/cfg.lua b/src/luarocks/core/cfg.lua
index 926d479..eb170f3 100644
--- a/src/luarocks/core/cfg.lua
+++ b/src/luarocks/core/cfg.lua
@@ -20,9 +20,7 @@ local vers = require("luarocks.core.vers")
 
 --------------------------------------------------------------------------------
 
-local program_version = "3.8.0"
-local program_series = "3.8"
-local major_version = (program_version:match("([^.]%.[^.])")) or program_series
+local program_version = "3.9.2"
 
 local is_windows = package.config:sub(1,1) == "\\"
 
@@ -37,6 +35,7 @@ local platform_order = {
    "netbsd",
    "openbsd",
    "freebsd",
+   "dragonfly",
    "linux",
    "macosx",
    "cygwin",
@@ -45,6 +44,7 @@ local platform_order = {
    -- Windows
    "windows",
    "win32",
+   "mingw",
    "mingw32",
    "msys2_mingw_w64",
 }
@@ -77,11 +77,16 @@ local load_config_file
 do
    -- Create global environment for the config files;
    local function env_for_config_file(cfg, platforms)
+      local platforms_copy = {}
+      for k,v in pairs(platforms) do
+         platforms_copy[k] = v
+      end
+
       local e
       e = {
          home = cfg.home,
          lua_version = cfg.lua_version,
-         platforms = util.make_shallow_copy(platforms),
+         platforms = platforms_copy,
          processor = cfg.target_cpu,   -- remains for compat reasons
          target_cpu = cfg.target_cpu,  -- replaces `processor`
          os_getenv = os.getenv,
@@ -145,6 +150,7 @@ end
 local platform_sets = {
    freebsd = { unix = true, bsd = true, freebsd = true },
    openbsd = { unix = true, bsd = true, openbsd = true },
+   dragonfly = { unix = true, bsd = true, dragonfly = true },
    solaris = { unix = true, solaris = true },
    windows = { windows = true, win32 = true },
    cygwin = { unix = true, cygwin = true },
@@ -195,7 +201,6 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
            "https://luarocks.org",
            "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/",
            "https://luafr.org/luarocks/",
-           "http://luarocks.logiceditor.com/rocks",
          }
       },
       disabled_servers = {},
@@ -210,11 +215,11 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
       connection_timeout = 30,  -- 0 = no timeout
 
       variables = {
-         MAKE = "make",
-         CC = "cc",
-         LD = "ld",
-         AR = "ar",
-         RANLIB = "ranlib",
+         MAKE = os.getenv("MAKE") or "make",
+         CC = os.getenv("CC") or "cc",
+         LD = os.getenv("CC") or "ld",
+         AR = os.getenv("AR") or "ar",
+         RANLIB = os.getenv("RANLIB") or "ranlib",
 
          CVS = "cvs",
          GIT = "git",
@@ -281,14 +286,16 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
       defaults.external_deps_dirs = { "c:/external/", "c:/windows/system32" }
 
       defaults.makefile = "Makefile.win"
-      defaults.variables.MAKE = "nmake"
-      defaults.variables.CC = "cl"
-      defaults.variables.RC = "rc"
-      defaults.variables.LD = "link"
-      defaults.variables.MT = "mt"
-      defaults.variables.AR = "lib"
+      defaults.variables.PWD = "echo %cd%"
+      defaults.variables.MAKE = os.getenv("MAKE") or "nmake"
+      defaults.variables.CC = os.getenv("CC") or "cl"
+      defaults.variables.RC = os.getenv("WINDRES") or "rc"
+      defaults.variables.LD = os.getenv("LINK") or "link"
+      defaults.variables.MT = os.getenv("MT") or "mt"
+      defaults.variables.AR = os.getenv("AR") or "lib"
       defaults.variables.LUALIB = "lua"..lua_version..".lib"
-      defaults.variables.CFLAGS = "/nologo /MD /O2"
+      defaults.variables.CFLAGS = os.getenv("CFLAGS") or "/nologo /MD /O2"
+      defaults.variables.LDFLAGS = os.getenv("LDFLAGS")
       defaults.variables.LIBFLAG = "/nologo /dll"
 
       defaults.external_deps_patterns = {
@@ -323,13 +330,19 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
       defaults.static_lib_extension = "a"
       defaults.external_deps_dirs = { "c:/external/", "c:/mingw", "c:/windows/system32" }
       defaults.cmake_generator = "MinGW Makefiles"
-      defaults.variables.MAKE = "mingw32-make"
-      defaults.variables.CC = "mingw32-gcc"
-      defaults.variables.RC = "windres"
-      defaults.variables.LD = "mingw32-gcc"
-      defaults.variables.AR = "ar"
-      defaults.variables.RANLIB = "ranlib"
-      defaults.variables.CFLAGS = "-O2"
+      defaults.variables.MAKE = os.getenv("MAKE") or "mingw32-make"
+      if target_cpu == "x86_64" then
+         defaults.variables.CC = os.getenv("CC") or "x86_64-w64-mingw32-gcc"
+         defaults.variables.LD = os.getenv("CC") or "x86_64-w64-mingw32-gcc"
+      else
+         defaults.variables.CC = os.getenv("CC") or "mingw32-gcc"
+         defaults.variables.LD = os.getenv("CC") or "mingw32-gcc"
+      end
+      defaults.variables.AR = os.getenv("AR") or "ar"
+      defaults.variables.RC = os.getenv("WINDRES") or "windres"
+      defaults.variables.RANLIB = os.getenv("RANLIB") or "ranlib"
+      defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2"
+      defaults.variables.LDFLAGS = os.getenv("LDFLAGS")
       defaults.variables.LIBFLAG = "-shared"
       defaults.makefile = "Makefile"
       defaults.external_deps_patterns = {
@@ -353,10 +366,19 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
       defaults.external_lib_extension = "so"
       defaults.obj_extension = "o"
       defaults.external_deps_dirs = { "/usr/local", "/usr", "/" }
-      defaults.variables.CFLAGS = "-O2"
+
+      defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2"
+      -- we pass -fPIC via CFLAGS because of old Makefile-based Lua projects
+      -- which didn't have -fPIC in their Makefiles but which honor CFLAGS
+      if not defaults.variables.CFLAGS:match("-fPIC") then
+         defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC"
+      end
+
+      defaults.variables.LDFLAGS = os.getenv("LDFLAGS")
+
       defaults.cmake_generator = "Unix Makefiles"
-      defaults.variables.CC = "gcc"
-      defaults.variables.LD = "gcc"
+      defaults.variables.CC = os.getenv("CC") or "gcc"
+      defaults.variables.LD = os.getenv("CC") or "gcc"
       defaults.gcc_rpath = true
       defaults.variables.LIBFLAG = "-shared"
       defaults.variables.TEST = "test"
@@ -375,9 +397,6 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
       defaults.wrapper_suffix = ""
       local xdg_cache_home = os.getenv("XDG_CACHE_HOME") or home.."/.cache"
       defaults.local_cache = xdg_cache_home.."/luarocks"
-      if not defaults.variables.CFLAGS:match("-fPIC") then
-         defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC"
-      end
       defaults.web_browser = "xdg-open"
    end
 
@@ -385,8 +404,8 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
       defaults.lib_extension = "so" -- can be overridden in the config file for mingw builds
       defaults.arch = "cygwin-"..target_cpu
       defaults.cmake_generator = "Unix Makefiles"
-      defaults.variables.CC = "echo -llua | xargs gcc"
-      defaults.variables.LD = "echo -llua | xargs gcc"
+      defaults.variables.CC = "echo -llua | xargs " .. (os.getenv("CC") or "gcc")
+      defaults.variables.LD = "echo -llua | xargs " .. (os.getenv("CC") or "gcc")
       defaults.variables.LIBFLAG = "-shared"
       defaults.link_lua_explicitly = true
    end
@@ -417,25 +436,33 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
          defaults.makefile = "Makefile"
          defaults.cmake_generator = "MSYS Makefiles"
          defaults.local_cache = home.."/.cache/luarocks"
-         defaults.variables.MAKE = "make"
-         defaults.variables.CC = "gcc"
-         defaults.variables.RC = "windres"
-         defaults.variables.LD = "gcc"
-         defaults.variables.MT = nil
-         defaults.variables.AR = "ar"
-         defaults.variables.RANLIB = "ranlib"
+         defaults.variables.MAKE = os.getenv("MAKE") or "make"
+         defaults.variables.CC = os.getenv("CC") or "gcc"
+         defaults.variables.RC = os.getenv("WINDRES") or "windres"
+         defaults.variables.LD = os.getenv("CC") or "gcc"
+         defaults.variables.MT = os.getenv("MT") or nil
+         defaults.variables.AR = os.getenv("AR") or "ar"
+         defaults.variables.RANLIB = os.getenv("RANLIB") or "ranlib"
          defaults.variables.LUALIB = "liblua"..lua_version..".dll.a"
-         defaults.variables.CFLAGS = "-O2 -fPIC"
+
+         defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2 -fPIC"
+         if not defaults.variables.CFLAGS:match("-fPIC") then
+            defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC"
+         end
+
          defaults.variables.LIBFLAG = "-shared"
       end
    end
 
    if platforms.bsd then
       defaults.variables.MAKE = "gmake"
+      defaults.gcc_rpath = false
+      defaults.variables.CC = os.getenv("CC") or "cc"
+      defaults.variables.LD = os.getenv("CC") or defaults.variables.CC
    end
 
    if platforms.macosx then
-      defaults.variables.MAKE = "make"
+      defaults.variables.MAKE = os.getenv("MAKE") or "make"
       defaults.external_lib_extension = "dylib"
       defaults.arch = "macosx-"..target_cpu
       defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load"
@@ -444,7 +471,9 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
          version = "10.3"
       end
       version = vers.parse_version(version)
-      if version >= vers.parse_version("10.10") then
+      if version >= vers.parse_version("11.0") then
+         version = vers.parse_version("11.0")
+      elseif version >= vers.parse_version("10.10") then
          version = vers.parse_version("10.8")
       elseif version >= vers.parse_version("10.5") then
          version = vers.parse_version("10.5")
@@ -454,6 +483,21 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
       defaults.variables.CC = "env MACOSX_DEPLOYMENT_TARGET="..tostring(version).." gcc"
       defaults.variables.LD = "env MACOSX_DEPLOYMENT_TARGET="..tostring(version).." gcc"
       defaults.web_browser = "open"
+
+      -- XCode SDK
+      local sdk_path = util.popen_read("xcrun --show-sdk-path 2>/dev/null")
+      if sdk_path then
+         table.insert(defaults.external_deps_dirs, sdk_path .. "/usr")
+         table.insert(defaults.external_deps_patterns.lib, 1, "lib?.tbd")
+         table.insert(defaults.runtime_external_deps_patterns.lib, 1, "lib?.tbd")
+      end
+
+      -- Homebrew
+      table.insert(defaults.external_deps_dirs, "/usr/local/opt")
+      defaults.external_deps_subdirs.lib = { "", "lib", }
+      defaults.runtime_external_deps_subdirs.lib = { "", "lib", }
+      table.insert(defaults.external_deps_patterns.lib, 1, "/?/lib/lib?.dylib")
+      table.insert(defaults.runtime_external_deps_patterns.lib, 1, "/?/lib/lib?.dylib")
    end
 
    if platforms.linux then
@@ -471,29 +515,14 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
 
    if platforms.freebsd then
       defaults.arch = "freebsd-"..target_cpu
-      defaults.gcc_rpath = false
-      defaults.variables.CC = os.getenv("CC") or "cc"
-      defaults.variables.CFLAGS = os.getenv("CFLAGS") or defaults.variables.CFLAGS
-      defaults.variables.LD = defaults.variables.CC
-      defaults.variables.LIBFLAG = (os.getenv("LDFLAGS") or "").." -shared"
-   end
-
-   if platforms.openbsd then
+   elseif platforms.dragonfly then
+      defaults.arch = "dragonfly-"..target_cpu
+   elseif platforms.openbsd then
       defaults.arch = "openbsd-"..target_cpu
-      defaults.gcc_rpath = false
-      defaults.variables.CC = os.getenv("CC") or "cc"
-      defaults.variables.CFLAGS = os.getenv("CFLAGS") or defaults.variables.CFLAGS
-      defaults.variables.LD = defaults.variables.CC
-      defaults.variables.LIBFLAG = (os.getenv("LDFLAGS") or "").." -shared"
-   end
-
-   if platforms.netbsd then
+   elseif platforms.netbsd then
       defaults.arch = "netbsd-"..target_cpu
-   end
-
-   if platforms.solaris then
+   elseif platforms.solaris then
       defaults.arch = "solaris-"..target_cpu
-      --defaults.platforms = {"unix", "solaris"}
       defaults.variables.MAKE = "gmake"
    end
 
@@ -558,6 +587,10 @@ local cfg = {}
 function cfg.init(detected, warning)
    detected = detected or {}
 
+   local exit_ok = true
+   local exit_err = nil
+   local exit_what = nil
+
    local hc_ok, hardcoded = pcall(require, "luarocks.core.hardcoded")
    if not hc_ok then
       hardcoded = {}
@@ -574,8 +607,6 @@ function cfg.init(detected, warning)
    end
 
    cfg.program_version = program_version
-   cfg.program_series = program_series
-   cfg.major_version = major_version
 
    if hardcoded.IS_BINARY then
       cfg.is_binary = true
@@ -666,7 +697,7 @@ function cfg.init(detected, warning)
    sys_config_file = (cfg.sysconfdir .. "/" .. config_file_name):gsub("\\", "/")
    local sys_config_ok, err = load_config_file(cfg, platforms, sys_config_file)
    if err then
-      return nil, err, "config"
+      exit_ok, exit_err, exit_what = nil, err, "config"
    end
 
    -- Load user configuration file (if allowed)
@@ -683,7 +714,7 @@ function cfg.init(detected, warning)
       if env_value then
          local env_ok, err = load_config_file(cfg, platforms, env_value)
          if err then
-            return nil, err, "config"
+            exit_ok, exit_err, exit_what = nil, err, "config"
          elseif warning and not env_ok then
             warning("Warning: could not load configuration file `"..env_value.."` given in environment variable "..env_var.."\n")
          end
@@ -700,7 +731,7 @@ function cfg.init(detected, warning)
          home_config_file = (cfg.homeconfdir .. "/" .. config_file_name):gsub("\\", "/")
          home_config_ok, err = load_config_file(cfg, platforms, home_config_file)
          if err then
-            return nil, err, "config"
+            exit_ok, exit_err, exit_what = nil, err, "config"
          end
       end
 
@@ -710,7 +741,7 @@ function cfg.init(detected, warning)
          home_config_file = (cfg.homeconfdir .. "/" .. config_file_name):gsub("\\", "/")
          home_config_ok, err = load_config_file(cfg, platforms, home_config_file)
          if err then
-            return nil, err, "config"
+            exit_ok, exit_err, exit_what = nil, err, "config"
          end
       end
 
@@ -719,7 +750,7 @@ function cfg.init(detected, warning)
          project_config_file = cfg.project_dir .. "/.luarocks/" .. config_file_name
          project_config_ok, err = load_config_file(cfg, platforms, project_config_file)
          if err then
-            return nil, err, "config"
+            exit_ok, exit_err, exit_what = nil, err, "config"
          end
       end
    end
@@ -754,7 +785,7 @@ function cfg.init(detected, warning)
    local defaults = make_defaults(cfg.lua_version, processor, platforms, cfg.home)
 
    if platforms.windows and hardcoded.WIN_TOOLS then
-      local tools = { "SEVENZ", "CP", "FIND", "LS", "MD5SUM", "PWD", "RMDIR", "WGET", "MKDIR" }
+      local tools = { "SEVENZ", "CP", "FIND", "LS", "MD5SUM", "WGET", }
       for _, tool in ipairs(tools) do
          defaults.variables[tool] = '"' .. hardcoded.WIN_TOOLS .. "/" .. defaults.variables[tool] .. '.exe"'
       end
@@ -872,7 +903,7 @@ function cfg.init(detected, warning)
       return table.concat(platform_keys, ", ")
    end
 
-   return true
+   return exit_ok, exit_err, exit_what
 end
 
 return cfg
diff --git a/src/luarocks/core/path.lua b/src/luarocks/core/path.lua
index bf6bdc2..b354a41 100644
--- a/src/luarocks/core/path.lua
+++ b/src/luarocks/core/path.lua
@@ -44,24 +44,29 @@ end
 function path.path_to_module(file)
    assert(type(file) == "string")
 
-   local name = file:match("(.*)%."..cfg.lua_extension.."$")
-   if name then
-      name = name:gsub("/", ".")
-   else
-      name = file:match("(.*)%."..cfg.lib_extension.."$")
+   local exts = {}
+   local paths = package.path .. ";" .. package.cpath
+   for entry in paths:gmatch("[^;]+") do
+      local ext = entry:match("%.([a-z]+)$")
+      if ext then
+         exts[ext] = true
+      end
+   end
+
+   local name
+   for ext, _ in pairs(exts) do
+      name = file:match("(.*)%." .. ext .. "$")
       if name then
-         name = name:gsub("/", ".")
-      --[[ TODO disable static libs until we fix the conflict in the manifest, which will take extending the manifest format.
-      else
-         name = file:match("(.*)%."..cfg.static_lib_extension.."$")
-         if name then
-            name = name:gsub("/", ".")
-         end
-      ]]
+         name = name:gsub("[/\\]", ".")
+         break
       end
    end
+
    if not name then name = file end
+
+   -- remove any beginning and trailing slashes-converted-to-dots
    name = name:gsub("^%.+", ""):gsub("%.+$", "")
+
    return name
 end
 
diff --git a/src/luarocks/core/sysdetect.lua b/src/luarocks/core/sysdetect.lua
index 02b8a49..d999203 100644
--- a/src/luarocks/core/sysdetect.lua
+++ b/src/luarocks/core/sysdetect.lua
@@ -153,6 +153,9 @@ local function detect_elf_system(fd, hdr, sections)
          return "netbsd"
       elseif sections[".note.openbsd.ident"] then
          return "openbsd"
+      elseif sections[".note.tag"] and
+             sections[".note.tag"].namedata == "DragonFly" then
+         return "dragonfly"
       end
 
       local gnu_version_r = sections[".gnu.version_r"]
diff --git a/src/luarocks/core/util.lua b/src/luarocks/core/util.lua
index 67a10b4..26e7836 100644
--- a/src/luarocks/core/util.lua
+++ b/src/luarocks/core/util.lua
@@ -28,19 +28,6 @@ function util.popen_read(cmd, spec)
    return out or ""
 end
 
---- Create a new shallow copy of a table: a new table with
--- the same keys and values. Keys point to the same objects as
--- the original table (ie, does not copy recursively).
--- @param tbl table: the input table
--- @return table: a new table with the same contents.
-function util.make_shallow_copy(tbl)
-   local copy = {}
-   for k,v in pairs(tbl) do
-      copy[k] = v
-   end
-   return copy
-end
-
 ---
 -- Formats tables with cycles recursively to any depth.
 -- References to other tables are shown as values.
diff --git a/src/luarocks/core/vers.lua b/src/luarocks/core/vers.lua
index e7251bb..8e61798 100644
--- a/src/luarocks/core/vers.lua
+++ b/src/luarocks/core/vers.lua
@@ -60,7 +60,7 @@ local version_mt = {
    -- @param v2 table: version table to compare.
    -- @return boolean: true if v1 is considered lower than or equal to v2.
    __le = function(v1, v2)
-       return not (v2 < v1)
+       return not (v2 < v1) -- luacheck: ignore
    end,
    --- Return version as a string.
    -- @param v The version table.
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua
index fc9ed80..2b8795a 100644
--- a/src/luarocks/deps.lua
+++ b/src/luarocks/deps.lua
@@ -665,11 +665,10 @@ local function lua_h_exists(d, luaver)
       if data:match("LUA_VERSION_NUM%s*" .. tostring(luanum)) then
          return d
       end
-
-      return nil, "Lua header mismatches configured version. You may need to install them or configure LUA_INCDIR.", "dependency"
+      return nil, "Lua header found at " .. d .. " does not match Lua version " .. luaver .. ". You may want to override this by configuring LUA_INCDIR.", "dependency", 2
    end
 
-   return nil, "Failed finding Lua header files. You may need to install them or configure LUA_INCDIR.", "dependency"
+   return nil, "Failed finding Lua header files. You may need to install them or configure LUA_INCDIR.", "dependency", 1
 end
 
 local function find_lua_incdir(prefix, luaver, luajitver)
@@ -682,16 +681,23 @@ local function find_lua_incdir(prefix, luaver, luajitver)
       prefix .. "/include/lua" .. shortv,
       prefix .. "/include",
       prefix,
-      luajitver and prefix .. "/include/luajit-" .. luajitver:match("^(%d+%.%d+)"),
+      luajitver and (prefix .. "/include/luajit-" .. (luajitver:match("^(%d+%.%d+)") or "")),
    }
+   local errprio = 0
+   local mainerr
    for _, d in ipairs(incdirs) do
-      if lua_h_exists(d, luaver) then
+      local ok, err, _, prio = lua_h_exists(d, luaver)
+      if ok then
          return d
       end
+      if prio > errprio then
+         mainerr = err
+         errprio = prio
+      end
    end
 
    -- not found, will fallback to a default
-   return nil
+   return nil, mainerr
 end
 
 function deps.check_lua_incdir(vars)
@@ -702,10 +708,12 @@ function deps.check_lua_incdir(vars)
    end
 
    if vars.LUA_DIR then
-      vars.LUA_INCDIR = find_lua_incdir(vars.LUA_DIR, cfg.lua_version, ljv)
-      if vars.LUA_INCDIR then
+      local d, err = find_lua_incdir(vars.LUA_DIR, cfg.lua_version, ljv)
+      if d then
+         vars.LUA_INCDIR = d
          return true
       end
+      return nil, err
    end
 
    return nil, "Failed finding Lua header files. You may need to install them or configure LUA_INCDIR.", "dependency"
@@ -734,13 +742,32 @@ function deps.check_lua_libdir(vars)
    local save_LUA_INCDIR = vars.LUA_INCDIR
    local ok = check_external_dependency("LUA", { library = libnames }, vars, "build", cache)
    vars.LUA_INCDIR = save_LUA_INCDIR
+   local err
    if ok then
-      if fs.exists(dir.path(vars.LUA_LIBDIR, vars.LUA_LIBDIR_FILE)) then
-         vars.LUALIB = vars.LUA_LIBDIR_FILE
+      local filename = dir.path(vars.LUA_LIBDIR, vars.LUA_LIBDIR_FILE)
+      local fd = io.open(filename, "r")
+      if fd then
+         if not vars.LUA_LIBDIR_FILE:match((cfg.lua_version:gsub("%.", "%%.?"))) then
+            -- if filename isn't versioned, check file contents
+            local txt = fd:read("*a")
+            ok = txt:match("Lua " .. cfg.lua_version, 1, true)
+                 or txt:match("lua" .. (cfg.lua_version:gsub("%.", "")), 1, true)
+            if not ok then
+               err = "Lua library at " .. filename .. " does not match Lua version " .. cfg.lua_version .. ". You may want to override this by configuring LUA_LIBDIR."
+            end
+         end
+
+         fd:close()
       end
+   end
+
+   if ok then
+      vars.LUALIB = vars.LUA_LIBDIR_FILE
       return true
+   else
+      err = err or "Failed finding Lua library. You may need to configure LUA_LIBDIR."
+      return nil, err, "dependency"
    end
-   return nil, "Failed finding Lua library. You may need to configure LUA_LIBDIR.", "dependency"
 end
 
 function deps.get_deps_mode(args)
diff --git a/src/luarocks/fetch/svn.lua b/src/luarocks/fetch/svn.lua
index b2ae59c..b6618af 100644
--- a/src/luarocks/fetch/svn.lua
+++ b/src/luarocks/fetch/svn.lua
@@ -20,7 +20,7 @@ function svn.get_sources(rockspec, extract, dest_dir)
    assert(type(dest_dir) == "string" or not dest_dir)
 
    local svn_cmd = rockspec.variables.SVN
-   local ok, err_msg = fs.is_tool_available(svn_cmd, "Subversion", "--version")
+   local ok, err_msg = fs.is_tool_available(svn_cmd, "Subversion")
    if not ok then
       return nil, err_msg
    end
diff --git a/src/luarocks/fs/freebsd.lua b/src/luarocks/fs/freebsd.lua
deleted file mode 100644
index f72faa2..0000000
--- a/src/luarocks/fs/freebsd.lua
+++ /dev/null
@@ -1,11 +0,0 @@
---- FreeBSD implementation of filesystem and platform abstractions.
-local freebsd = {}
-
-local fs = require("luarocks.fs")
-
-function freebsd.init()
-   fs.set_tool_available("zip", true)
-   fs.set_tool_available("unzip", true)
-end
-
-return freebsd
diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua
index 6bd8048..145a60d 100644
--- a/src/luarocks/fs/lua.lua
+++ b/src/luarocks/fs/lua.lua
@@ -114,19 +114,29 @@ end
 -- The tool is executed using a flag, usually just to ask its version.
 -- @param tool_cmd string: The command to be used to check the tool's presence (e.g. hg in case of Mercurial)
 -- @param tool_name string: The actual name of the tool (e.g. Mercurial)
--- @param arg string: The flag to pass to the tool. '--version' by default.
-function fs_lua.is_tool_available(tool_cmd, tool_name, arg)
+function fs_lua.is_tool_available(tool_cmd, tool_name)
    assert(type(tool_cmd) == "string")
    assert(type(tool_name) == "string")
 
-   arg = arg or "--version"
-   assert(type(arg) == "string")
-
    local ok
    if tool_available_cache[tool_name] ~= nil then
       ok = tool_available_cache[tool_name]
    else
-      ok = fs.execute_quiet(tool_cmd, arg)
+      local tool_cmd_no_args = tool_cmd:gsub(" [^\"]*$", "")
+
+      -- if it looks like the tool has a pathname, try that first
+      if tool_cmd_no_args:match("[/\\]") then
+         local fd = io.open(tool_cmd_no_args, "r")
+         if fd then
+            fd:close()
+            ok = true
+         end
+      end
+
+      if not ok then
+         ok = fs.search_in_path(tool_cmd_no_args)
+      end
+
       tool_available_cache[tool_name] = (ok == true)
    end
 
@@ -1035,7 +1045,7 @@ function fs_lua.current_user()
 end
 
 function fs_lua.is_superuser()
-   return false
+   return posix.geteuid() == 0
 end
 
 -- This call is not available on all systems, see #677
diff --git a/src/luarocks/fs/netbsd.lua b/src/luarocks/fs/netbsd.lua
deleted file mode 100644
index b961033..0000000
--- a/src/luarocks/fs/netbsd.lua
+++ /dev/null
@@ -1,14 +0,0 @@
---- NetBSD implementation of filesystem and platform abstractions.
-local netbsd = {}
-
-local fs = require("luarocks.fs")
-
-function netbsd.init()
-    local uz=io.open("/usr/bin/unzip", "r")
-    if uz ~= nil then 
-        io.close(uz) 
-        fs.set_tool_available("unzip", true)
-    end
-end
-
-return netbsd
diff --git a/src/luarocks/fs/tools.lua b/src/luarocks/fs/tools.lua
index 4fe8e10..5c317f6 100644
--- a/src/luarocks/fs/tools.lua
+++ b/src/luarocks/fs/tools.lua
@@ -22,8 +22,8 @@ do
       md5checker = {
          desc = "MD5 checker",
          { var = "MD5SUM", name = "md5sum" },
-         { var = "OPENSSL", name = "openssl", cmdarg = "md5", checkarg = "version" },
-         { var = "MD5", name = "md5", checkarg = "-shello" },
+         { var = "OPENSSL", name = "openssl", cmdarg = "md5" },
+         { var = "MD5", name = "md5" },
       },
    }
 
@@ -33,7 +33,7 @@ do
       if not tool then
          for _, opt in ipairs(tool_options[tooltype]) do
             table.insert(names, opt.name)
-            if fs.is_tool_available(vars[opt.var], opt.name, opt.checkarg) then
+            if fs.is_tool_available(vars[opt.var], opt.name) then
                tool = opt
                tool_cache[tooltype] = opt
                break
@@ -57,7 +57,7 @@ do
       local current = cache_pwd
       if not current then
          local pipe = io.popen(fs.quiet_stderr(vars.PWD))
-         current = pipe:read("*l")
+         current = pipe:read("*a"):gsub("^%s*", ""):gsub("%s*$", "")
          pipe:close()
          cache_pwd = current
       end
diff --git a/src/luarocks/fs/unix.lua b/src/luarocks/fs/unix.lua
index 2c66eaa..61569e3 100644
--- a/src/luarocks/fs/unix.lua
+++ b/src/luarocks/fs/unix.lua
@@ -90,7 +90,8 @@ function unix.wrap_script(script, target, deps_mode, name, version, ...)
    }
 
    local remove_interpreter = false
-   if target == "luarocks" or target == "luarocks-admin" then
+   local base = dir.base_name(target):gsub("%..*$", "")
+   if base == "luarocks" or base == "luarocks-admin" then
       if cfg.is_binary then
          remove_interpreter = true
       end
@@ -175,14 +176,6 @@ function unix.tmpname()
    return os.tmpname()
 end
 
-function unix.current_user()
-   return os.getenv("USER")
-end
-
-function unix.is_superuser()
-   return os.getenv("USER") == "root"
-end
-
 function unix.export_cmd(var, val)
    return ("export %s='%s'"):format(var, val)
 end
@@ -233,4 +226,15 @@ function unix.system_cache_dir()
    return dir.path(fs.system_temp_dir(), "cache")
 end
 
+function unix.search_in_path(program)
+   for d in (os.getenv("PATH") or ""):gmatch("([^:]+)") do
+      local fd = io.open(dir.path(d, program), "r")
+      if fd then
+         fd:close()
+         return true, d
+      end
+   end
+   return false
+end
+
 return unix
diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua
index d36d407..b7fd4de 100644
--- a/src/luarocks/fs/unix/tools.lua
+++ b/src/luarocks/fs/unix/tools.lua
@@ -141,7 +141,7 @@ end
 -- @return boolean: true on success, nil and error message on failure.
 function tools.unzip(zipfile)
    assert(zipfile)
-   local ok, err = fs.is_tool_available(vars.UNZIP, "unzip", "--help")
+   local ok, err = fs.is_tool_available(vars.UNZIP, "unzip")
    if not ok then
       return nil, err
    end
@@ -297,4 +297,22 @@ function tools.is_file(file)
    return fs.execute(vars.TEST, "-f", file)
 end
 
+function tools.current_user()
+   local user = os.getenv("USER")
+   if user then
+      return user
+   end
+   local pd = io.popen("whoami", "r")
+   if not pd then
+      return ""
+   end
+   user = pd:read("*l")
+   pd:close()
+   return user
+end
+
+function tools.is_superuser()
+   return fs.current_user() == "root"
+end
+
 return tools
diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua
index 6d869d9..6c49f44 100644
--- a/src/luarocks/fs/win32.lua
+++ b/src/luarocks/fs/win32.lua
@@ -154,10 +154,9 @@ function win32.wrap_script(script, target, deps_mode, name, version, ...)
    assert(type(name) == "string" or not name)
    assert(type(version) == "string" or not version)
 
-   local batname = target .. ".bat"
-   local wrapper = io.open(batname, "wb")
+   local wrapper = io.open(target, "wb")
    if not wrapper then
-      return nil, "Could not open "..batname.." for writing."
+      return nil, "Could not open "..target.." for writing."
    end
 
    local lpath, lcpath = path.package_paths(deps_mode)
@@ -168,7 +167,8 @@ function win32.wrap_script(script, target, deps_mode, name, version, ...)
    }
 
    local remove_interpreter = false
-   if target == "luarocks" or target == "luarocks-admin" then
+   local base = dir.base_name(target):gsub("%..*$", "")
+   if base == "luarocks" or base == "luarocks-admin" then
       if cfg.is_binary then
          remove_interpreter = true
       end
@@ -363,4 +363,15 @@ function win32.system_cache_dir()
    return dir.path(fs.system_temp_dir(), "cache")
 end
 
+function win32.search_in_path(program)
+   for d in (os.getenv("PATH") or ""):gmatch("([^;]+)") do
+      local fd = io.open(dir.path(d, program .. ".exe"), "r")
+      if fd then
+         fd:close()
+         return true, d
+      end
+   end
+   return false
+end
+
 return win32
diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua
index 80f0786..9bd050c 100644
--- a/src/luarocks/fs/win32/tools.lua
+++ b/src/luarocks/fs/win32/tools.lua
@@ -36,7 +36,7 @@ end
 function tools.make_dir(directory)
    assert(directory)
    directory = dir.normalize(directory)
-   fs.execute_quiet(vars.MKDIR.." -p ", directory)
+   fs.execute_quiet(vars.MKDIR, directory)
    if not fs.is_dir(directory) then
       return false, "failed making directory "..directory
    end
@@ -58,7 +58,15 @@ end
 -- @param directory string: pathname of directory to remove.
 function tools.remove_dir_tree_if_empty(directory)
    assert(directory)
-   fs.execute_quiet(vars.RMDIR, directory)
+   while true do
+      fs.execute_quiet(vars.RMDIR, directory)
+      local parent = dir.dir_name(directory)
+      if parent ~= directory then
+         directory = parent
+      else
+         break
+      end
+   end
 end
 
 --- Copy a file.
diff --git a/src/luarocks/loader.lua b/src/luarocks/loader.lua
index 825e4ce..772fdfc 100644
--- a/src/luarocks/loader.lua
+++ b/src/luarocks/loader.lua
@@ -194,11 +194,47 @@ end
 
 --- Return the pathname of the file that would be loaded for a module.
 -- @param module string: module name (eg. "socket.core")
--- @return filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"),
--- the rock name and the rock version.
-function loader.which(module)
-   local rock_name, rock_version, file_name = select_module(module, path.which_i)
-   return file_name, rock_name, rock_version
+-- @param where string: places to look for the module. If `where` contains
+-- "l", it will search using the LuaRocks loader; if it contains "p",
+-- it will look in the filesystem using package.path and package.cpath.
+-- You can use both at the same time.
+-- @return If successful, it will return four values.
+-- * If found using the LuaRocks loader, it will return:
+--   * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"),
+--   * rock name
+--   * rock version
+--   * "l" to indicate the match comes from the loader.
+-- * If found scanning package.path and package.cpath, it will return:
+--   * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"),
+--   * "path" or "cpath"
+--   * nil
+--   * "p" to indicate the match comes from scanning package.path and cpath.
+-- If unsuccessful, nothing is returned.
+function loader.which(module, where)
+   where = where or "l"
+   if where:match("l") then
+      local rock_name, rock_version, file_name = select_module(module, path.which_i)
+      if rock_name then
+         local fd = io.open(file_name)
+         if fd then
+            fd:close()
+            return file_name, rock_name, rock_version, "l"
+         end
+      end
+   end
+   if where:match("p") then
+      local modpath = module:gsub("%.", "/")
+      for _, v in ipairs({"path", "cpath"}) do
+         for p in package[v]:gmatch("([^;]+)") do
+            local file_name = p:gsub("%?", modpath)  -- luacheck: ignore 421
+            local fd = io.open(file_name)
+            if fd then
+               fd:close()
+               return file_name, v, nil, "p"
+            end
+         end
+      end
+   end
 end
 
 --- Package loader for LuaRocks support.
diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua
index 02c5016..4dcd930 100644
--- a/src/luarocks/persist.lua
+++ b/src/luarocks/persist.lua
@@ -188,6 +188,8 @@ end
 -- @return boolean or (nil, string): true if successful, or nil and a
 -- message in case of errors.
 function persist.save_from_table(filename, tbl, field_order)
+   local prefix = dir.dir_name(filename)
+   fs.make_dir(prefix)
    local out = io.open(filename, "w")
    if not out then
       return nil, "Cannot create file at "..filename
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua
index cf2ce14..764fe3a 100644
--- a/src/luarocks/repos.lua
+++ b/src/luarocks/repos.lua
@@ -309,7 +309,7 @@ local function prepare_op_install()
          return nil, err
       end
 
-      local backup, err = backup_existing(op.backup, op.realdst or op.dst)
+      local backup, err = backup_existing(op.backup, op.dst)
       if err then
          return nil, err
       end
@@ -403,14 +403,22 @@ end
 --- Double check that all files referenced in `rock_manifest` are installed in `repo`.
 function repos.check_everything_is_installed(name, version, rock_manifest, repo, accept_versioned)
    local missing = {}
+   local suffix = cfg.wrapper_suffix or ""
    for _, category in ipairs({"bin", "lua", "lib"}) do
-      local suffix = (category == "bin") and cfg.wrapper_suffix or ""
       if rock_manifest[category] then
          repos.recurse_rock_manifest_entry(rock_manifest[category], function(file_path)
             local paths = get_deploy_paths(name, version, category, file_path, repo)
-            if not (fs.exists(paths.nv .. suffix) or (accept_versioned and fs.exists(paths.v .. suffix))) then
-               table.insert(missing, paths.nv .. suffix)
+            if category == "bin" then
+               if (fs.exists(paths.nv) or fs.exists(paths.nv .. suffix))
+               or (accept_versioned and (fs.exists(paths.v) or fs.exists(paths.v .. suffix))) then
+                  return
+               end
+            else
+               if fs.exists(paths.nv) or (accept_versioned and fs.exists(paths.v)) then
+                  return
+               end
             end
+            table.insert(missing, paths.nv)
          end)
       end
    end
@@ -470,10 +478,10 @@ function repos.deploy_files(name, version, wrap_bin_scripts, deps_mode)
          end
          local target = mode == "nv" and paths.nv or paths.v
          local backup = name ~= cur_name or version ~= cur_version
-         local realdst = (wrap_bin_scripts and fs.is_lua(source))
-                         and (target .. (cfg.wrapper_suffix or ""))
-                         or target
-         table.insert(installs, { fn = install_binary, src = source, dst = target, backup = backup, realdst = realdst })
+         if wrap_bin_scripts and fs.is_lua(source) then
+            target = target .. (cfg.wrapper_suffix or "")
+         end
+         table.insert(installs, { fn = install_binary, src = source, dst = target, backup = backup })
       end)
    end
 
diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua
index 8a79d99..e76d459 100644
--- a/src/luarocks/search.lua
+++ b/src/luarocks/search.lua
@@ -370,7 +370,6 @@ function search.pick_installed_rock(query, given_tree)
       return nil, table.concat(out)
    end
 
-   local version = nil
    local repo_url
 
    local name, versions
@@ -380,15 +379,12 @@ function search.pick_installed_rock(query, given_tree)
       name, versions = util.sortedpairs(result_tree)()
    end
 
-   --question: what do we do about multiple versions? This should
-   --give us the latest version on the last repo (which is usually the global one)
-   for vs, repositories in util.sortedpairs(versions, vers.compare_versions) do
-      if not version then version = vs end
-      for _, rp in ipairs(repositories) do repo_url = rp.repo end
-   end
+   local version, repositories = util.sortedpairs(versions, vers.compare_versions)()
+   for _, rp in ipairs(repositories) do repo_url = rp.repo end
 
    local repo = tree_map[repo_url]
    return name, version, repo, repo_url
 end
 
 return search
+
diff --git a/src/luarocks/test.lua b/src/luarocks/test.lua
index cf475fd..d074b95 100644
--- a/src/luarocks/test.lua
+++ b/src/luarocks/test.lua
@@ -3,6 +3,7 @@ local test = {}
 
 local fetch = require("luarocks.fetch")
 local deps = require("luarocks.deps")
+local util = require("luarocks.util")
 
 local test_types = {
    "busted",
@@ -55,10 +56,17 @@ function test.run_test_suite(rockspec_arg, test_type, args, prepare)
    end
    assert(test_type)
 
-   if next(rockspec.test_dependencies) then
-      local ok, err, errcode = deps.fulfill_dependencies(rockspec, "test_dependencies", "all")
-      if err then
-         return nil, err, errcode
+   local all_deps = {
+      "dependencies",
+      "build_dependencies",
+      "test_dependencies",
+   }
+   for _, dep_kind in ipairs(all_deps) do
+      if rockspec[dep_kind] and next(rockspec[dep_kind]) then
+         local ok, err, errcode = deps.fulfill_dependencies(rockspec, dep_kind, "all")
+         if err then
+            return nil, err, errcode
+         end
       end
    end
 
@@ -69,8 +77,22 @@ function test.run_test_suite(rockspec_arg, test_type, args, prepare)
    end
 
    if prepare then
-      return test_mod.run_tests(rockspec_arg, {"--version"})
+      if test_type == "busted" then
+         return test_mod.run_tests(rockspec_arg, {"--version"})
+      else
+         return true
+      end
    else
+      local flags = rockspec.test and rockspec.test.flags
+      if type(flags) == "table" then
+         util.variable_substitutions(flags, rockspec.variables)
+
+         -- insert any flags given in test.flags at the front of args
+         for i = 1, #flags do
+            table.insert(args, i, flags[i])
+         end
+      end
+
       return test_mod.run_tests(rockspec.test, args)
    end
 end
diff --git a/src/luarocks/test/busted.lua b/src/luarocks/test/busted.lua
index 8fa7880..c73909c 100644
--- a/src/luarocks/test/busted.lua
+++ b/src/luarocks/test/busted.lua
@@ -40,13 +40,6 @@ function busted.run_tests(test, args)
       end
    end
 
-   if type(test.flags) == "table" then
-      -- insert any flags given in test.flags at the front of args
-      for i = 1, #test.flags do
-         table.insert(args, i, test.flags[i])
-      end
-   end
-
    local err
    ok, err = fs.execute(busted_exe, unpack(args))
    if ok then
diff --git a/src/luarocks/test/command.lua b/src/luarocks/test/command.lua
index 1795c4e..58fa22c 100644
--- a/src/luarocks/test/command.lua
+++ b/src/luarocks/test/command.lua
@@ -25,13 +25,6 @@ function command.run_tests(test, args)
       test.script = "test.lua"
    end
 
-   if type(test.flags) == "table" then
-      -- insert any flags given in test.flags at the front of args
-      for i = 1, #test.flags do
-         table.insert(args, i, test.flags[i])
-      end
-   end
-
    local ok
 
    if test.script then
diff --git a/src/luarocks/tools/patch.lua b/src/luarocks/tools/patch.lua
index b12f38f..6f36d71 100644
--- a/src/luarocks/tools/patch.lua
+++ b/src/luarocks/tools/patch.lua
@@ -540,7 +540,8 @@ local function write_new_file(filename, hunk)
   local fh = io.open(filename, "wb")
   if not fh then return false end
   for _, hline in ipairs(hunk.text) do
-    if not hline:sub(1,1) == "+" then
+    local c = hline:sub(1,1)
+    if c ~= "+" and c ~= "-" and c ~= " " then
       return false, "malformed patch"
     end
     fh:write(hline:sub(2))
diff --git a/src/luarocks/tools/tar.lua b/src/luarocks/tools/tar.lua
index aea2809..21d5920 100644
--- a/src/luarocks/tools/tar.lua
+++ b/src/luarocks/tools/tar.lua
@@ -81,7 +81,7 @@ local function read_header_block(block)
    -- if header.version ~= "00" and header.version ~= " \0" then
    --    return false, "Unknown version "..header.version
    -- end
-   if not checksum_header(block) == header.chksum then
+   if checksum_header(block) ~= header.chksum then
       return false, "Failed header checksum"
    end
    return header
diff --git a/src/luarocks/tools/zip.lua b/src/luarocks/tools/zip.lua
index 7803b50..82d582f 100644
--- a/src/luarocks/tools/zip.lua
+++ b/src/luarocks/tools/zip.lua
@@ -329,19 +329,13 @@ local function read_file_in_zip(zh, cdr)
       return nil, "failed reading Local File Header signature"
    end
 
-   local lfh = {}
-   lfh.version_needed = lestring_to_number(zh:read(2))
-   lfh.bitflag = lestring_to_number(zh:read(2))
-   lfh.compression_method = lestring_to_number(zh:read(2))
-   lfh.last_mod_file_time = lestring_to_number(zh:read(2))
-   lfh.last_mod_file_date = lestring_to_number(zh:read(2))
-   lfh.crc32 = lestring_to_number(zh:read(4))
-   lfh.compressed_size = lestring_to_number(zh:read(4))
-   lfh.uncompressed_size = lestring_to_number(zh:read(4))
-   lfh.file_name_length = lestring_to_number(zh:read(2))
-   lfh.extra_field_length = lestring_to_number(zh:read(2))
-   lfh.file_name = zh:read(lfh.file_name_length)
-   lfh.extra_field = zh:read(lfh.extra_field_length)
+   -- Skip over the rest of the zip file header. See
+   -- zipwriter_close_file_in_zip for the format.
+   zh:seek("cur", 22)
+   local file_name_length = lestring_to_number(zh:read(2))
+   local extra_field_length = lestring_to_number(zh:read(2))
+   zh:read(file_name_length)
+   zh:read(extra_field_length)
 
    local data = zh:read(cdr.compressed_size)
 
diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua
index bb474ff..fa3a628 100644
--- a/src/luarocks/util.lua
+++ b/src/luarocks/util.lua
@@ -90,14 +90,16 @@ local var_format_pattern = "%$%((%a[%a%d_]+)%)"
 -- needed variables.
 -- @param msg string: the warning message to display.
 function util.warn_if_not_used(var_defs, needed_set, msg)
-   needed_set = core.make_shallow_copy(needed_set)
+   local seen = {}
    for _, val in pairs(var_defs) do
       for used in val:gmatch(var_format_pattern) do
-         needed_set[used] = nil
+         seen[used] = true
       end
    end
    for var, _ in pairs(needed_set) do
-      util.warning(msg:format(var))
+      if not seen[var] then
+         util.warning(msg:format(var))
+      end
    end
 end
 

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/share/lua/5.1/luarocks/fs/freebsd.lua
-rw-r--r--  root/root   /usr/share/lua/5.1/luarocks/fs/netbsd.lua
lrwxrwxrwx  root/root   /usr/share/lua/5.2/luarocks/fs/freebsd.lua -> ../../../5.1/luarocks/fs/freebsd.lua
lrwxrwxrwx  root/root   /usr/share/lua/5.2/luarocks/fs/netbsd.lua -> ../../../5.1/luarocks/fs/netbsd.lua
lrwxrwxrwx  root/root   /usr/share/lua/5.3/luarocks/fs/freebsd.lua -> ../../../5.1/luarocks/fs/freebsd.lua
lrwxrwxrwx  root/root   /usr/share/lua/5.3/luarocks/fs/netbsd.lua -> ../../../5.1/luarocks/fs/netbsd.lua
lrwxrwxrwx  root/root   /usr/share/lua/5.4/luarocks/fs/freebsd.lua -> ../../../5.1/luarocks/fs/freebsd.lua
lrwxrwxrwx  root/root   /usr/share/lua/5.4/luarocks/fs/netbsd.lua -> ../../../5.1/luarocks/fs/netbsd.lua

No differences were encountered in the control files

More details

Full run details