Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/torch/luajit-rocks.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonan Collobert <ronan@collobert.com>2013-10-25 13:40:44 +0400
committerRonan Collobert <ronan@collobert.com>2013-10-25 13:40:44 +0400
commit009a990f201a9b57c768cd96a97466d044d122b1 (patch)
tree28e7d19df2e31db204c42df3773e9adad4244b53
Squashed 'luarocks/' content from commit c7a3685
git-subtree-dir: luarocks git-subtree-split: c7a3685013ad5bfa60bce6a91707903b699df431
-rw-r--r--.gitignore2
-rw-r--r--COPYING46
-rw-r--r--COPYING_7z56
-rw-r--r--COPYING_lua34
-rw-r--r--Makefile173
-rw-r--r--README.md22
-rw-r--r--config.ld6
-rwxr-xr-xconfigure444
-rw-r--r--install.bat649
-rw-r--r--lfw/7z.dllbin0 -> 858624 bytes
-rw-r--r--lfw/7z.exebin0 -> 161792 bytes
-rw-r--r--lfw/lua/luarocks/config.lua16
-rw-r--r--lfw/luarocks-admin.bat4
-rw-r--r--lfw/luarocks-admin.lua16
-rw-r--r--lfw/luarocks.bat4
-rw-r--r--lfw/luarocks.lua20
-rw-r--r--lfw/luarocks_config.lua10
-rw-r--r--lfw/rclauncher.obin0 -> 2374 bytes
-rw-r--r--lfw/rclauncher.objbin0 -> 4339 bytes
-rw-r--r--lfw/rocks/index.html87
-rw-r--r--lfw/rocks/luafilesystem/1.5.0-1/doc/us/examples.html103
-rw-r--r--lfw/rocks/luafilesystem/1.5.0-1/doc/us/index.html192
-rw-r--r--lfw/rocks/luafilesystem/1.5.0-1/doc/us/license.html122
-rw-r--r--lfw/rocks/luafilesystem/1.5.0-1/doc/us/luafilesystem.pngbin0 -> 8535 bytes
-rw-r--r--lfw/rocks/luafilesystem/1.5.0-1/doc/us/manual.html271
-rw-r--r--lfw/rocks/luafilesystem/1.5.0-1/luafilesystem-1.5.0-1.rockspec27
-rw-r--r--lfw/rocks/luafilesystem/1.5.0-1/rock_manifest18
-rw-r--r--lfw/rocks/luafilesystem/1.5.0-1/tests/test.lua130
-rw-r--r--lfw/rocks/luasocket/2.0.2-3/luasocket-2.0.2-3.rockspec34
-rw-r--r--lfw/rocks/luasocket/2.0.2-3/rock_manifest23
-rw-r--r--lfw/rocks/luazip/1.2.3-2/luazip-1.2.3-2.rockspec37
-rw-r--r--lfw/rocks/luazip/1.2.3-2/rock_manifest6
-rw-r--r--lfw/rocks/manifest159
-rw-r--r--lfw/rocks/md5/1.1.2-1/md5-1.1.2-1.rockspec39
-rw-r--r--lfw/rocks/md5/1.1.2-1/rock_manifest12
-rwxr-xr-xmakedist76
-rw-r--r--rockspec38
-rwxr-xr-xsrc/bin/luarocks24
-rwxr-xr-xsrc/bin/luarocks-admin16
-rw-r--r--src/luarocks/add.lua113
-rw-r--r--src/luarocks/admin_remove.lua87
-rw-r--r--src/luarocks/build.lua355
-rw-r--r--src/luarocks/build/builtin.lua251
-rw-r--r--src/luarocks/build/cmake.lua58
-rw-r--r--src/luarocks/build/command.lua32
-rw-r--r--src/luarocks/build/make.lua92
-rw-r--r--src/luarocks/cache.lua85
-rw-r--r--src/luarocks/cfg.lua484
-rw-r--r--src/luarocks/command_line.lua168
-rw-r--r--src/luarocks/deps.lua714
-rw-r--r--src/luarocks/dir.lua70
-rw-r--r--src/luarocks/download.lua88
-rw-r--r--src/luarocks/fetch.lua325
-rw-r--r--src/luarocks/fetch/cvs.lua44
-rw-r--r--src/luarocks/fetch/git.lua81
-rw-r--r--src/luarocks/fetch/git_file.lua17
-rw-r--r--src/luarocks/fetch/hg.lua54
-rw-r--r--src/luarocks/fetch/sscm.lua42
-rw-r--r--src/luarocks/fetch/svn.lua53
-rw-r--r--src/luarocks/fs.lua40
-rw-r--r--src/luarocks/fs/lua.lua698
-rw-r--r--src/luarocks/fs/unix.lua111
-rw-r--r--src/luarocks/fs/unix/tools.lua318
-rw-r--r--src/luarocks/fs/win32.lua133
-rw-r--r--src/luarocks/fs/win32/tools.lua346
-rw-r--r--src/luarocks/help.lua107
-rw-r--r--src/luarocks/index.lua172
-rw-r--r--src/luarocks/install.lua164
-rw-r--r--src/luarocks/lint.lua41
-rw-r--r--src/luarocks/list.lua38
-rw-r--r--src/luarocks/loader.lua212
-rw-r--r--src/luarocks/make.lua86
-rw-r--r--src/luarocks/make_manifest.lua40
-rw-r--r--src/luarocks/manif.lua452
-rw-r--r--src/luarocks/manif_core.lua79
-rw-r--r--src/luarocks/new_version.lua178
-rw-r--r--src/luarocks/pack.lua204
-rw-r--r--src/luarocks/path.lua417
-rw-r--r--src/luarocks/persist.lua173
-rw-r--r--src/luarocks/purge.lua70
-rw-r--r--src/luarocks/refresh_cache.lua30
-rw-r--r--src/luarocks/remove.lua157
-rw-r--r--src/luarocks/repos.lua309
-rw-r--r--src/luarocks/require.lua6
-rw-r--r--src/luarocks/search.lua386
-rw-r--r--src/luarocks/show.lua156
-rw-r--r--src/luarocks/tools/patch.lua712
-rw-r--r--src/luarocks/tools/tar.lua144
-rw-r--r--src/luarocks/tools/zip.lua245
-rw-r--r--src/luarocks/type_check.lua267
-rw-r--r--src/luarocks/unpack.lua151
-rw-r--r--src/luarocks/util.lua504
-rw-r--r--src/luarocks/validate.lua160
-rwxr-xr-xtest/testing.sh269
-rw-r--r--win32/bin/7z.dllbin0 -> 858624 bytes
-rw-r--r--win32/bin/7z.exebin0 -> 161792 bytes
-rw-r--r--win32/bin/LuaRocks.reg.template59
-rw-r--r--win32/bin/chmod.exebin0 -> 81920 bytes
-rwxr-xr-xwin32/bin/cp.exebin0 -> 130048 bytes
-rw-r--r--win32/bin/create_reg_file.lua51
-rwxr-xr-xwin32/bin/find.exebin0 -> 160256 bytes
-rw-r--r--win32/bin/libeay32.dllbin0 -> 1177600 bytes
-rw-r--r--win32/bin/libiconv2.dllbin0 -> 1008128 bytes
-rw-r--r--win32/bin/libintl3.dllbin0 -> 103424 bytes
-rw-r--r--win32/bin/libssl32.dllbin0 -> 232960 bytes
-rwxr-xr-xwin32/bin/ls.exebin0 -> 180736 bytes
-rw-r--r--win32/bin/lua.icobin0 -> 22486 bytes
-rw-r--r--win32/bin/luarocksw.bat49
-rw-r--r--win32/bin/md5sum.exebin0 -> 41984 bytes
-rwxr-xr-xwin32/bin/mkdir.exebin0 -> 32768 bytes
-rwxr-xr-xwin32/bin/mv.exebin0 -> 138752 bytes
-rw-r--r--win32/bin/objdump.exebin0 -> 2247694 bytes
-rwxr-xr-xwin32/bin/pwd.exebin0 -> 61440 bytes
-rw-r--r--win32/bin/rclauncher.c139
-rwxr-xr-xwin32/bin/rm.exebin0 -> 109056 bytes
-rwxr-xr-xwin32/bin/rmdir.exebin0 -> 25088 bytes
-rwxr-xr-xwin32/bin/test.exebin0 -> 62976 bytes
-rwxr-xr-xwin32/bin/uname.exebin0 -> 33792 bytes
-rw-r--r--win32/bin/wget.exebin0 -> 449024 bytes
-rw-r--r--win32/lua5.1/bin/Microsoft.VC80.CRT.manifest8
-rw-r--r--win32/lua5.1/bin/bin2c5.1.exebin0 -> 94208 bytes
-rw-r--r--win32/lua5.1/bin/lua5.1.dllbin0 -> 167936 bytes
-rw-r--r--win32/lua5.1/bin/lua5.1.exebin0 -> 45056 bytes
-rw-r--r--win32/lua5.1/bin/lua5.1.libbin0 -> 26112 bytes
-rw-r--r--win32/lua5.1/bin/lua51.dllbin0 -> 11264 bytes
-rw-r--r--win32/lua5.1/bin/lua51.libbin0 -> 25974 bytes
-rw-r--r--win32/lua5.1/bin/luac5.1.exebin0 -> 208896 bytes
-rw-r--r--win32/lua5.1/bin/msvcm80.dllbin0 -> 479232 bytes
-rw-r--r--win32/lua5.1/bin/msvcp80.dllbin0 -> 548864 bytes
-rw-r--r--win32/lua5.1/bin/msvcr80.dllbin0 -> 626688 bytes
-rw-r--r--win32/lua5.1/bin/wlua5.1.exebin0 -> 35840 bytes
-rw-r--r--win32/lua5.1/include/lauxlib.h174
-rw-r--r--win32/lua5.1/include/lua.h388
-rw-r--r--win32/lua5.1/include/lua.hpp9
-rw-r--r--win32/lua5.1/include/luaconf.h763
-rw-r--r--win32/lua5.1/include/lualib.h53
136 files changed, 15397 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..13a0772
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/config.*
+/src/luarocks/site_config.lua
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..4311883
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,46 @@
+LuaRocks is free software: it can be used for both academic and commercial
+purposes at absolutely no cost. There are no royalties or GNU-like "copyleft"
+restrictions. LuaRocks qualifies as Open Source software. Its licenses are
+compatible with the GPL. LuaRocks is not in the public domain and the Kepler
+Project keeps its copyright. The legal details are below.
+
+The spirit of the license is that you are free to use LuaRocks for any purpose
+at no cost without having to ask us. The only requirement is that if you do
+use LuaRocks, then you should give us credit by including the appropriate
+copyright notice somewhere in your product or its documentation.
+
+7z.exe and 7z.dll are covered by another license, please see COPYING.7z for
+details.
+
+find.exe, mv.exe, rm.exe, wget.exe, ls.exe, pwd.exe, rmdir.exe, chmod.exe,
+md5sum.exe, test.exe, cp.exe, mkdir.exe, and uname.exe are part of UnxUtils,
+check http://unxutils.sourceforge.net/ for license information.
+
+Files under win32/lua5.1, except for Microsoft.VC80.CRT.manifest and msv*.*,
+are covered by another license, please see COPYING.lua for details.
+
+Microsoft.VC80.CRT.manifest, msvcm80.dll, msvcp80.dll, msvcr80.dll are part
+of the Microsoft Visual C++ 2005 SP1 Redistributable Package (x86) and
+are Copyright Microsoft, Inc. 2007.
+
+------------------------------------------------------------------------------
+
+Copyright 2007-2010 Kepler Project.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/COPYING_7z b/COPYING_7z
new file mode 100644
index 0000000..e25910a
--- /dev/null
+++ b/COPYING_7z
@@ -0,0 +1,56 @@
+ 7-Zip
+ ~~~~~
+ License for use and distribution
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ 7-Zip Copyright (C) 1999-2010 Igor Pavlov.
+
+ Licenses for files are:
+
+ 1) 7z.dll: GNU LGPL + unRAR restriction
+ 2) All other files: GNU LGPL
+
+ The GNU LGPL + unRAR restriction means that you must follow both
+ GNU LGPL rules and unRAR restriction rules.
+
+
+ Note:
+ You can use 7-Zip on any computer, including a computer in a commercial
+ organization. You don't need to register or pay for 7-Zip.
+
+
+ GNU LGPL information
+ --------------------
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You can receive a copy of the GNU Lesser General Public License from
+ http://www.gnu.org/
+
+
+ unRAR restriction
+ -----------------
+
+ The decompression engine for RAR archives was developed using source
+ code of unRAR program.
+ All copyrights to original unRAR code are owned by Alexander Roshal.
+
+ The license for original unRAR code has the following restriction:
+
+ The unRAR sources cannot be used to re-create the RAR compression algorithm,
+ which is proprietary. Distribution of modified unRAR sources in separate form
+ or as a part of other software is permitted, provided that it is clearly
+ stated in the documentation and source comments that the code may
+ not be used to develop a RAR (WinRAR) compatible archiver.
+
+
+ --
+ Igor Pavlov
diff --git a/COPYING_lua b/COPYING_lua
new file mode 100644
index 0000000..3a53e74
--- /dev/null
+++ b/COPYING_lua
@@ -0,0 +1,34 @@
+Lua License
+-----------
+
+Lua is licensed under the terms of the MIT license reproduced below.
+This means that Lua is free software and can be used for both academic
+and commercial purposes at absolutely no cost.
+
+For details and rationale, see http://www.lua.org/license.html .
+
+===============================================================================
+
+Copyright (C) 1994-2008 Lua.org, PUC-Rio.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+===============================================================================
+
+(end of COPYRIGHT)
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..be83c01
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,173 @@
+# $Id: Makefile,v 1.30 2008/08/18 14:07:35 hisham Exp $
+
+include config.unix
+
+DESTDIR =
+PREFIX ?= /usr/local
+ROCKS_TREE ?= $(PREFIX)
+SYSCONFDIR ?= $(PREFIX)/etc/luarocks
+BINDIR ?= $(PREFIX)/bin
+LUADIR ?= $(PREFIX)/share/lua/$(LUA_VERSION)/
+LUA_DIR ?= /usr/local
+LUA_BINDIR ?= $(LUA_DIR)/bin
+
+BIN_FILES = luarocks luarocks-admin
+LUAROCKS_FILES = fs/unix/tools.lua fs/unix.lua fs/win32/tools.lua fs/win32.lua \
+fs/lua.lua persist.lua list.lua require.lua repos.lua dir.lua make_manifest.lua \
+command_line.lua install.lua build/command.lua build/cmake.lua build/make.lua \
+build/builtin.lua fetch/cvs.lua fetch/git.lua fetch/sscm.lua tools/patch.lua \
+fetch/svn.lua tools/zip.lua tools/tar.lua pack.lua type_check.lua make.lua path.lua \
+remove.lua fs.lua manif.lua add.lua deps.lua build.lua search.lua show.lua \
+manif_core.lua fetch.lua unpack.lua validate.lua cfg.lua download.lua \
+help.lua util.lua index.lua cache.lua refresh_cache.lua loader.lua \
+admin_remove.lua fetch/hg.lua fetch/git_file.lua new_version.lua lint.lua purge.lua
+
+CONFIG_FILE = $(SYSCONFDIR)/config-$(LUA_VERSION).lua
+
+all:
+ @echo "- Type 'make build' and 'make install':"
+ @echo " to install to $(PREFIX) as usual."
+ @echo "- Type 'make bootstrap':"
+ @echo " to install LuaRocks in $(PREFIX) as a rock."
+ @echo
+
+build: built
+
+src/luarocks/site_config.lua: config.unix
+ rm -f src/luarocks/site_config.lua
+ echo 'module("luarocks.site_config")' >> src/luarocks/site_config.lua
+ if [ -n "$(PREFIX)" ] ;\
+ then \
+ echo "LUAROCKS_PREFIX=[[$(PREFIX)]]" >> src/luarocks/site_config.lua ;\
+ fi
+ if [ -n "$(LUA_INCDIR)" ] ;\
+ then \
+ echo "LUA_INCDIR=[[$(LUA_INCDIR)]]" >> src/luarocks/site_config.lua ;\
+ fi
+ if [ -n "$(LUA_LIBDIR)" ] ;\
+ then \
+ echo "LUA_LIBDIR=[[$(LUA_LIBDIR)]]" >> src/luarocks/site_config.lua ;\
+ fi
+ if [ -n "$(LUA_BINDIR)" ] ;\
+ then \
+ echo "LUA_BINDIR=[[$(LUA_BINDIR)]]" >> src/luarocks/site_config.lua ;\
+ fi
+ if [ -n "$(LUA_SUFFIX)" ] ;\
+ then \
+ echo "LUA_INTERPRETER=[[lua$(LUA_SUFFIX)]]" >> src/luarocks/site_config.lua ;\
+ fi
+ if [ -n "$(SYSCONFDIR)" ] ;\
+ then \
+ echo "LUAROCKS_SYSCONFDIR=[[$(SYSCONFDIR)]]" >> src/luarocks/site_config.lua ;\
+ fi
+ if [ -n "$(ROCKS_TREE)" ] ;\
+ then \
+ echo "LUAROCKS_ROCKS_TREE=[[$(ROCKS_TREE)]]" >> src/luarocks/site_config.lua ;\
+ fi
+ if [ -n "$(FORCE_CONFIG)" ] ;\
+ then \
+ echo "LUAROCKS_FORCE_CONFIG=true" >> src/luarocks/site_config.lua ;\
+ fi
+ if [ -n "$(LUAROCKS_ROCKS_SUBDIR)" ] ;\
+ then \
+ echo "LUAROCKS_ROCKS_SUBDIR=[[$(LUAROCKS_ROCKS_SUBDIR)]]" >> src/luarocks/site_config.lua ;\
+ fi
+ if [ "$(LUA_DIR_SET)" = "yes" ] ;\
+ then \
+ echo "LUA_DIR_SET=true" >> src/luarocks/site_config.lua ;\
+ fi
+ echo "LUAROCKS_UNAME_S=[[$(LUAROCKS_UNAME_S)]]" >> src/luarocks/site_config.lua
+ echo "LUAROCKS_UNAME_M=[[$(LUAROCKS_UNAME_M)]]" >> src/luarocks/site_config.lua
+ echo "LUAROCKS_DOWNLOADER=[[$(LUAROCKS_DOWNLOADER)]]" >> src/luarocks/site_config.lua
+ echo "LUAROCKS_MD5CHECKER=[[$(LUAROCKS_MD5CHECKER)]]" >> src/luarocks/site_config.lua
+
+dev:
+ $(MAKE) build_bins LUADIR=$(PWD)/src
+
+build_bins: cleanup_bins
+ for f in $(BIN_FILES) ;\
+ do \
+ sed "1d" src/bin/$$f > src/bin/$$f.bak ;\
+ echo "#!$(LUA_BINDIR)/lua$(LUA_SUFFIX)" > src/bin/$$f ;\
+ echo "package.path = [[$(LUADIR)/?.lua;$(LUADIR)/?/init.lua;]]..package.path" >> src/bin/$$f ;\
+ cat src/bin/$$f.bak >> src/bin/$$f ;\
+ chmod +x src/bin/$$f ;\
+ rm -f src/bin/$$f.bak ;\
+ done
+
+built: src/luarocks/site_config.lua build_bins
+ touch built
+ @echo
+ @echo "Done. Type 'make install' to install into $(PREFIX)."
+ @echo
+
+luadoc:
+ rm -rf doc/luadoc
+ mkdir -p doc/luadoc
+ cd src && luadoc -d ../doc/luadoc --nofiles luarocks/*.lua
+
+check_makefile: clean
+ echo $(BIN_FILES) | tr " " "\n" | sort > makefile_list.txt
+ ( cd src/bin && ls -d * ) | sort > luarocks_dir.txt
+ echo $(LUAROCKS_FILES) | tr " " "\n" | sort >> makefile_list.txt
+ ( cd src/luarocks && find * -name "*.lua" ) | sort >> luarocks_dir.txt
+ diff makefile_list.txt luarocks_dir.txt
+ rm -f makefile_list.txt luarocks_dir.txt
+ @echo
+ @echo "Makefile is sane."
+ @echo
+
+cleanup_bins:
+ for f in $(BIN_FILES) ;\
+ do \
+ mv src/bin/$$f src/bin/$$f.bak ;\
+ sed "s,^#!.*lua.*,#!/usr/bin/env lua,;/^package.path/d" < src/bin/$$f.bak > src/bin/$$f ;\
+ chmod +x src/bin/$$f ;\
+ rm -f src/bin/$$f.bak ;\
+ done
+
+clean: cleanup_bins
+ rm -f src/luarocks/site_config.lua
+ rm -f built
+
+install_bins: built
+ mkdir -p "$(DESTDIR)$(BINDIR)"
+ cd src/bin && for f in $(BIN_FILES); \
+ do \
+ cp "$$f" "$(DESTDIR)$(BINDIR)/$$f-$(LUA_VERSION)"; \
+ ln -nfs "$(DESTDIR)$(BINDIR)/$$f-$(LUA_VERSION)" "$(DESTDIR)$(BINDIR)/$$f"; \
+ done
+
+install_luas: built
+ mkdir -p "$(DESTDIR)$(LUADIR)/luarocks"
+ cd src/luarocks && for f in $(LUAROCKS_FILES); \
+ do \
+ d="$(DESTDIR)$(LUADIR)/luarocks"/`dirname "$$f"` && \
+ mkdir -p "$$d" && \
+ cp "$$f" "$$d" || exit 1; \
+ done
+
+install_site_config: built
+ mkdir -p "$(DESTDIR)$(LUADIR)/luarocks"
+ cd src/luarocks && cp site_config.lua "$(DESTDIR)$(LUADIR)/luarocks"
+
+write_sysconfig: built
+ mkdir -p "$(DESTDIR)$(ROCKS_TREE)"
+ if [ ! -f "$(DESTDIR)$(CONFIG_FILE)" ] ;\
+ then \
+ mkdir -p `dirname "$(DESTDIR)$(CONFIG_FILE)"` ;\
+ echo 'rocks_trees = {' >> "$(DESTDIR)$(CONFIG_FILE)" ;\
+ if [ ! -n "$(FORCE_CONFIG)" ] ;\
+ then \
+ echo ' home..[[/.luarocks]],' >> "$(DESTDIR)$(CONFIG_FILE)" ;\
+ fi ;\
+ echo ' [[$(ROCKS_TREE)]]' >> "$(DESTDIR)$(CONFIG_FILE)" ;\
+ echo '}' >> "$(DESTDIR)$(CONFIG_FILE)" ;\
+ fi
+
+install: install_bins install_luas install_site_config write_sysconfig
+
+bootstrap: src/luarocks/site_config.lua install_site_config write_sysconfig
+ LUA_PATH="$$PWD/src/?.lua;$$LUA_PATH" src/bin/luarocks make rockspec --tree="$(PREFIX)"
+
+install_rock: install_bins install_luas
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..87345a2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+This is LuaRocks, a deployment and management system for Lua modules.
+
+Main website: [luarocks.org](http://www.luarocks.org)
+
+LuaRocks allows you to install Lua modules as self-contained packages called
+[*rocks*][1], which also contain version [dependency][2] information. This
+information is used both during installation, 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][3] repositories, and multiple local rocks
+trees. You can [download][4] and install LuaRocks on [Unix][5] and
+[Windows][6].
+
+LuaRocks is free software and uses the same [license][7] as Lua 5.1.
+
+[1]: http://luarocks.org/en/Types_of_rocks
+[2]: http://luarocks.org/en/Dependencies
+[3]: http://luarocks.org/en/Rocks_repositories
+[4]: http://luarocks.org/en/Download
+[5]: http://luarocks.org/en/Installation_instructions_for_Unix
+[6]: http://luarocks.org/en/Installation_instructions_for_Windows
+[7]: http://luarocks.org/en/License
diff --git a/config.ld b/config.ld
new file mode 100644
index 0000000..231a89f
--- /dev/null
+++ b/config.ld
@@ -0,0 +1,6 @@
+file = "src/luarocks"
+project = "LuaRocks"
+dir = "docs/ldoc"
+description = [[
+LuaRocks - a deployment and management system for Lua modules
+]]
diff --git a/configure b/configure
new file mode 100755
index 0000000..a5aa1f4
--- /dev/null
+++ b/configure
@@ -0,0 +1,444 @@
+#!/bin/sh
+
+# A basic configure script for LuaRocks.
+# Not doing any fancy shell stuff here to keep good compatibility.
+
+# Defaults
+
+PREFIX="/usr/local"
+SYSCONFDIR="$PREFIX/etc/luarocks"
+ROCKS_TREE="$PREFIX"
+LUA_SUFFIX=""
+LUA_DIR="/usr"
+LUA_BINDIR="/usr/bin"
+LUA_INCDIR="/usr/include"
+LUA_LIBDIR="/usr/lib"
+LUA_VERSION="5.1"
+
+# ----------------------------------------------------------------------------
+# FUNCTION DEFINITIONS
+# ----------------------------------------------------------------------------
+
+# Help
+
+show_help() {
+cat <<EOF
+Configure LuaRocks.
+
+--help This help.
+--prefix=DIR Prefix where LuaRocks should be installed.
+ Default is $PREFIX
+--sysconfdir=DIR Location where the config file should be installed.
+ Default is \$PREFIX/etc/luarocks
+
+Where to install files installed by rocks, to make the accessible to Lua and
+your \$PATH. Beware of clashes between files installed by LuaRocks and by your
+system's package manager.
+
+--rocks-tree=FILE Root of the local tree of installed rocks.
+ Default is \$PREFIX
+
+--lua-version=VERSION Use specific Lua version: 5.1 or 5.2
+ Default is "$LUA_VERSION"
+--lua-suffix=SUFFIX Versioning suffix to use in Lua filenames.
+ Default is "$LUA_SUFFIX" (lua$LUA_SUFFIX...)
+--with-lua=PREFIX Use Lua from given prefix.
+ Default is $LUA_DIR
+--with-lua-include=DIR You can also specify Lua's includes dir.
+ Default is \$LUA_DIR/include
+--with-lua-lib=DIR You can also specify Lua's libraries dir.
+ Default is \$LUA_DIR/lib
+--with-downloader=TOOL Which tool to use as a downloader.
+ Valid options are: wget, curl.
+ Default is to auto-detect.
+--with-md5-checker=TOOL Which tool to use as a downloader.
+ Valid options are: md5sum, openssl
+ Default is to auto-detect.
+--versioned-rocks-dir Use a versioned rocks dir, such as
+ \$PREFIX/lib/luarocks/rocks-$LUA_VERSION/.
+ Default is to auto-detect the necessity.
+--force-config Use a single config location. Do not use the
+ \$LUAROCKS_CONFIG variable or the user's home
+ directory. Useful to avoid conflicts when LuaRocks
+ is embedded within an application.
+EOF
+}
+
+# Helper functions
+
+find_program() {
+ path="$PATH"
+ item="`echo "$path" | sed 's/\([^:]*\):.*/\1/'`"
+ path="`echo "$path" | sed -n 's/[^:]*::*\(.*\)/\1/p'`"
+ found="no"
+ while [ -n "$item" ]
+ do
+ if [ -f "$item/$1" ]
+ then
+ found="yes"
+ break
+ fi
+ item="`echo "$path" | sed 's/\([^:]*\):.*/\1/'`"
+ path="`echo "$path" | sed -n 's/[^:]*::*\(.*\)/\1/p'`"
+ done
+ if [ "$found" = "yes" ]
+ then
+ echo "$item"
+ else
+ echo ""
+ fi
+}
+
+die() {
+ echo "$*"
+ echo
+ echo "configure failed."
+ echo
+ exit 1
+}
+
+find_helper() {
+ explanation="$1"
+ shift
+ tried="$*"
+ while [ -n "$1" ]
+ do
+ found=`find_program "$1"`
+ if [ -n "$found" ]
+ then
+ echo "$1 found at $found"
+ HELPER=$1
+ return
+ fi
+ shift
+ done
+ echo "Could not find a $explanation. Tried: $tried."
+ die "Make sure one of them is installed and available in your PATH."
+}
+
+case `echo -n x` in
+-n*) echo_n_flag='';;
+*) echo_n_flag='-n';;
+esac
+
+echo_n() {
+ echo $echo_n_flag "$*"
+}
+
+# ----------------------------------------------------------------------------
+# MAIN PROGRAM
+# ----------------------------------------------------------------------------
+
+# Parse options
+
+while [ -n "$1" ]
+do
+ value="`echo $1 | sed 's/[^=]*.\(.*\)/\1/'`"
+ key="`echo $1 | sed 's/=.*//'`"
+ if `echo "$value" | grep "~" >/dev/null 2>/dev/null`
+ then
+ echo
+ echo '*WARNING*: the "~" sign is not expanded in flags.'
+ echo 'If you mean the home directory, use $HOME instead.'
+ echo
+ fi
+ case "$key" in
+ --help)
+ show_help
+ exit 0
+ ;;
+ --prefix)
+ [ -n "$value" ] || die "Missing value in flag $key."
+ PREFIX="$value"
+ PREFIX_SET=yes
+ ;;
+ --sysconfdir)
+ [ -n "$value" ] || die "Missing value in flag $key."
+ SYSCONFDIR="$value"
+ SYSCONFDIR_SET=yes
+ ;;
+ --rocks-tree)
+ [ -n "$value" ] || die "Missing value in flag $key."
+ ROCKS_TREE="$value"
+ ROCKS_TREE_SET=yes
+ ;;
+ --force-config)
+ FORCE_CONFIG=yes
+ ;;
+ --versioned-rocks-dir)
+ VERSIONED_ROCKS_DIR=yes
+ ;;
+ --lua-suffix)
+ [ -n "$value" ] || die "Missing value in flag $key."
+ LUA_SUFFIX="$value"
+ LUA_SUFFIX_SET=yes
+ ;;
+ --lua-version)
+ [ -n "$value" ] || die "Missing value in flag $key."
+ LUA_VERSION="$value"
+ [ "$LUA_VERSION" = "5.1" -o "$LUA_VERSION" = "5.2" ] || die "Invalid Lua version in flag $key."
+ LUA_VERSION_SET=yes
+ ;;
+ --with-lua)
+ [ -n "$value" ] || die "Missing value in flag $key."
+ LUA_DIR="$value"
+ LUA_DIR_SET=yes
+ ;;
+ --with-lua-include)
+ [ -n "$value" ] || die "Missing value in flag $key."
+ LUA_INCDIR="$value"
+ LUA_INCDIR_SET=yes
+ ;;
+ --with-lua-lib)
+ [ -n "$value" ] || die "Missing value in flag $key."
+ LUA_LIBDIR="$value"
+ LUA_LIBDIR_SET=yes
+ ;;
+ --with-downloader)
+ [ -n "$value" ] || die "Missing value in flag $key."
+ case "$value" in
+ wget|curl) LUAROCKS_DOWNLOADER="$value" ;;
+ *) die "Invalid option: $value. See --help." ;;
+ esac
+ LUAROCKS_DOWNLOADER_SET=yes
+ ;;
+ --with-md5-checker)
+ [ -n "$value" ] || die "Missing value in flag $key."
+ case "$value" in
+ md5sum|openssl|md5) LUAROCKS_MD5CHECKER="$value" ;;
+ *) die "Invalid option: $value. See --help." ;;
+ esac
+ LUAROCKS_MD5CHECKER_SET=yes
+ ;;
+ *)
+ die "Error: Unknown flag: $1"
+ ;;
+ esac
+ shift
+done
+
+if [ "$PREFIX_SET" = "yes" -a ! "$SYSCONFDIR_SET" = "yes" ]
+then
+ if [ "$PREFIX" = "/usr" ]
+ then SYSCONFDIR=/etc/luarocks
+ else SYSCONFDIR=$PREFIX/etc/luarocks
+ fi
+fi
+
+
+if [ "$PREFIX_SET" = "yes" -a ! "$ROCKS_TREE_SET" = "yes" ]
+then
+ ROCKS_TREE=$PREFIX
+fi
+
+detect_lua_version() {
+ detected_lua=`$1 -e 'print(_VERSION:sub(5))' 2> /dev/null`
+ if [ "$detected_lua" = "5.1" -o "$detected_lua" = "5.2" ]
+ then
+ echo "Lua version detected: $detected_lua"
+ if [ "$LUA_VERSION_SET" != "yes" ]
+ then
+ LUA_VERSION=$detected_lua
+ elif [ "$LUA_VERSION" != "$detected_lua" ]
+ then
+ die "This clashes with the value of --with-lua-version. Please check your configuration."
+ fi
+ fi
+}
+
+search_interpreter() {
+ LUA_SUFFIX="$1"
+ if [ "$LUA_DIR_SET" = "yes" ]
+ then
+ if [ -f "$LUA_DIR/bin/lua$suffix" ]
+ then
+ find_lua="$LUA_DIR/bin"
+ fi
+ else
+ find_lua=`find_program lua$suffix`
+ fi
+ if [ -n "$find_lua" ]
+ then
+ echo "Lua interpreter found: $find_lua/lua$suffix..."
+ detect_lua_version "$find_lua/lua$suffix"
+ return 0
+ fi
+ return 1
+}
+
+if [ "$LUA_SUFFIX_SET" != "yes" ]
+then
+ if [ "$LUA_VERSION_SET" = "yes" -a "$LUA_VERSION" = "5.1" ]
+ then
+ suffixes="5.1 51"
+ elif [ "$LUA_VERSION_SET" = "yes" -a "$LUA_VERSION" = "5.2" ]
+ then
+ suffixes="5.2 52"
+ else
+ suffixes="5.2 52 5.1 51"
+ fi
+ for suffix in "" `echo $suffixes` ""
+ do
+ search_interpreter "$suffix" && break
+ done
+fi
+
+if [ "$LUA_DIR_SET" != "yes" ]
+then
+ echo_n "Looking for Lua... "
+ if [ ! -n "$find_lua" ]
+ then
+ find_lua=`find_program lua$LUA_SUFFIX`
+ fi
+
+ if [ -n "$find_lua" ]
+ then
+ LUA_DIR=`dirname $find_lua`
+ LUA_BINDIR="$find_lua"
+ echo "lua$LUA_SUFFIX found in \$PATH: $find_lua"
+ else
+ echo "lua$LUA_SUFFIX not found in \$PATH."
+ die "You may want to use the flags --with-lua and/or --lua-suffix. See --help."
+ fi
+fi
+
+if [ "$LUA_INCDIR_SET" != "yes" ]
+then
+ LUA_INCDIR="$LUA_DIR/include"
+fi
+
+if [ "$LUA_LIBDIR_SET" != "yes" ]
+then
+ LUA_LIBDIR="$LUA_DIR/lib"
+fi
+
+if [ "$LUA_DIR_SET" = "yes" ]
+then
+ LUA_BINDIR="$LUA_DIR/bin"
+fi
+
+echo_n "Checking Lua includes... "
+lua_h="$LUA_INCDIR/lua.h"
+if [ -f "$lua_h" ]
+then
+ echo "lua.h found in $lua_h"
+else
+ v_dir="$LUA_INCDIR/lua/$LUA_VERSION"
+ lua_h="$v_dir/lua.h"
+ if [ -f "$lua_h" ]
+ then
+ echo "lua.h found in $lua_h"
+ LUA_INCDIR="$v_dir"
+ else
+ d_dir="$LUA_INCDIR/lua$LUA_VERSION"
+ lua_h="$d_dir/lua.h"
+ if [ -f "$lua_h" ]
+ then
+ echo "lua.h found in $lua_h (Debian/Ubuntu)"
+ LUA_INCDIR="$d_dir"
+ else
+ echo "lua.h not found (looked in $LUA_INCDIR, $v_dir, $d_dir)"
+ die "You may want to use the flag --with-lua or --with-lua-include. See --help."
+ fi
+ fi
+fi
+
+if [ "$LUAROCKS_DOWNLOADER_SET" != "yes" ]
+then
+ find_helper "downloader helper program" wget curl fetch
+ LUAROCKS_DOWNLOADER=$HELPER
+fi
+
+if [ "$LUAROCKS_MD5CHECKER_SET" != "yes" ]
+then
+ find_helper "MD5 checksum calculator" md5sum openssl md5
+ LUAROCKS_MD5CHECKER=$HELPER
+fi
+
+echo_n "Configuring for system... "
+if uname -s
+then
+ LUAROCKS_UNAME_S=`uname -s`
+else
+ die "Could not determine operating system. 'uname -s' failed."
+fi
+echo_n "Configuring for architecture... "
+if uname -m
+then
+ LUAROCKS_UNAME_M=`uname -m`
+else
+ die "Could not determine processor architecture. 'uname -m' failed."
+fi
+
+if [ "$LUA_VERSION" = "5.2" ]
+then
+ LUA_OTHER_VERSION=5.1
+else
+ LUA_OTHER_VERSION=5.2
+fi
+
+LUAROCKS_ROCKS_SUBDIR=/lib/luarocks/rocks
+if [ "$VERSIONED_ROCKS_DIR" = "yes" ]
+then
+ LUAROCKS_ROCKS_SUBDIR=$LUAROCKS_ROCKS_SUBDIR-$LUA_VERSION
+ echo "Using versioned rocks dir: $PREFIX$LUAROCKS_ROCKS_SUBDIR"
+elif [ -e "$PREFIX/share/lua/$LUA_VERSION/luarocks/site_config.lua" ]
+then
+ echo "Existing installation detected."
+ LUAROCKS_ROCKS_SUBDIR=`grep "LUAROCKS_ROCKS_SUBDIR" "$PREFIX/share/lua/$LUA_VERSION/luarocks/site_config.lua" | sed 's,.*=\[\[\(.*\)\]\],\1,'`
+ echo "Using previously configured rocks dir: $PREFIX$LUAROCKS_ROCKS_SUBDIR"
+elif [ -e "$PREFIX/share/lua/$LUA_OTHER_VERSION/luarocks/site_config.lua" ]
+then
+ echo "Existing installation detected for other Lua version ($LUA_OTHER_VERSION)."
+ LUAROCKS_ROCKS_SUBDIR=$LUAROCKS_ROCKS_SUBDIR-$LUA_VERSION
+ echo "Using versioned rocks dir: $PREFIX$LUAROCKS_ROCKS_SUBDIR"
+else
+ echo "Using unversioned rocks dir: $PREFIX$LUAROCKS_ROCKS_SUBDIR"
+fi
+
+if [ -f config.unix ]; then
+ rm -f config.unix
+fi
+
+# Write config
+
+echo "Writing configuration..."
+echo
+
+rm -f built
+cat <<EOF > config.unix
+# This file was automatically generated by the configure script.
+# Run "./configure --help" for details.
+
+LUA_VERSION=$LUA_VERSION
+PREFIX=$PREFIX
+SYSCONFDIR=$SYSCONFDIR
+ROCKS_TREE=$ROCKS_TREE
+LUA_SUFFIX=$LUA_SUFFIX
+LUA_DIR=$LUA_DIR
+LUA_DIR_SET=$LUA_DIR_SET
+LUA_INCDIR=$LUA_INCDIR
+LUA_LIBDIR=$LUA_LIBDIR
+LUA_BINDIR=$LUA_BINDIR
+FORCE_CONFIG=$FORCE_CONFIG
+LUAROCKS_UNAME_M=$LUAROCKS_UNAME_M
+LUAROCKS_UNAME_S=$LUAROCKS_UNAME_S
+LUAROCKS_DOWNLOADER=$LUAROCKS_DOWNLOADER
+LUAROCKS_MD5CHECKER=$LUAROCKS_MD5CHECKER
+LUAROCKS_ROCKS_SUBDIR=$LUAROCKS_ROCKS_SUBDIR
+
+EOF
+
+echo "Installation prefix: $PREFIX"
+echo "LuaRocks configuration directory: $SYSCONFDIR"
+echo "Using Lua from: $LUA_DIR"
+
+make clean > /dev/null 2> /dev/null
+
+echo
+echo "Done configuring."
+echo "- Type 'make build' and 'make install':"
+echo " to install to $PREFIX as usual."
+echo "- Type 'make bootstrap':"
+echo " to install LuaRocks in $PREFIX as a rock."
+echo
diff --git a/install.bat b/install.bat
new file mode 100644
index 0000000..15f2607
--- /dev/null
+++ b/install.bat
@@ -0,0 +1,649 @@
+rem=rem --[[
+@setlocal& set luafile="%~f0" & if exist "%~f0.bat" set luafile="%~f0.bat"
+@lua5.1\bin\lua5.1.exe %luafile% %*& exit /b ]]
+
+local vars = {}
+
+vars.PREFIX = [[C:\LuaRocks]]
+vars.VERSION = "2.1"
+vars.SYSCONFDIR = [[C:\LuaRocks]]
+vars.ROCKS_TREE = [[C:\LuaRocks]]
+vars.SCRIPTS_DIR = nil
+vars.LUA_INTERPRETER = nil
+vars.LUA_PREFIX = nil
+vars.LUA_BINDIR = nil
+vars.LUA_INCDIR = nil
+vars.LUA_LIBDIR = nil
+vars.LUA_LIBNAME = nil
+vars.LUA_VERSION = "5.1"
+vars.LUA_SHORTV = nil
+vars.LUA_LIB_NAMES = "lua5.1.lib lua51.dll liblua.dll.a"
+vars.LUA_RUNTIME = nil
+
+local P_SET = false
+local FORCE = false
+local FORCE_CONFIG = false
+local INSTALL_LUA = false
+local USE_MINGW = false
+local REGISTRY = false
+
+---
+-- Some helpers
+--
+local function die(message)
+ if message then print(message) end
+ print()
+ print("Failed installing LuaRocks. Run with /? for help.")
+ os.exit(1)
+end
+
+local function exec(cmd)
+ --print(cmd)
+ local status = os.execute(cmd)
+ return status == 0
+end
+
+local function exists(filename)
+ local cmd = [[.\bin\test -e "]]..filename..[["]]
+ return exec(cmd)
+end
+
+local function mkdir (dir)
+ return exec([[.\bin\mkdir -p "]]..dir..[[" >NUL]])
+end
+
+-- interpolate string with values from 'vars' table
+local function S (tmpl)
+ return (tmpl:gsub('%$([%a_][%w_]*)', vars))
+end
+
+local function print_help()
+ print(S[[
+Installs LuaRocks.
+
+/P [dir] (REQUIRED) Where to install.
+ Note that version; $VERSION, will be
+ appended to this path.
+/CONFIG [dir] Location where the config file should be installed.
+ Default is same place of installation
+/TREE [dir] Root of the local tree of installed rocks.
+ Default is same place of installation
+/SCRIPTS [dir] Where to install scripts installed by rocks.
+ Default is TREE/bin.
+
+/LV [version] Lua version to use; either 5.1 or 5.2.
+ Default is 5.1
+/L Install LuaRocks' own copy of Lua even if detected,
+ this will always be a 5.1 installation.
+ (/LUA, /INC, /LIB, /BIN cannot be used with /L)
+/LUA [dir] Location where Lua is installed - e.g. c:\lua\5.1\
+ This is the base directory, the installer will look
+ for subdirectories bin, lib, include. Alternatively
+ these can be specified explicitly using the /INC,
+ /LIB, and /BIN options.
+/INC [dir] Location of Lua includes - e.g. c:\lua\5.1\include
+ If provided overrides sub directory found using /LUA.
+/LIB [dir] Location of Lua libraries -e.g. c:\lua\5.1\lib
+ If provided overrides sub directory found using /LUA.
+/BIN [dir] Location of Lua executables - e.g. c:\lua\5.1\bin
+ If provided overrides sub directory found using /LUA.
+
+/MW Use mingw as build system instead of MSVC
+
+/FORCECONFIG Use a single config location. Do not use the
+ LUAROCKS_CONFIG variable or the user's home directory.
+ Useful to avoid conflicts when LuaRocks
+ is embedded within an application.
+
+/F Remove installation directory if it already exists.
+
+/R Load registry information to register '.rockspec'
+ extension with LuaRocks commands (right-click).
+
+]])
+end
+
+-- ***********************************************************
+-- Option parser
+-- ***********************************************************
+local function parse_options(args)
+ for _, option in ipairs(args) do
+ local name = option.name:upper()
+ if name == "/?" then
+ print_help()
+ os.exit(0)
+ elseif name == "/P" then
+ vars.PREFIX = option.value
+ vars.SYSCONFDIR = option.value
+ vars.ROCKS_TREE = option.value
+ P_SET = true
+ elseif name == "/CONFIG" then
+ vars.SYSCONFDIR = option.value
+ elseif name == "/TREE" then
+ vars.ROCKS_TREE = option.value
+ elseif name == "/SCRIPTS" then
+ vars.SCRIPTS_DIR = option.value
+ elseif name == "/LV" then
+ vars.LUA_VERSION = option.value
+ elseif name == "/L" then
+ INSTALL_LUA = true
+ elseif name == "/MW" then
+ USE_MINGW = true
+ elseif name == "/LUA" then
+ vars.LUA_PREFIX = option.value
+ elseif name == "/LIB" then
+ vars.LUA_LIBDIR = option.value
+ elseif name == "/INC" then
+ vars.LUA_INCDIR = option.value
+ elseif name == "/BIN" then
+ vars.LUA_BINDIR = option.value
+ elseif name == "/FORCECONFIG" then
+ FORCE_CONFIG = true
+ elseif name == "/F" then
+ FORCE = true
+ elseif name == "/R" then
+ REGISTRY = true
+ else
+ die("Unrecognized option: " .. name)
+ end
+ end
+end
+
+-- check for combination/required flags
+local function check_flags()
+ if not P_SET then
+ die("Missing required parameter /P")
+ end
+ if INSTALL_LUA then
+ if vars.LUA_INCDIR or vars.LUA_BINDIR or vars.LUA_LIBDIR or vars.LUA_PREFIX then
+ die("Cannot combine option /L with any of /LUA /BIN /LIB /INC")
+ end
+ if vars.LUA_VERSION ~= "5.1" then
+ die("Bundled Lua version is 5.1, cannot install 5.2")
+ end
+ end
+ if vars.LUA_VERSION ~= "5.1" then
+ if vars.LUA_VERSION == "5.2" then
+ vars.LUA_LIB_NAMES = vars.LUA_LIB_NAMES:gsub("5([%.]?)1", "5%12")
+ else
+ die("Bad argument: /LV must either be 5.1 or 5.2")
+ end
+ end
+end
+
+-- ***********************************************************
+-- Detect Lua
+-- ***********************************************************
+local function look_for_interpreter (directory)
+ if vars.LUA_BINDIR then
+ if exists( S"$LUA_BINDIR\\lua$LUA_VERSION.exe" ) then
+ vars.LUA_INTERPRETER = S"lua$LUA_VERSION.exe"
+ print(S" Found $LUA_BINDIR\\$LUA_INTERPRETER")
+ return true
+ elseif exists(S"$LUA_BINDIR\\lua.exe") then
+ vars.LUA_INTERPRETER = "lua.exe"
+ print(S" Found $LUA_BINDIR\\$LUA_INTERPRETER")
+ return true
+ elseif exists(S"$LUA_BINDIR\\luajit.exe") then
+ vars.LUA_INTERPRETER = "luajit.exe"
+ print(S" Found $LUA_BINDIR\\$LUA_INTERPRETER")
+ return true
+ end
+ die(S"Lua executable lua.exe, luajit.exe or lua$LUA_VERSION.exe not found in $LUA_BINDIR")
+ end
+
+ for _, e in ipairs{ [[\]], [[\bin\]] } do
+ if exists(directory..e.."\\lua"..vars.LUA_VERSION..".exe") then
+ vars.LUA_INTERPRETER = S"lua$LUA_VERSION.exe"
+ vars.LUA_BINDIR = directory .. e
+ print(" Found ."..e..vars.LUA_INTERPRETER)
+ return true
+
+ elseif exists(directory..e.."\\lua.exe") then
+ vars.LUA_INTERPRETER = "lua.exe"
+ vars.LUA_BINDIR = directory..e
+ print(" Found ."..e..vars.LUA_INTERPRETER)
+ return true
+
+ elseif exists(directory..e.."\\luajit.exe") then
+ vars.LUA_INTERPRETER = "luajit.exe"
+ vars.LUA_BINDIR = directory..e
+ print(" Found ."..e..vars.LUA_INTERPRETER)
+ return true
+ end
+ end
+ print(" No Lua interpreter found")
+ return false
+end
+
+local function look_for_link_libraries (directory)
+ if vars.LUA_LIBDIR then
+ for name in vars.LUA_LIB_NAMES:gmatch("[^%s]+") do
+ print(S" checking for $LUA_LIBDIR\\"..name)
+ if exists(vars.LUA_LIBDIR.."\\"..name) then
+ vars.LUA_LIBNAME = name
+ print(" Found "..name)
+ return true
+ end
+ end
+ die(S"link library (one of; $LUA_LIB_NAMES) not found in $LUA_LIBDIR")
+ end
+
+ for _, e in ipairs{ [[\]], [[\lib\]], [[\bin\]]} do
+ for name in vars.LUA_LIB_NAMES:gmatch("[^%s]+") do
+ print(" checking for "..directory..e.."\\"..name)
+ if exists(directory..e.."\\"..name) then
+ vars.LUA_LIBDIR = directory .. e
+ vars.LUA_LIBNAME = name
+ print(" Found "..name)
+ return true
+ end
+ end
+ end
+ return false
+end
+
+local function look_for_headers (directory)
+ if vars.LUA_INCDIR then
+ print(S" checking for $LUA_INCDIR\\lua.h")
+ if exists(S"$LUA_INCDIR\\lua.h") then
+ print(" Found lua.h")
+ return true
+ end
+ die(S"lua.h not found in $LUA_INCDIR")
+ end
+
+ for _, e in ipairs{ [[\]], [[\include\]]} do
+ print(" checking for "..directory..e.."\\lua.h")
+ if exists(directory..e.."\\lua.h") then
+ vars.LUA_INCDIR = directory..e
+ print(" Found lua.h")
+ return true
+ end
+ end
+ return false
+end
+
+-- Checks a binary file for the runtime dll used by it. If nu runtime is found, it returns an
+-- array of dll's is depends upon.
+-- result: string = runtime used, table = list of dll's depended upon, nil = nothing found.
+local function get_file_runtime(p,f) -- path, filename
+ local infile = p.."\\"..f
+ local outfile = "output.txt"
+ local content
+ -- analyze binary
+ if exec([[.\bin\objdump -x "]]..infile..[[" > ]]..outfile..[[ 2<&1]]) then
+ -- read temp file
+ local fh = io.open(outfile)
+ content = fh:read("*a")
+ fh:close()
+ end
+ -- delete temp file
+ os.remove(outfile)
+ if not content then
+ print(" Failed to analyze "..infile.." for the runtime used")
+ return nil
+ end
+
+ -- lookup
+ content = content:upper()
+ local result = content:match('DLL NAME%: (MSVCR%d*)%.DLL')
+ if not result then
+ result = content:match('DLL NAME%: (MSVCRT)%.DLL')
+ end
+
+ if result then
+ print(" "..f.." uses "..tostring(result)..".DLL as runtime")
+ else
+ print(" No runtime found for "..f)
+ -- so; create a list of dll's this file is depending upon, next level of the tree
+ result = {}
+ for name in content:gmatch("DLL NAME%: (.-%.DLL)") do
+ --print("found dll:", name)
+ table.insert(result, name)
+ end
+ end
+ return result
+end
+
+local function get_runtime()
+ -- first check interpreter
+ vars.LUA_RUNTIME = get_file_runtime(vars.LUA_BINDIR, vars.LUA_INTERPRETER)
+ if type(vars.LUA_RUNTIME) == "table" then
+ -- a table with dll's depended upon was returned, check this list
+ -- note: we only check 1 level deep
+ for _,dll in ipairs(vars.LUA_RUNTIME) do
+ local t = get_file_runtime(vars.LUA_BINDIR, dll)
+ if type(t) == "string" then
+ -- found it
+ vars.LUA_RUNTIME = t
+ break
+ end
+ end
+ end
+ if type(vars.LUA_RUNTIME) ~= "string" then
+ -- analysis failed, issue a warning
+ vars.LUA_RUNTIME = "MSVCR80"
+ print("*** WARNING ***: could not analyse the runtime used, defaulting to "..vars.LUA_RUNTIME)
+ end
+ return true
+end
+
+local function look_for_lua_install ()
+ print("Looking for Lua interpreter")
+ local directories = { [[c:\lua5.1.2]], [[c:\lua]], [[c:\kepler\1.1]] }
+ if vars.LUA_PREFIX then
+ table.insert(directories, 1, vars.LUA_PREFIX)
+ end
+ if vars.LUA_BINDIR and vars.LUA_LIBDIR and vars.LUA_INCDIR then
+ if look_for_interpreter(vars.LUA_BINDIR) and
+ look_for_link_libraries(vars.LUA_LIBDIR) and
+ look_for_headers(vars.LUA_INCDIR)
+ then
+ if get_runtime() then
+ print("Runtime check completed, now testing interpreter...")
+ if exec(S[[$LUA_BINDIR\$LUA_INTERPRETER -v 2>NUL]]) then
+ print(" Ok")
+ return true
+ end
+ print(" Interpreter returned an error, not ok")
+ end
+ end
+ return false
+ end
+
+ for _, directory in ipairs(directories) do
+ print(" checking " .. directory)
+ if exists(directory) then
+ if look_for_interpreter(directory) then
+ print("Interpreter found, now looking for link libraries...")
+ if look_for_link_libraries(directory) then
+ print("Link library found, now looking for headers...")
+ if look_for_headers(directory) then
+ print("Headers found, checking runtime to use...")
+ if get_runtime() then
+ print("Runtime check completed, now testing interpreter...")
+ if exec(S[[$LUA_BINDIR\$LUA_INTERPRETER -v 2>NUL]]) then
+ print(" Ok")
+ return true
+ end
+ print(" Interpreter returned an error, not ok")
+ end
+ end
+ end
+ end
+ end
+ end
+ return false
+end
+
+---
+-- Poor man's command-line parsing
+local config = {}
+local with_arg = { -- options followed by an argument, others are flags
+ ["/P"] = true,
+ ["/CONFIG"] = true,
+ ["/TREE"] = true,
+ ["/SCRIPTS"] = true,
+ ["/LV"] = true,
+ ["/LUA"] = true,
+ ["/INC"] = true,
+ ["/BIN"] = true,
+ ["/LIB"] = true,
+}
+local i = 1
+while i <= #arg do
+ local opt = arg[i]
+ if with_arg[opt] then
+ local value = arg[i + 1]
+ if not value then
+ die("Missing value for option "..opt)
+ end
+ config[#config + 1] = { name = opt, value = value }
+ i = i + 1
+ else
+ config[#config + 1] = { name = opt }
+ end
+ i = i + 1
+end
+
+print(S"LuaRocks $VERSION.x installer.\n")
+
+parse_options(config)
+check_flags()
+
+vars.FULL_PREFIX = S"$PREFIX\\$VERSION"
+vars.BINDIR = vars.FULL_PREFIX
+vars.LIBDIR = vars.FULL_PREFIX
+vars.LUADIR = S"$FULL_PREFIX\\lua"
+vars.INCDIR = S"$FULL_PREFIX\\include"
+vars.LUA_SHORTV = vars.LUA_VERSION:gsub("%.", "")
+
+if not look_for_lua_install() then
+ print("Could not find Lua. Will install its own copy.")
+ print("See /? for options for specifying the location of Lua.")
+ if vars.LUA_VERSION ~= "5.1" then
+ die("Cannot install own copy because no 5.2 version is bundled")
+ end
+ INSTALL_LUA = true
+ vars.LUA_INTERPRETER = "lua5.1"
+ vars.LUA_BINDIR = vars.BINDIR
+ vars.LUA_LIBDIR = vars.LIBDIR
+ vars.LUA_INCDIR = vars.INCDIR
+ vars.LUA_LIBNAME = "lua5.1.lib"
+ vars.LUA_RUNTIME = "MSVCR80"
+else
+ print(S[[
+
+Will configure LuaRocks with the following paths:
+LuaRocks : $FULL_PREFIX
+Lua interpreter: $LUA_BINDIR\$LUA_INTERPRETER
+Lua binaries : $LUA_BINDIR
+Lua libraries : $LUA_LIBDIR
+Lua includes : $LUA_INCDIR
+Binaries will be linked against: $LUA_LIBNAME with runtime $LUA_RUNTIME
+
+]])
+end
+
+-- ***********************************************************
+-- Install LuaRocks files
+-- ***********************************************************
+if FORCE then
+ print(S"Removing $FULL_PREFIX...")
+ exec(S[[RD /S /Q "$FULL_PREFIX"]])
+ print()
+end
+
+if exists(vars.FULL_PREFIX) then
+ die(S"$FULL_PREFIX exists. Use /F to force removal and reinstallation.")
+end
+
+print(S"Installing LuaRocks in $FULL_PREFIX...")
+if not exists(vars.BINDIR) then
+ if not mkdir(vars.BINDIR) then
+ die()
+ end
+end
+
+if INSTALL_LUA then
+ -- Copy the included Lua interpreter binaries
+ if not exists(vars.LUA_BINDIR) then
+ mkdir(vars.LUA_BINDIR)
+ end
+ if not exists(vars.LUA_INCDIR) then
+ mkdir(vars.LUA_INCDIR)
+ end
+ exec(S[[COPY lua5.1\bin\*.* "$LUA_BINDIR" >NUL]])
+ exec(S[[COPY lua5.1\include\*.* "$LUA_INCDIR" >NUL]])
+ print(S"Installed the LuaRocks bundled Lua interpreter in $LUA_BINDIR")
+end
+
+-- Copy the LuaRocks binaries
+if not exec(S[[COPY bin\*.* "$BINDIR" >NUL]]) then
+ die()
+end
+-- Copy the LuaRocks lua source files
+if not exists(S[[$LUADIR\luarocks]]) then
+ if not mkdir(S[[$LUADIR\luarocks]]) then
+ die()
+ end
+end
+if not exec(S[[XCOPY /S src\luarocks\*.* "$LUADIR\luarocks" >NUL]]) then
+ die()
+end
+-- Create start scripts
+if not exec(S[[COPY src\bin\*.* "$BINDIR" >NUL]]) then
+ die()
+end
+for _, c in ipairs{"luarocks", "luarocks-admin"} do
+ -- rename unix-lua scripts to .lua files
+ if not exec( (S[[RENAME "$BINDIR\%s" %s.lua]]):format(c, c) ) then
+ die()
+ end
+ -- create a bootstrap batch file for the lua file, to start them
+ exec(S[[DEL /F /Q "$BINDIR\]]..c..[[.bat" 2>NUL]])
+ local f = io.open(vars.BINDIR.."\\"..c..".bat", "w")
+ f:write(S[[
+@ECHO OFF
+SETLOCAL
+SET LUA_PATH=$LUADIR\?.lua;$LUADIR\?\init.lua;%LUA_PATH%
+SET PATH=$BINDIR\;%PATH%
+"$LUA_INTERPRETER" "$BINDIR\]]..c..[[.lua" %*
+ENDLOCAL
+]])
+ f:close()
+ print(S"Created LuaRocks command: $BINDIR\\"..c..".bat")
+end
+-- configure 'scripts' directory
+if vars.SCRIPTS_DIR then
+ mkdir(vars.SCRIPTS_DIR)
+ if not USE_MINGW then
+ -- definitly not for MinGW because of conflicting runtimes
+ -- but is it ok to do it for others???
+ exec(S[[COPY lua5.1\bin\*.dll "$SCRIPTS_DIR" >NUL]])
+ end
+else
+ if not USE_MINGW then
+ mkdir(S[[$ROCKS_TREE\bin]])
+ -- definitly not for MinGW because of conflicting runtimes
+ -- but is it ok to do it for others???
+ exec(S[[COPY lua5.1\bin\*.dll "$ROCKS_TREE"\bin >NUL]])
+ end
+end
+
+
+print()
+print("Configuring LuaRocks...")
+-- Create a site-config file
+if exists(S[[$LUADIR\luarocks\site_config.lua]]) then
+ exec(S[[RENAME "$LUADIR\luarocks\site_config.lua" site_config.lua.bak]])
+end
+local f = io.open(vars.LUADIR.."\\luarocks\\site_config.lua", "w")
+f:write(S[=[
+module("luarocks.site_config")
+LUA_INCDIR=[[$LUA_INCDIR]]
+LUA_LIBDIR=[[$LUA_LIBDIR]]
+LUA_BINDIR=[[$LUA_BINDIR]]
+LUA_INTERPRETER=[[$LUA_INTERPRETER]]
+]=])
+if USE_MINGW then
+ f:write("LUAROCKS_UNAME_S=[[MINGW]]\n")
+else
+ f:write("LUAROCKS_UNAME_S=[[WindowsNT]]\n")
+end
+f:write(S[=[
+LUAROCKS_UNAME_M=[[x86]]
+LUAROCKS_SYSCONFIG=[[$SYSCONFDIR\config.lua]]
+LUAROCKS_ROCKS_TREE=[[$ROCKS_TREE]]
+LUAROCKS_PREFIX=[[$PREFIX]]
+LUAROCKS_DOWNLOADER=[[wget]]
+LUAROCKS_MD5CHECKER=[[md5sum]]
+]=])
+if FORCE_CONFIG then
+ f:write("local LUAROCKS_FORCE_CONFIG=true\n")
+end
+if exists(vars.LUADIR.."\\luarocks\\site_config.lua.bak") then
+ for line in io.lines(vars.LUADIR.."\\luarocks\\site_config.lua.bak", "r") do
+ f:write(line)
+ f:write("\n")
+ end
+ exec(S[[DEL /F /Q "$LUADIR\luarocks\site_config.lua.bak"]])
+end
+f:close()
+print(S[[Created LuaRocks site-config file: $LUADIR\luarocks\site_config.lua]])
+
+-- create config file
+vars.CONFIG_FILE = vars.SYSCONFDIR.."\\config.lua"
+if not exists(vars.SYSCONFDIR) then
+ mkdir(vars.SYSCONFDIR)
+end
+if not exists(vars.CONFIG_FILE) then
+ local f = io.open(vars.CONFIG_FILE, "w")
+ f:write([=[
+rocks_servers = {
+ [[http://luarocks.org/repositories/rocks]]
+}
+rocks_trees = {
+]=])
+ if FORCE_CONFIG then
+ f:write(" home..[[/luarocks]],\n")
+ end
+ f:write(S" [[$ROCKS_TREE]]\n")
+ f:write("}\n")
+ if vars.SCRIPTS_DIR then
+ f:write(S"scripts_dir=[[$SCRIPTS_DIR]]\n")
+ end
+ f:write("variables = {\n")
+ if USE_MINGW and vars.LUA_RUNTIME == "MSVCRT" then
+ f:write(" MSVCRT = 'm', -- make MinGW use MSVCRT.DLL as runtime\n")
+ else
+ f:write(" MSVCRT = '"..vars.LUA_RUNTIME.."',\n")
+ end
+ f:write(S" LUALIB = '$LUA_LIBNAME'\n")
+ f:write("}\n")
+ f:close()
+ print(S"Created LuaRocks config file: $CONFIG_FILE")
+else
+ print(S"LuaRocks config file already exists: $CONFIG_FILE")
+end
+
+print()
+print("Creating rocktrees...")
+if not exists(vars.ROCKS_TREE) then
+ mkdir(vars.ROCKS_TREE)
+ print(S[[Created rocktree: "$ROCKS_TREE"]])
+else
+ print(S[[Rocktree exists: "$ROCKS_TREE"]])
+end
+local APPDATA = os.getenv("APPDATA")
+if not exists(APPDATA.."\\luarocks") then
+ mkdir(APPDATA.."\\luarocks")
+ print([[Created rocktree: "]]..APPDATA..[[\luarocks"]])
+else
+ print([[Rocktree exists: "]]..APPDATA..[[\luarocks"]])
+end
+
+-- Load registry information
+if REGISTRY then
+ -- expand template with correct path information
+ print()
+ print([[Loading registry information for ".rockspec" files]])
+ exec( S[[lua5.1\bin\lua5.1.exe "$FULL_PREFIX\create_reg_file.lua" "$FULL_PREFIX\LuaRocks.reg.template"]] )
+ exec( S"$FULL_PREFIX\\LuaRocks.reg" )
+end
+
+-- ***********************************************************
+-- Exit handlers
+-- ***********************************************************
+
+print(S[[
+*** LuaRocks is installed! ***
+
+ You may want to add the following elements to your paths;
+PATH : $LUA_BINDIR;$FULL_PREFIX
+LUA_PATH : $ROCKS_TREE\share\lua\$LUA_VERSION\?.lua;$ROCKS_TREE\share\lua\$LUA_VERSION\?\init.lua
+LUA_CPATH: $LUA_LIBDIR\lua\$LUA_VERSION\?.dll
+
+]])
+os.exit(0)
diff --git a/lfw/7z.dll b/lfw/7z.dll
new file mode 100644
index 0000000..c0ff7fb
--- /dev/null
+++ b/lfw/7z.dll
Binary files differ
diff --git a/lfw/7z.exe b/lfw/7z.exe
new file mode 100644
index 0000000..5e3d6f9
--- /dev/null
+++ b/lfw/7z.exe
Binary files differ
diff --git a/lfw/lua/luarocks/config.lua b/lfw/lua/luarocks/config.lua
new file mode 100644
index 0000000..fd0e2fb
--- /dev/null
+++ b/lfw/lua/luarocks/config.lua
@@ -0,0 +1,16 @@
+local os = os
+
+module("luarocks.config")
+LFW_ROOT = os.getenv("LUA_DEV")
+LUA_INCDIR=LFW_ROOT..[[\include]]
+LUA_LIBDIR=LFW_ROOT..[[\lib]]
+LUA_BINDIR=LFW_ROOT
+LUA_INTERPRETER=[[lua]]
+LUAROCKS_UNAME_S=[[WindowsNT]]
+LUAROCKS_UNAME_M=[[x86]]
+LUAROCKS_SYSCONFIG=LFW_ROOT..[[\luarocks_config.lua]]
+LUAROCKS_ROCKS_TREE=LFW_ROOT
+LUAROCKS_PREFIX=LFW_ROOT
+LUAROCKS_DOWNLOADER=[[wget]]
+LUAROCKS_MD5CHECKER=[[md5sum]]
+
diff --git a/lfw/luarocks-admin.bat b/lfw/luarocks-admin.bat
new file mode 100644
index 0000000..fb95d0f
--- /dev/null
+++ b/lfw/luarocks-admin.bat
@@ -0,0 +1,4 @@
+@ECHO OFF
+SETLOCAL
+"%LUA_DEV%\lua" "%LUA_DEV%\luarocks-admin.lua" %*
+ENDLOCAL
diff --git a/lfw/luarocks-admin.lua b/lfw/luarocks-admin.lua
new file mode 100644
index 0000000..4f7a9a2
--- /dev/null
+++ b/lfw/luarocks-admin.lua
@@ -0,0 +1,16 @@
+#!/usr/local/bin/lua
+
+local command_line = require("luarocks.command_line")
+
+program_name = "luarocks-admin"
+program_description = "LuaRocks repository administration interface"
+
+commands = {
+}
+
+commands.help = require("luarocks.help")
+commands.make_manifest = require("luarocks.make_manifest")
+commands.add = require("luarocks.add")
+commands.refresh_cache = require("luarocks.refresh_cache")
+
+command_line.run_command(...)
diff --git a/lfw/luarocks.bat b/lfw/luarocks.bat
new file mode 100644
index 0000000..44360aa
--- /dev/null
+++ b/lfw/luarocks.bat
@@ -0,0 +1,4 @@
+@ECHO OFF
+SETLOCAL
+"%LUA_DEV%\lua" "%LUA_DEV%\luarocks.lua" %*
+ENDLOCAL
diff --git a/lfw/luarocks.lua b/lfw/luarocks.lua
new file mode 100644
index 0000000..1c78125
--- /dev/null
+++ b/lfw/luarocks.lua
@@ -0,0 +1,20 @@
+#!/usr/local/bin/lua
+
+local command_line = require("luarocks.command_line")
+
+program_name = "luarocks"
+program_description = "LuaRocks main command-line interface"
+
+commands = {}
+commands.help = require("luarocks.help")
+commands.pack = require("luarocks.pack")
+commands.unpack = require("luarocks.unpack")
+commands.build = require("luarocks.build")
+commands.install = require("luarocks.install")
+commands.search = require("luarocks.search")
+commands.list = require("luarocks.list")
+commands.remove = require("luarocks.remove")
+commands.make = require("luarocks.make")
+commands.download = require("luarocks.download")
+
+command_line.run_command(...)
diff --git a/lfw/luarocks_config.lua b/lfw/luarocks_config.lua
new file mode 100644
index 0000000..557890f
--- /dev/null
+++ b/lfw/luarocks_config.lua
@@ -0,0 +1,10 @@
+local LFW_ROOT = config.LFW_ROOT
+rocks_servers = {
+ [[http://luarocks.org/repositories/rocks]]
+}
+rocks_trees = {
+ { root = LFW_ROOT, rocks_dir = LFW_ROOT..[[\rocks]],
+ bin_dir = LFW_ROOT, lua_dir = LFW_ROOT..[[\lua]],
+ lib_dir = LFW_ROOT..[[\clibs]] }
+}
+variables.WRAPPER = LFW_ROOT..[[\rclauncher.c]]
diff --git a/lfw/rclauncher.o b/lfw/rclauncher.o
new file mode 100644
index 0000000..0fe5d95
--- /dev/null
+++ b/lfw/rclauncher.o
Binary files differ
diff --git a/lfw/rclauncher.obj b/lfw/rclauncher.obj
new file mode 100644
index 0000000..86a3279
--- /dev/null
+++ b/lfw/rclauncher.obj
Binary files differ
diff --git a/lfw/rocks/index.html b/lfw/rocks/index.html
new file mode 100644
index 0000000..d6baff4
--- /dev/null
+++ b/lfw/rocks/index.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<title>Available rocks</title>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<style>
+body {
+ background-color: white;
+ font-family: "bitstream vera sans", "verdana", "sans";
+ font-size: 14px;
+}
+a {
+ color: #0000c0;
+ text-decoration: none;
+}
+a:hover {
+ text-decoration: underline;
+}
+td.main {
+ border-style: none;
+}
+blockquote {
+ font-size: 12px;
+}
+td.package {
+ background-color: #f0f0f0;
+ vertical-align: top;
+}
+td.spacer {
+ height: 5px;
+}
+td.version {
+ background-color: #d0d0d0;
+ vertical-align: top;
+ text-align: left;
+ padding: 5px;
+ width: 100px;
+}
+p.manifest {
+ font-size: 8px;
+}
+</style>
+</head>
+<body>
+<h1>Available rocks</h1>
+<p>
+Lua modules available from this location for use with <a href="http://www.luarocks.org">LuaRocks</a>:
+</p>
+<table class="main">
+<td class="package">
+<p><a name="luafilesystem"></a><b>luafilesystem</b> - <br/>
+</p><blockquote><p><br/>
+<font size="-1"><a href="">latest sources</a> | License: </font></p>
+</blockquote></a></td>
+<td class="version">
+1.5.0-1:&nbsp;<a href="luafilesystem-1.5.0-1.installed.rock">installed</a><br/></td></tr>
+<tr><td colspan="2" class="spacer"></td></tr>
+<td class="package">
+<p><a name="luasocket"></a><b>luasocket</b> - <br/>
+</p><blockquote><p><br/>
+<font size="-1"><a href="">latest sources</a> | License: </font></p>
+</blockquote></a></td>
+<td class="version">
+2.0.2-3:&nbsp;<a href="luasocket-2.0.2-3.installed.rock">installed</a><br/></td></tr>
+<tr><td colspan="2" class="spacer"></td></tr>
+<td class="package">
+<p><a name="luazip"></a><b>luazip</b> - <br/>
+</p><blockquote><p><br/>
+<font size="-1"><a href="">latest sources</a> | License: </font></p>
+</blockquote></a></td>
+<td class="version">
+1.2.3-2:&nbsp;<a href="luazip-1.2.3-2.installed.rock">installed</a><br/></td></tr>
+<tr><td colspan="2" class="spacer"></td></tr>
+<td class="package">
+<p><a name="md5"></a><b>md5</b> - <br/>
+</p><blockquote><p><br/>
+<font size="-1"><a href="">latest sources</a> | License: </font></p>
+</blockquote></a></td>
+<td class="version">
+1.1.2-1:&nbsp;<a href="md5-1.1.2-1.installed.rock">installed</a><br/></td></tr>
+<tr><td colspan="2" class="spacer"></td></tr>
+</table>
+<p class="manifest">
+<a href="manifest">manifest file</a>
+</p>
+</body>
+</html>
diff --git a/lfw/rocks/luafilesystem/1.5.0-1/doc/us/examples.html b/lfw/rocks/luafilesystem/1.5.0-1/doc/us/examples.html
new file mode 100644
index 0000000..746df62
--- /dev/null
+++ b/lfw/rocks/luafilesystem/1.5.0-1/doc/us/examples.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>LuaFileSystem</title>
+ <link rel="stylesheet" href="http://www.keplerproject.org/doc.css" type="text/css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo">
+ <a href="http://www.keplerproject.org">
+ <img alt="LuaFileSystem" src="luafilesystem.png"/>
+ </a>
+ </div>
+ <div id="product_name"><big><strong>LuaFileSystem</strong></big></div>
+ <div id="product_description">File System Library for the Lua Programming Language</div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<h1>LuaFileSystem</h1>
+ <ul>
+ <li><a href="index.html">Home</a>
+ <ul>
+ <li><a href="index.html#overview">Overview</a></li>
+ <li><a href="index.html#status">Status</a></li>
+ <li><a href="index.html#download">Download</a></li>
+ <li><a href="index.html#history">History</a></li>
+ <li><a href="index.html#credits">Credits</a></li>
+ <li><a href="index.html#contact">Contact us</a></li>
+ </ul>
+ </li>
+ <li><a href="manual.html">Manual</a>
+ <ul>
+ <li><a href="manual.html#introduction">Introduction</a></li>
+ <li><a href="manual.html#building">Building</a></li>
+ <li><a href="manual.html#installation">Installation</a></li>
+ <li><a href="manual.html#reference">Reference</a></li>
+ </ul>
+ </li>
+ <li><strong>Examples</strong></li>
+ <li><a href="http://luaforge.net/projects/luafilesystem/">Project</a>
+ <ul>
+ <li><a href="http://luaforge.net/tracker/?group_id=66">Bug Tracker</a></li>
+ <li><a href="http://luaforge.net/scm/?group_id=66">CVS</a></li>
+ </ul>
+ </li>
+ <li><a href="license.html">License</a></li>
+ </ul>
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h2><a name="example"></a>Examples</h2>
+
+<h3>Directory iterator</h3>
+
+<p>The following example iterates over a directory and recursively lists the
+attributes for each file inside it.</p>
+
+<pre class="example">
+require"lfs"
+
+function attrdir (path)
+ for file in lfs.dir(path) do
+ if file ~= "." and file ~= ".." then
+ local f = path..'/'..file
+ print ("\t "..f)
+ local attr = lfs.attributes (f)
+ assert (type(attr) == "table")
+ if attr.mode == "directory" then
+ attrdir (f)
+ else
+ for name, value in pairs(attr) do
+ print (name, value)
+ end
+ end
+ end
+ end
+end
+
+attrdir (".")
+</pre>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+ <p><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0!</a></p>
+ <p><small>$Id: examples.html,v 1.8 2007/12/14 15:28:04 carregal Exp $</small></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" -->
+
+</body>
+</html>
diff --git a/lfw/rocks/luafilesystem/1.5.0-1/doc/us/index.html b/lfw/rocks/luafilesystem/1.5.0-1/doc/us/index.html
new file mode 100644
index 0000000..43edefc
--- /dev/null
+++ b/lfw/rocks/luafilesystem/1.5.0-1/doc/us/index.html
@@ -0,0 +1,192 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>LuaFileSystem</title>
+ <link rel="stylesheet" href="http://www.keplerproject.org/doc.css" type="text/css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo">
+ <a href="http://www.keplerproject.org">
+ <img alt="LuaFileSystem" src="luafilesystem.png"/>
+ </a>
+ </div>
+ <div id="product_name"><big><strong>LuaFileSystem</strong></big></div>
+ <div id="product_description">File System Library for the Lua Programming Language</div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<h1>LuaFileSystem</h1>
+ <ul>
+ <li><strong>Home</strong>
+ <ul>
+ <li><a href="index.html#overview">Overview</a></li>
+ <li><a href="index.html#status">Status</a></li>
+ <li><a href="index.html#download">Download</a></li>
+ <li><a href="index.html#history">History</a></li>
+ <li><a href="index.html#credits">Credits</a></li>
+ <li><a href="index.html#contact">Contact us</a></li>
+ </ul>
+ </li>
+ <li><a href="manual.html">Manual</a>
+ <ul>
+ <li><a href="manual.html#introduction">Introduction</a></li>
+ <li><a href="manual.html#building">Building</a></li>
+ <li><a href="manual.html#installation">Installation</a></li>
+ <li><a href="manual.html#reference">Reference</a></li>
+ </ul>
+ </li>
+ <li><a href="examples.html">Examples</a></li>
+ <li><a href="http://luaforge.net/projects/luafilesystem/">Project</a>
+ <ul>
+ <li><a href="http://luaforge.net/tracker/?group_id=66">Bug Tracker</a></li>
+ <li><a href="http://luaforge.net/scm/?group_id=66">CVS</a></li>
+ </ul>
+ </li>
+ <li><a href="license.html">License</a></li>
+ </ul>
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h2><a name="overview"></a>Overview</h2>
+
+<p>LuaFileSystem is a <a href="http://www.lua.org">Lua</a> library
+developed to complement the set of functions related to file
+systems offered by the standard Lua distribution.</p>
+
+<p>LuaFileSystem offers a portable way to access
+the underlying directory structure and file attributes.</p>
+
+<p>LuaFileSystem is free software and uses the same
+<a href="license.html">license</a> as Lua 5.1.</p>
+
+<h2><a name="status"></a>Status</h2>
+
+<p>Current version is 1.5.0. It was developed for Lua 5.1.</p>
+
+<h2><a name="download"></a>Download</h2>
+
+<p>LuaFileSystem source can be downloaded from its
+<a href="http://github.com/keplerproject/luafilesystem">Github</a>
+page.</p>
+
+<h2><a name="history"></a>History</h2>
+
+<dl class="history">
+ <dt><strong>Version 1.5.0</strong> [20/Oct/2009]</dt>
+ <li>Added explicit next and close methods to second return value of lfs.dir
+(the directory object), for explicit iteration or explicit closing.</li>
+ <li>Added directory locking via lfs.lock_dir function (see the <a href="manual.html">manual</a>).</li>
+ <dt><strong>Version 1.4.2</strong> [03/Feb/2009]</dt>
+ <dd>
+ <ul>
+ <li>fixed bug [<a href="http://luaforge.net/tracker/?func=detail&amp;group_id=66&amp;aid=13198&amp;atid=356">#13198</a>]
+ lfs.attributes(filename, 'size') overflow on files > 2 Gb again (bug report and patch by KUBO Takehiro).</li>
+ <li>fixed bug [<a href="http://luaforge.net/tracker/?group_id=66&amp;atid=356&amp;func=detail&amp;aid=39794">#39794</a>]
+ Compile error on Solaris 10 (bug report and patch by Aaron B).</li>
+ <li>fixed compilation problems with Borland C.</li>
+ </ul>
+ </dd>
+
+ <dt><strong>Version 1.4.1</strong> [07/May/2008]</dt>
+ <dd>
+ <ul>
+ <li>documentation review</li>
+ <li>fixed Windows compilation issues</li>
+ <li>fixed bug in the Windows tests (patch by Shmuel Zeigerman)</li>
+ <li>fixed bug [<a href="http://luaforge.net/tracker/?func=detail&amp;group_id=66&amp;aid=2185&amp;atid=356">#2185</a>]
+ <code>lfs.attributes(filename, 'size')</code> overflow on files > 2 Gb
+ </li>
+ </ul>
+ </dd>
+
+ <dt><strong>Version 1.4.0</strong> [13/Feb/2008]</dt>
+ <dd>
+ <ul>
+ <li>added function
+ <a href="manual.html#setmode"><code>lfs.setmode</code></a>
+ (works only in Windows systems).</li>
+ <li><a href="manual.html#attributes"><code>lfs.attributes</code></a>
+ raises an error if attribute does not exist</li>
+ </ul>
+ </dd>
+
+ <dt><strong><a href="http://www.keplerproject.org/luafilesystem/1.3/">Version 1.3.0</a></strong> [26/Oct/2007]</dt>
+ <dd>
+ <ul>
+ <li>added function
+ <a href="manual.html#symlinkattributes"><code>lfs.symlinkattributes</code></a>
+ (works only in non Windows systems).</li>
+ </ul>
+ </dd>
+
+ <dt><strong><a href="http://www.keplerproject.org/luafilesystem/1.2/">Version 1.2.1</a></strong> [08/May/2007]</dt>
+ <dd>
+ <ul>
+ <li>compatible only with Lua 5.1 (Lua 5.0 support was dropped)</li>
+ </ul>
+ </dd>
+
+ <dt><strong><a href="http://www.keplerproject.org/luafilesystem/1.2/">Version 1.2</a></strong> [15/Mar/2006]</dt>
+ <dd>
+ <ul>
+ <li>added optional argument to
+ <a href="manual.html#attributes"><code>lfs.attributes</code></a></li>
+ <li>added function
+ <a href="manual.html#rmdir"><code>lfs.rmdir</code></a></li>
+ <li>bug correction on <a href="manual.html#dir"><code>lfs.dir</code></a></li>
+ </ul>
+ </dd>
+
+ <dt><strong><a href="http://www.keplerproject.org/luafilesystem/1.1/">Version 1.1</a></strong> [30/May/2005]</dt>
+ <dd>
+ <ul>
+ <li>added function <a href="manual.html#touch"><code>lfs.touch</code></a>.</li>
+ </ul>
+ </dd>
+
+ <dt><strong><a href="http://www.keplerproject.org/luafilesystem/1.0/">Version 1.0</a></strong> [21/Jan/2005]</dt>
+ <dd />
+
+ <dt><strong>Version 1.0 Beta</strong> [10/Nov/2004]</dt>
+ <dd />
+</dl>
+
+<h2><a name="credits"></a>Credits</h2>
+
+<p>LuaFileSystem was designed by Roberto Ierusalimschy,
+Andr&eacute; Carregal and Tom&aacute;s Guisasola as part of the
+<a href="http://www.keplerproject.org">Kepler Project</a>,
+which holds its copyright. LuaFileSystem is currently maintained by F&aacute;bio Mascarenhas.</p>
+
+<h2><a name="contact"></a>Contact us</h2>
+
+<p>For more information please
+<a href="mailto:info-NO-SPAM-THANKS@keplerproject.org">contact us</a>.
+Comments are welcome!</p>
+
+<p>You can also reach other Kepler developers and users on the Kepler Project
+<a href="http://luaforge.net/mail/?group_id=104">mailing list</a>.</p>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+ <p><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0!</a></p>
+ <p><small>$Id: index.html,v 1.44 2009/02/04 21:21:33 carregal Exp $</small></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" -->
+
+</body>
+</html>
diff --git a/lfw/rocks/luafilesystem/1.5.0-1/doc/us/license.html b/lfw/rocks/luafilesystem/1.5.0-1/doc/us/license.html
new file mode 100644
index 0000000..4ecad4b
--- /dev/null
+++ b/lfw/rocks/luafilesystem/1.5.0-1/doc/us/license.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>LuaFileSystem</title>
+ <link rel="stylesheet" href="http://www.keplerproject.org/doc.css" type="text/css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo">
+ <a href="http://www.keplerproject.org">
+ <img alt="LuaFileSystem" src="luafilesystem.png"/>
+ </a>
+ </div>
+ <div id="product_name"><big><strong>LuaFileSystem</strong></big></div>
+ <div id="product_description">File System Library for the Lua Programming Language</div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<h1>LuaFileSystem</h1>
+ <ul>
+ <li><a href="index.html">Home</a>
+ <ul>
+ <li><a href="index.html#overview">Overview</a></li>
+ <li><a href="index.html#status">Status</a></li>
+ <li><a href="index.html#download">Download</a></li>
+ <li><a href="index.html#history">History</a></li>
+ <li><a href="index.html#credits">Credits</a></li>
+ <li><a href="index.html#contact">Contact us</a></li>
+ </ul>
+ </li>
+ <li><a href="manual.html">Manual</a>
+ <ul>
+ <li><a href="manual.html#introduction">Introduction</a></li>
+ <li><a href="manual.html#building">Building</a></li>
+ <li><a href="manual.html#installation">Installation</a></li>
+ <li><a href="manual.html#reference">Reference</a></li>
+ </ul>
+ </li>
+ <li><a href="examples.html">Examples</a></li>
+ <li><a href="http://luaforge.net/projects/luafilesystem/">Project</a>
+ <ul>
+ <li><a href="http://luaforge.net/tracker/?group_id=66">Bug Tracker</a></li>
+ <li><a href="http://luaforge.net/scm/?group_id=66">CVS</a></li>
+ </ul>
+ </li>
+ <li><strong>License</strong></li>
+ </ul>
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h1>License</h1>
+
+<p>
+LuaFileSystem is free software: it can be used for both academic
+and commercial purposes at absolutely no cost. There are no
+royalties or GNU-like "copyleft" restrictions. LuaFileSystem
+qualifies as
+<a href="http://www.opensource.org/docs/definition.html">Open Source</a>
+software.
+Its licenses are compatible with
+<a href="http://www.gnu.org/licenses/gpl.html">GPL</a>.
+LuaFileSystem is not in the public domain and the
+<a href="http://www.keplerproject.org">Kepler Project</a>
+keep its copyright.
+The legal details are below.
+</p>
+
+<p>The spirit of the license is that you are free to use
+LuaFileSystem for any purpose at no cost without having to ask us.
+The only requirement is that if you do use LuaFileSystem, then you
+should give us credit by including the appropriate copyright notice
+somewhere in your product or its documentation.</p>
+
+<p>The LuaFileSystem library is designed and implemented by Roberto
+Ierusalimschy, Andr&eacute; Carregal and Tom&aacute;s Guisasola.
+The implementation is not derived from licensed software.</p>
+
+<hr/>
+<p>Copyright &copy; 2003 Kepler Project.</p>
+
+<p>Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:</p>
+
+<p>The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.</p>
+
+<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.</p>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+ <p><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0!</a></p>
+ <p><small>$Id: license.html,v 1.13 2008/02/11 22:42:21 carregal Exp $</small></p>
+</div><!-- id="about" -->
+
+</div><!-- id="container" -->
+
+</body>
+</html>
diff --git a/lfw/rocks/luafilesystem/1.5.0-1/doc/us/luafilesystem.png b/lfw/rocks/luafilesystem/1.5.0-1/doc/us/luafilesystem.png
new file mode 100644
index 0000000..e1dd8c6
--- /dev/null
+++ b/lfw/rocks/luafilesystem/1.5.0-1/doc/us/luafilesystem.png
Binary files differ
diff --git a/lfw/rocks/luafilesystem/1.5.0-1/doc/us/manual.html b/lfw/rocks/luafilesystem/1.5.0-1/doc/us/manual.html
new file mode 100644
index 0000000..1409c40
--- /dev/null
+++ b/lfw/rocks/luafilesystem/1.5.0-1/doc/us/manual.html
@@ -0,0 +1,271 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>LuaFileSystem</title>
+ <link rel="stylesheet" href="http://www.keplerproject.org/doc.css" type="text/css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo">
+ <a href="http://www.keplerproject.org"><img alt="LuaFileSystem" src="luafilesystem.png"/></a>
+ </div>
+ <div id="product_name"><big><strong>LuaFileSystem</strong></big></div>
+ <div id="product_description">File System Library for the Lua Programming Language</div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<h1>LuaFileSystem</h1>
+ <ul>
+ <li><a href="index.html">Home</a>
+ <ul>
+ <li><a href="index.html#overview">Overview</a></li>
+ <li><a href="index.html#status">Status</a></li>
+ <li><a href="index.html#download">Download</a></li>
+ <li><a href="index.html#history">History</a></li>
+ <li><a href="index.html#credits">Credits</a></li>
+ <li><a href="index.html#contact">Contact us</a></li>
+ </ul>
+ </li>
+ <li><strong>Manual</strong>
+ <ul>
+ <li><a href="manual.html#introduction">Introduction</a></li>
+ <li><a href="manual.html#building">Building</a></li>
+ <li><a href="manual.html#installation">Installation</a></li>
+ <li><a href="manual.html#reference">Reference</a></li>
+ </ul>
+ </li>
+ <li><a href="examples.html">Examples</a></li>
+ <li><a href="http://luaforge.net/projects/luafilesystem/">Project</a>
+ <ul>
+ <li><a href="http://luaforge.net/tracker/?group_id=66">Bug Tracker</a></li>
+ <li><a href="http://luaforge.net/scm/?group_id=66">CVS</a></li>
+ </ul>
+ </li>
+ <li><a href="license.html">License</a></li>
+ </ul>
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h2><a name="introduction"></a>Introduction</h2>
+
+<p>LuaFileSystem is a <a href="http://www.lua.org">Lua</a> library
+developed to complement the set of functions related to file
+systems offered by the standard Lua distribution.</p>
+
+<p>LuaFileSystem offers a portable way to access
+the underlying directory structure and file attributes.</p>
+
+<h2><a name="building"></a>Building</h2>
+
+<p>
+LuaFileSystem should be built with Lua 5.1 so the language library
+and header files for the target version must be installed properly.
+</p>
+
+<p>
+LuaFileSystem offers a Makefile and a separate configuration file,
+<code>config</code>,
+which should be edited to suit your installation before running
+<code>make</code>.
+The file has some definitions like paths to the external libraries,
+compiler options and the like.
+</p>
+
+<p>On Windows, the C runtime used to compile LuaFileSystem must be the same
+runtime that Lua uses, or some LuaFileSystem functions will not work.</p>
+
+<h2><a name="installation"></a>Installation</h2>
+
+<p>The easiest way to install LuaFileSystem is to use LuaRocks:</p>
+
+<pre class="example">
+luarocks install luafilesystem
+</pre>
+
+<p>If you prefer to install LuaFileSystem manually, the compiled binary should be copied to a directory in your
+<a href="http://www.lua.org/manual/5.1/manual.html#pdf-package.cpath">C path</a>.</p>
+
+<h2><a name="reference"></a>Reference</h2>
+
+<p>
+LuaFileSystem offers the following functions:
+</p>
+
+<dl class="reference">
+ <dt><a name="attributes"></a><strong><code>lfs.attributes (filepath [, aname])</code></strong></dt>
+ <dd>Returns a table with the file attributes corresponding to
+ <code>filepath</code> (or <code>nil</code> followed by an error message
+ in case of error).
+ If the second optional argument is given, then only the value of the
+ named attribute is returned (this use is equivalent to
+ <code>lfs.attributes(filepath).aname</code>, but the table is not created
+ and only one attribute is retrieved from the O.S.).
+ The attributes are described as follows;
+ attribute <code>mode</code> is a string, all the others are numbers,
+ and the time related attributes use the same time reference of
+ <a href="http://www.lua.org/manual/5.1/manual.html#pdf-os.time"><code>os.time</code></a>:
+ <dl>
+ <dt><strong><code>dev</code></strong></dt>
+ <dd>on Unix systems, this represents the device that the inode resides on. On Windows systems,
+ represents the drive number of the disk containing the file</dd>
+
+ <dt><strong><code>ino</code></strong></dt>
+ <dd>on Unix systems, this represents the inode number. On Windows systems this has no meaning</dd>
+
+ <dt><strong><code>mode</code></strong></dt>
+ <dd>string representing the associated protection mode (the values could be
+ <code>file</code>, <code>directory</code>, <code>link</code>, <code>socket</code>,
+ <code>named pipe</code>, <code>char device</code>, <code>block device</code> or
+ <code>other</code>)</dd>
+
+ <dt><strong><code>nlink</code></strong></dt>
+ <dd>number of hard links to the file</dd>
+
+ <dt><strong><code>uid</code></strong></dt>
+ <dd>user-id of owner (Unix only, always 0 on Windows)</dd>
+
+ <dt><strong><code>gid</code></strong></dt>
+ <dd>group-id of owner (Unix only, always 0 on Windows)</dd>
+
+ <dt><strong><code>rdev</code></strong></dt>
+ <dd>on Unix systems, represents the device type, for special file inodes.
+ On Windows systems represents the same as <code>dev</code></dd>
+
+ <dt><strong><code>access</code></strong></dt>
+ <dd>time of last access</dd>
+
+ <dt><strong><code>modification</code></strong></dt>
+ <dd>time of last data modification</dd>
+
+ <dt><strong><code>change</code></strong></dt>
+ <dd>time of last file status change</dd>
+
+ <dt><strong><code>size</code></strong></dt>
+ <dd>file size, in bytes</dd>
+
+ <dt><strong><code>blocks</code></strong></dt>
+ <dd>block allocated for file; (Unix only)</dd>
+
+ <dt><strong><code>blksize</code></strong></dt>
+ <dd>optimal file system I/O blocksize; (Unix only)</dd>
+ </dl>
+ This function uses <code>stat</code> internally thus if the given
+ <code>filepath</code> is a symbolic link, it is followed (if it points to
+ another link the chain is followed recursively) and the information
+ is about the file it refers to.
+ To obtain information about the link itself, see function
+ <a href="#symlinkattributes">lfs.symlinkattributes</a>.
+ </dd>
+
+ <dt><a name="chdir"></a><strong><code>lfs.chdir (path)</code></strong></dt>
+ <dd>Changes the current working directory to the given
+ <code>path</code>.<br />
+ Returns <code>true</code> in case of success or <code>nil</code> plus an
+ error string.</dd>
+
+ <dt><a name="chdir"></a><strong><code>lfs.lock_dir(path, [seconds_stale])</code></strong></dt>
+ <dd>Creates a lockfile (called lockfile.lfs) in <code>path</code> if it does not
+ exist and returns the lock. If the lock already exists checks it
+ it's stale, using the second parameter (default for the second
+ parameter is <code>INT_MAX</code>, which in practice means the lock will never
+ be stale. To free the the lock call <code>lock:free()</code>. <br/>
+ In case of any errors it returns nil and the error message. In
+ particular, if the lock exists and is not stale it returns the
+ "File exists" message.</dd>
+
+ <dt><a name="getcwd"></a><strong><code>lfs.currentdir ()</code></strong></dt>
+ <dd>Returns a string with the current working directory or <code>nil</code>
+ plus an error string.</dd>
+
+ <dt><a name="dir"></a><strong><code>iter, dir_obj = lfs.dir (path)</code></strong></dt>
+ <dd>
+ Lua iterator over the entries of a given directory.
+ Each time the iterator is called with <code>dir_obj</code> it returns a directory entry's name as a string, or
+ <code>nil</code> if there are no more entries. You can also iterate by calling <code>dir_obj:next()</code>, and
+ explicitly close the directory before the iteration finished with <code>dir_obj:close()</code>.
+ Raises an error if <code>path</code> is not a directory.
+ </dd>
+
+ <dt><a name="lock"></a><strong><code>lfs.lock (filehandle, mode[, start[, length]])</code></strong></dt>
+ <dd>Locks a file or a part of it. This function works on <em>open files</em>; the
+ file handle should be specified as the first argument.
+ The string <code>mode</code> could be either
+ <code>r</code> (for a read/shared lock) or <code>w</code> (for a
+ write/exclusive lock). The optional arguments <code>start</code>
+ and <code>length</code> can be used to specify a starting point and
+ its length; both should be numbers.<br />
+ Returns <code>true</code> if the operation was successful; in
+ case of error, it returns <code>nil</code> plus an error string.
+ </dd>
+
+ <dt><a name="mkdir"></a><strong><code>lfs.mkdir (dirname)</code></strong></dt>
+ <dd>Creates a new directory. The argument is the name of the new
+ directory.<br />
+ Returns <code>true</code> if the operation was successful;
+ in case of error, it returns <code>nil</code> plus an error string.
+ </dd>
+
+ <dt><a name="rmdir"></a><strong><code>lfs.rmdir (dirname)</code></strong></dt>
+ <dd>Removes an existing directory. The argument is the name of the directory.<br />
+ Returns <code>true</code> if the operation was successful;
+ in case of error, it returns <code>nil</code> plus an error string.</dd>
+
+ <dt><a name="setmode"></a><strong><code>lfs.setmode (file, mode)</code></strong></dt>
+ <dd>Sets the writing mode for a file. The mode string can be either <code>binary</code> or <code>text</code>.
+ Returns the previous mode string for the file. This function is only available in Windows, so you may want to make sure that
+ <code>lfs.setmode</code> exists before using it.
+ </dd>
+
+ <dt><a name="symlinkattributes"></a><strong><code>lfs.symlinkattributes (filepath [, aname])</code></strong></dt>
+ <dd>Identical to <a href="#attributes">lfs.attributes</a> except that
+ it obtains information about the link itself (not the file it refers to).
+ This function is not available in Windows so you may want to make sure that
+ <code>lfs.symlinkattributes</code> exists before using it.
+ </dd>
+
+ <dt><a name="touch"></a><strong><code>lfs.touch (filepath [, atime [, mtime]])</code></strong></dt>
+ <dd>Set access and modification times of a file. This function is
+ a bind to <code>utime</code> function. The first argument is the
+ filename, the second argument (<code>atime</code>) is the access time,
+ and the third argument (<code>mtime</code>) is the modification time.
+ Both times are provided in seconds (which should be generated with
+ Lua standard function <code>os.time</code>).
+ If the modification time is omitted, the access time provided is used;
+ if both times are omitted, the current time is used.<br />
+ Returns <code>true</code> if the operation was successful;
+ in case of error, it returns <code>nil</code> plus an error string.
+ </dd>
+
+ <dt><a name="unlock"></a><strong><code>lfs.unlock (filehandle[, start[, length]])</code></strong></dt>
+ <dd>Unlocks a file or a part of it. This function works on
+ <em>open files</em>; the file handle should be specified as the first
+ argument. The optional arguments <code>start</code> and
+ <code>length</code> can be used to specify a starting point and its
+ length; both should be numbers.<br />
+ Returns <code>true</code> if the operation was successful;
+ in case of error, it returns <code>nil</code> plus an error string.
+ </dd>
+</dl>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+ <p><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0!</a></p>
+ <p><small>$Id: manual.html,v 1.45 2009/06/03 20:53:55 mascarenhas Exp $</small></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" -->
+
+</body>
+</html>
diff --git a/lfw/rocks/luafilesystem/1.5.0-1/luafilesystem-1.5.0-1.rockspec b/lfw/rocks/luafilesystem/1.5.0-1/luafilesystem-1.5.0-1.rockspec
new file mode 100644
index 0000000..1170ad2
--- /dev/null
+++ b/lfw/rocks/luafilesystem/1.5.0-1/luafilesystem-1.5.0-1.rockspec
@@ -0,0 +1,27 @@
+package = "LuaFileSystem"
+
+version = "1.5.0-1"
+
+source = {
+ url = "http://cloud.github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.5.0.tar.gz",
+}
+
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+
+dependencies = {
+ "lua >= 5.1"
+}
+
+build = {
+ type = "module",
+ modules = { lfs = "src/lfs.c" },
+ copy_directories = { "doc", "tests" }
+}
diff --git a/lfw/rocks/luafilesystem/1.5.0-1/rock_manifest b/lfw/rocks/luafilesystem/1.5.0-1/rock_manifest
new file mode 100644
index 0000000..f04415b
--- /dev/null
+++ b/lfw/rocks/luafilesystem/1.5.0-1/rock_manifest
@@ -0,0 +1,18 @@
+rock_manifest = {
+ doc={
+ us={
+ ['examples.html']='bc2c38e7bb14ee8a2c7dfde31d847589',
+ ['license.html']='d6b3b3fc89fc8e2632120161dbccb91c',
+ ['luafilesystem.png']='81e923e976e99f894ea0aa8b52baff29',
+ ['index.html']='3280eecd8a8213280ea6fc63aeca85d3',
+ ['manual.html']='4ce5fbcb073538cb5509c20e7fa4b13b'
+ }
+ },
+ ['luafilesystem-1.5.0-1.rockspec']='f24df0bf7653276bcff6e80c53b45cb0',
+ lib={
+ ['lfs.dll']='e0500be912db2d07f08b4c4de202046e'
+ },
+ tests={
+ ['test.lua']='ce1edc52d74c6d9a28aefb73c80c6f29'
+ }
+}
diff --git a/lfw/rocks/luafilesystem/1.5.0-1/tests/test.lua b/lfw/rocks/luafilesystem/1.5.0-1/tests/test.lua
new file mode 100644
index 0000000..7111074
--- /dev/null
+++ b/lfw/rocks/luafilesystem/1.5.0-1/tests/test.lua
@@ -0,0 +1,130 @@
+#!/usr/local/bin/lua5.1
+
+local tmp = "/tmp"
+local sep = "/"
+local upper = ".."
+
+require"lfs"
+print (lfs._VERSION)
+
+function attrdir (path)
+ for file in lfs.dir(path) do
+ if file ~= "." and file ~= ".." then
+ local f = path..sep..file
+ print ("\t=> "..f.." <=")
+ local attr = lfs.attributes (f)
+ assert (type(attr) == "table")
+ if attr.mode == "directory" then
+ attrdir (f)
+ else
+ for name, value in pairs(attr) do
+ print (name, value)
+ end
+ end
+ end
+ end
+end
+
+-- Checking changing directories
+local current = assert (lfs.currentdir())
+local reldir = string.gsub (current, "^.*%"..sep.."([^"..sep.."])$", "%1")
+assert (lfs.chdir (upper), "could not change to upper directory")
+assert (lfs.chdir (reldir), "could not change back to current directory")
+assert (lfs.currentdir() == current, "error trying to change directories")
+assert (lfs.chdir ("this couldn't be an actual directory") == nil, "could change to a non-existent directory")
+
+-- Changing creating and removing directories
+local tmpdir = current..sep.."lfs_tmp_dir"
+local tmpfile = tmpdir..sep.."tmp_file"
+-- Test for existence of a previous lfs_tmp_dir
+-- that may have resulted from an interrupted test execution and remove it
+if lfs.chdir (tmpdir) then
+ assert (lfs.chdir (upper), "could not change to upper directory")
+ assert (os.remove (tmpfile), "could not remove file from previous test")
+ assert (lfs.rmdir (tmpdir), "could not remove directory from previous test")
+end
+
+-- tries to create a directory
+assert (lfs.mkdir (tmpdir), "could not make a new directory")
+local attrib, errmsg = lfs.attributes (tmpdir)
+if not attrib then
+ error ("could not get attributes of file `"..tmpdir.."':\n"..errmsg)
+end
+local f = io.open(tmpfile, "w")
+f:close()
+
+-- Change access time
+local testdate = os.time({ year = 2007, day = 10, month = 2, hour=0})
+assert (lfs.touch (tmpfile, testdate))
+local new_att = assert (lfs.attributes (tmpfile))
+assert (new_att.access == testdate, "could not set access time")
+assert (new_att.modification == testdate, "could not set modification time")
+
+-- Change access and modification time
+local testdate1 = os.time({ year = 2007, day = 10, month = 2, hour=0})
+local testdate2 = os.time({ year = 2007, day = 11, month = 2, hour=0})
+
+assert (lfs.touch (tmpfile, testdate2, testdate1))
+local new_att = assert (lfs.attributes (tmpfile))
+assert (new_att.access == testdate2, "could not set access time")
+assert (new_att.modification == testdate1, "could not set modification time")
+
+local res, err = lfs.symlinkattributes(tmpfile)
+if err ~= "symlinkattributes not supported on this platform" then
+ -- Checking symbolic link information (does not work in Windows)
+ assert (os.execute ("ln -s "..tmpfile.." _a_link_for_test_"))
+ assert (lfs.attributes"_a_link_for_test_".mode == "file")
+ assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link")
+ assert (os.remove"_a_link_for_test_")
+end
+
+if lfs.setmode then
+ -- Checking text/binary modes (works only in Windows)
+ local f = io.open(tmpfile, "w")
+ local result, mode = lfs.setmode(f, "binary")
+ assert((result and mode == "text") or (not result and mode == "setmode not supported on this platform"))
+ result, mode = lfs.setmode(f, "text")
+ assert((result and mode == "binary") or (not result and mode == "setmode not supported on this platform"))
+ f:close()
+end
+
+-- Restore access time to current value
+assert (lfs.touch (tmpfile, attrib.access, attrib.modification))
+new_att = assert (lfs.attributes (tmpfile))
+assert (new_att.access == attrib.access)
+assert (new_att.modification == attrib.modification)
+
+-- Remove new file and directory
+assert (os.remove (tmpfile), "could not remove new file")
+assert (lfs.rmdir (tmpdir), "could not remove new directory")
+assert (lfs.mkdir (tmpdir..sep.."lfs_tmp_dir") == nil, "could create a directory inside a non-existent one")
+
+-- Trying to get attributes of a non-existent file
+assert (lfs.attributes ("this couldn't be an actual file") == nil, "could get attributes of a non-existent file")
+assert (type(lfs.attributes (upper)) == "table", "couldn't get attributes of upper directory")
+
+-- Stressing directory iterator
+count = 0
+for i = 1, 4000 do
+ for file in lfs.dir (tmp) do
+ count = count + 1
+ end
+end
+
+-- Stressing directory iterator, explicit version
+count = 0
+for i = 1, 4000 do
+ local iter, dir = lfs.dir(tmp)
+ local file = dir:next()
+ while file do
+ count = count + 1
+ file = dir:next()
+ end
+ assert(not pcall(dir.next, dir))
+end
+
+-- directory explicit close
+local iter, dir = lfs.dir(tmp)
+dir:close()
+assert(not pcall(dir.next, dir))
+print"Ok!"
diff --git a/lfw/rocks/luasocket/2.0.2-3/luasocket-2.0.2-3.rockspec b/lfw/rocks/luasocket/2.0.2-3/luasocket-2.0.2-3.rockspec
new file mode 100644
index 0000000..aa1fa91
--- /dev/null
+++ b/lfw/rocks/luasocket/2.0.2-3/luasocket-2.0.2-3.rockspec
@@ -0,0 +1,34 @@
+package = "LuaSocket"
+version = "2.0.2-3"
+source = {
+ url = "http://luaforge.net/frs/download.php/2664/luasocket-2.0.2.tar.gz",
+ md5 = "41445b138deb7bcfe97bff957503da8e"
+}
+description = {
+ summary = "Network support for the Lua language",
+ detailed = [[
+ LuaSocket is a Lua extension library that is composed by two parts: a C core
+ that provides support for the TCP and UDP transport layers, and a set of Lua
+ modules that add support for functionality commonly needed by applications
+ that deal with the Internet.
+ ]]
+}
+build = {
+ type = "make",
+ build_variables = {
+ CFLAGS = "$(CFLAGS) -DLUASOCKET_DEBUG -I$(LUA_INCDIR)",
+ LDFLAGS = "$(LIBFLAG) -O -fpic",
+ LD = "$(CC)"
+ },
+ install_variables = {
+ INSTALL_TOP_SHARE = "$(LUADIR)",
+ INSTALL_TOP_LIB = "$(LIBDIR)"
+ },
+ platforms = {
+ macosx = {
+ build_variables = {
+ CFLAGS = "$(CFLAGS) -DLUASOCKET_DEBUG -DUNIX_HAS_SUN_LEN -fno-common -I$(LUA_INCDIR)"
+ }
+ }
+ }
+}
diff --git a/lfw/rocks/luasocket/2.0.2-3/rock_manifest b/lfw/rocks/luasocket/2.0.2-3/rock_manifest
new file mode 100644
index 0000000..08776c0
--- /dev/null
+++ b/lfw/rocks/luasocket/2.0.2-3/rock_manifest
@@ -0,0 +1,23 @@
+rock_manifest = {
+ ['luasocket-2.0.2-3.rockspec']='eb546dbbd806881232d4164ac2121d1a',
+ lua={
+ ['ltn12.lua']='3dfc54ef5c4d74c9558b503ea5595d0d',
+ socket={
+ ['ftp.lua']='a8fbe980f396bccfdaa5671a981e60cd',
+ ['url.lua']='2bb6b15f77e9fcf4fc028435d41ad748',
+ ['http.lua']='811e12534358f97907079ec49db9d753',
+ ['smtp.lua']='1d32e3dc5060e7e2f67b59e8f8376c63',
+ ['tp.lua']='b98814d6a43aa13dd01f78f3b573f4f6'
+ },
+ ['mime.lua']='6042de20ee4cacb2089388f1038bb92b',
+ ['socket.lua']='f8d9f766ce71816a68c90bb12a29eed9'
+ },
+ lib={
+ socket={
+ ['core.dll']='58a9887fb51f92e707c80f9ce4196d5c'
+ },
+ mime={
+ ['core.dll']='05efb07488c0ba45f35230b0066422f4'
+ }
+ }
+}
diff --git a/lfw/rocks/luazip/1.2.3-2/luazip-1.2.3-2.rockspec b/lfw/rocks/luazip/1.2.3-2/luazip-1.2.3-2.rockspec
new file mode 100644
index 0000000..92a9987
--- /dev/null
+++ b/lfw/rocks/luazip/1.2.3-2/luazip-1.2.3-2.rockspec
@@ -0,0 +1,37 @@
+package = "LuaZip"
+version = "1.2.3-2"
+source = {
+ url = "http://luaforge.net/frs/download.php/2493/luazip-1.2.3.tar.gz"
+}
+description = {
+ summary = "Library for reading files inside zip files",
+ detailed = [[
+ LuaZip is a lightweight Lua extension library used to read files
+ stored inside zip files. The API is very similar to the standard
+ Lua I/O library API.
+ ]],
+ license = "MIT/X11",
+ homepage = "http://www.keplerproject.org/luaexpat/"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+external_dependencies = {
+ ZZIP = {
+ header = "zzip.h"
+ }
+}
+build = {
+ type = "make",
+ variables = {
+ LUA_VERSION_NUM="501",
+ },
+ build_variables = {
+ LIB_OPTION = "$(LIBFLAG) -L$(ZZIP_LIBDIR)",
+ CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR) -I$(ZZIP_INCDIR)",
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)",
+ LUA_DIR = "$(LUADIR)"
+ }
+}
diff --git a/lfw/rocks/luazip/1.2.3-2/rock_manifest b/lfw/rocks/luazip/1.2.3-2/rock_manifest
new file mode 100644
index 0000000..8b71eec
--- /dev/null
+++ b/lfw/rocks/luazip/1.2.3-2/rock_manifest
@@ -0,0 +1,6 @@
+rock_manifest = {
+ lib={
+ ['zip.dll']='2d450eb4b48a5d6fd8a7ce99f3e24e8e'
+ },
+ ['luazip-1.2.3-2.rockspec']='b0086cd00fa9693c0083199e9b57e717'
+}
diff --git a/lfw/rocks/manifest b/lfw/rocks/manifest
new file mode 100644
index 0000000..8f462a9
--- /dev/null
+++ b/lfw/rocks/manifest
@@ -0,0 +1,159 @@
+modules = {
+ ['socket.http']={
+ 'luasocket/2.0.2-3'
+ },
+ socket={
+ 'luasocket/2.0.2-3'
+ },
+ ['des56']={
+ 'md5/1.1.2-1'
+ },
+ ['md5.core']={
+ 'md5/1.1.2-1'
+ },
+ lfs={
+ 'luafilesystem/1.5.0-1'
+ },
+ ['md5']={
+ 'md5/1.1.2-1'
+ },
+ ['socket.ftp']={
+ 'luasocket/2.0.2-3'
+ },
+ ['socket.url']={
+ 'luasocket/2.0.2-3'
+ },
+ ['socket.smtp']={
+ 'luasocket/2.0.2-3'
+ },
+ ['mime.core']={
+ 'luasocket/2.0.2-3'
+ },
+ zip={
+ 'luazip/1.2.3-2'
+ },
+ ['ltn12']={
+ 'luasocket/2.0.2-3'
+ },
+ mime={
+ 'luasocket/2.0.2-3'
+ },
+ ['socket.tp']={
+ 'luasocket/2.0.2-3'
+ },
+ ['socket.core']={
+ 'luasocket/2.0.2-3'
+ }
+}
+commands = {}
+dependencies = {
+ luazip={
+ ['1.2.3-2']={
+ {
+ name='lua',
+ constraints={
+ {
+ op='>=',
+ version={
+ 5, 1, string='5.1'
+ }
+ }
+ }
+ }
+ }
+ },
+ luafilesystem={
+ ['1.5.0-1']={
+ {
+ name='lua',
+ constraints={
+ {
+ op='>=',
+ version={
+ 5, 1, string='5.1'
+ }
+ }
+ }
+ }
+ }
+ },
+ luasocket={
+ ['2.0.2-3']={}
+ },
+ ['md5']={
+ ['1.1.2-1']={
+ {
+ name='lua',
+ constraints={
+ {
+ op='>=',
+ version={
+ 5, 1, string='5.1'
+ }
+ }
+ }
+ }
+ }
+ }
+}
+repository = {
+ luafilesystem={
+ ['1.5.0-1']={
+ {
+ modules={
+ lfs='lfs.dll'
+ },
+ commands={},
+ dependencies={},
+ arch='installed'
+ }
+ }
+ },
+ luazip={
+ ['1.2.3-2']={
+ {
+ modules={
+ zip='zip.dll'
+ },
+ commands={},
+ dependencies={},
+ arch='installed'
+ }
+ }
+ },
+ luasocket={
+ ['2.0.2-3']={
+ {
+ modules={
+ ['socket.http']='socket/http.lua',
+ socket='socket.lua',
+ ['socket.url']='socket/url.lua',
+ ['socket.smtp']='socket/smtp.lua',
+ ['socket.ftp']='socket/ftp.lua',
+ ['socket.core']='socket/core.dll',
+ ['ltn12']='ltn12.lua',
+ mime='mime.lua',
+ ['mime.core']='mime/core.dll',
+ ['socket.tp']='socket/tp.lua'
+ },
+ commands={},
+ dependencies={},
+ arch='installed'
+ }
+ }
+ },
+ ['md5']={
+ ['1.1.2-1']={
+ {
+ modules={
+ ['md5.core']='md5/core.dll',
+ ['des56']='des56.dll',
+ ['md5']='md5.lua'
+ },
+ commands={},
+ dependencies={},
+ arch='installed'
+ }
+ }
+ }
+}
diff --git a/lfw/rocks/md5/1.1.2-1/md5-1.1.2-1.rockspec b/lfw/rocks/md5/1.1.2-1/md5-1.1.2-1.rockspec
new file mode 100644
index 0000000..6626701
--- /dev/null
+++ b/lfw/rocks/md5/1.1.2-1/md5-1.1.2-1.rockspec
@@ -0,0 +1,39 @@
+package = "MD5"
+version = "1.1.2-1"
+source = {
+ url = ""
+}
+description = {
+ summary = "Basic cryptographic library",
+ detailed = [[
+ MD5 offers basic cryptographic facilities for Lua 5.1:
+ a hash (digest) function, a pair crypt/decrypt based on MD5 and CFB,
+ and a pair crypt/decrypt based on DES with 56-bit keys.
+ ]],
+ license = "MIT/X11",
+ homepage = "http://www.keplerproject.org/md5/"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "make",
+ variables = {
+ LUA_VERSION_NUM="501",
+ },
+ build_variables = {
+ LIB_OPTION = "$(LIBFLAG)",
+ CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR)",
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)",
+ LUA_DIR = "$(LUADIR)"
+ },
+ platforms = {
+ win32 = {
+ build_variables = {
+ LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib"
+ }
+ }
+ }
+}
diff --git a/lfw/rocks/md5/1.1.2-1/rock_manifest b/lfw/rocks/md5/1.1.2-1/rock_manifest
new file mode 100644
index 0000000..120edb5
--- /dev/null
+++ b/lfw/rocks/md5/1.1.2-1/rock_manifest
@@ -0,0 +1,12 @@
+rock_manifest = {
+ ['md5-1.1.2-1.rockspec']='a3953425b9c63515ae647a874fc07f96',
+ lua={
+ ['md5.lua']='d4cd3727e9968f1cddbbe02d85288a9c'
+ },
+ lib={
+ ['des56.dll']='13ffbb58e4b1685d5d27b41840b88d43',
+ ['md5']={
+ ['core.dll']='b925346324ca57f32d8c42541f881119'
+ }
+ }
+}
diff --git a/makedist b/makedist
new file mode 100755
index 0000000..9b3308e
--- /dev/null
+++ b/makedist
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+if ! [ "$1" ]
+then
+ echo "usage: $0 <version>"
+ exit 1
+fi
+
+if ! [ -d ".git" ]
+then
+ echo "Should be run inside a git repo dir."
+ exit 1
+fi
+
+make clean || exit 1
+
+grep -q "\"$1\"" rockspec || {
+ echo
+ echo "Version in rockspec is incorrect. Please fix it."
+ exit 1
+}
+
+grep -q "program_version = \"$1\"" src/luarocks/cfg.lua || {
+ echo
+ echo "Version in src/luarocks/cfg.lua is incorrect. Please fix it."
+ exit 1
+}
+
+out="luarocks-$1"
+rm -rf "$out"
+mkdir "$out"
+rm -f "missing_ref"
+git ls-files | while read i
+do
+ if [ -f "$i" ]
+ then
+ dir=`dirname $i`
+ mkdir -p "$out/$dir"
+ cp "$i" "$out/$dir"
+ if echo "$i" | grep -v "/bin/" | grep -q "^src/"
+ then
+ grep -qw `basename "$i"` Makefile || {
+ echo "Missing ref in makefile: $i"
+ touch "missing_ref"
+ exit 1
+ }
+ fi
+ fi
+done
+if [ -e "missing_ref" ]
+then
+ rm -f "missing_ref"
+ exit 1
+fi
+
+rm -rf "release-unix" "release-windows" "$out.tar.gz" "$out-win32.zip"
+
+mkdir "release-unix"
+cp -a "$out" "release-unix"
+mkdir "release-windows"
+mv "$out" "release-windows/$out-win32"
+
+cd "release-unix/$out"
+rm -rf makedist install.bat COPYING.lua COPYING.7z win32 lfw
+cd ..
+tar czvpf ../"$out.tar.gz" "$out"
+cd ..
+rm -rf "release-unix"
+
+cd "release-windows/$out-win32"
+cp -va win32/* .
+rm -rf makedist Makefile configure lfw win32
+cd ..
+zip -r ../"$out-win32.zip" "$out-win32"
+cd ..
+rm -rf "release-windows"
diff --git a/rockspec b/rockspec
new file mode 100644
index 0000000..69f253b
--- /dev/null
+++ b/rockspec
@@ -0,0 +1,38 @@
+package = "LuaRocks"
+local VER = "2.1.0"
+local REV = "1"
+version = VER.."-"..REV
+
+description = {
+ summary = "A deployment and management system for Lua modules.",
+ detailed = [[
+ LuaRocks allows you to install Lua modules as self-contained
+ packages called "rocks", which also contain version dependency
+ information. This information is used both during installation,
+ 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.
+ ]],
+ license = "MIT/X11",
+ homepage = "http://www.luarocks.org",
+ maintainer = "Hisham Muhammad"
+}
+
+dependencies = {
+ "lua >= 5.1"
+}
+
+source = {
+ url = "http://luarocks.org/releases/luarocks-"..VER..".tar.gz",
+}
+
+build = {
+ type = "make",
+ install_target = "install_rock",
+ build_pass=false,
+ install_variables = {
+ BINDIR="$(BINDIR)",
+ LUADIR="$(LUADIR)"
+ }
+}
diff --git a/src/bin/luarocks b/src/bin/luarocks
new file mode 100755
index 0000000..b64051d
--- /dev/null
+++ b/src/bin/luarocks
@@ -0,0 +1,24 @@
+#!/usr/bin/env lua
+
+local command_line = require("luarocks.command_line")
+
+program_description = "LuaRocks main command-line interface"
+
+commands = {}
+commands.help = require("luarocks.help")
+commands.pack = require("luarocks.pack")
+commands.unpack = require("luarocks.unpack")
+commands.build = require("luarocks.build")
+commands.install = require("luarocks.install")
+commands.search = require("luarocks.search")
+commands.list = require("luarocks.list")
+commands.remove = require("luarocks.remove")
+commands.make = require("luarocks.make")
+commands.download = require("luarocks.download")
+commands.path = require("luarocks.path")
+commands.show = require("luarocks.show")
+commands.new_version = require("luarocks.new_version")
+commands.lint = require("luarocks.lint")
+commands.purge = require("luarocks.purge")
+
+command_line.run_command(...)
diff --git a/src/bin/luarocks-admin b/src/bin/luarocks-admin
new file mode 100755
index 0000000..4c5613c
--- /dev/null
+++ b/src/bin/luarocks-admin
@@ -0,0 +1,16 @@
+#!/usr/bin/env lua
+
+local command_line = require("luarocks.command_line")
+
+program_description = "LuaRocks repository administration interface"
+
+commands = {
+}
+
+commands.help = require("luarocks.help")
+commands.make_manifest = require("luarocks.make_manifest")
+commands.add = require("luarocks.add")
+commands.remove = require("luarocks.admin_remove")
+commands.refresh_cache = require("luarocks.refresh_cache")
+
+command_line.run_command(...)
diff --git a/src/luarocks/add.lua b/src/luarocks/add.lua
new file mode 100644
index 0000000..d7c293e
--- /dev/null
+++ b/src/luarocks/add.lua
@@ -0,0 +1,113 @@
+
+--- Module implementing the luarocks-admin "add" command.
+-- Adds a rock or rockspec to a rocks server.
+module("luarocks.add", package.seeall)
+
+local cfg = require("luarocks.cfg")
+local util = require("luarocks.util")
+local fetch = require("luarocks.fetch")
+local dir = require("luarocks.dir")
+local manif = require("luarocks.manif")
+local index = require("luarocks.index")
+local fs = require("luarocks.fs")
+local cache = require("luarocks.cache")
+
+help_summary = "Add a rock or rockspec to a rocks server."
+help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}"
+help = [[
+Arguments are local files, which may be rockspecs or rocks.
+The flag --server indicates which server to use.
+If not given, the default server set in the upload_server variable
+from the configuration file is used instead.
+The flag --no-refresh indicates the local cache should not be refreshed
+prior to generation of the updated manifest.
+]]
+
+local function add_files_to_server(refresh, rockfiles, server, upload_server)
+ assert(type(refresh) == "boolean" or not refresh)
+ assert(type(rockfiles) == "table")
+ assert(type(server) == "string")
+ assert(type(upload_server) == "table" or not upload_server)
+
+ local download_url, login_url = cache.get_server_urls(server, upload_server)
+ local at = fs.current_dir()
+ local refresh_fn = refresh and cache.refresh_local_cache or cache.split_server_url
+
+ local local_cache, protocol, server_path, user, password = refresh_fn(server, download_url, cfg.upload_user, cfg.upload_password)
+ if not local_cache then
+ return nil, protocol
+ end
+ if protocol == "file" then
+ return nil, "Server "..server.." is not recognized, check your configuration."
+ end
+
+ if not login_url then
+ login_url = protocol.."://"..server_path
+ end
+
+ fs.change_dir(at)
+
+ local files = {}
+ for i, rockfile in ipairs(rockfiles) do
+ if fs.exists(rockfile) then
+ util.printout("Copying file "..rockfile.." to "..local_cache.."...")
+ local absolute = fs.absolute_name(rockfile)
+ fs.copy(absolute, local_cache)
+ table.insert(files, dir.base_name(absolute))
+ else
+ util.printerr("File "..rockfile.." not found")
+ end
+ end
+ if #files == 0 then
+ return nil, "No files found"
+ end
+
+ fs.change_dir(local_cache)
+
+ util.printout("Updating manifest...")
+ manif.make_manifest(local_cache, "one", true)
+ util.printout("Updating index.html...")
+ index.make_index(local_cache)
+
+ local login_info = ""
+ if user then login_info = " -u "..user end
+ if password then login_info = login_info..":"..password end
+ if not login_url:match("/$") then
+ login_url = login_url .. "/"
+ end
+
+ table.insert(files, "index.html")
+ table.insert(files, "manifest")
+ table.insert(files, "manifest-5.1")
+ table.insert(files, "manifest-5.2")
+
+ -- TODO abstract away explicit 'curl' call
+
+ local cmd
+ if protocol == "rsync" then
+ local srv, path = server_path:match("([^/]+)(/.+)")
+ cmd = cfg.variables.RSYNC.." --exclude=.git -Oavz -e ssh "..local_cache.."/ "..user.."@"..srv..":"..path.."/"
+ elseif upload_server and upload_server.sftp then
+ local part1, part2 = upload_server.sftp:match("^([^/]*)/(.*)$")
+ cmd = cfg.variables.SCP.." "..table.concat(files, " ").." "..user.."@"..part1..":/"..part2
+ else
+ cmd = cfg.variables.CURL.." "..login_info.." -T '{"..table.concat(files, ",").."}' "..login_url
+ end
+
+ util.printout(cmd)
+ fs.execute(cmd)
+
+ return true
+end
+
+function run(...)
+ local files = { util.parse_flags(...) }
+ local flags = table.remove(files, 1)
+ if #files < 1 then
+ return nil, "Argument missing. "..util.see_help("add", "luarocks-admin")
+ end
+ local server, server_table = cache.get_upload_server(flags["server"])
+ if not server then return nil, server_table end
+ return add_files_to_server(not flags["no-refresh"], files, server, server_table)
+end
+
diff --git a/src/luarocks/admin_remove.lua b/src/luarocks/admin_remove.lua
new file mode 100644
index 0000000..83b57fc
--- /dev/null
+++ b/src/luarocks/admin_remove.lua
@@ -0,0 +1,87 @@
+
+--- Module implementing the luarocks-admin "remove" command.
+-- Removes a rock or rockspec from a rocks server.
+module("luarocks.admin_remove", package.seeall)
+
+local cfg = require("luarocks.cfg")
+local util = require("luarocks.util")
+local fetch = require("luarocks.fetch")
+local dir = require("luarocks.dir")
+local manif = require("luarocks.manif")
+local index = require("luarocks.index")
+local fs = require("luarocks.fs")
+local cache = require("luarocks.cache")
+
+help_summary = "Remove a rock or rockspec from a rocks server."
+help_arguments = "[--from=<server>] [--no-refresh] {<rockspec>|<rock>...}"
+help = [[
+Arguments are local files, which may be rockspecs or rocks.
+The flag --from indicates which server to use.
+If not given, the default server set in the upload_server variable
+from the configuration file is used instead.
+The flag --no-refresh indicates the local cache should not be refreshed
+prior to generation of the updated manifest.
+]]
+
+local function remove_files_from_server(refresh, rockfiles, server, upload_server)
+ assert(type(refresh) == "boolean" or not refresh)
+ assert(type(rockfiles) == "table")
+ assert(type(server) == "string")
+ assert(type(upload_server) == "table" or not upload_server)
+
+ local download_url, login_url = cache.get_server_urls(server, upload_server)
+ local at = fs.current_dir()
+ local refresh_fn = refresh and cache.refresh_local_cache or cache.split_server_url
+
+ local local_cache, protocol, server_path, user, password = refresh_fn(server, download_url, cfg.upload_user, cfg.upload_password)
+ if not local_cache then
+ return nil, protocol
+ end
+ if protocol ~= "rsync" then
+ return nil, "This command requires 'rsync', check your configuration."
+ end
+
+ fs.change_dir(at)
+
+ local nr_files = 0
+ for i, rockfile in ipairs(rockfiles) do
+ local basename = dir.base_name(rockfile)
+ local file = dir.path(local_cache, basename)
+ util.printout("Removing file "..file.."...")
+ if fs.delete(file) then
+ nr_files = nr_files + 1
+ else
+ util.printerr("Failed removing "..file)
+ end
+ end
+ if nr_files == 0 then
+ return nil, "No files removed."
+ end
+
+ fs.change_dir(local_cache)
+
+ util.printout("Updating manifest...")
+ manif.make_manifest(local_cache, "one", true)
+ util.printout("Updating index.html...")
+ index.make_index(local_cache)
+
+ local srv, path = server_path:match("([^/]+)(/.+)")
+ local cmd = "rsync -Oavz --delete -e ssh "..local_cache.."/ "..user.."@"..srv..":"..path.."/"
+
+ util.printout(cmd)
+ fs.execute(cmd)
+
+ return true
+end
+
+function run(...)
+ local files = { util.parse_flags(...) }
+ local flags = table.remove(files, 1)
+ if #files < 1 then
+ return nil, "Argument missing. "..util.see_help("remove", "luarocks-admin")
+ end
+ local server, server_table = cache.get_upload_server(flags["server"])
+ if not server then return nil, server_table end
+ return remove_files_from_server(not flags["no-refresh"], files, server, server_table)
+end
+
diff --git a/src/luarocks/build.lua b/src/luarocks/build.lua
new file mode 100644
index 0000000..dbe450a
--- /dev/null
+++ b/src/luarocks/build.lua
@@ -0,0 +1,355 @@
+
+--- Module implementing the LuaRocks "build" command.
+-- Builds a rock, compiling its C parts if any.
+module("luarocks.build", package.seeall)
+
+local pack = require("luarocks.pack")
+local path = require("luarocks.path")
+local util = require("luarocks.util")
+local repos = require("luarocks.repos")
+local fetch = require("luarocks.fetch")
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local deps = require("luarocks.deps")
+local manif = require("luarocks.manif")
+local search = require("luarocks.search")
+local remove = require("luarocks.remove")
+local cfg = require("luarocks.cfg")
+
+help_summary = "Build/compile a rock."
+help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}"
+help = [[
+Build and install a rock, compiling its C parts if any.
+Argument may be a rockspec file, a source rock file
+or the name of a rock to be fetched from a repository.
+
+--pack-binary-rock Do not install rock. Instead, produce a .rock file
+ with the contents of compilation in the current
+ directory.
+
+--keep Do not remove previously installed versions of the
+ rock after building a new one. This behavior can
+ be made permanent by setting keep_other_versions=true
+ in the configuration file.
+]]
+
+--- Install files to a given location.
+-- Takes a table where the array part is a list of filenames to be copied.
+-- In the hash part, other keys, if is_module_path is set, are identifiers
+-- in Lua module format, to indicate which subdirectory the file should be
+-- copied to. For example, install_files({["foo.bar"] = "src/bar.lua"}, "boo")
+-- will copy src/bar.lua to boo/foo.
+-- @param files table or nil: A table containing a list of files to copy in
+-- the format described above. If nil is passed, this function is a no-op.
+-- Directories should be delimited by forward slashes as in internet URLs.
+-- @param location string: The base directory files should be copied to.
+-- @param is_module_path boolean: True if string keys in files should be
+-- interpreted as dotted module paths.
+-- @return boolean or (nil, string): True if succeeded or
+-- nil and an error message.
+local function install_files(files, location, is_module_path)
+ assert(type(files) == "table" or not files)
+ assert(type(location) == "string")
+ if files then
+ for k, file in pairs(files) do
+ local dest = location
+ if type(k) == "string" then
+ if is_module_path then
+ dest = dir.path(location, path.module_to_path(k))
+ fs.make_dir(dest)
+ else
+ dest = dir.path(location, dir.dir_name(k))
+ fs.make_dir(dest)
+ dest = dir.path(dest, dir.base_name(k))
+ end
+ else
+ fs.make_dir(dest)
+ end
+ local ok = fs.copy(dir.path(file), dest)
+ if not ok then
+ return nil, "Failed copying "..file
+ end
+ end
+ end
+ return true
+end
+
+--- Write to the current directory the contents of a table,
+-- where each key is a file name and its value is the file content.
+-- @param files table: The table of files to be written.
+local function extract_from_rockspec(files)
+ for name, content in pairs(files) do
+ local fd = io.open(dir.path(fs.current_dir(), name), "w+")
+ fd:write(content)
+ fd:close()
+ end
+end
+
+--- Applies patches inlined in the build.patches section
+-- and extracts files inlined in the build.extra_files section
+-- of a rockspec.
+-- @param rockspec table: A rockspec table.
+-- @return boolean or (nil, string): True if succeeded or
+-- nil and an error message.
+function apply_patches(rockspec)
+ assert(type(rockspec) == "table")
+
+ local build = rockspec.build
+ if build.extra_files then
+ extract_from_rockspec(build.extra_files)
+ end
+ if build.patches then
+ extract_from_rockspec(build.patches)
+ for patch, patchdata in util.sortedpairs(build.patches) do
+ util.printout("Applying patch "..patch.."...")
+ local ok, err = fs.apply_patch(tostring(patch), patchdata)
+ if not ok then
+ return nil, "Failed applying patch "..patch
+ end
+ end
+ end
+ return true
+end
+
+--- Build and install a rock given a rockspec.
+-- @param rockspec_file string: local or remote filename of a rockspec.
+-- @param need_to_fetch boolean: true if sources need to be fetched,
+-- false if the rockspec was obtained from inside a source rock.
+-- @param minimal_mode boolean: true if there's no need to fetch,
+-- unpack or change dir (this is used by "luarocks make"). Implies
+-- need_to_fetch = false.
+-- @param deps_mode string: Dependency mode: "one" for the current default tree,
+-- "all" for all trees, "order" for all trees with priority >= the current default,
+-- "none" for no trees.
+-- @return (string, string) or (nil, string, [string]): Name and version of
+-- installed rock if succeeded or nil and an error message followed by an error code.
+function build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_mode)
+ assert(type(rockspec_file) == "string")
+ assert(type(need_to_fetch) == "boolean")
+
+ local rockspec, err, errcode = fetch.load_rockspec(rockspec_file)
+ if err then
+ return nil, err, errcode
+ elseif not rockspec.build then
+ return nil, "Rockspec error: build table not specified"
+ elseif not rockspec.build.type then
+ return nil, "Rockspec error: build type not specified"
+ end
+
+ if deps_mode == "none" then
+ util.printerr("Warning: skipping dependency checks.")
+ else
+ local ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode)
+ if err then
+ return nil, err, errcode
+ end
+ end
+
+ ok, err, errcode = deps.check_external_deps(rockspec, "build")
+ if err then
+ return nil, err, errcode
+ end
+
+ local name, version = rockspec.name, rockspec.version
+ if repos.is_installed(name, version) then
+ repos.delete_version(name, version)
+ end
+
+ if not minimal_mode then
+ local _, source_dir
+ if need_to_fetch then
+ ok, source_dir, errcode = fetch.fetch_sources(rockspec, true)
+ if not ok then
+ return nil, source_dir, errcode
+ end
+ fs.change_dir(source_dir)
+ elseif rockspec.source.file then
+ local ok, err = fs.unpack_archive(rockspec.source.file)
+ if not ok then
+ return nil, err
+ end
+ end
+ fs.change_dir(rockspec.source.dir)
+ end
+
+ local dirs = {
+ lua = { name = path.lua_dir(name, version), is_module_path = true },
+ lib = { name = path.lib_dir(name, version), is_module_path = true },
+ conf = { name = path.conf_dir(name, version), is_module_path = false },
+ bin = { name = path.bin_dir(name, version), is_module_path = false },
+ }
+
+ for _, d in pairs(dirs) do
+ fs.make_dir(d.name)
+ end
+ local rollback = util.schedule_function(function()
+ fs.delete(path.install_dir(name, version))
+ fs.remove_dir_if_empty(path.versions_dir(name))
+ end)
+
+ local build = rockspec.build
+
+ if not minimal_mode then
+ ok, err = apply_patches(rockspec)
+ if err then
+ return nil, err
+ end
+ end
+
+ if build.type ~= "none" then
+
+ -- Temporary compatibility
+ if build.type == "module" then
+ util.printout("Do not use 'module' as a build type. Use 'builtin' instead.")
+ build.type = "builtin"
+ end
+
+ if cfg.accepted_build_types and util.array_contains(cfg.accepted_build_types, build.type) then
+ return nil, "This rockspec uses the '"..build.type.."' build type, which is blocked by the 'accepted_build_types' setting in your LuaRocks configuration."
+ end
+
+ local build_type
+ ok, build_type = pcall(require, "luarocks.build." .. build.type)
+ if not ok or not type(build_type) == "table" then
+ return nil, "Failed initializing build back-end for build type '"..build.type.."': "..build_type
+ end
+
+ ok, err = build_type.run(rockspec)
+ if not ok then
+ return nil, "Build error: " .. err
+ end
+ end
+
+ if build.install then
+ for id, install_dir in pairs(dirs) do
+ ok, err = install_files(build.install[id], install_dir.name, install_dir.is_module_path)
+ if not ok then
+ return nil, err
+ end
+ end
+ end
+
+ local copy_directories = build.copy_directories or {"doc"}
+
+ for _, copy_dir in pairs(copy_directories) do
+ if fs.is_dir(copy_dir) then
+ local dest = dir.path(path.install_dir(name, version), copy_dir)
+ fs.make_dir(dest)
+ fs.copy_contents(copy_dir, dest)
+ else
+ util.warning("Directory '"..copy_dir.."' not found")
+ end
+ end
+
+ for _, d in pairs(dirs) do
+ fs.remove_dir_if_empty(d.name)
+ end
+
+ fs.pop_dir()
+
+ fs.copy(rockspec.local_filename, path.rockspec_file(name, version))
+ if need_to_fetch then
+ fs.pop_dir()
+ end
+
+ ok, err = manif.make_rock_manifest(name, version)
+ if err then return nil, err end
+
+ ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec))
+ if err then return nil, err end
+
+ util.remove_scheduled_function(rollback)
+ rollback = util.schedule_function(function()
+ repos.delete_version(name, version)
+ end)
+
+ ok, err = repos.run_hook(rockspec, "post_install")
+ if err then return nil, err end
+
+ ok, err = manif.update_manifest(name, version, nil, deps_mode)
+ if err then return nil, err end
+
+ local license = ""
+ if rockspec.description and rockspec.description.license then
+ license = ("(license: "..rockspec.description.license..")")
+ end
+
+ local root_dir = path.root_dir(cfg.rocks_dir)
+ util.printout()
+ util.printout(name.." "..version.." is now built and installed in "..root_dir.." "..license)
+
+ util.remove_scheduled_function(rollback)
+ return name, version
+end
+
+--- Build and install a rock.
+-- @param rock_file string: local or remote filename of a rock.
+-- @param need_to_fetch boolean: true if sources need to be fetched,
+-- false if the rockspec was obtained from inside a source rock.
+-- @param deps_mode: string: Which trees to check dependencies for:
+-- "one" for the current default tree, "all" for all trees,
+-- "order" for all trees with priority >= the current default, "none" for no trees.
+-- @return boolean or (nil, string, [string]): True if build was successful,
+-- or false and an error message and an optional error code.
+function build_rock(rock_file, need_to_fetch, deps_mode)
+ assert(type(rock_file) == "string")
+ assert(type(need_to_fetch) == "boolean")
+
+ local unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_file)
+ if not unpack_dir then
+ return nil, err, errcode
+ end
+ local rockspec_file = path.rockspec_name_from_rock(rock_file)
+ fs.change_dir(unpack_dir)
+ local ok, err, errcode = build_rockspec(rockspec_file, need_to_fetch, false, deps_mode)
+ fs.pop_dir()
+ return ok, err, errcode
+end
+
+local function do_build(name, version, deps_mode)
+ if name:match("%.rockspec$") then
+ return build_rockspec(name, true, false, deps_mode)
+ elseif name:match("%.src%.rock$") then
+ return build_rock(name, false, deps_mode)
+ elseif name:match("%.all%.rock$") then
+ local install = require("luarocks.install")
+ return install.install_binary_rock(name, deps_mode)
+ elseif name:match("%.rock$") then
+ return build_rock(name, true, deps_mode)
+ elseif not name:match(dir.separator) then
+ local search = require("luarocks.search")
+ return search.act_on_src_or_rockspec(run, name:lower(), version, deps.deps_mode_to_flag(deps_mode))
+ end
+ return nil, "Don't know what to do with "..name
+end
+
+--- Driver function for "build" command.
+-- @param name string: A local or remote rockspec or rock file.
+-- If a package name is given, forwards the request to "search" and,
+-- if returned a result, installs the matching rock.
+-- @param version string: When passing a package name, a version number may
+-- also be given.
+-- @return boolean or (nil, string): True if build was successful; nil and an
+-- error message otherwise.
+function run(...)
+ local flags, name, version = util.parse_flags(...)
+ if type(name) ~= "string" then
+ return nil, "Argument missing. "..util.see_help("build")
+ end
+ assert(type(version) == "string" or not version)
+
+ if flags["pack-binary-rock"] then
+ return pack.pack_binary_rock(name, version, do_build, name, version, deps.get_deps_mode(flags))
+ else
+ local ok, err = fs.check_command_permissions(flags)
+ if not ok then return nil, err end
+ ok, err = do_build(name, version, deps.get_deps_mode(flags))
+ if not ok then return nil, err end
+ local name, version = ok, err
+ if (not flags["keep"]) and not cfg.keep_other_versions then
+ local ok, err = remove.remove_other_versions(name, version, flags["force"])
+ if not ok then util.printerr(err) end
+ end
+ return name, version
+ end
+end
diff --git a/src/luarocks/build/builtin.lua b/src/luarocks/build/builtin.lua
new file mode 100644
index 0000000..9d97d58
--- /dev/null
+++ b/src/luarocks/build/builtin.lua
@@ -0,0 +1,251 @@
+
+--- A builtin build system: back-end to provide a portable way of building C-based Lua modules.
+module("luarocks.build.builtin", package.seeall)
+
+local fs = require("luarocks.fs")
+local path = require("luarocks.path")
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+local dir = require("luarocks.dir")
+
+--- Run a command displaying its execution on standard output.
+-- @return boolean: true if command succeeds (status code 0), false
+-- otherwise.
+local function execute(...)
+ io.stdout:write(table.concat({...}, " ").."\n")
+ return fs.execute(...)
+end
+
+--- Makes an RC file with an embedded Lua script, for building .exes on Windows
+-- @return nil if could open files, error otherwise
+local function make_rc(luafilename, rcfilename)
+ local rcfile = io.open(rcfilename, "w")
+ if not rcfile then
+ error("Could not open "..rcfilename.." for writing.")
+ end
+ rcfile:write("STRINGTABLE\r\nBEGIN\r\n")
+
+ local i = 1
+ for line in io.lines(luafilename) do
+ if not line:match("^#!") then
+ rcfile:write(i .. " \"")
+ line = line:gsub("\\", "\\\\"):gsub('"', '""'):gsub("[\r\n]+", "")
+ rcfile:write(line .. "\\r\\n\"\r\n")
+ i = i + 1
+ end
+ end
+
+ rcfile:write("END\r\n")
+
+ rcfile:close()
+end
+
+--- Driver function for the builtin build back-end.
+-- @param rockspec table: the loaded rockspec.
+-- @return boolean or (nil, string): true if no errors ocurred,
+-- nil and an error message otherwise.
+function run(rockspec)
+ assert(type(rockspec) == "table")
+ local compile_object, compile_library, compile_wrapper_binary
+
+ local build = rockspec.build
+ local variables = rockspec.variables
+
+ local function add_flags(extras, flag, flags)
+ if flags then
+ if type(flags) ~= "table" then
+ flags = { tostring(flags) }
+ end
+ util.variable_substitutions(flags, variables)
+ for _, v in ipairs(flags) do
+ table.insert(extras, flag:format(v))
+ end
+ end
+ end
+
+ if cfg.is_platform("mingw32") then
+ compile_object = function(object, source, defines, incdirs)
+ local extras = {}
+ add_flags(extras, "-D%s", defines)
+ 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, 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))
+ return ok
+ end
+ compile_wrapper_binary = function(fullname, name)
+ local fullbasename = fullname:gsub("%.lua$", ""):gsub("/", "\\")
+ local basename = name:gsub("%.lua$", ""):gsub("/", "\\")
+ local rcname = basename..".rc"
+ local resname = basename..".o"
+ local wrapname = basename..".exe"
+ make_rc(fullname, fullbasename..".rc")
+ local ok = execute(variables.RC, "-o", resname, rcname)
+ if not ok then return ok end
+ ok = execute(variables.CC.." "..variables.CFLAGS, "-I"..variables.LUA_INCDIR,
+ "-o", wrapname, resname, variables.WRAPPER,
+ dir.path(variables.LUA_LIBDIR, variables.LUALIB),
+ "-l" .. (variables.MSVCRT or "m"), "-luser32")
+ return ok, wrapname
+ end
+ elseif cfg.is_platform("win32") then
+ compile_object = function(object, source, defines, incdirs)
+ local extras = {}
+ add_flags(extras, "-D%s", defines)
+ add_flags(extras, "-I%s", incdirs)
+ return execute(variables.CC.." "..variables.CFLAGS, "-c", "-Fo"..object, "-I"..variables.LUA_INCDIR, source, unpack(extras))
+ end
+ compile_library = function(library, objects, libraries, libdirs, name)
+ local extras = { unpack(objects) }
+ add_flags(extras, "-libpath:%s", libdirs)
+ add_flags(extras, "%s.lib", libraries)
+ local basename = dir.base_name(library):gsub(".[^.]*$", "")
+ local deffile = basename .. ".def"
+ local def = io.open(dir.path(fs.current_dir(), deffile), "w+")
+ def:write("EXPORTS\n")
+ def:write("luaopen_"..name:gsub("%.", "_").."\n")
+ def:close()
+ local ok = execute(variables.LD, "-dll", "-def:"..deffile, "-out:"..library, dir.path(variables.LUA_LIBDIR, variables.LUALIB), unpack(extras))
+ local manifestfile = basename..".dll.manifest"
+ if ok and fs.exists(manifestfile) then
+ ok = execute(variables.MT, "-manifest", manifestfile, "-outputresource:"..basename..".dll;2")
+ end
+ return ok
+ end
+ compile_wrapper_binary = function(fullname, name)
+ local fullbasename = fullname:gsub("%.lua$", ""):gsub("/", "\\")
+ local basename = name:gsub("%.lua$", ""):gsub("/", "\\")
+ local object = basename..".obj"
+ local rcname = basename..".rc"
+ local resname = basename..".res"
+ local wrapname = basename..".exe"
+ make_rc(fullname, fullbasename..".rc")
+ local ok = execute(variables.RC, "-r", "-fo"..resname, rcname)
+ if not ok then return ok end
+ ok = execute(variables.CC.." "..variables.CFLAGS, "-c", "-Fo"..object,
+ "-I"..variables.LUA_INCDIR, variables.WRAPPER)
+ if not ok then return ok end
+ ok = execute(variables.LD, "-out:"..wrapname, resname, object,
+ dir.path(variables.LUA_LIBDIR, variables.LUALIB), "user32.lib")
+ local manifestfile = wrapname..".manifest"
+ if ok and fs.exists(manifestfile) then
+ ok = execute(variables.MT, "-manifest", manifestfile, "-outputresource:"..wrapname..";1")
+ end
+ return ok, wrapname
+ end
+ else
+ compile_object = function(object, source, defines, incdirs)
+ local extras = {}
+ add_flags(extras, "-D%s", defines)
+ add_flags(extras, "-I%s", incdirs)
+ return execute(variables.CC.." "..variables.CFLAGS, "-I"..variables.LUA_INCDIR, "-c", source, "-o", object, unpack(extras))
+ end
+ compile_library = function (library, objects, libraries, libdirs)
+ local extras = { unpack(objects) }
+ add_flags(extras, "-L%s", libdirs)
+ if cfg.gcc_rpath then
+ add_flags(extras, "-Wl,-rpath,%s:", libdirs)
+ end
+ add_flags(extras, "-l%s", libraries)
+ if cfg.is_platform("cygwin") then
+ add_flags(extras, "-l%s", {"lua"})
+ end
+ return execute(variables.LD.." "..variables.LIBFLAG, "-o", library, "-L"..variables.LUA_LIBDIR, unpack(extras))
+ end
+ compile_wrapper_binary = function(fullname, name) return true, name end
+ end
+
+ local ok = true
+ local err = "Build error"
+ local built_modules = {}
+ local luadir = path.lua_dir(rockspec.name, rockspec.version)
+ local libdir = path.lib_dir(rockspec.name, rockspec.version)
+ local docdir = path.doc_dir(rockspec.name, rockspec.version)
+ -- On Windows, compiles an .exe for each Lua file in build.install.bin, and
+ -- replaces the filename with the .exe name. Strips the .lua extension if it exists,
+ -- otherwise just appends .exe to the name
+ if build.install and build.install.bin then
+ for i, name in ipairs(build.install.bin) do
+ local fullname = dir.path(fs.current_dir(), name)
+ local match = name:match("%.lua$")
+ local basename = name:gsub("%.lua$", "")
+ local file
+ if not match then
+ file = io.open(fullname)
+ end
+ if match or (file and file:read():match("#!.*lua.*")) then
+ ok, name = compile_wrapper_binary(fullname, name)
+ if ok then
+ build.install.bin[i] = name
+ else
+ if file then file:close() end
+ return nil, "Build error in wrapper binaries"
+ end
+ end
+ if file then file:close() end
+ end
+ end
+ for name, info in pairs(build.modules) do
+ local moddir = path.module_to_path(name)
+ if type(info) == "string" then
+ local ext = info:match(".([^.]+)$")
+ if ext == "lua" then
+ if info:match("init%.lua$") and not name:match("%.init$") then
+ moddir = path.module_to_path(name..".init")
+ end
+ local dest = dir.path(luadir, moddir)
+ built_modules[info] = dest
+ else
+ info = {info}
+ end
+ end
+ if type(info) == "table" then
+ local objects = {}
+ local sources = info.sources
+ if info[1] then sources = info end
+ if type(sources) == "string" then sources = {sources} end
+ for _, source in ipairs(sources) do
+ local object = source:gsub(".[^.]*$", "."..cfg.obj_extension)
+ if not object then
+ object = source.."."..cfg.obj_extension
+ end
+ ok = compile_object(object, source, info.defines, info.incdirs)
+ if not ok then
+ return nil, "Failed compiling object "..object
+ end
+ table.insert(objects, object)
+ end
+ if not ok then break end
+ local module_name = dir.path(moddir, name:match("([^.]*)$").."."..util.matchquote(cfg.lib_extension)):gsub("//", "/")
+ if moddir ~= "" then
+ fs.make_dir(moddir)
+ end
+ local dest = dir.path(libdir, moddir)
+ built_modules[module_name] = dest
+ ok = compile_library(module_name, objects, info.libraries, info.libdirs, name)
+ if not ok then
+ return nil, "Failed compiling module "..module_name
+ end
+ end
+ end
+ for name, dest in pairs(built_modules) do
+ fs.make_dir(dest)
+ ok = fs.copy(name, dest)
+ if not ok then
+ return nil, "Failed installing "..name.." in "..dest
+ end
+ end
+ if fs.is_dir("lua") then
+ ok, err = fs.copy_contents("lua", luadir)
+ if not ok then
+ return nil, "Failed copying contents of 'lua' directory: "..err
+ end
+ end
+ return true
+end
diff --git a/src/luarocks/build/cmake.lua b/src/luarocks/build/cmake.lua
new file mode 100644
index 0000000..82f4ff5
--- /dev/null
+++ b/src/luarocks/build/cmake.lua
@@ -0,0 +1,58 @@
+
+--- Build back-end for CMake-based modules.
+module("luarocks.build.cmake", package.seeall)
+
+local fs = require("luarocks.fs")
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+
+--- Driver function for the "cmake" build back-end.
+-- @param rockspec table: the loaded rockspec.
+-- @return boolean or (nil, string): true if no errors ocurred,
+-- nil and an error message otherwise.
+function run(rockspec)
+ assert(type(rockspec) == "table")
+ local build = rockspec.build
+ local variables = build.variables or {}
+
+ -- Pass Env variables
+ variables.CMAKE_MODULE_PATH=os.getenv("CMAKE_MODULE_PATH")
+ variables.CMAKE_LIBRARY_PATH=os.getenv("CMAKE_LIBRARY_PATH")
+ variables.CMAKE_INCLUDE_PATH=os.getenv("CMAKE_INCLUDE_PATH")
+
+ util.variable_substitutions(variables, rockspec.variables)
+
+ if not fs.execute_string(fs.quiet(rockspec.variables.CMAKE.." --help")) then
+ return nil, "'"..rockspec.variables.CMAKE.."' program not found. Is cmake installed? You may want to edit variables.CMAKE"
+ end
+
+ -- If inline cmake is present create CMakeLists.txt from it.
+ if type(build.cmake) == "string" then
+ local cmake = assert(io.open(fs.current_dir().."/CMakeLists.txt", "w"))
+ cmake:write(build.cmake)
+ cmake:close()
+ end
+
+
+ -- Execute cmake with variables.
+ local args = ""
+ if cfg.cmake_generator then
+ args = args .. ' -G"'..cfg.cmake_generator.. '"'
+ end
+ for k,v in pairs(variables) do
+ args = args .. ' -D' ..k.. '="' ..v.. '"'
+ end
+
+ if not fs.execute_string(rockspec.variables.CMAKE.." . " ..args) then
+ return nil, "Failed cmake."
+ end
+
+ if not fs.execute_string(rockspec.variables.MAKE.." -fMakefile") then
+ return nil, "Failed building."
+ end
+
+ if not fs.execute_string(rockspec.variables.MAKE.." -fMakefile install") then
+ return nil, "Failed installing."
+ end
+ return true
+end
diff --git a/src/luarocks/build/command.lua b/src/luarocks/build/command.lua
new file mode 100644
index 0000000..aeec0da
--- /dev/null
+++ b/src/luarocks/build/command.lua
@@ -0,0 +1,32 @@
+
+--- Build back-end for raw listing of commands in rockspec files.
+module("luarocks.build.command", package.seeall)
+
+local fs = require("luarocks.fs")
+local util = require("luarocks.util")
+
+--- Driver function for the "command" build back-end.
+-- @param rockspec table: the loaded rockspec.
+-- @return boolean or (nil, string): true if no errors ocurred,
+-- nil and an error message otherwise.
+function run(rockspec)
+ assert(type(rockspec) == "table")
+
+ local build = rockspec.build
+
+ util.variable_substitutions(build, rockspec.variables)
+
+ if build.build_command then
+ util.printout(build.build_command)
+ if not fs.execute(build.build_command) then
+ return nil, "Failed building."
+ end
+ end
+ if build.install_command then
+ util.printout(build.install_command)
+ if not fs.execute(build.install_command) then
+ return nil, "Failed installing."
+ end
+ end
+ return true
+end
diff --git a/src/luarocks/build/make.lua b/src/luarocks/build/make.lua
new file mode 100644
index 0000000..c4b2157
--- /dev/null
+++ b/src/luarocks/build/make.lua
@@ -0,0 +1,92 @@
+
+--- Build back-end for using Makefile-based packages.
+module("luarocks.build.make", package.seeall)
+
+local fs = require("luarocks.fs")
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+
+--- Call "make" with given target and variables
+-- @param make_cmd string: the make command to be used (typically
+-- configured through variables.MAKE in the config files, or
+-- the appropriate platform-specific default).
+-- @param pass boolean: If true, run make; if false, do nothing.
+-- @param target string: The make target; an empty string indicates
+-- the default target.
+-- @param variables table: A table containing string-string key-value
+-- pairs representing variable assignments to be passed to make.
+-- @return boolean: false if any errors occurred, true otherwise.
+local function make_pass(make_cmd, pass, target, variables)
+ assert(type(pass) == "boolean")
+ assert(type(target) == "string")
+ assert(type(variables) == "table")
+
+ local assignments = {}
+ for k,v in pairs(variables) do
+ table.insert(assignments, k.."="..v)
+ end
+ if pass then
+ return fs.execute(make_cmd.." "..target, unpack(assignments))
+ else
+ return true
+ end
+end
+
+--- Driver function for the "make" build back-end.
+-- @param rockspec table: the loaded rockspec.
+-- @return boolean or (nil, string): true if no errors ocurred,
+-- nil and an error message otherwise.
+function run(rockspec)
+ assert(type(rockspec) == "table")
+
+ local build = rockspec.build
+
+ if build.build_pass == nil then build.build_pass = true end
+ if build.install_pass == nil then build.install_pass = true end
+ build.build_variables = build.build_variables or {}
+ build.install_variables = build.install_variables or {}
+ build.build_target = build.build_target or ""
+ build.install_target = build.install_target or "install"
+ local makefile = build.makefile or cfg.makefile
+ if makefile then
+ -- Assumes all make's accept -f. True for POSIX make, GNU make and Microsoft nmake.
+ build.build_target = "-f "..makefile.." "..build.build_target
+ build.install_target = "-f "..makefile.." "..build.install_target
+ end
+
+ if build.variables then
+ for var, val in pairs(build.variables) do
+ build.build_variables[var] = val
+ build.install_variables[var] = val
+ end
+ end
+
+ util.warn_if_not_used(build.build_variables, { CFLAGS=true }, "variable %s was not passed in build_variables")
+
+ util.variable_substitutions(build.build_variables, rockspec.variables)
+ util.variable_substitutions(build.install_variables, rockspec.variables)
+
+ local auto_variables = { "CC" }
+
+ for _, variable in pairs(auto_variables) do
+ if not build.build_variables[variable] then
+ build.build_variables[variable] = rockspec.variables[variable]
+ end
+ if not build.install_variables[variable] then
+ build.install_variables[variable] = rockspec.variables[variable]
+ end
+ end
+
+ -- backwards compatibility
+ local make_cmd = cfg.make or rockspec.variables.MAKE
+
+ local ok = make_pass(make_cmd, build.build_pass, build.build_target, build.build_variables)
+ if not ok then
+ return nil, "Failed building."
+ end
+ ok = make_pass(make_cmd, build.install_pass, build.install_target, build.install_variables)
+ if not ok then
+ return nil, "Failed installing."
+ end
+ return true
+end
diff --git a/src/luarocks/cache.lua b/src/luarocks/cache.lua
new file mode 100644
index 0000000..21185c1
--- /dev/null
+++ b/src/luarocks/cache.lua
@@ -0,0 +1,85 @@
+
+--- Module handling the LuaRocks local cache.
+-- Adds a rock or rockspec to a rocks server.
+module("luarocks.cache", package.seeall)
+
+local fs = require("luarocks.fs")
+local cfg = require("luarocks.cfg")
+local dir = require("luarocks.dir")
+local util = require("luarocks.util")
+
+function get_upload_server(server)
+ if not server then server = cfg.upload_server end
+ if not server then
+ return nil, "No server specified and no default configured with upload_server."
+ end
+ return server, cfg.upload_servers and cfg.upload_servers[server]
+end
+
+function get_server_urls(server, upload_server)
+ local download_url = server
+ local login_url = nil
+ if upload_server then
+ if upload_server.rsync then download_url = "rsync://"..upload_server.rsync
+ elseif upload_server.http then download_url = "http://"..upload_server.http
+ elseif upload_server.ftp then download_url = "ftp://"..upload_server.ftp
+ end
+
+ if upload_server.ftp then login_url = "ftp://"..upload_server.ftp
+ elseif upload_server.sftp then login_url = "sftp://"..upload_server.sftp
+ end
+ end
+ return download_url, login_url
+end
+
+function split_server_url(server, url, user, password)
+ local protocol, server_path = dir.split_url(url)
+ if server_path:match("@") then
+ local credentials
+ credentials, server_path = server_path:match("([^@]*)@(.*)")
+ if credentials:match(":") then
+ user, password = credentials:match("([^:]*):(.*)")
+ else
+ user = credentials
+ end
+ end
+ local local_cache
+ if cfg.local_cache then
+ local_cache = cfg.local_cache .. "/" .. server
+ end
+ return local_cache, protocol, server_path, user, password
+end
+
+function refresh_local_cache(server, url, user, password)
+ local local_cache, protocol, server_path, user, password = split_server_url(server, url, user, password)
+
+ fs.make_dir(cfg.local_cache)
+
+ local tmp_cache = false
+ if not local_cache then
+ local_cache = fs.make_temp_dir("local_cache")
+ tmp_cache = true
+ end
+ local ok = fs.make_dir(local_cache)
+ if not ok then
+ return nil, "Failed creating local cache dir."
+ end
+ fs.change_dir(local_cache)
+ util.printout("Refreshing cache "..local_cache.."...")
+
+ -- TODO abstract away explicit 'wget' call
+ local ok = false
+ if protocol == "rsync" then
+ local srv, path = server_path:match("([^/]+)(/.+)")
+ ok = fs.execute(cfg.variables.RSYNC.." -avz -e ssh "..user.."@"..srv..":"..path.."/ "..local_cache.."/")
+ else
+ local login_info = ""
+ if user then login_info = " --user="..user end
+ if password then login_info = login_info .. " --password="..password end
+ ok = fs.execute(cfg.variables.WGET.." --no-cache -q -m -np -nd "..protocol.."://"..server_path..login_info)
+ end
+ if not ok then
+ return nil, "Failed downloading cache."
+ end
+ return local_cache, protocol, server_path, user, password
+end
diff --git a/src/luarocks/cfg.lua b/src/luarocks/cfg.lua
new file mode 100644
index 0000000..5d918b1
--- /dev/null
+++ b/src/luarocks/cfg.lua
@@ -0,0 +1,484 @@
+--- Configuration for LuaRocks.
+-- Tries to load the user's configuration file and
+-- defines defaults for unset values. See the
+-- <a href="http://luarocks.org/en/Config_file_format">config
+-- file format documentation</a> for details.
+--
+-- End-users shouldn't edit this file. They can override any defaults
+-- set in this file using their system-wide $LUAROCKS_SYSCONFIG file
+-- (see luarocks.site_config) or their user-specific configuration file
+-- (~/.luarocks/config.lua on Unix or %APPDATA%/luarocks/config.lua on
+-- Windows).
+
+local rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION =
+ rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION
+
+module("luarocks.cfg")
+
+lua_version = _VERSION:sub(5)
+local version_suffix = lua_version:gsub("%.", "_")
+
+-- Load site-local global configurations
+local ok, site_config = pcall(require, "luarocks.site_config_"..version_suffix)
+if not ok then
+ ok, site_config = pcall(require, "luarocks.site_config")
+end
+if not ok then
+ io.stderr:write("Site-local luarocks/site_config.lua file not found. Incomplete installation?\n")
+ site_config = {}
+end
+
+_M.site_config = site_config
+
+program_version = "2.1.0"
+
+local persist = require("luarocks.persist")
+
+local popen_ok, popen_result = pcall(io.popen, "")
+if popen_ok then
+ if popen_result then
+ popen_result:close()
+ end
+else
+ io.stderr:write("Your version of Lua does not support io.popen,\n")
+ io.stderr:write("which is required by LuaRocks. Please check your Lua installation.\n")
+ os.exit(1)
+end
+
+-- System detection:
+
+local detected = {}
+local system,proc
+
+-- A proper installation of LuaRocks will hardcode the system
+-- and proc values with site_config.LUAROCKS_UNAME_S and site_config.LUAROCKS_UNAME_M,
+-- so that this detection does not run every time. When it is
+-- performed, we use the Unix way to identify the system,
+-- even on Windows (assuming UnxUtils or Cygwin).
+system = site_config.LUAROCKS_UNAME_S or io.popen("uname -s"):read("*l")
+proc = site_config.LUAROCKS_UNAME_M or io.popen("uname -m"):read("*l")
+if proc:match("i[%d]86") then
+ proc = "x86"
+elseif proc:match("amd64") or proc:match("x86_64") then
+ proc = "x86_64"
+elseif proc:match("Power Macintosh") then
+ proc = "powerpc"
+end
+
+if system == "FreeBSD" then
+ detected.unix = true
+ detected.freebsd = true
+ detected.bsd = true
+elseif system == "OpenBSD" then
+ detected.unix = true
+ detected.openbsd = true
+ detected.bsd = true
+elseif system == "NetBSD" then
+ detected.unix = true
+ detected.netbsd = true
+ detected.bsd = true
+elseif system == "Darwin" then
+ detected.unix = true
+ detected.macosx = true
+ detected.bsd = true
+elseif system == "Linux" then
+ detected.unix = true
+ detected.linux = true
+elseif system == "SunOS" then
+ detected.unix = true
+ detected.solaris = true
+elseif system and system:match("^CYGWIN") then
+ detected.unix = true
+ detected.cygwin = true
+elseif system and system:match("^Windows") then
+ detected.windows = true
+elseif system and system:match("^MINGW") then
+ detected.windows = true
+ detected.mingw32 = true
+else
+ detected.unix = true
+ -- Fall back to Unix in unknown systems.
+end
+
+-- Path configuration:
+
+local sys_config_file, home_config_file
+local sys_config_dir, home_config_dir
+local sys_config_ok, home_config_ok = false, false
+sys_config_dir = site_config.LUAROCKS_SYSCONFDIR
+if detected.windows then
+ home = os.getenv("APPDATA") or "c:"
+ sys_config_dir = sys_config_dir or "c:/luarocks"
+ home_config_dir = home.."/luarocks"
+ home_tree = home.."/luarocks/"
+else
+ home = os.getenv("HOME") or ""
+ sys_config_dir = sys_config_dir or "/etc/luarocks"
+ home_config_dir = home.."/.luarocks"
+ home_tree = home.."/.luarocks/"
+end
+
+variables = {}
+rocks_trees = {}
+
+sys_config_file = site_config.LUAROCKS_SYSCONFIG or sys_config_dir.."/config-"..lua_version..".lua"
+local err
+sys_config_ok, err = persist.load_into_table(sys_config_file, _M)
+
+if not sys_config_ok then
+ sys_config_file = sys_config_dir.."/config.lua"
+ sys_config_ok, err = persist.load_into_table(sys_config_file, _M)
+end
+if err and ok == nil then
+ io.stderr:write(err.."\n")
+end
+
+if not site_config.LUAROCKS_FORCE_CONFIG then
+ local home_overrides, err
+ home_config_file = os.getenv("LUAROCKS_CONFIG_" .. version_suffix) or os.getenv("LUAROCKS_CONFIG")
+ if home_config_file then
+ home_overrides, err = persist.load_into_table(home_config_file, { home = home, lua_version = lua_version })
+ else
+ home_config_file = home_config_dir.."/config-"..lua_version..".lua"
+ home_overrides, err = persist.load_into_table(home_config_file, { home = home, lua_version = lua_version })
+ if not home_overrides then
+ home_config_file = home_config_dir.."/config.lua"
+ home_overrides, err = persist.load_into_table(home_config_file, { home = home, lua_version = lua_version })
+ end
+ end
+ if home_overrides then
+ home_config_ok = true
+ local util = require("luarocks.util")
+ if home_overrides.rocks_trees then
+ _M.rocks_trees = nil
+ end
+ if home_overrides.rocks_servers then
+ _M.rocks_servers = nil
+ end
+ util.deep_merge(_M, home_overrides)
+ else -- nil or false
+ home_config_ok = home_overrides
+ if err and home_config_ok == nil then
+ io.stderr:write(err.."\n")
+ end
+ end
+end
+
+if not next(rocks_trees) then
+ if home_tree then
+ table.insert(rocks_trees, home_tree)
+ end
+ if site_config.LUAROCKS_ROCKS_TREE then
+ table.insert(rocks_trees, site_config.LUAROCKS_ROCKS_TREE)
+ end
+end
+
+-- Configure defaults:
+
+local root = rocks_trees[#rocks_trees]
+local defaults = {
+
+ local_by_default = false,
+ use_extensions = false,
+ accept_unknown_fields = false,
+ fs_use_modules = true,
+ hooks_enabled = true,
+ deps_mode = "one",
+
+ lua_modules_path = "/share/lua/"..lua_version,
+ lib_modules_path = "/lib/lua/"..lua_version,
+ rocks_subdir = site_config.LUAROCKS_ROCKS_SUBDIR or "/lib/luarocks/rocks",
+
+ arch = "unknown",
+ lib_extension = "unknown",
+ obj_extension = "unknown",
+
+ rocks_servers = {
+ {
+ "http://www.luarocks.org/repositories/rocks",
+ "http://luarocks.giga.puc-rio.br/",
+ "http://luafr.org/luarocks/rocks",
+ "http://liblua.so/luarocks/repositories/rocks",
+ "http://luarocks.logiceditor.com/rocks",
+ }
+ },
+
+ lua_extension = "lua",
+ lua_interpreter = site_config.LUA_INTERPRETER or "lua",
+ downloader = site_config.LUAROCKS_DOWNLOADER or "wget",
+ md5checker = site_config.LUAROCKS_MD5CHECKER or "md5sum",
+
+ variables = {
+ MAKE = "make",
+ CC = "cc",
+ LD = "ld",
+
+ CVS = "cvs",
+ GIT = "git",
+ SSCM = "sscm",
+ SVN = "svn",
+ HG = "hg",
+
+ RSYNC = "rsync",
+ WGET = "wget",
+ SCP = "scp",
+ CURL = "curl",
+
+ PWD = "pwd",
+ MKDIR = "mkdir",
+ RMDIR = "rmdir",
+ CP = "cp",
+ LS = "ls",
+ RM = "rm",
+ FIND = "find",
+ TEST = "test",
+ CHMOD = "chmod",
+ PATCH = "patch",
+
+ ZIP = "zip",
+ UNZIP = "unzip -n",
+ GUNZIP = "gunzip",
+ BUNZIP2 = "bunzip2",
+ TAR = "tar",
+
+ MD5SUM = "md5sum",
+ OPENSSL = "openssl",
+ MD5 = "md5",
+ STAT = "stat",
+
+ CMAKE = "cmake",
+ SEVENZ = "7z",
+
+ STATFLAG = "-c '%a'",
+ },
+
+ external_deps_subdirs = {
+ bin = "bin",
+ lib = "lib",
+ include = "include"
+ },
+ runtime_external_deps_subdirs = {
+ bin = "bin",
+ lib = "lib",
+ include = "include"
+ },
+}
+
+if detected.windows then
+ home_config_file = home_config_file and home_config_file:gsub("\\","/")
+ defaults.fs_use_modules = false
+ defaults.arch = "win32-"..proc
+ defaults.platforms = {"win32", "windows" }
+ defaults.lib_extension = "dll"
+ defaults.external_lib_extension = "dll"
+ defaults.obj_extension = "obj"
+ defaults.external_deps_dirs = { "c:/external/" }
+ defaults.variables.LUA_BINDIR = site_config.LUA_BINDIR and site_config.LUA_BINDIR:gsub("\\", "/") or "c:/lua"..lua_version.."/bin"
+ defaults.variables.LUA_INCDIR = site_config.LUA_INCDIR and site_config.LUA_INCDIR:gsub("\\", "/") or "c:/lua"..lua_version.."/include"
+ defaults.variables.LUA_LIBDIR = site_config.LUA_LIBDIR and site_config.LUA_LIBDIR:gsub("\\", "/") or "c:/lua"..lua_version.."/lib"
+ defaults.cmake_generator = "MinGW Makefiles"
+ defaults.makefile = "Makefile.win"
+ defaults.variables.MAKE = "nmake"
+ defaults.variables.CC = "cl"
+ defaults.variables.RC = "rc"
+ defaults.variables.WRAPPER = site_config.LUAROCKS_PREFIX .. "\\2.0\\rclauncher.c"
+ defaults.variables.LD = "link"
+ defaults.variables.MT = "mt"
+ defaults.variables.LUALIB = "lua"..lua_version..".lib"
+ defaults.variables.CFLAGS = "/MD /O2"
+ defaults.variables.LIBFLAG = "/dll"
+ defaults.variables.LUALIB = "lua"..lua_version..".lib"
+ defaults.external_deps_patterns = {
+ bin = { "?.exe", "?.bat" },
+ lib = { "?.lib", "?.dll", "lib?.dll" },
+ include = { "?.h" }
+ }
+ defaults.runtime_external_deps_patterns = {
+ bin = { "?.exe", "?.bat" },
+ lib = { "?.dll", "lib?.dll" },
+ include = { "?.h" }
+ }
+ defaults.export_path = "SET PATH=%s"
+ defaults.export_path_separator = ";"
+ defaults.export_lua_path = "SET LUA_PATH=%s"
+ defaults.export_lua_cpath = "SET LUA_CPATH=%s"
+ defaults.local_cache = home.."/cache/luarocks"
+end
+
+if detected.mingw32 then
+ defaults.platforms = { "win32", "mingw32", "windows" }
+ defaults.obj_extension = "o"
+ defaults.cmake_generator = "MinGW Makefiles"
+ defaults.variables.MAKE = "mingw32-make"
+ defaults.variables.CC = "mingw32-gcc"
+ defaults.variables.RC = "windres"
+ defaults.variables.WRAPPER = site_config.LUAROCKS_PREFIX .. "\\2.0\\rclauncher.c"
+ defaults.variables.LD = "mingw32-gcc"
+ defaults.variables.CFLAGS = "-O2"
+ defaults.variables.LIBFLAG = "-shared"
+end
+
+if detected.unix then
+ defaults.lib_extension = "so"
+ defaults.external_lib_extension = "so"
+ defaults.obj_extension = "o"
+ defaults.external_deps_dirs = { "/usr/local", "/usr" }
+ defaults.variables.LUA_BINDIR = site_config.LUA_BINDIR or "/usr/local/bin"
+ defaults.variables.LUA_INCDIR = site_config.LUA_INCDIR or "/usr/local/include"
+ defaults.variables.LUA_LIBDIR = site_config.LUA_LIBDIR or "/usr/local/lib"
+ defaults.variables.CFLAGS = "-O2"
+ defaults.cmake_generator = "Unix Makefiles"
+ defaults.platforms = { "unix" }
+ defaults.variables.CC = "gcc"
+ defaults.variables.LD = "gcc"
+ defaults.gcc_rpath = true
+ defaults.variables.LIBFLAG = "-shared"
+ defaults.external_deps_patterns = {
+ bin = { "?" },
+ lib = { "lib?.a", "lib?.so", "lib?.so.*" },
+ include = { "?.h" }
+ }
+ defaults.runtime_external_deps_patterns = {
+ bin = { "?" },
+ lib = { "lib?.so", "lib?.so.*" },
+ include = { "?.h" }
+ }
+ defaults.export_path = "export PATH='%s'"
+ defaults.export_path_separator = ":"
+ defaults.export_lua_path = "export LUA_PATH='%s'"
+ defaults.export_lua_cpath = "export LUA_CPATH='%s'"
+ defaults.local_cache = home.."/.cache/luarocks"
+ if not defaults.variables.CFLAGS:match("-fPIC") then
+ defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC"
+ end
+end
+
+if detected.cygwin then
+ defaults.lib_extension = "so" -- can be overridden in the config file for mingw builds
+ defaults.arch = "cygwin-"..proc
+ defaults.platforms = {"unix", "cygwin"}
+ defaults.cmake_generator = "Unix Makefiles"
+ defaults.variables.CC = "echo -llua | xargs gcc"
+ defaults.variables.LD = "echo -llua | xargs gcc"
+ defaults.variables.LIBFLAG = "-shared"
+end
+
+if detected.bsd then
+ defaults.variables.MAKE = "gmake"
+ defaults.variables.STATFLAG = "-f '%OLp'"
+end
+
+if detected.macosx then
+ defaults.variables.MAKE = "make"
+ defaults.external_lib_extension = "dylib"
+ defaults.arch = "macosx-"..proc
+ defaults.platforms = {"unix", "bsd", "macosx"}
+ defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load"
+ defaults.variables.STATFLAG = "-f '%A'"
+ local version = io.popen("sw_vers -productVersion"):read("*l")
+ version = tonumber(version and version:match("^[^.]+%.([^.]+)")) or 3
+ if version >= 5 then
+ version = 5
+ else
+ defaults.gcc_rpath = false
+ end
+ defaults.variables.CC = "export MACOSX_DEPLOYMENT_TARGET=10."..version.."; gcc"
+ defaults.variables.LD = "export MACOSX_DEPLOYMENT_TARGET=10."..version.."; gcc"
+end
+
+if detected.linux then
+ defaults.arch = "linux-"..proc
+ defaults.platforms = {"unix", "linux"}
+end
+
+if detected.freebsd then
+ defaults.arch = "freebsd-"..proc
+ defaults.platforms = {"unix", "bsd", "freebsd"}
+end
+
+if detected.openbsd then
+ defaults.arch = "openbsd-"..proc
+ defaults.platforms = {"unix", "bsd", "openbsd"}
+end
+
+if detected.netbsd then
+ defaults.arch = "netbsd-"..proc
+ defaults.platforms = {"unix", "bsd", "netbsd"}
+end
+
+if detected.solaris then
+ defaults.arch = "solaris-"..proc
+ defaults.platforms = {"unix", "solaris"}
+ defaults.variables.MAKE = "gmake"
+end
+
+-- Expose some more values detected by LuaRocks for use by rockspec authors.
+defaults.variables.LIB_EXTENSION = defaults.lib_extension
+defaults.variables.OBJ_EXTENSION = defaults.obj_extension
+defaults.variables.LUAROCKS_PREFIX = site_config.LUAROCKS_PREFIX
+defaults.variables.LUA = site_config.LUA_DIR_SET and (defaults.variables.LUA_BINDIR.."/"..defaults.lua_interpreter) or defaults.lua_interpreter
+
+-- Use defaults:
+
+-- Populate values from 'defaults.variables' in 'variables' if they were not
+-- already set by user.
+if not _M.variables then
+ _M.variables = {}
+end
+for k,v in pairs(defaults.variables) do
+ if not _M.variables[k] then
+ _M.variables[k] = v
+ end
+end
+
+-- For values not set in the config file, use values from the 'defaults' table.
+local cfg_mt = {
+ __index = function(t, k)
+ local default = defaults[k]
+ if default then
+ rawset(t, k, default)
+ end
+ return default
+ end
+}
+setmetatable(_M, cfg_mt)
+
+function package_paths()
+ local new_path, new_cpath = {}, {}
+ for _,tree in ipairs(rocks_trees) do
+ if type(tree) == "string" then
+ table.insert(new_path, 1, tree..lua_modules_path.."/?.lua;"..tree..lua_modules_path.."/?/init.lua")
+ table.insert(new_cpath, 1, tree..lib_modules_path.."/?."..lib_extension)
+ else
+ table.insert(new_path, 1, (tree.lua_dir or tree.root..lua_modules_path).."/?.lua;"..
+ (tree.lua_dir or tree.root..lua_modules_path).."/?/init.lua")
+ table.insert(new_cpath, 1, (tree.lib_dir or tree.root..lib_modules_path).."/?."..lib_extension)
+ end
+ end
+ return table.concat(new_path, ";"), table.concat(new_cpath, ";")
+end
+
+do
+ local new_path, new_cpath = package_paths()
+ package.path = new_path..";"..package.path
+ package.cpath = new_cpath..";"..package.cpath
+end
+
+function which_config()
+ return sys_config_file, sys_config_ok, home_config_file, home_config_ok
+end
+
+user_agent = "LuaRocks/"..program_version.." "..arch
+
+--- Check if platform was detected
+-- @param query string: The platform name to check.
+-- @return boolean: true if LuaRocks is currently running on queried platform.
+function is_platform(query)
+ assert(type(query) == "string")
+
+ for _, platform in ipairs(platforms) do
+ if platform == query then
+ return true
+ end
+ end
+end
diff --git a/src/luarocks/command_line.lua b/src/luarocks/command_line.lua
new file mode 100644
index 0000000..d16ef8e
--- /dev/null
+++ b/src/luarocks/command_line.lua
@@ -0,0 +1,168 @@
+
+--- Functions for command-line scripts.
+module("luarocks.command_line", package.seeall)
+
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+local path = require("luarocks.path")
+local dir = require("luarocks.dir")
+local deps = require("luarocks.deps")
+
+local program = util.this_program("luarocks")
+
+--- Display an error message and exit.
+-- @param message string: The error message.
+local function die(message)
+ assert(type(message) == "string")
+
+ local ok, err = pcall(util.run_scheduled_functions)
+ if not ok then
+ util.printerr("\nLuaRocks "..cfg.program_version.." internal bug (please report at luarocks-developers@lists.sourceforge.net):\n"..err)
+ end
+ util.printerr("\nError: "..message)
+ os.exit(1)
+end
+
+--- Main command-line processor.
+-- Parses input arguments and calls the appropriate driver function
+-- to execute the action requested on the command-line, forwarding
+-- to it any additional arguments passed by the user.
+-- Uses the global table "commands", which contains
+-- the loaded modules representing commands.
+-- @param ... string: Arguments given on the command-line.
+function run_command(...)
+ local args = {...}
+ local cmdline_vars = {}
+ for i = #args, 1, -1 do
+ local arg = args[i]
+ if arg:match("^[^-][^=]*=") then
+ local var, val = arg:match("^([A-Z_][A-Z0-9_]*)=(.*)")
+ if val then
+ cmdline_vars[var] = val
+ table.remove(args, i)
+ else
+ die("Invalid assignment: "..arg)
+ end
+ end
+ end
+ local nonflags = { util.parse_flags(unpack(args)) }
+ local flags = table.remove(nonflags, 1)
+
+ if flags["from"] then flags["server"] = flags["from"] end
+ if flags["only-from"] then flags["only-server"] = flags["only-from"] end
+ if flags["only-sources-from"] then flags["only-sources"] = flags["only-sources-from"] end
+ if flags["to"] then flags["tree"] = flags["to"] end
+ if flags["nodeps"] then
+ flags["deps-mode"] = "none"
+ table.insert(args, "--deps-mode=none")
+ end
+
+ cfg.flags = flags
+
+ local command
+
+ if flags["version"] then
+ util.printout(program.." "..cfg.program_version)
+ util.printout(program_description)
+ util.printout()
+ os.exit(0)
+ elseif flags["help"] or #nonflags == 0 then
+ command = "help"
+ args = nonflags
+ else
+ command = nonflags[1]
+ for i, arg in ipairs(args) do
+ if arg == command then
+ table.remove(args, i)
+ break
+ end
+ end
+ end
+ command = command:gsub("-", "_")
+
+ if flags["extensions"] then
+ cfg.use_extensions = true
+ local type_check = require("luarocks.type_check")
+ type_check.load_extensions()
+ end
+
+ if cfg.local_by_default then
+ flags["local"] = true
+ end
+
+ if flags["deps-mode"] and not deps.check_deps_mode_flag(flags["deps-mode"]) then
+ die("Invalid entry for --deps-mode.")
+ end
+
+ if flags["tree"] then
+ if flags["tree"] == true or flags["tree"] == "" then
+ die("Argument error: use --tree=<path>")
+ end
+ local fs = require("luarocks.fs")
+ local root_dir = fs.absolute_name(flags["tree"])
+ path.use_tree(root_dir)
+ elseif flags["local"] then
+ path.use_tree(cfg.home_tree)
+ else
+ local trees = cfg.rocks_trees
+ path.use_tree(trees[#trees])
+ end
+
+ if type(cfg.root_dir) == "string" then
+ cfg.root_dir = cfg.root_dir:gsub("/+$", "")
+ else
+ cfg.root_dir.root = cfg.root_dir.root:gsub("/+$", "")
+ end
+ cfg.rocks_dir = cfg.rocks_dir:gsub("/+$", "")
+ cfg.deploy_bin_dir = cfg.deploy_bin_dir:gsub("/+$", "")
+ cfg.deploy_lua_dir = cfg.deploy_lua_dir:gsub("/+$", "")
+ cfg.deploy_lib_dir = cfg.deploy_lib_dir:gsub("/+$", "")
+
+ cfg.variables.ROCKS_TREE = cfg.rocks_dir
+ cfg.variables.SCRIPTS_DIR = cfg.deploy_bin_dir
+
+ if flags["server"] then
+ if flags["server"] == true then
+ die("Argument error: use --server=<url>")
+ end
+ local protocol, path = dir.split_url(flags["server"])
+ table.insert(cfg.rocks_servers, 1, protocol.."://"..path)
+ end
+
+ if flags["only-server"] then
+ if flags["only-server"] == true then
+ die("Argument error: use --only-server=<url>")
+ end
+ cfg.rocks_servers = { flags["only-server"] }
+ end
+
+ if flags["only-sources"] then
+ cfg.only_sources_from = flags["only-sources"]
+ end
+
+ if command ~= "help" then
+ for k, v in pairs(cmdline_vars) do
+ cfg.variables[k] = v
+ end
+ end
+
+ if commands[command] then
+ -- TODO the interface of run should be modified, to receive the
+ -- flags table and the (possibly unpacked) nonflags arguments.
+ -- This would remove redundant parsing of arguments.
+ -- I'm not changing this now to avoid messing with the run()
+ -- interface, which I know some people use (even though
+ -- I never published it as a public API...)
+ local xp, ok, err = xpcall(function() return commands[command].run(unpack(args)) end, function(err)
+ die(debug.traceback("LuaRocks "..cfg.program_version
+ .." bug (please report at luarocks-developers@lists.sourceforge.net).\n"
+ ..err, 2))
+ end)
+ if xp and (not ok) then
+ die(err)
+ end
+ else
+ die("Unknown command: "..command)
+ end
+ util.run_scheduled_functions()
+end
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua
new file mode 100644
index 0000000..5ac822c
--- /dev/null
+++ b/src/luarocks/deps.lua
@@ -0,0 +1,714 @@
+
+--- Dependency handling functions.
+-- Dependencies are represented in LuaRocks through strings with
+-- a package name followed by a comma-separated list of constraints.
+-- Each constraint consists of an operator and a version number.
+-- In this string format, version numbers are represented as
+-- naturally as possible, like they are used by upstream projects
+-- (e.g. "2.0beta3"). Internally, LuaRocks converts them to a purely
+-- numeric representation, allowing comparison following some
+-- "common sense" heuristics. The precise specification of the
+-- comparison criteria is the source code of this module, but the
+-- test/test_deps.lua file included with LuaRocks provides some
+-- insights on what these criteria are.
+module("luarocks.deps", package.seeall)
+
+local cfg = require("luarocks.cfg")
+local manif_core = require("luarocks.manif_core")
+local path = require("luarocks.path")
+local dir = require("luarocks.dir")
+local util = require("luarocks.util")
+
+local operators = {
+ ["=="] = "==",
+ ["~="] = "~=",
+ [">"] = ">",
+ ["<"] = "<",
+ [">="] = ">=",
+ ["<="] = "<=",
+ ["~>"] = "~>",
+ -- plus some convenience translations
+ [""] = "==",
+ ["="] = "==",
+ ["!="] = "~="
+}
+
+local deltas = {
+ scm = 1000,
+ cvs = 1000,
+ rc = -1000,
+ pre = -10000,
+ beta = -100000,
+ alpha = -1000000
+}
+
+local version_mt = {
+ --- Equality comparison for versions.
+ -- All version numbers must be equal.
+ -- If both versions have revision numbers, they must be equal;
+ -- otherwise the revision number is ignored.
+ -- @param v1 table: version table to compare.
+ -- @param v2 table: version table to compare.
+ -- @return boolean: true if they are considered equivalent.
+ __eq = function(v1, v2)
+ if #v1 ~= #v2 then
+ return false
+ end
+ for i = 1, #v1 do
+ if v1[i] ~= v2[i] then
+ return false
+ end
+ end
+ if v1.revision and v2.revision then
+ return (v1.revision == v2.revision)
+ end
+ return true
+ end,
+ --- Size comparison for versions.
+ -- All version numbers are compared.
+ -- If both versions have revision numbers, they are compared;
+ -- otherwise the revision number is ignored.
+ -- @param v1 table: version table to compare.
+ -- @param v2 table: version table to compare.
+ -- @return boolean: true if v1 is considered lower than v2.
+ __lt = function(v1, v2)
+ for i = 1, math.max(#v1, #v2) do
+ local v1i, v2i = v1[i] or 0, v2[i] or 0
+ if v1i ~= v2i then
+ return (v1i < v2i)
+ end
+ end
+ if v1.revision and v2.revision then
+ return (v1.revision < v2.revision)
+ end
+ return false
+ end
+}
+
+local version_cache = {}
+setmetatable(version_cache, {
+ __mode = "kv"
+})
+
+--- Parse a version string, converting to table format.
+-- A version table contains all components of the version string
+-- converted to numeric format, stored in the array part of the table.
+-- If the version contains a revision, it is stored numerically
+-- in the 'revision' field. The original string representation of
+-- the string is preserved in the 'string' field.
+-- Returned version tables use a metatable
+-- allowing later comparison through relational operators.
+-- @param vstring string: A version number in string format.
+-- @return table or nil: A version table or nil
+-- if the input string contains invalid characters.
+function parse_version(vstring)
+ if not vstring then return nil end
+ assert(type(vstring) == "string")
+
+ local cached = version_cache[vstring]
+ if cached then
+ return cached
+ end
+
+ local version = {}
+ local i = 1
+
+ local function add_token(number)
+ version[i] = version[i] and version[i] + number/100000 or number
+ i = i + 1
+ end
+
+ -- trim leading and trailing spaces
+ vstring = vstring:match("^%s*(.*)%s*$")
+ version.string = vstring
+ -- store revision separately if any
+ local main, revision = vstring:match("(.*)%-(%d+)$")
+ if revision then
+ vstring = main
+ version.revision = tonumber(revision)
+ end
+ while #vstring > 0 do
+ -- extract a number
+ local token, rest = vstring:match("^(%d+)[%.%-%_]*(.*)")
+ if token then
+ add_token(tonumber(token))
+ else
+ -- extract a word
+ token, rest = vstring:match("^(%a+)[%.%-%_]*(.*)")
+ if not token then
+ util.printerr("Warning: version number '"..vstring.."' could not be parsed.")
+ version[i] = 0
+ break
+ end
+ local last = #version
+ version[i] = deltas[token] or (token:byte() / 1000)
+ end
+ vstring = rest
+ end
+ setmetatable(version, version_mt)
+ version_cache[vstring] = version
+ return version
+end
+
+--- Utility function to compare version numbers given as strings.
+-- @param a string: one version.
+-- @param b string: another version.
+-- @return boolean: True if a > b.
+function compare_versions(a, b)
+ return parse_version(a) > parse_version(b)
+end
+
+--- Consumes a constraint from a string, converting it to table format.
+-- For example, a string ">= 1.0, > 2.0" is converted to a table in the
+-- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned
+-- back to the caller.
+-- @param input string: A list of constraints in string format.
+-- @return (table, string) or nil: A table representing the same
+-- constraints and the string with the unused input, or nil if the
+-- input string is invalid.
+local function parse_constraint(input)
+ assert(type(input) == "string")
+
+ local no_upgrade, op, version, rest = input:match("^(@?)([<>=~!]*)%s*([%w%.%_%-]+)[%s,]*(.*)")
+ local _op = operators[op]
+ version = parse_version(version)
+ if not _op then
+ return nil, "Encountered bad constraint operator: '"..tostring(op).."' in '"..input.."'"
+ end
+ if not version then
+ return nil, "Could not parse version from constraint: '"..input.."'"
+ end
+ return { op = _op, version = version, no_upgrade = no_upgrade=="@" and true or nil }, rest
+end
+
+--- Convert a list of constraints from string to table format.
+-- For example, a string ">= 1.0, < 2.0" is converted to a table in the format
+-- {{op = ">=", version={1,0}}, {op = "<", version={2,0}}}.
+-- Version tables use a metatable allowing later comparison through
+-- relational operators.
+-- @param input string: A list of constraints in string format.
+-- @return table or nil: A table representing the same constraints,
+-- or nil if the input string is invalid.
+function parse_constraints(input)
+ assert(type(input) == "string")
+
+ local constraints, constraint, oinput = {}, nil, input
+ while #input > 0 do
+ constraint, input = parse_constraint(input)
+ if constraint then
+ table.insert(constraints, constraint)
+ else
+ return nil, "Failed to parse constraint '"..tostring(oinput).."' with error: ".. input
+ end
+ end
+ return constraints
+end
+
+--- Convert a dependency from string to table format.
+-- For example, a string "foo >= 1.0, < 2.0"
+-- is converted to a table in the format
+-- {name = "foo", constraints = {{op = ">=", version={1,0}},
+-- {op = "<", version={2,0}}}}. Version tables use a metatable
+-- allowing later comparison through relational operators.
+-- @param dep string: A dependency in string format
+-- as entered in rockspec files.
+-- @return table or nil: A table representing the same dependency relation,
+-- or nil if the input string is invalid.
+function parse_dep(dep)
+ assert(type(dep) == "string")
+
+ local name, rest = dep:match("^%s*([a-zA-Z][a-zA-Z0-9%.%-%_]*)%s*(.*)")
+ if not name then return nil, "failed to extract dependency name from '"..tostring(dep).."'" end
+ local constraints, err = parse_constraints(rest)
+ if not constraints then return nil, err end
+ return { name = name, constraints = constraints }
+end
+
+--- Convert a version table to a string.
+-- @param v table: The version table
+-- @param internal boolean or nil: Whether to display versions in their
+-- internal representation format or how they were specified.
+-- @return string: The dependency information pretty-printed as a string.
+function show_version(v, internal)
+ assert(type(v) == "table")
+ assert(type(internal) == "boolean" or not internal)
+
+ return (internal
+ and table.concat(v, ":")..(v.revision and tostring(v.revision) or "")
+ or v.string)
+end
+
+--- Convert a dependency in table format to a string.
+-- @param dep table: The dependency in table format
+-- @param internal boolean or nil: Whether to display versions in their
+-- internal representation format or how they were specified.
+-- @return string: The dependency information pretty-printed as a string.
+function show_dep(dep, internal)
+ assert(type(dep) == "table")
+ assert(type(internal) == "boolean" or not internal)
+
+ local pretty = {}
+ for _, c in ipairs(dep.constraints) do
+ table.insert(pretty, c.op .. " " .. show_version(c.version, internal))
+ end
+ return dep.name.." "..table.concat(pretty, ", ")
+end
+
+--- A more lenient check for equivalence between versions.
+-- This returns true if the requested components of a version
+-- match and ignore the ones that were not given. For example,
+-- when requesting "2", then "2", "2.1", "2.3.5-9"... all match.
+-- When requesting "2.1", then "2.1", "2.1.3" match, but "2.2"
+-- doesn't.
+-- @param version string or table: Version to be tested; may be
+-- in string format or already parsed into a table.
+-- @param requested string or table: Version requested; may be
+-- in string format or already parsed into a table.
+-- @return boolean: True if the tested version matches the requested
+-- version, false otherwise.
+local function partial_match(version, requested)
+ assert(type(version) == "string" or type(version) == "table")
+ assert(type(requested) == "string" or type(version) == "table")
+
+ if type(version) ~= "table" then version = parse_version(version) end
+ if type(requested) ~= "table" then requested = parse_version(requested) end
+ if not version or not requested then return false end
+
+ for i, ri in ipairs(requested) do
+ local vi = version[i] or 0
+ if ri ~= vi then return false end
+ end
+ if requested.revision then
+ return requested.revision == version.revision
+ end
+ return true
+end
+
+--- Check if a version satisfies a set of constraints.
+-- @param version table: A version in table format
+-- @param constraints table: An array of constraints in table format.
+-- @return boolean: True if version satisfies all constraints,
+-- false otherwise.
+function match_constraints(version, constraints)
+ assert(type(version) == "table")
+ assert(type(constraints) == "table")
+ local ok = true
+ setmetatable(version, version_mt)
+ for _, constr in pairs(constraints) do
+ if type(constr.version) == "string" then
+ constr.version = parse_version(constr.version)
+ end
+ local constr_version, constr_op = constr.version, constr.op
+ setmetatable(constr_version, version_mt)
+ if constr_op == "==" then ok = version == constr_version
+ elseif constr_op == "~=" then ok = version ~= constr_version
+ elseif constr_op == ">" then ok = version > constr_version
+ elseif constr_op == "<" then ok = version < constr_version
+ elseif constr_op == ">=" then ok = version >= constr_version
+ elseif constr_op == "<=" then ok = version <= constr_version
+ elseif constr_op == "~>" then ok = partial_match(version, constr_version)
+ end
+ if not ok then break end
+ end
+ return ok
+end
+
+--- Attempt to match a dependency to an installed rock.
+-- @param dep table: A dependency parsed in table format.
+-- @param blacklist table: Versions that can't be accepted. Table where keys
+-- are program versions and values are 'true'.
+-- @return table or nil: A table containing fields 'name' and 'version'
+-- representing an installed rock which matches the given dependency,
+-- or nil if it could not be matched.
+local function match_dep(dep, blacklist, deps_mode)
+ assert(type(dep) == "table")
+
+ local versions
+ if dep.name == "lua" then
+ versions = { cfg.lua_version }
+ else
+ versions = manif_core.get_versions(dep.name, deps_mode)
+ end
+ if not versions then
+ return nil
+ end
+ if blacklist then
+ local i = 1
+ while versions[i] do
+ if blacklist[versions[i]] then
+ table.remove(versions, i)
+ else
+ i = i + 1
+ end
+ end
+ end
+ local candidates = {}
+ for _, vstring in ipairs(versions) do
+ local version = parse_version(vstring)
+ if match_constraints(version, dep.constraints) then
+ table.insert(candidates, version)
+ end
+ end
+ if #candidates == 0 then
+ return nil
+ else
+ table.sort(candidates)
+ return {
+ name = dep.name,
+ version = candidates[#candidates].string
+ }
+ end
+end
+
+--- Attempt to match dependencies of a rockspec to installed rocks.
+-- @param rockspec table: The rockspec loaded as a table.
+-- @param blacklist table or nil: Program versions to not use as valid matches.
+-- Table where keys are program names and values are tables where keys
+-- are program versions and values are 'true'.
+-- @return table, table: A table where keys are dependencies parsed
+-- in table format and values are tables containing fields 'name' and
+-- version' representing matches, and a table of missing dependencies
+-- parsed as tables.
+function match_deps(rockspec, blacklist, deps_mode)
+ assert(type(rockspec) == "table")
+ assert(type(blacklist) == "table" or not blacklist)
+ local matched, missing, no_upgrade = {}, {}, {}
+
+ for _, dep in ipairs(rockspec.dependencies) do
+ local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode)
+ if found then
+ if dep.name ~= "lua" then
+ matched[dep] = found
+ end
+ else
+ if dep.constraints[1] and dep.constraints[1].no_upgrade then
+ no_upgrade[dep.name] = dep
+ else
+ missing[dep.name] = dep
+ end
+ end
+ end
+ return matched, missing, no_upgrade
+end
+
+--- Return a set of values of a table.
+-- @param tbl table: The input table.
+-- @return table: The array of keys.
+local function values_set(tbl)
+ local set = {}
+ for _, v in pairs(tbl) do
+ set[v] = true
+ end
+ return set
+end
+
+--- Check dependencies of a rock and attempt to install any missing ones.
+-- Packages are installed using the LuaRocks "install" command.
+-- Aborts the program if a dependency could not be fulfilled.
+-- @param rockspec table: A rockspec in table format.
+-- @return boolean or (nil, string, [string]): True if no errors occurred, or
+-- nil and an error message if any test failed, followed by an optional
+-- error code.
+function fulfill_dependencies(rockspec, deps_mode)
+
+ local search = require("luarocks.search")
+ local install = require("luarocks.install")
+
+ if rockspec.supported_platforms then
+ if not platforms_set then
+ platforms_set = values_set(cfg.platforms)
+ end
+ local supported = nil
+ for _, plat in pairs(rockspec.supported_platforms) do
+ local neg, plat = plat:match("^(!?)(.*)")
+ if neg == "!" then
+ if platforms_set[plat] then
+ return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms."
+ end
+ else
+ if platforms_set[plat] then
+ supported = true
+ else
+ if supported == nil then
+ supported = false
+ end
+ end
+ end
+ end
+ if supported == false then
+ local plats = table.concat(cfg.platforms, ", ")
+ return nil, "This rockspec for "..rockspec.package.." does not support "..plats.." platforms."
+ end
+ end
+
+ local matched, missing, no_upgrade = match_deps(rockspec, nil, deps_mode)
+
+ if next(no_upgrade) then
+ util.printerr("Missing dependencies for "..rockspec.name.." "..rockspec.version..":")
+ for _, dep in pairs(no_upgrade) do
+ util.printerr(show_dep(dep))
+ end
+ if next(missing) then
+ for _, dep in pairs(missing) do
+ util.printerr(show_dep(dep))
+ end
+ end
+ util.printerr()
+ for _, dep in pairs(no_upgrade) do
+ util.printerr("This version of "..rockspec.name.." is designed for use with")
+ util.printerr(show_dep(dep)..", but is configured to avoid upgrading it")
+ util.printerr("automatically. Please upgrade "..dep.name.." with")
+ util.printerr(" luarocks install "..dep.name)
+ util.printerr("or choose an older version of "..rockspec.name.." with")
+ util.printerr(" luarocks search "..rockspec.name)
+ end
+ return nil, "Failed matching dependencies."
+ end
+
+ if next(missing) then
+ util.printerr()
+ util.printerr("Missing dependencies for "..rockspec.name..":")
+ for _, dep in pairs(missing) do
+ util.printerr(show_dep(dep))
+ end
+ util.printerr()
+
+ for _, dep in pairs(missing) do
+ -- Double-check in case dependency was filled during recursion.
+ if not match_dep(dep, nil, deps_mode) then
+ local rock = search.find_suitable_rock(dep)
+ if not rock then
+ return nil, "Could not satisfy dependency: "..show_dep(dep)
+ end
+ local ok, err, errcode = install.run(rock)
+ if not ok then
+ return nil, "Failed installing dependency: "..rock.." - "..err, errcode
+ end
+ end
+ end
+ end
+ return true
+end
+
+--- If filename matches a pattern, return the capture.
+-- For example, given "libfoo.so" and "lib?.so" is a pattern,
+-- returns "foo" (which can then be used to build names
+-- based on other patterns.
+-- @param file string: a filename
+-- @param pattern string: a pattern, where ? is to be matched by the filename.
+-- @return string The pattern, if found, or nil.
+local function deconstruct_pattern(file, pattern)
+ local depattern = "^"..(pattern:gsub("%.", "%%."):gsub("%*", ".*"):gsub("?", "(.*)")).."$"
+ return (file:match(depattern))
+end
+
+--- Construct all possible patterns for a name and add to the files array.
+-- Run through the patterns array replacing all occurrences of "?"
+-- with the given file name and store them in the files array.
+-- @param file string A raw name (e.g. "foo")
+-- @param array of string An array of patterns with "?" as the wildcard
+-- (e.g. {"?.so", "lib?.so"})
+-- @param files The array of constructed names
+local function add_all_patterns(file, patterns, files)
+ for _, pattern in ipairs(patterns) do
+ table.insert(files, (pattern:gsub("?", file)))
+ end
+end
+
+--- Set up path-related variables for external dependencies.
+-- For each key in the external_dependencies table in the
+-- rockspec file, four variables are created: <key>_DIR, <key>_BINDIR,
+-- <key>_INCDIR and <key>_LIBDIR. These are not overwritten
+-- if already set (e.g. by the LuaRocks config file or through the
+-- command-line). Values in the external_dependencies table
+-- are tables that may contain a "header" or a "library" field,
+-- with filenames to be tested for existence.
+-- @param rockspec table: The rockspec table.
+-- @param mode string: if "build" is given, checks all files;
+-- if "install" is given, do not scan for headers.
+-- @return boolean or (nil, string): True if no errors occurred, or
+-- nil and an error message if any test failed.
+function check_external_deps(rockspec, mode)
+ assert(type(rockspec) == "table")
+
+ local fs = require("luarocks.fs")
+
+ local vars = rockspec.variables
+ local patterns = cfg.external_deps_patterns
+ local subdirs = cfg.external_deps_subdirs
+ if mode == "install" then
+ patterns = cfg.runtime_external_deps_patterns
+ subdirs = cfg.runtime_external_deps_subdirs
+ end
+ if rockspec.external_dependencies then
+ for name, files in pairs(rockspec.external_dependencies) do
+ local ok = true
+ local failed_file = nil
+ local failed_dirname = nil
+ for _, extdir in ipairs(cfg.external_deps_dirs) do
+ ok = true
+ local prefix = vars[name.."_DIR"]
+ local dirs = {
+ BINDIR = { subdir = subdirs.bin, testfile = "program", pattern = patterns.bin },
+ INCDIR = { subdir = subdirs.include, testfile = "header", pattern = patterns.include },
+ LIBDIR = { subdir = subdirs.lib, testfile = "library", pattern = patterns.lib }
+ }
+ if mode == "install" then
+ dirs.INCDIR = nil
+ end
+ if not prefix then
+ prefix = extdir
+ end
+ if type(prefix) == "table" then
+ if prefix.bin then
+ dirs.BINDIR.subdir = prefix.bin
+ end
+ if prefix.include then
+ if dirs.INCDIR then
+ dirs.INCDIR.subdir = prefix.include
+ end
+ end
+ if prefix.lib then
+ dirs.LIBDIR.subdir = prefix.lib
+ end
+ prefix = prefix.prefix
+ end
+ for dirname, dirdata in pairs(dirs) do
+ dirdata.dir = vars[name.."_"..dirname] or dir.path(prefix, dirdata.subdir)
+ local file = files[dirdata.testfile]
+ if file then
+ local files = {}
+ if not file:match("%.") then
+ add_all_patterns(file, dirdata.pattern, files)
+ else
+ for _, pattern in ipairs(dirdata.pattern) do
+ local matched = deconstruct_pattern(file, pattern)
+ if matched then
+ add_all_patterns(matched, dirdata.pattern, files)
+ end
+ end
+ table.insert(files, file)
+ end
+ local found = false
+ failed_file = nil
+ for _, f in pairs(files) do
+ -- small convenience hack
+ if f:match("%.so$") or f:match("%.dylib$") or f:match("%.dll$") then
+ f = f:gsub("%.[^.]+$", "."..cfg.external_lib_extension)
+ end
+ if f:match("%*") then
+ local replaced = f:gsub("%.", "%%."):gsub("%*", ".*")
+ for _, entry in ipairs(fs.list_dir(dirdata.dir)) do
+ if entry:match(replaced) then
+ found = true
+ break
+ end
+ end
+ else
+ found = fs.is_file(dir.path(dirdata.dir, f))
+ end
+ if found then
+ break
+ else
+ if failed_file then
+ failed_file = failed_file .. ", or " .. f
+ else
+ failed_file = f
+ end
+ end
+ end
+ if not found then
+ ok = false
+ failed_dirname = dirname
+ break
+ end
+ end
+ end
+ if ok then
+ for dirname, dirdata in pairs(dirs) do
+ vars[name.."_"..dirname] = dirdata.dir
+ end
+ vars[name.."_DIR"] = prefix
+ break
+ end
+ end
+ if not ok then
+ return nil, "Could not find expected file "..failed_file.." for "..name.." -- you may have to install "..name.." in your system and/or pass "..name.."_DIR or "..name.."_"..failed_dirname.." to the luarocks command. Example: luarocks install "..rockspec.name.." "..name.."_DIR=/usr/local", "dependency"
+ end
+ end
+ end
+ return true
+end
+
+--- Recursively scan dependencies, to build a transitive closure of all
+-- dependent packages.
+-- @param results table: The results table being built.
+-- @param missing table: The table of missing dependencies being recursively built.
+-- @param manifest table: The manifest table containing dependencies.
+-- @param name string: Package name.
+-- @param version string: Package version.
+-- @return (table, table): The results and a table of missing dependencies.
+function scan_deps(results, missing, manifest, name, version, deps_mode)
+ assert(type(results) == "table")
+ assert(type(missing) == "table")
+ assert(type(manifest) == "table")
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+
+ local fetch = require("luarocks.fetch")
+
+ local err
+ if results[name] then
+ return results, missing
+ end
+ if not manifest.dependencies then manifest.dependencies = {} end
+ local dependencies = manifest.dependencies
+ if not dependencies[name] then dependencies[name] = {} end
+ local dependencies_name = dependencies[name]
+ local deplist = dependencies_name[version]
+ local rockspec, err
+ if not deplist then
+ rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version))
+ if err then
+ missing[name.." "..version] = err
+ return results, missing
+ end
+ dependencies_name[version] = rockspec.dependencies
+ else
+ rockspec = { dependencies = deplist }
+ end
+ local matched, failures = match_deps(rockspec, nil, deps_mode)
+ for _, match in pairs(matched) do
+ results, missing = scan_deps(results, missing, manifest, match.name, match.version, deps_mode)
+ end
+ if next(failures) then
+ for _, failure in pairs(failures) do
+ missing[show_dep(failure)] = "failed"
+ end
+ end
+ results[name] = version
+ return results, missing
+end
+
+local valid_deps_modes = {
+ one = true,
+ order = true,
+ all = true,
+ none = true,
+}
+
+function check_deps_mode_flag(flag)
+ return valid_deps_modes[flag]
+end
+
+function get_deps_mode(flags)
+ if flags["deps-mode"] then
+ return flags["deps-mode"]
+ else
+ return cfg.deps_mode
+ end
+end
+
+function deps_mode_to_flag(deps_mode)
+ return "--deps-mode="..deps_mode
+end
diff --git a/src/luarocks/dir.lua b/src/luarocks/dir.lua
new file mode 100644
index 0000000..b496c96
--- /dev/null
+++ b/src/luarocks/dir.lua
@@ -0,0 +1,70 @@
+
+--- Generic utilities for handling pathnames.
+module("luarocks.dir", package.seeall)
+
+separator = "/"
+
+--- Strip the path off a path+filename.
+-- @param pathname string: A path+name, such as "/a/b/c"
+-- or "\a\b\c".
+-- @return string: The filename without its path, such as "c".
+function base_name(pathname)
+ assert(type(pathname) == "string")
+
+ local base = pathname:gsub("[/\\]*$", ""):match(".*[/\\]([^/\\]*)")
+ return base or pathname
+end
+
+--- Strip the name off a path+filename.
+-- @param pathname string: A path+name, such as "/a/b/c".
+-- @return string: The filename without its path, such as "/a/b/".
+-- For entries such as "/a/b/", "/a/" is returned. If there are
+-- no directory separators in input, "" is returned.
+function dir_name(pathname)
+ assert(type(pathname) == "string")
+
+ return (pathname:gsub("/*$", ""):match("(.*/)[^/]*")) or ""
+end
+
+--- Describe a path in a cross-platform way.
+-- Use this function to avoid platform-specific directory
+-- separators in other modules. Removes trailing slashes from
+-- each component given, to avoid repeated separators.
+-- Separators inside strings are kept, to handle URLs containing
+-- protocols.
+-- @param ... strings representing directories
+-- @return string: a string with a platform-specific representation
+-- of the path.
+function path(...)
+ local items = {...}
+ local i = 1
+ while items[i] do
+ items[i] = items[i]:gsub("(.+)/+$", "%1")
+ if items[i] == "" then
+ table.remove(items, i)
+ else
+ i = i + 1
+ end
+ end
+ return (table.concat(items, "/"):gsub("(.+)/+$", "%1"))
+end
+
+--- Split protocol and path from an URL or local pathname.
+-- URLs should be in the "protocol://path" format.
+-- For local pathnames, "file" is returned as the protocol.
+-- @param url string: an URL or a local pathname.
+-- @return string, string: the protocol, and the pathname without the protocol.
+function split_url(url)
+ assert(type(url) == "string")
+
+ local protocol, pathname = url:match("^([^:]*)://(.*)")
+ if not protocol then
+ protocol = "file"
+ pathname = url
+ end
+ return protocol, pathname
+end
+
+function normalize(name)
+ return name:gsub("\\", "/"):gsub("(.)/*$", "%1")
+end
diff --git a/src/luarocks/download.lua b/src/luarocks/download.lua
new file mode 100644
index 0000000..0012cb1
--- /dev/null
+++ b/src/luarocks/download.lua
@@ -0,0 +1,88 @@
+
+--- Module implementing the luarocks "download" command.
+-- Download a rock from the repository.
+module("luarocks.download", package.seeall)
+
+local util = require("luarocks.util")
+local path = require("luarocks.path")
+local fetch = require("luarocks.fetch")
+local search = require("luarocks.search")
+
+help_summary = "Download a specific rock file from a rocks server."
+help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]"
+
+help = [[
+--all Download all files if there are multiple matches.
+--source Download .src.rock if available.
+--rockspec Download .rockspec if available.
+--arch=<arch> Download rock for a specific architecture.
+]]
+
+function download(arch, name, version, all)
+ local results, err
+ local query = search.make_query(name, version)
+ if arch then query.arch = arch end
+ if all then
+ if name == "" then query.exact_name = false end
+ results = search.search_repos(query)
+ else
+ results, err = search.find_suitable_rock(query)
+ end
+ if type(results) == "string" then
+ local file = fetch.fetch_url(results)
+ return file
+ elseif type(results) == "table" and next(results) then
+ if all then
+ local all_ok = true
+ local any_err = ""
+ for name, result in pairs(results) do
+ for version, versions in pairs(result) do
+ for _,items in pairs(versions) do
+ local filename = path.make_url(items.repo, name, version, items.arch)
+ local ok, err = fetch.fetch_url(filename)
+ if not ok then
+ all_ok = false
+ any_err = any_err .. "\n" .. err
+ end
+ end
+ end
+ end
+ return all_ok, any_err
+ else
+ util.printerr("Multiple search results were returned.")
+ util.title("Search results:")
+ search.print_results(results)
+ return nil, "Please narrow your query or use --all."
+ end
+ end
+ return nil, "Could not find a result named "..name..(version and " "..version or "").."."
+end
+
+--- Driver function for the "download" command.
+-- @param name string: a rock name.
+-- @param version string or nil: if the name of a package is given, a
+-- version may also be passed.
+-- @return boolean or (nil, string): true if successful or nil followed
+-- by an error message.
+function run(...)
+ local flags, name, version = util.parse_flags(...)
+
+ assert(type(version) == "string" or not version)
+ if type(name) ~= "string" and not flags["all"] then
+ return nil, "Argument missing, see help."
+ end
+ if not name then name, version = "", "" end
+
+ local arch
+
+ if flags["source"] then
+ arch = "src"
+ elseif flags["rockspec"] then
+ arch = "rockspec"
+ elseif flags["arch"] then
+ arch = flags["arch"]
+ end
+
+ local dl, err = download(arch, name, version, flags["all"])
+ return dl and true, err
+end
diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua
new file mode 100644
index 0000000..bfdbace
--- /dev/null
+++ b/src/luarocks/fetch.lua
@@ -0,0 +1,325 @@
+
+--- Functions related to fetching and loading local and remote files.
+module("luarocks.fetch", package.seeall)
+
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local type_check = require("luarocks.type_check")
+local path = require("luarocks.path")
+local deps = require("luarocks.deps")
+local persist = require("luarocks.persist")
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+
+--- Fetch a local or remote file.
+-- Make a remote or local URL/pathname local, fetching the file if necessary.
+-- Other "fetch" and "load" functions use this function to obtain files.
+-- If a local pathname is given, it is returned as a result.
+-- @param url string: a local pathname or a remote URL.
+-- @param filename string or nil: this function attempts to detect the
+-- resulting local filename of the remote file as the basename of the URL;
+-- if that is not correct (due to a redirection, for example), the local
+-- filename can be given explicitly as this second argument.
+-- @return string or (nil, string, [string]): the absolute local pathname for the
+-- fetched file, or nil and a message in case of errors, followed by
+-- an optional error code.
+function fetch_url(url, filename)
+ assert(type(url) == "string")
+ assert(type(filename) == "string" or not filename)
+
+ local protocol, pathname = dir.split_url(url)
+ if protocol == "file" then
+ return fs.absolute_name(pathname)
+ elseif protocol == "http" or protocol == "ftp" or protocol == "https" then
+ local ok, err = fs.download(url, filename)
+ if not ok then
+ return nil, "Failed downloading "..url..(err and " - "..err or ""), "network"
+ end
+ return dir.path(fs.current_dir(), filename or dir.base_name(url))
+ else
+ return nil, "Unsupported protocol "..protocol
+ end
+end
+
+--- For remote URLs, create a temporary directory and download URL inside it.
+-- This temporary directory will be deleted on program termination.
+-- For local URLs, just return the local pathname and its directory.
+-- @param url string: URL to be downloaded
+-- @param tmpname string: name pattern to use for avoiding conflicts
+-- when creating temporary directory.
+-- @param filename string or nil: local filename of URL to be downloaded,
+-- in case it can't be inferred from the URL.
+-- @return (string, string) or (nil, string, [string]): absolute local pathname of
+-- the fetched file and temporary directory name; or nil and an error message
+-- followed by an optional error code
+function fetch_url_at_temp_dir(url, tmpname, filename)
+ assert(type(url) == "string")
+ assert(type(tmpname) == "string")
+ assert(type(filename) == "string" or not filename)
+ filename = filename or dir.base_name(url)
+
+ local protocol, pathname = dir.split_url(url)
+ if protocol == "file" then
+ if fs.exists(pathname) then
+ return pathname, dir.dir_name(fs.absolute_name(pathname))
+ else
+ return nil, "File not found: "..pathname
+ end
+ else
+ local temp_dir = fs.make_temp_dir(tmpname)
+ if not temp_dir then
+ return nil, "Failed creating temporary directory."
+ end
+ util.schedule_function(fs.delete, temp_dir)
+ fs.change_dir(temp_dir)
+ local file, err, errcode = fetch_url(url, filename)
+ fs.pop_dir()
+ if not file then
+ return nil, "Error fetching file: "..err, errcode
+ end
+ return file, temp_dir
+ end
+end
+
+--- Obtain a rock and unpack it.
+-- If a directory is not given, a temporary directory will be created,
+-- which will be deleted on program termination.
+-- @param rock_file string: URL or filename of the rock.
+-- @param dest string or nil: if given, directory will be used as
+-- a permanent destination.
+-- @return string or (nil, string, [string]): the directory containing the contents
+-- of the unpacked rock.
+function fetch_and_unpack_rock(rock_file, dest)
+ assert(type(rock_file) == "string")
+ assert(type(dest) == "string" or not dest)
+
+ local name = dir.base_name(rock_file):match("(.*)%.[^.]*%.rock")
+
+ local rock_file, err, errcode = fetch_url_at_temp_dir(rock_file,"luarocks-rock-"..name)
+ if not rock_file then
+ return nil, "Could not fetch rock file: " .. err, errcode
+ end
+
+ rock_file = fs.absolute_name(rock_file)
+ local unpack_dir
+ if dest then
+ unpack_dir = dest
+ fs.make_dir(unpack_dir)
+ else
+ unpack_dir = fs.make_temp_dir(name)
+ end
+ if not dest then
+ util.schedule_function(fs.delete, unpack_dir)
+ end
+ fs.change_dir(unpack_dir)
+ local ok = fs.unzip(rock_file)
+ if not ok then
+ return nil, "Failed unpacking rock file: " .. rock_file
+ end
+ fs.pop_dir()
+ return unpack_dir
+end
+
+function url_to_base_dir(url)
+ local base = dir.base_name(url)
+ return base:gsub("%.[^.]*$", ""):gsub("%.tar$", "")
+end
+
+--- Back-end function that actually loads the local rockspec.
+-- Performs some validation and postprocessing of the rockspec contents.
+-- @param filename string: The local filename of the rockspec file.
+-- @return table or (nil, string): A table representing the rockspec
+-- or nil followed by an error message.
+function load_local_rockspec(filename)
+ assert(type(filename) == "string")
+ filename = fs.absolute_name(filename)
+ local rockspec, err = persist.load_into_table(filename)
+ if not rockspec then
+ return nil, "Could not load rockspec file "..filename.." ("..err..")"
+ end
+
+ local ok, err = type_check.type_check_rockspec(rockspec)
+ if not ok then
+ return nil, filename..": "..err
+ end
+
+ if rockspec.rockspec_format then
+ if deps.compare_versions(rockspec.rockspec_format, type_check.rockspec_format) then
+ return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks."
+ end
+ end
+
+ util.platform_overrides(rockspec.build)
+ util.platform_overrides(rockspec.dependencies)
+ util.platform_overrides(rockspec.external_dependencies)
+ util.platform_overrides(rockspec.source)
+ util.platform_overrides(rockspec.hooks)
+
+ local basename = dir.base_name(filename)
+ if basename == "rockspec" then
+ rockspec.name = rockspec.package:lower()
+ else
+ rockspec.name = basename:match("(.*)-[^-]*-[0-9]*")
+ if not rockspec.name then
+ return nil, "Expected filename in format 'name-version-revision.rockspec'."
+ end
+ end
+
+ local protocol, pathname = dir.split_url(rockspec.source.url)
+ if protocol == "http" or protocol == "https" or protocol == "ftp" or protocol == "file" then
+ rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url)
+ end
+ rockspec.source.protocol, rockspec.source.pathname = protocol, pathname
+
+ -- Temporary compatibility
+ if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end
+ if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end
+
+ local name_version = rockspec.package:lower() .. "-" .. rockspec.version
+ if basename ~= "rockspec" and basename ~= name_version .. ".rockspec" then
+ return nil, "Inconsistency between rockspec filename ("..basename..") and its contents ("..name_version..".rockspec)."
+ end
+
+ rockspec.local_filename = filename
+ local filebase = rockspec.source.file or rockspec.source.url
+ local base = url_to_base_dir(filebase)
+ rockspec.source.dir = rockspec.source.dir
+ or rockspec.source.module
+ or ((filebase:match(".lua$") or filebase:match(".c$")) and ".")
+ or base
+ if rockspec.dependencies then
+ for i = 1, #rockspec.dependencies do
+ local parsed, err = deps.parse_dep(rockspec.dependencies[i])
+ if not parsed then
+ return nil, "Parse error processing dependency '"..rockspec.dependencies[i].."': "..tostring(err)
+ end
+ rockspec.dependencies[i] = parsed
+ end
+ else
+ rockspec.dependencies = {}
+ end
+ local ok, err = path.configure_paths(rockspec)
+ if err then
+ return nil, "Error verifying paths: "..err
+ end
+
+ return rockspec
+end
+
+--- Load a local or remote rockspec into a table.
+-- This is the entry point for the LuaRocks tools.
+-- Only the LuaRocks runtime loader should use
+-- load_local_rockspec directly.
+-- @param filename string: Local or remote filename of a rockspec.
+-- @param location string or nil: Where to download. If not given,
+-- a temporary dir is created.
+-- @return table or (nil, string, [string]): A table representing the rockspec
+-- or nil followed by an error message and optional error code.
+function load_rockspec(filename, location)
+ assert(type(filename) == "string")
+
+ local name
+ local basename = dir.base_name(filename)
+ if basename == "rockspec" then
+ name = "rockspec"
+ else
+ name = basename:match("(.*)%.rockspec")
+ if not name and not basename == "rockspec" then
+ return nil, "Filename '"..filename.."' does not look like a rockspec."
+ end
+ end
+
+ local err, errcode
+ if location then
+ fs.change_dir(location)
+ filename, err = fetch_url(filename)
+ fs.pop_dir()
+ else
+ filename, err, errcode = fetch_url_at_temp_dir(filename,"luarocks-rockspec-"..name)
+ end
+ if not filename then
+ return nil, err, errcode
+ end
+
+ return load_local_rockspec(filename)
+end
+
+--- Download sources for building a rock using the basic URL downloader.
+-- @param rockspec table: The rockspec table
+-- @param extract boolean: Whether to extract the sources from
+-- the fetched source tarball or not.
+-- @param dest_dir string or nil: If set, will extract to the given directory.
+-- @return (string, string) or (nil, string, [string]): The absolute pathname of
+-- the fetched source tarball and the temporary directory created to
+-- store it; or nil and an error message and optional error code.
+function get_sources(rockspec, extract, dest_dir)
+ assert(type(rockspec) == "table")
+ assert(type(extract) == "boolean")
+ assert(type(dest_dir) == "string" or not dest_dir)
+
+ local url = rockspec.source.url
+ local name = rockspec.name.."-"..rockspec.version
+ local filename = rockspec.source.file
+ local source_file, store_dir, err, errcode
+ if dest_dir then
+ fs.change_dir(dest_dir)
+ source_file, err, errcode = fetch_url(url, filename)
+ fs.pop_dir()
+ store_dir = dest_dir
+ else
+ source_file, store_dir, errcode = fetch_url_at_temp_dir(url, "luarocks-source-"..name, filename)
+ end
+ if not source_file then
+ return nil, err or store_dir, errcode
+ end
+ if rockspec.source.md5 then
+ if not fs.check_md5(source_file, rockspec.source.md5) then
+ return nil, "MD5 check for "..filename.." has failed."
+ end
+ end
+ if extract then
+ fs.change_dir(store_dir)
+ fs.unpack_archive(rockspec.source.file)
+ if not fs.exists(rockspec.source.dir) then
+ return nil, "Directory "..rockspec.source.dir.." not found inside archive "..rockspec.source.file
+ end
+ fs.pop_dir()
+ end
+ return source_file, store_dir
+end
+
+--- Download sources for building a rock, calling the appropriate protocol method.
+-- @param rockspec table: The rockspec table
+-- @param extract boolean: When downloading compressed formats, whether to extract
+-- the sources from the fetched archive or not.
+-- @param dest_dir string or nil: If set, will extract to the given directory.
+-- @return (string, string) or (nil, string): The absolute pathname of
+-- the fetched source tarball and the temporary directory created to
+-- store it; or nil and an error message.
+function fetch_sources(rockspec, extract, dest_dir)
+ assert(type(rockspec) == "table")
+ assert(type(extract) == "boolean")
+ assert(type(dest_dir) == "string" or not dest_dir)
+
+ local protocol = rockspec.source.protocol
+ local ok, proto
+ if protocol == "http" or protocol == "https" or protocol == "ftp" or protocol == "file" then
+ proto = require("luarocks.fetch")
+ else
+ ok, proto = pcall(require, "luarocks.fetch."..protocol:gsub("[+-]", "_"))
+ if not ok then
+ return nil, "Unknown protocol "..protocol
+ end
+ end
+
+ if cfg.only_sources_from
+ and rockspec.source.pathname
+ and #rockspec.source.pathname > 0 then
+ if #cfg.only_sources_from == 0 then
+ return nil, "Can't download "..rockspec.source.url.." -- download from remote servers disabled"
+ elseif rockspec.source.pathname:find(cfg.only_sources_from, 1, true) ~= 1 then
+ return nil, "Can't download "..rockspec.source.url.." -- only downloading from "..cfg.only_sources_from
+ end
+ end
+ return proto.get_sources(rockspec, extract, dest_dir)
+end
diff --git a/src/luarocks/fetch/cvs.lua b/src/luarocks/fetch/cvs.lua
new file mode 100644
index 0000000..a622cdc
--- /dev/null
+++ b/src/luarocks/fetch/cvs.lua
@@ -0,0 +1,44 @@
+
+--- Fetch back-end for retrieving sources from CVS.
+module("luarocks.fetch.cvs", package.seeall)
+
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local util = require("luarocks.util")
+
+--- Download sources for building a rock, using CVS.
+-- @param rockspec table: The rockspec table
+-- @param extract boolean: Unused in this module (required for API purposes.)
+-- @param dest_dir string or nil: If set, will extract to the given directory.
+-- @return (string, string) or (nil, string): The absolute pathname of
+-- the fetched source tarball and the temporary directory created to
+-- store it; or nil and an error message.
+function get_sources(rockspec, extract, dest_dir)
+ assert(type(rockspec) == "table")
+ assert(type(dest_dir) == "string" or not dest_dir)
+
+ local name_version = rockspec.name .. "-" .. rockspec.version
+ local module = rockspec.source.module or dir.base_name(rockspec.source.url)
+ local command = {rockspec.variables.CVS, "-d"..rockspec.source.pathname, "export", module}
+ if rockspec.source.tag then
+ table.insert(command, 4, "-r")
+ table.insert(command, 5, rockspec.source.tag)
+ end
+ local store_dir
+ if not dest_dir then
+ store_dir = fs.make_temp_dir(name_version)
+ if not store_dir then
+ return nil, "Failed creating temporary directory."
+ end
+ util.schedule_function(fs.delete, store_dir)
+ else
+ store_dir = dest_dir
+ end
+ fs.change_dir(store_dir)
+ if not fs.execute(unpack(command)) then
+ return nil, "Failed fetching files from CVS."
+ end
+ fs.pop_dir()
+ return module, store_dir
+end
+
diff --git a/src/luarocks/fetch/git.lua b/src/luarocks/fetch/git.lua
new file mode 100644
index 0000000..e7c8943
--- /dev/null
+++ b/src/luarocks/fetch/git.lua
@@ -0,0 +1,81 @@
+
+--- Fetch back-end for retrieving sources from GIT.
+module("luarocks.fetch.git", package.seeall)
+
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local util = require("luarocks.util")
+
+--- Git >= 1.7.10 can clone a branch **or tag**, < 1.7.10 by branch only. We
+-- need to know this in order to build the appropriate command; if we can't
+-- clone by tag then we'll have to issue a subsequent command to check out the
+-- given tag.
+-- @return boolean: Whether Git can clone by tag.
+local function git_can_clone_by_tag()
+ local version_string = io.popen('git --version'):read()
+ local major, minor, tiny = version_string:match('(%d-)%.(%d+)%.?(%d*)')
+ major, minor, tiny = tonumber(major), tonumber(minor), tonumber(tiny) or 0
+ local value = major > 1 or (major == 1 and (minor > 7 or (minor == 7 and tiny >= 10)))
+ git_can_clone_by_tag = function() return value end
+ return git_can_clone_by_tag()
+end
+
+--- Download sources for building a rock, using git.
+-- @param rockspec table: The rockspec table
+-- @param extract boolean: Unused in this module (required for API purposes.)
+-- @param dest_dir string or nil: If set, will extract to the given directory.
+-- @return (string, string) or (nil, string): The absolute pathname of
+-- the fetched source tarball and the temporary directory created to
+-- store it; or nil and an error message.
+function get_sources(rockspec, extract, dest_dir)
+ assert(type(rockspec) == "table")
+ assert(type(dest_dir) == "string" or not dest_dir)
+
+ local git_cmd = rockspec.variables.GIT
+ local name_version = rockspec.name .. "-" .. rockspec.version
+ local module = dir.base_name(rockspec.source.url)
+ -- Strip off .git from base name if present
+ module = module:gsub("%.git$", "")
+
+ local store_dir
+ if not dest_dir then
+ store_dir = fs.make_temp_dir(name_version)
+ if not store_dir then
+ return nil, "Failed creating temporary directory."
+ end
+ util.schedule_function(fs.delete, store_dir)
+ else
+ store_dir = dest_dir
+ end
+ store_dir = fs.absolute_name(store_dir)
+ fs.change_dir(store_dir)
+
+ local command = {git_cmd, "clone", "--depth=1", rockspec.source.url, module}
+ local tag_or_branch = rockspec.source.tag or rockspec.source.branch
+ -- If the tag or branch is explicitly set to "master" in the rockspec, then
+ -- we can avoid passing it to Git since it's the default.
+ if tag_or_branch == "master" then tag_or_branch = nil end
+ if tag_or_branch then
+ if git_can_clone_by_tag() then
+ -- The argument to `--branch` can actually be a branch or a tag as of
+ -- Git 1.7.10.
+ table.insert(command, 4, "--branch=" .. tag_or_branch)
+ end
+ end
+ if not fs.execute(unpack(command)) then
+ return nil, "Failed cloning git repository."
+ end
+ fs.change_dir(module)
+ if tag_or_branch and not git_can_clone_by_tag() then
+ local checkout_command = {git_cmd, "checkout", tag_or_branch}
+ if not fs.execute(unpack(checkout_command)) then
+ return nil, 'Failed to check out the "' .. tag_or_branch ..'" tag or branch.'
+ end
+ end
+
+ fs.delete(dir.path(store_dir, module, ".git"))
+ fs.delete(dir.path(store_dir, module, ".gitignore"))
+ fs.pop_dir()
+ fs.pop_dir()
+ return module, store_dir
+end
diff --git a/src/luarocks/fetch/git_file.lua b/src/luarocks/fetch/git_file.lua
new file mode 100644
index 0000000..1b18d0f
--- /dev/null
+++ b/src/luarocks/fetch/git_file.lua
@@ -0,0 +1,17 @@
+
+--- Fetch back-end for retrieving sources from local Git repositories.
+module("luarocks.fetch.git_file", package.seeall)
+
+local git = require("luarocks.fetch.git")
+
+--- Fetch sources for building a rock from a local Git repository.
+-- @param rockspec table: The rockspec table
+-- @param extract boolean: Unused in this module (required for API purposes.)
+-- @param dest_dir string or nil: If set, will extract to the given directory.
+-- @return (string, string) or (nil, string): The absolute pathname of
+-- the fetched source tarball and the temporary directory created to
+-- store it; or nil and an error message.
+function get_sources(rockspec, extract, dest_dir)
+ rockspec.source.url = rockspec.source.url:gsub("^git.file://", "")
+ return git.get_sources(rockspec, extract, dest_dir)
+end
diff --git a/src/luarocks/fetch/hg.lua b/src/luarocks/fetch/hg.lua
new file mode 100644
index 0000000..a08520a
--- /dev/null
+++ b/src/luarocks/fetch/hg.lua
@@ -0,0 +1,54 @@
+
+--- Fetch back-end for retrieving sources from HG.
+module("luarocks.fetch.hg", package.seeall)
+
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local util = require("luarocks.util")
+
+--- Download sources for building a rock, using hg.
+-- @param rockspec table: The rockspec table
+-- @param extract boolean: Unused in this module (required for API purposes.)
+-- @param dest_dir string or nil: If set, will extract to the given directory.
+-- @return (string, string) or (nil, string): The absolute pathname of
+-- the fetched source tarball and the temporary directory created to
+-- store it; or nil and an error message.
+function get_sources(rockspec, extract, dest_dir)
+ assert(type(rockspec) == "table")
+ assert(type(dest_dir) == "string" or not dest_dir)
+
+ local hg_cmd = rockspec.variables.HG
+ local name_version = rockspec.name .. "-" .. rockspec.version
+ -- Strip off special hg:// protocol type
+ local url = rockspec.source.url:gsub("^hg://", "")
+
+ local module = dir.base_name(url)
+
+ local command = {hg_cmd, "clone", url, module}
+ local tag_or_branch = rockspec.source.tag or rockspec.source.branch
+ if tag_or_branch then
+ command = {hg_cmd, "clone", "--rev", url, module}
+ end
+ local store_dir
+ if not dest_dir then
+ store_dir = fs.make_temp_dir(name_version)
+ if not store_dir then
+ return nil, "Failed creating temporary directory."
+ end
+ util.schedule_function(fs.delete, store_dir)
+ else
+ store_dir = dest_dir
+ end
+ fs.change_dir(store_dir)
+ if not fs.execute(unpack(command)) then
+ return nil, "Failed cloning hg repository."
+ end
+ fs.change_dir(module)
+
+ fs.delete(dir.path(store_dir, module, ".hg"))
+ fs.delete(dir.path(store_dir, module, ".hgignore"))
+ fs.pop_dir()
+ fs.pop_dir()
+ return module, store_dir
+end
+
diff --git a/src/luarocks/fetch/sscm.lua b/src/luarocks/fetch/sscm.lua
new file mode 100644
index 0000000..e52e801
--- /dev/null
+++ b/src/luarocks/fetch/sscm.lua
@@ -0,0 +1,42 @@
+
+--- Fetch back-end for retrieving sources from Surround SCM Server
+module("luarocks.fetch.sscm", package.seeall)
+
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+
+--- Download sources via Surround SCM Server for building a rock.
+-- @param rockspec table: The rockspec table
+-- @param extract boolean: Unused in this module (required for API purposes.)
+-- @param dest_dir string or nil: If set, will extract to the given directory.
+-- @return (string, string) or (nil, string): The absolute pathname of
+-- the fetched source tarball and the temporary directory created to
+-- store it; or nil and an error message.
+function get_sources(rockspec, extract, dest_dir)
+ assert(type(rockspec) == "table")
+ assert(type(dest_dir) == "string" or not dest_dir)
+
+ local sscm_cmd = rockspec.variables.SSCM
+ local module = rockspec.source.module or dir.base_name(rockspec.source.url)
+ local branch, repository = string.match(rockspec.source.pathname, "^([^/]*)/(.*)")
+ if not branch or not repository then
+ return nil, "Error retrieving branch and repository from rockspec."
+ end
+ -- Search for working directory.
+ local working_dir
+ local tmp = io.popen(string.format(sscm_cmd..[[ property "/" -d -b%s -p%s]], branch, repository))
+ for line in tmp:lines() do
+ --%c because a chr(13) comes in the end.
+ working_dir = string.match(line, "Working directory:[%s]*(.*)%c$")
+ if working_dir then break end
+ end
+ tmp:close()
+ if not working_dir then
+ return nil, "Error retrieving working directory from SSCM."
+ end
+ if not fs.execute(sscm_cmd, "get", "*", "-e" , "-r", "-b"..branch, "-p"..repository, "-tmodify", "-wreplace") then
+ return nil, "Failed fetching files from SSCM."
+ end
+ -- FIXME: This function does not honor the dest_dir parameter.
+ return module, working_dir
+end
diff --git a/src/luarocks/fetch/svn.lua b/src/luarocks/fetch/svn.lua
new file mode 100644
index 0000000..a4e952d
--- /dev/null
+++ b/src/luarocks/fetch/svn.lua
@@ -0,0 +1,53 @@
+
+--- Fetch back-end for retrieving sources from Subversion.
+module("luarocks.fetch.svn", package.seeall)
+
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local util = require("luarocks.util")
+
+--- Download sources for building a rock, using Subversion.
+-- @param rockspec table: The rockspec table
+-- @param extract boolean: Unused in this module (required for API purposes.)
+-- @param dest_dir string or nil: If set, will extract to the given directory.
+-- @return (string, string) or (nil, string): The absolute pathname of
+-- the fetched source tarball and the temporary directory created to
+-- store it; or nil and an error message.
+function get_sources(rockspec, extract, dest_dir)
+ assert(type(rockspec) == "table")
+ assert(type(dest_dir) == "string" or not dest_dir)
+
+ local svn_cmd = rockspec.variables.SVN
+ local name_version = rockspec.name .. "-" .. rockspec.version
+ local module = rockspec.source.module or dir.base_name(rockspec.source.url)
+ local url = rockspec.source.url:gsub("^svn://", "")
+ local command = {svn_cmd, "checkout", url, module}
+ if rockspec.source.tag then
+ table.insert(command, 5, "-r")
+ table.insert(command, 6, rockspec.source.tag)
+ end
+ local store_dir
+ if not dest_dir then
+ store_dir = fs.make_temp_dir(name_version)
+ if not store_dir then
+ return nil, "Failed creating temporary directory."
+ end
+ util.schedule_function(fs.delete, store_dir)
+ else
+ store_dir = dest_dir
+ end
+ fs.change_dir(store_dir)
+ if not fs.execute(unpack(command)) then
+ return nil, "Failed fetching files from Subversion."
+ end
+ fs.change_dir(module)
+ for _, d in ipairs(fs.find(".")) do
+ if dir.base_name(d) == ".svn" then
+ fs.delete(dir.path(store_dir, module, d))
+ end
+ end
+ fs.pop_dir()
+ fs.pop_dir()
+ return module, store_dir
+end
+
diff --git a/src/luarocks/fs.lua b/src/luarocks/fs.lua
new file mode 100644
index 0000000..467b194
--- /dev/null
+++ b/src/luarocks/fs.lua
@@ -0,0 +1,40 @@
+
+--- Proxy module for filesystem and platform abstractions.
+-- All code using "fs" code should require "luarocks.fs",
+-- and not the various platform-specific implementations.
+-- However, see the documentation of the implementation
+-- for the API reference.
+
+local pairs = pairs
+
+module("luarocks.fs", package.seeall)
+
+local cfg = require("luarocks.cfg")
+
+local function load_fns(fs_table)
+ for name, fn in pairs(fs_table) do
+ if not _M[name] then
+ _M[name] = fn
+ end
+ end
+end
+
+-- Load platform-specific functions
+local loaded_platform = nil
+for _, platform in ipairs(cfg.platforms) do
+ local ok, fs_plat = pcall(require, "luarocks.fs."..platform)
+ if ok and fs_plat then
+ loaded_platform = platform
+ load_fns(fs_plat)
+ break
+ end
+end
+
+-- Load platform-independent pure-Lua functionality
+local fs_lua = require("luarocks.fs.lua")
+load_fns(fs_lua)
+
+-- Load platform-specific fallbacks for missing Lua modules
+local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools")
+if ok and fs_plat_tools then load_fns(fs_plat_tools) end
+
diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua
new file mode 100644
index 0000000..36b3369
--- /dev/null
+++ b/src/luarocks/fs/lua.lua
@@ -0,0 +1,698 @@
+
+--- Native Lua implementation of filesystem and platform abstractions,
+-- using LuaFileSystem, LZLib, MD5 and LuaCurl.
+module("luarocks.fs.lua", package.seeall)
+
+local fs = require("luarocks.fs")
+
+local cfg = require("luarocks.cfg")
+local dir = require("luarocks.dir")
+local util = require("luarocks.util")
+local path = require("luarocks.path")
+
+local socket_ok, zip_ok, unzip_ok, lfs_ok, md5_ok, posix_ok, _
+local http, ftp, lrzip, luazip, lfs, md5, posix
+
+if cfg.fs_use_modules then
+ socket_ok, http = pcall(require, "socket.http")
+ _, ftp = pcall(require, "socket.ftp")
+ zip_ok, lrzip = pcall(require, "luarocks.tools.zip")
+ unzip_ok, luazip = pcall(require, "zip"); _G.zip = nil
+ lfs_ok, lfs = pcall(require, "lfs")
+ md5_ok, md5 = pcall(require, "md5")
+ posix_ok, posix = pcall(require, "posix")
+end
+
+local patch = require("luarocks.tools.patch")
+
+local dir_stack = {}
+
+math.randomseed(os.time())
+
+dir_separator = "/"
+
+--- Quote argument for shell processing.
+-- Adds single quotes and escapes.
+-- @param arg string: Unquoted argument.
+-- @return string: Quoted argument.
+function Q(arg)
+ assert(type(arg) == "string")
+
+ -- FIXME Unix-specific
+ return "'" .. arg:gsub("\\", "\\\\"):gsub("'", "'\\''") .. "'"
+end
+
+--- Test is file/dir is writable.
+-- Warning: testing if a file/dir is writable does not guarantee
+-- that it will remain writable and therefore it is no replacement
+-- for checking the result of subsequent operations.
+-- @param file string: filename to test
+-- @return boolean: true if file exists, false otherwise.
+function is_writable(file)
+ assert(file)
+ file = dir.normalize(file)
+ local result
+ if fs.is_dir(file) then
+ local file2 = dir.path(file, '.tmpluarockstestwritable')
+ local fh = io.open(file2, 'wb')
+ result = fh ~= nil
+ if fh then fh:close() end
+ os.remove(file2)
+ else
+ local fh = io.open(file, 'r+b')
+ result = fh ~= nil
+ if fh then fh:close() end
+ end
+ return result
+end
+
+--- Create a temporary directory.
+-- @param name string: name pattern to use for avoiding conflicts
+-- when creating temporary directory.
+-- @return string or nil: name of temporary directory or nil on failure.
+function make_temp_dir(name)
+ assert(type(name) == "string")
+ name = dir.normalize(name)
+
+ local temp_dir = (os.getenv("TMP") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000))
+ if fs.make_dir(temp_dir) then
+ return temp_dir
+ else
+ return nil
+ end
+end
+
+--- Run the given command, quoting its arguments.
+-- The command is executed in the current directory in the dir stack.
+-- @param command string: The command to be executed. No quoting/escaping
+-- is applied.
+-- @param ... Strings containing additional arguments, which are quoted.
+-- @return boolean: true if command succeeds (status code 0), false
+-- otherwise.
+function execute(command, ...)
+ assert(type(command) == "string")
+
+ for _, arg in ipairs({...}) do
+ assert(type(arg) == "string")
+ command = command .. " " .. fs.Q(arg)
+ end
+ return fs.execute_string(command)
+end
+
+--- Check the MD5 checksum for a file.
+-- @param file string: The file to be checked.
+-- @param md5sum string: The string with the expected MD5 checksum.
+-- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false if not
+-- or if it could not perform the check for any reason.
+function check_md5(file, md5sum)
+ file = dir.normalize(file)
+ local computed = fs.get_md5(file)
+ if not computed then
+ return false
+ end
+ if computed:match("^"..md5sum) then
+ return true
+ else
+ return false
+ end
+end
+
+---------------------------------------------------------------------
+-- LuaFileSystem functions
+---------------------------------------------------------------------
+
+if lfs_ok then
+
+--- Run the given command.
+-- The command is executed in the current directory in the dir stack.
+-- @param cmd string: No quoting/escaping is applied to the command.
+-- @return boolean: true if command succeeds (status code 0), false
+-- otherwise.
+function execute_string(cmd)
+ if cfg.verbose then print("Executing: "..cmd) end
+ local code = os.execute(cmd)
+ if code == 0 or code == true then
+ return true
+ else
+ return false
+ end
+end
+
+--- Obtain current directory.
+-- Uses the module's internal dir stack.
+-- @return string: the absolute pathname of the current directory.
+function current_dir()
+ return lfs.currentdir()
+end
+
+--- Change the current directory.
+-- Uses the module's internal dir stack. This does not have exact
+-- semantics of chdir, as it does not handle errors the same way,
+-- but works well for our purposes for now.
+-- @param d string: The directory to switch to.
+function change_dir(d)
+ table.insert(dir_stack, lfs.currentdir())
+ d = dir.normalize(d)
+ lfs.chdir(d)
+end
+
+--- Change directory to root.
+-- Allows leaving a directory (e.g. for deleting it) in
+-- a crossplatform way.
+function change_dir_to_root()
+ table.insert(dir_stack, lfs.currentdir())
+ lfs.chdir("/") -- works on Windows too
+end
+
+--- Change working directory to the previous in the dir stack.
+-- @return true if a pop ocurred, false if the stack was empty.
+function pop_dir()
+ local d = table.remove(dir_stack)
+ if d then
+ lfs.chdir(d)
+ return true
+ else
+ return false
+ end
+end
+
+--- Create a directory if it does not already exist.
+-- If any of the higher levels in the path name does not exist
+-- too, they are created as well.
+-- @param directory string: pathname of directory to create.
+-- @return boolean: true on success, false on failure.
+function make_dir(directory)
+ assert(type(directory) == "string")
+ directory = dir.normalize(directory)
+ local path = nil
+ if directory:sub(2, 2) == ":" then
+ path = directory:sub(1, 2)
+ directory = directory:sub(4)
+ else
+ if directory:match("^/") then
+ path = ""
+ end
+ end
+ for d in directory:gmatch("([^"..dir.separator.."]+)"..dir.separator.."*") do
+ path = path and path .. dir.separator .. d or d
+ local mode = lfs.attributes(path, "mode")
+ if not mode then
+ if not lfs.mkdir(path) then
+ return false
+ end
+ elseif mode ~= "directory" then
+ return false
+ end
+ end
+ return true
+end
+
+--- Remove a directory if it is empty.
+-- Does not return errors (for example, if directory is not empty or
+-- if already does not exist)
+-- @param d string: pathname of directory to remove.
+function remove_dir_if_empty(d)
+ assert(d)
+ d = dir.normalize(d)
+ lfs.rmdir(d)
+end
+
+--- Remove a directory if it is empty.
+-- Does not return errors (for example, if directory is not empty or
+-- if already does not exist)
+-- @param d string: pathname of directory to remove.
+function remove_dir_tree_if_empty(d)
+ assert(d)
+ d = dir.normalize(d)
+ for i=1,10 do
+ lfs.rmdir(d)
+ d = dir.dir_name(d)
+ end
+end
+
+--- Copy a file.
+-- @param src string: Pathname of source
+-- @param dest string: Pathname of destination
+-- @param perms string or nil: Permissions for destination file,
+-- or nil to use the source filename permissions
+-- @return boolean or (boolean, string): true on success, false on failure,
+-- plus an error message.
+function copy(src, dest, perms)
+ assert(src and dest)
+ src = dir.normalize(src)
+ dest = dir.normalize(dest)
+ local destmode = lfs.attributes(dest, "mode")
+ if destmode == "directory" then
+ dest = dir.path(dest, dir.base_name(src))
+ end
+ if not perms then perms = fs.get_permissions(src) end
+ local src_h, err = io.open(src, "rb")
+ if not src_h then return nil, err end
+ local dest_h, err = io.open(dest, "w+b")
+ if not dest_h then src_h:close() return nil, err end
+ while true do
+ local block = src_h:read(8192)
+ if not block then break end
+ dest_h:write(block)
+ end
+ src_h:close()
+ dest_h:close()
+ fs.chmod(dest, perms)
+ return true
+end
+
+--- Implementation function for recursive copy of directory contents.
+-- Assumes paths are normalized.
+-- @param src string: Pathname of source
+-- @param dest string: Pathname of destination
+-- @return boolean or (boolean, string): true on success, false on failure
+local function recursive_copy(src, dest)
+ local srcmode = lfs.attributes(src, "mode")
+
+ if srcmode == "file" then
+ local ok = fs.copy(src, dest)
+ if not ok then return false end
+ elseif srcmode == "directory" then
+ local subdir = dir.path(dest, dir.base_name(src))
+ fs.make_dir(subdir)
+ for file in lfs.dir(src) do
+ if file ~= "." and file ~= ".." then
+ local ok = recursive_copy(dir.path(src, file), subdir)
+ if not ok then return false end
+ end
+ end
+ end
+ return true
+end
+
+--- Recursively copy the contents of a directory.
+-- @param src string: Pathname of source
+-- @param dest string: Pathname of destination
+-- @return boolean or (boolean, string): true on success, false on failure,
+-- plus an error message.
+function copy_contents(src, dest)
+ assert(src and dest)
+ src = dir.normalize(src)
+ dest = dir.normalize(dest)
+ assert(lfs.attributes(src, "mode") == "directory")
+
+ for file in lfs.dir(src) do
+ if file ~= "." and file ~= ".." then
+ local ok = recursive_copy(dir.path(src, file), dest)
+ if not ok then
+ return false, "Failed copying "..src.." to "..dest
+ end
+ end
+ end
+ return true
+end
+
+--- Implementation function for recursive removal of directories.
+-- Assumes paths are normalized.
+-- @param name string: Pathname of file
+-- @return boolean or (boolean, string): true on success,
+-- or nil and an error message on failure.
+local function recursive_delete(name)
+ local mode = lfs.attributes(name, "mode")
+
+ if mode == "file" then
+ return os.remove(name)
+ elseif mode == "directory" then
+ for file in lfs.dir(name) do
+ if file ~= "." and file ~= ".." then
+ local ok, err = recursive_delete(dir.path(name, file))
+ if not ok then return nil, err end
+ end
+ end
+ local ok, err = lfs.rmdir(name)
+ if not ok then return nil, err end
+ end
+ return true
+end
+
+--- Delete a file or a directory and all its contents.
+-- @param name string: Pathname of source
+-- @return boolean: true on success, false on failure.
+function delete(name)
+ name = dir.normalize(name)
+ return recursive_delete(name) or false
+end
+
+--- List the contents of a directory.
+-- @param at string or nil: directory to list (will be the current
+-- directory if none is given).
+-- @return table: an array of strings with the filenames representing
+-- the contents of a directory.
+function list_dir(at)
+ assert(type(at) == "string" or not at)
+ if not at then
+ at = fs.current_dir()
+ end
+ at = dir.normalize(at)
+ if not fs.is_dir(at) then
+ return {}
+ end
+ local result = {}
+ for file in lfs.dir(at) do
+ if file ~= "." and file ~= ".." then
+ table.insert(result, file)
+ end
+ end
+ return result
+end
+
+--- Implementation function for recursive find.
+-- Assumes paths are normalized.
+-- @param cwd string: Current working directory in recursion.
+-- @param prefix string: Auxiliary prefix string to form pathname.
+-- @param result table: Array of strings where results are collected.
+local function recursive_find(cwd, prefix, result)
+ for file in lfs.dir(cwd) do
+ if file ~= "." and file ~= ".." then
+ local item = prefix .. file
+ table.insert(result, item)
+ local pathname = dir.path(cwd, file)
+ if lfs.attributes(pathname, "mode") == "directory" then
+ recursive_find(pathname, item..dir_separator, result)
+ end
+ end
+ end
+end
+
+--- Recursively scan the contents of a directory.
+-- @param at string or nil: directory to scan (will be the current
+-- directory if none is given).
+-- @return table: an array of strings with the filenames representing
+-- the contents of a directory.
+function find(at)
+ assert(type(at) == "string" or not at)
+ if not at then
+ at = fs.current_dir()
+ end
+ at = dir.normalize(at)
+ if not fs.is_dir(at) then
+ return {}
+ end
+ local result = {}
+ recursive_find(at, "", result)
+ return result
+end
+
+--- Test for existance of a file.
+-- @param file string: filename to test
+-- @return boolean: true if file exists, false otherwise.
+function exists(file)
+ assert(file)
+ file = dir.normalize(file)
+ return type(lfs.attributes(file)) == "table"
+end
+
+--- Test is pathname is a directory.
+-- @param file string: pathname to test
+-- @return boolean: true if it is a directory, false otherwise.
+function is_dir(file)
+ assert(file)
+ file = dir.normalize(file)
+ return lfs.attributes(file, "mode") == "directory"
+end
+
+--- Test is pathname is a regular file.
+-- @param file string: pathname to test
+-- @return boolean: true if it is a file, false otherwise.
+function is_file(file)
+ assert(file)
+ file = dir.normalize(file)
+ return lfs.attributes(file, "mode") == "file"
+end
+
+function set_time(file, time)
+ file = dir.normalize(file)
+ return lfs.touch(file, time)
+end
+
+end
+
+---------------------------------------------------------------------
+-- LuaZip functions
+---------------------------------------------------------------------
+
+if zip_ok then
+
+function zip(zipfile, ...)
+ return lrzip.zip(zipfile, ...)
+end
+
+end
+
+if unzip_ok then
+--- Uncompress files from a .zip archive.
+-- @param zipfile string: pathname of .zip archive to be extracted.
+-- @return boolean: true on success, false on failure.
+function unzip(zipfile)
+ local zipfile, err = luazip.open(zipfile)
+ if not zipfile then return nil, err end
+ local files = zipfile:files()
+ local file = files()
+ repeat
+ if file.filename:sub(#file.filename) == "/" then
+ fs.make_dir(dir.path(fs.current_dir(), file.filename))
+ else
+ local rf, err = zipfile:open(file.filename)
+ if not rf then zipfile:close(); return nil, err end
+ local contents = rf:read("*a")
+ rf:close()
+ local wf, err = io.open(dir.path(fs.current_dir(), file.filename), "wb")
+ if not wf then zipfile:close(); return nil, err end
+ wf:write(contents)
+ wf:close()
+ end
+ file = files()
+ until not file
+ zipfile:close()
+ return true
+end
+
+end
+
+---------------------------------------------------------------------
+-- LuaSocket functions
+---------------------------------------------------------------------
+
+if socket_ok then
+
+local ltn12 = require("ltn12")
+local luasec_ok, https = pcall(require, "ssl.https")
+local redirect_protocols = {
+ http = http,
+ https = luasec_ok and https,
+}
+
+local function http_request(url, http, loop_control)
+ local result = {}
+
+ local proxy = cfg.proxy
+ if type(proxy) ~= "string" then proxy = nil end
+ -- LuaSocket's http.request crashes when given URLs missing the scheme part.
+ if proxy and not proxy:find("://") then
+ proxy = "http://" .. proxy
+ end
+
+ local res, status, headers, err = http.request {
+ url = url,
+ proxy = proxy,
+ redirect = false,
+ sink = ltn12.sink.table(result),
+ headers = {
+ ["user-agent"] = cfg.user_agent.." via LuaSocket"
+ },
+ }
+ if not res then
+ return nil, status
+ elseif status == 301 or status == 302 then
+ local location = headers.location
+ if location then
+ local protocol, rest = dir.split_url(location)
+ if redirect_protocols[protocol] then
+ if not loop_control then
+ loop_control = {}
+ elseif loop_control[location] then
+ return nil, "Redirection loop -- broken URL?"
+ end
+ loop_control[url] = true
+ return http_request(location, redirect_protocols[protocol], loop_control)
+ else
+ return nil, "URL redirected to unsupported protocol - install luasec to get HTTPS support."
+ end
+ end
+ return nil, err
+ elseif status ~= 200 then
+ return nil, err
+ else
+ return table.concat(result)
+ end
+end
+
+--- Download a remote file.
+-- @param url string: URL to be fetched.
+-- @param filename string or nil: this function attempts to detect the
+-- resulting local filename of the remote file as the basename of the URL;
+-- if that is not correct (due to a redirection, for example), the local
+-- filename can be given explicitly as this second argument.
+-- @return boolean: true on success, false on failure.
+function download(url, filename)
+ assert(type(url) == "string")
+ assert(type(filename) == "string" or not filename)
+
+ filename = dir.path(fs.current_dir(), filename or dir.base_name(url))
+
+ local content, err
+ if util.starts_with(url, "http:") then
+ content, err = http_request(url, http)
+ elseif util.starts_with(url, "ftp:") then
+ content, err = ftp.get(url)
+ elseif util.starts_with(url, "https:") then
+ if luasec_ok then
+ content, err = http_request(url, https)
+ else
+ err = "Unsupported protocol - install luasec to get HTTPS support."
+ end
+ else
+ err = "Unsupported protocol"
+ end
+ if not content then
+ return false, tostring(err)
+ end
+ local file = io.open(filename, "wb")
+ if not file then return false end
+ file:write(content)
+ file:close()
+ return true
+end
+
+end
+---------------------------------------------------------------------
+-- MD5 functions
+---------------------------------------------------------------------
+
+if md5_ok then
+
+--- Get the MD5 checksum for a file.
+-- @param file string: The file to be computed.
+-- @return string: The MD5 checksum
+function get_md5(file)
+ file = fs.absolute_name(file)
+ local file = io.open(file, "rb")
+ if not file then return false end
+ local computed = md5.sumhexa(file:read("*a"))
+ file:close()
+ return computed
+end
+
+end
+
+---------------------------------------------------------------------
+-- POSIX functions
+---------------------------------------------------------------------
+
+if posix_ok then
+
+local octal_to_rwx = {
+ ["0"] = "---",
+ ["1"] = "--x",
+ ["2"] = "-w-",
+ ["3"] = "-wx",
+ ["4"] = "r--",
+ ["5"] = "r-x",
+ ["6"] = "rw-",
+ ["7"] = "rwx",
+}
+
+function chmod(file, mode)
+ -- LuaPosix (as of 5.1.15) does not support octal notation...
+ if mode:sub(1,1) == "0" then
+ local new_mode = {}
+ for c in mode:sub(2):gmatch(".") do
+ table.insert(new_mode, octal_to_rwx[c])
+ end
+ mode = table.concat(new_mode)
+ end
+ local err = posix.chmod(file, mode)
+ return err == 0
+end
+
+function get_permissions(file)
+ return posix.stat(file, "mode")
+end
+
+end
+
+---------------------------------------------------------------------
+-- Other functions
+---------------------------------------------------------------------
+
+--- Apply a patch.
+-- @param patchname string: The filename of the patch.
+-- @param patchdata string or nil: The actual patch as a string.
+function apply_patch(patchname, patchdata)
+ local p, all_ok = patch.read_patch(patchname, patchdata)
+ if not all_ok then
+ return nil, "Failed reading patch "..patchname
+ end
+ if p then
+ return patch.apply_patch(p, 1)
+ end
+end
+
+--- Move a file.
+-- @param src string: Pathname of source
+-- @param dest string: Pathname of destination
+-- @return boolean or (boolean, string): true on success, false on failure,
+-- plus an error message.
+function move(src, dest)
+ assert(src and dest)
+ if fs.exists(dest) and not fs.is_dir(dest) then
+ return false, "File already exists: "..dest
+ end
+ local ok, err = fs.copy(src, dest)
+ if not ok then
+ return false, err
+ end
+ ok = fs.delete(src)
+ if not ok then
+ return false, "Failed move: could not delete "..src.." after copy."
+ end
+ return true
+end
+
+--- Check if user has write permissions for the command.
+-- Assumes the configuration variables under cfg have been previously set up.
+-- @param flags table: the flags table passed to run() drivers.
+-- @return boolean or (boolean, string): true on success, false on failure,
+-- plus an error message.
+function check_command_permissions(flags)
+ local root_dir = path.root_dir(cfg.rocks_dir)
+ local ok = true
+ local err = ""
+ for _, dir in ipairs { cfg.rocks_dir, root_dir } do
+ if fs.exists(dir) and not fs.is_writable(dir) then
+ ok = false
+ err = "Your user does not have write permissions in " .. dir
+ break
+ end
+ end
+ local root_parent = dir.dir_name(root_dir)
+ if ok and not fs.exists(root_dir) and not fs.is_writable(root_parent) then
+ ok = false
+ err = root_dir.." does not exist and your user does not have write permissions in " .. root_parent
+ end
+ if ok then
+ return true
+ else
+ if flags["local"] then
+ err = err .. " \n-- please check your permissions."
+ else
+ err = err .. " \n-- you may want to run as a privileged user or use your local tree with --local."
+ end
+ return nil, err
+ end
+end
diff --git a/src/luarocks/fs/unix.lua b/src/luarocks/fs/unix.lua
new file mode 100644
index 0000000..cccbbd3
--- /dev/null
+++ b/src/luarocks/fs/unix.lua
@@ -0,0 +1,111 @@
+
+--- Unix implementation of filesystem and platform abstractions.
+
+local assert, type, table, io, package, math, os, ipairs =
+ assert, type, table, io, package, math, os, ipairs
+
+module("luarocks.fs.unix", package.seeall)
+
+local fs = require("luarocks.fs")
+
+local cfg = require("luarocks.cfg")
+local dir = require("luarocks.dir")
+local fs = require("luarocks.fs")
+local util = require("luarocks.util")
+
+math.randomseed(os.time())
+
+--- Annotate command string for quiet execution.
+-- @param cmd string: A command-line string.
+-- @return string: The command-line, with silencing annotation.
+function quiet(cmd)
+ return cmd.." 1> /dev/null 2> /dev/null"
+end
+
+--- Return an absolute pathname from a potentially relative one.
+-- @param pathname string: pathname to convert.
+-- @param relative_to string or nil: path to prepend when making
+-- pathname absolute, or the current dir in the dir stack if
+-- not given.
+-- @return string: The pathname converted to absolute.
+function absolute_name(pathname, relative_to)
+ assert(type(pathname) == "string")
+ assert(type(relative_to) == "string" or not relative_to)
+
+ relative_to = relative_to or fs.current_dir()
+ if pathname:sub(1,1) == "/" then
+ return pathname
+ else
+ return relative_to .. "/" .. pathname
+ end
+end
+
+--- Create a wrapper to make a script executable from the command-line.
+-- @param file string: Pathname of script to be made executable.
+-- @param dest string: Directory where to put the wrapper.
+-- @param name string: rock name to be used in loader context.
+-- @param version string: rock version to be used in loader context.
+-- @return boolean or (nil, string): True if succeeded, or nil and
+-- an error message.
+function wrap_script(file, dest, name, version)
+ assert(type(file) == "string")
+ assert(type(dest) == "string")
+
+ local base = dir.base_name(file)
+ local wrapname = fs.is_dir(dest) and dest.."/"..base or dest
+ local wrapper = io.open(wrapname, "w")
+ if not wrapper then
+ return nil, "Could not open "..wrapname.." for writing."
+ end
+ wrapper:write("#!/bin/sh\n\n")
+ wrapper:write('LUA_PATH="'..package.path..';$LUA_PATH"\n')
+ wrapper:write('LUA_CPATH="'..package.cpath..';$LUA_CPATH"\n')
+ wrapper:write('export LUA_PATH LUA_CPATH\n')
+ wrapper:write('exec "'..dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)..'" -lluarocks.loader -e\'luarocks.loader.add_context([['..name..']],[['..version..']])\' "'..file..'" "$@"\n')
+ wrapper:close()
+ if fs.chmod(wrapname, "0755") then
+ return true
+ else
+ return nil, "Could not make "..wrapname.." executable."
+ end
+end
+
+--- Check if a file (typically inside path.bin_dir) is an actual binary
+-- or a Lua wrapper.
+-- @param filename string: the file name with full path.
+-- @return boolean: returns true if file is an actual binary
+-- (or if it couldn't check) or false if it is a Lua wrapper.
+function is_actual_binary(filename)
+ if filename:match("%.lua$") then
+ return false
+ end
+ local file = io.open(filename)
+ if not file then
+ return true
+ end
+ local first = file:read(2)
+ file:close()
+ if not first then
+ util.printerr("Warning: could not read "..filename)
+ return true
+ end
+ return first ~= "#!"
+end
+
+function copy_binary(filename, dest)
+ return fs.copy(filename, dest, "0755")
+end
+
+--- Move a file on top of the other.
+-- The new file ceases to exist under its original name,
+-- and takes over the name of the old file.
+-- On Unix this is done through a single rename operation.
+-- @param old_file The name of the original file,
+-- which will be the new name of new_file.
+-- @param new_file The name of the new file,
+-- which will replace old_file.
+-- @return boolean or (nil, string): True if succeeded, or nil and
+-- an error message.
+function replace_file(old_file, new_file)
+ return os.rename(new_file, old_file)
+end
diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua
new file mode 100644
index 0000000..3b853be
--- /dev/null
+++ b/src/luarocks/fs/unix/tools.lua
@@ -0,0 +1,318 @@
+
+--- fs operations implemented with third-party tools for Unix platform abstractions.
+module("luarocks.fs.unix.tools", package.seeall)
+
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local cfg = require("luarocks.cfg")
+
+local dir_stack = {}
+
+local vars = cfg.variables
+
+local function command_at(directory, cmd)
+ return "cd " .. fs.Q(directory) .. " && " .. cmd
+end
+
+--- Obtain current directory.
+-- Uses the module's internal directory stack.
+-- @return string: the absolute pathname of the current directory.
+function current_dir()
+ local pipe = io.popen(vars.PWD)
+ local current = pipe:read("*l")
+ pipe:close()
+ for _, directory in ipairs(dir_stack) do
+ current = fs.absolute_name(directory, current)
+ end
+ return current
+end
+
+--- Run the given command.
+-- The command is executed in the current directory in the directory stack.
+-- @param cmd string: No quoting/escaping is applied to the command.
+-- @return boolean: true if command succeeds (status code 0), false
+-- otherwise.
+function execute_string(cmd)
+ local code = os.execute(command_at(fs.current_dir(), cmd))
+ if code == 0 or code == true then
+ return true
+ else
+ return false
+ end
+end
+
+--- Change the current directory.
+-- Uses the module's internal directory stack. This does not have exact
+-- semantics of chdir, as it does not handle errors the same way,
+-- but works well for our purposes for now.
+-- @param directory string: The directory to switch to.
+function change_dir(directory)
+ assert(type(directory) == "string")
+ table.insert(dir_stack, directory)
+end
+
+--- Change directory to root.
+-- Allows leaving a directory (e.g. for deleting it) in
+-- a crossplatform way.
+function change_dir_to_root()
+ table.insert(dir_stack, "/")
+end
+
+--- Change working directory to the previous in the directory stack.
+function pop_dir()
+ local directory = table.remove(dir_stack)
+ return directory ~= nil
+end
+
+--- Create a directory if it does not already exist.
+-- If any of the higher levels in the path name does not exist
+-- too, they are created as well.
+-- @param directory string: pathname of directory to create.
+-- @return boolean: true on success, false on failure.
+function make_dir(directory)
+ assert(directory)
+ return fs.execute(vars.MKDIR.." -p", directory)
+end
+
+--- Remove a directory if it is empty.
+-- Does not return errors (for example, if directory is not empty or
+-- if already does not exist)
+-- @param directory string: pathname of directory to remove.
+function remove_dir_if_empty(directory)
+ assert(directory)
+ fs.execute_string(fs.quiet(vars.RMDIR.." "..fs.Q(directory)))
+end
+
+--- Remove a directory if it is empty.
+-- Does not return errors (for example, if directory is not empty or
+-- if already does not exist)
+-- @param directory string: pathname of directory to remove.
+function remove_dir_tree_if_empty(directory)
+ assert(directory)
+ fs.execute_string(fs.quiet(vars.RMDIR.." -p "..fs.Q(directory)))
+end
+
+--- Copy a file.
+-- @param src string: Pathname of source
+-- @param dest string: Pathname of destination
+-- @param perm string or nil: Permissions for destination file,
+-- @return boolean or (boolean, string): true on success, false on failure,
+-- plus an error message.
+function copy(src, dest, perm)
+ assert(src and dest)
+ if fs.execute(vars.CP, src, dest) then
+ if perm then
+ if fs.is_dir(dest) then
+ dest = dir.path(dest, dir.base_name(src))
+ end
+ if fs.chmod(dest, perm) then
+ return true
+ else
+ return false, "Failed setting permissions of "..dest
+ end
+ end
+ return true
+ else
+ return false, "Failed copying "..src.." to "..dest
+ end
+end
+
+--- Recursively copy the contents of a directory.
+-- @param src string: Pathname of source
+-- @param dest string: Pathname of destination
+-- @return boolean or (boolean, string): true on success, false on failure,
+-- plus an error message.
+function copy_contents(src, dest)
+ assert(src and dest)
+ if fs.execute_string(fs.quiet(vars.CP.." -pPR "..fs.Q(src).."/* "..fs.Q(dest))) then
+ return true
+ else
+ return false, "Failed copying "..src.." to "..dest
+ end
+end
+--- Delete a file or a directory and all its contents.
+-- For safety, this only accepts absolute paths.
+-- @param arg string: Pathname of source
+-- @return boolean: true on success, false on failure.
+function delete(arg)
+ assert(arg)
+ assert(arg:sub(1,1) == "/")
+ return fs.execute_string(fs.quiet(vars.RM.." -rf " .. fs.Q(arg)))
+end
+
+--- List the contents of a directory.
+-- @param at string or nil: directory to list (will be the current
+-- directory if none is given).
+-- @return table: an array of strings with the filenames representing
+-- the contents of a directory.
+function list_dir(at)
+ assert(type(at) == "string" or not at)
+ if not at then
+ at = fs.current_dir()
+ end
+ if not fs.is_dir(at) then
+ return {}
+ end
+ local result = {}
+ local pipe = io.popen(command_at(at, vars.LS))
+ for file in pipe:lines() do
+ table.insert(result, file)
+ end
+ pipe:close()
+ return result
+end
+
+--- Recursively scan the contents of a directory.
+-- @param at string or nil: directory to scan (will be the current
+-- directory if none is given).
+-- @return table: an array of strings with the filenames representing
+-- the contents of a directory.
+function find(at)
+ assert(type(at) == "string" or not at)
+ if not at then
+ at = fs.current_dir()
+ end
+ if not fs.is_dir(at) then
+ return {}
+ end
+ local result = {}
+ local pipe = io.popen(command_at(at, vars.FIND.." * 2>/dev/null"))
+ for file in pipe:lines() do
+ table.insert(result, file)
+ end
+ pipe:close()
+ return result
+end
+
+--- Compress files in a .zip archive.
+-- @param zipfile string: pathname of .zip archive to be created.
+-- @param ... Filenames to be stored in the archive are given as
+-- additional arguments.
+-- @return boolean: true on success, false on failure.
+function zip(zipfile, ...)
+ return fs.execute(vars.ZIP.." -r", zipfile, ...)
+end
+
+--- Uncompress files from a .zip archive.
+-- @param zipfile string: pathname of .zip archive to be extracted.
+-- @return boolean: true on success, false on failure.
+function unzip(zipfile)
+ assert(zipfile)
+ return fs.execute(vars.UNZIP, zipfile)
+end
+
+--- Test is file/directory exists
+-- @param file string: filename to test
+-- @return boolean: true if file exists, false otherwise.
+function exists(file)
+ assert(file)
+ return fs.execute(vars.TEST, "-e", file)
+end
+
+--- Test is pathname is a directory.
+-- @param file string: pathname to test
+-- @return boolean: true if it is a directory, false otherwise.
+function is_dir(file)
+ assert(file)
+ return fs.execute(vars.TEST, "-d", file)
+end
+
+--- Test is pathname is a regular file.
+-- @param file string: pathname to test
+-- @return boolean: true if it is a regular file, false otherwise.
+function is_file(file)
+ assert(file)
+ return fs.execute(vars.TEST, "-f", file)
+end
+
+--- Download a remote file.
+-- @param url string: URL to be fetched.
+-- @param filename string or nil: this function attempts to detect the
+-- resulting local filename of the remote file as the basename of the URL;
+-- if that is not correct (due to a redirection, for example), the local
+-- filename can be given explicitly as this second argument.
+-- @return boolean: true on success, false on failure.
+function download(url, filename)
+ assert(type(url) == "string")
+ assert(type(filename) == "string" or not filename)
+
+ if cfg.downloader == "wget" then
+ local wget_cmd = vars.WGET.." --no-check-certificate --no-cache --user-agent='"..cfg.user_agent.." via wget' --quiet --continue "
+ if filename then
+ return fs.execute(wget_cmd.." --output-document ", filename, url)
+ else
+ return fs.execute(wget_cmd, url)
+ end
+ elseif cfg.downloader == "curl" then
+ filename = filename or dir.base_name(url)
+ return fs.execute_string(vars.CURL.." -L --user-agent '"..cfg.user_agent.." via curl' "..fs.Q(url).." 2> /dev/null 1> "..fs.Q(filename))
+ end
+end
+
+function chmod(pathname, mode)
+ if mode then
+ return fs.execute(vars.CHMOD, mode, pathname)
+ else
+ return false
+ end
+end
+
+--- Apply a patch.
+-- @param patchname string: The filename of the patch.
+function apply_patch(patchname)
+ return fs.execute(vars.PATCH.." -p1 -f -i ", patchname)
+end
+
+--- Unpack an archive.
+-- Extract the contents of an archive, detecting its format by
+-- filename extension.
+-- @param archive string: Filename of archive.
+-- @return boolean or (boolean, string): true on success, false and an error message on failure.
+function unpack_archive(archive)
+ assert(type(archive) == "string")
+
+ local ok
+ if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then
+ ok = fs.execute_string(vars.GUNZIP.." -c "..archive.."|"..vars.TAR.." -xf -")
+ elseif archive:match("%.tar%.bz2$") then
+ ok = fs.execute_string(vars.BUNZIP2.." -c "..archive.."|tar -xf -")
+ elseif archive:match("%.zip$") then
+ ok = fs.execute(vars.UNZIP, archive)
+ elseif archive:match("%.lua$") or archive:match("%.c$") then
+ -- Ignore .lua and .c files; they don't need to be extracted.
+ return true
+ else
+ local ext = archive:match(".*(%..*)")
+ return false, "Unrecognized filename extension "..(ext or "")
+ end
+ if not ok then
+ return false, "Failed extracting "..archive
+ end
+ return true
+end
+
+local md5_cmd = {
+ md5sum = vars.MD5SUM,
+ openssl = vars.OPENSSL.." md5",
+ md5 = vars.MD5,
+}
+
+--- Get the MD5 checksum for a file.
+-- @param file string: The file to be computed.
+-- @return string: The MD5 checksum
+function get_md5(file)
+ local cmd = md5_cmd[cfg.md5checker]
+ if not cmd then return nil end
+ local pipe = io.popen(cmd.." "..fs.absolute_name(file))
+ local computed = pipe:read("*a")
+ pipe:close()
+ if not computed then return nil end
+ return computed:match("("..("%x"):rep(32)..")")
+end
+
+function get_permissions(filename)
+ local pipe = io.popen(vars.STAT.." "..vars.STATFLAG.." "..fs.Q(filename))
+ local ret = pipe:read("*l")
+ pipe:close()
+ return ret
+end
diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua
new file mode 100644
index 0000000..2b5bb95
--- /dev/null
+++ b/src/luarocks/fs/win32.lua
@@ -0,0 +1,133 @@
+--- Windows implementation of filesystem and platform abstractions.
+-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities
+-- used by this module.
+module("luarocks.fs.win32", package.seeall)
+
+local fs = require("luarocks.fs")
+
+local cfg = require("luarocks.cfg")
+local dir = require("luarocks.dir")
+
+--- Annotate command string for quiet execution.
+-- @param cmd string: A command-line string.
+-- @return string: The command-line, with silencing annotation.
+function quiet(cmd)
+ return cmd.." 2> NUL 1> NUL"
+end
+
+--- Quote argument for shell processing. Fixes paths on Windows.
+-- Adds single quotes and escapes.
+-- @param arg string: Unquoted argument.
+-- @return string: Quoted argument.
+function Q(arg)
+ assert(type(arg) == "string")
+ -- Quote DIR for Windows
+ if arg:match("^[%.a-zA-Z]?:?[\\/]") then
+ return '"' .. arg:gsub("/", "\\"):gsub('"', '\\"') .. '"'
+ end
+ -- URLs and anything else
+ return '"' .. arg:gsub('"', '\\"') .. '"'
+end
+
+--- Return an absolute pathname from a potentially relative one.
+-- @param pathname string: pathname to convert.
+-- @param relative_to string or nil: path to prepend when making
+-- pathname absolute, or the current dir in the dir stack if
+-- not given.
+-- @return string: The pathname converted to absolute.
+function absolute_name(pathname, relative_to)
+ assert(type(pathname) == "string")
+ assert(type(relative_to) == "string" or not relative_to)
+
+ relative_to = relative_to or fs.current_dir()
+ -- FIXME I'm not sure this first \\ should be there at all.
+ -- What are the Windows rules for drive letters?
+ if pathname:match("^[\\.a-zA-Z]?:?[\\/]") then
+ return pathname
+ else
+ return relative_to .. "/" .. pathname
+ end
+end
+
+--- Create a wrapper to make a script executable from the command-line.
+-- @param file string: Pathname of script to be made executable.
+-- @param dest string: Directory where to put the wrapper.
+-- @param name string: rock name to be used in loader context.
+-- @param version string: rock version to be used in loader context.
+-- @return boolean or (nil, string): True if succeeded, or nil and
+-- an error message.
+function wrap_script(file, dest, name, version)
+ assert(type(file) == "string")
+ assert(type(dest) == "string")
+
+ local base = dir.base_name(file)
+ local wrapname = fs.is_dir(dest) and dest.."/"..base or dest
+ wrapname = wrapname..".bat"
+ local wrapper = io.open(wrapname, "w")
+ if not wrapper then
+ return nil, "Could not open "..wrapname.." for writing."
+ end
+ wrapper:write("@echo off\n")
+ wrapper:write("setlocal\n")
+ wrapper:write('set LUA_PATH='..package.path..";%LUA_PATH%\n")
+ wrapper:write('set LUA_CPATH='..package.cpath..";%LUA_CPATH%\n")
+ wrapper:write('"'..dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)..'" -lluarocks.loader -e\'luarocks.loader.add_context([['..name..']],[['..version..']])\' "'..file..'" %*\n')
+ wrapper:write("endlocal\n")
+ wrapper:close()
+ return true
+end
+
+function is_actual_binary(name)
+ name = name:lower()
+ if name:match("%.bat$") or name:match("%.exe$") then
+ return true
+ end
+ return false
+end
+
+function copy_binary(filename, dest)
+ local ok, err = fs.copy(filename, dest)
+ if not ok then
+ return nil, err
+ end
+ local exe_pattern = "%.[Ee][Xx][Ee]$"
+ local base = dir.base_name(filename)
+ local dest = dir.dir_name(dest)
+ if base:match(exe_pattern) then
+ base = base:gsub(exe_pattern, ".lua")
+ local helpname = dest.."/"..base
+ local helper = io.open(helpname, "w")
+ if not helper then
+ return nil, "Could not open "..helpname.." for writing."
+ end
+ helper:write('package.path=\"'..package.path:gsub("\\","\\\\")..';\"..package.path\n')
+ helper:write('package.cpath=\"'..package.path:gsub("\\","\\\\")..';\"..package.cpath\n')
+ helper:close()
+ end
+ return true
+end
+
+function chmod(filename, mode)
+ return true
+end
+
+function get_permissions(filename)
+ return ""
+end
+
+--- Move a file on top of the other.
+-- The new file ceases to exist under its original name,
+-- and takes over the name of the old file.
+-- On Windows this is done by removing the original file and
+-- renaming the new file to its original name.
+-- @param old_file The name of the original file,
+-- which will be the new name of new_file.
+-- @param new_file The name of the new file,
+-- which will replace old_file.
+-- @return boolean or (nil, string): True if succeeded, or nil and
+-- an error message.
+function replace_file(old_file, new_file)
+ os.remove(old_file)
+ return os.rename(new_file, old_file)
+end
+
diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua
new file mode 100644
index 0000000..1af1dd9
--- /dev/null
+++ b/src/luarocks/fs/win32/tools.lua
@@ -0,0 +1,346 @@
+
+--- fs operations implemented with third-party tools for Windows platform abstractions.
+-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities
+-- used by this module.
+module("luarocks.fs.win32.tools", package.seeall)
+
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local cfg = require("luarocks.cfg")
+
+local dir_stack = {}
+
+local vars = cfg.variables
+
+local function pack(...)
+ return { n = select("#", ...), ... }
+end
+
+--- Strip the last extension of a filename.
+-- Example: "foo.tar.gz" becomes "foo.tar".
+-- If filename has no dots, returns it unchanged.
+-- @param filename string: The file name to strip.
+-- @return string: The stripped name.
+local function strip_extension(filename)
+ assert(type(filename) == "string")
+
+ return (filename:gsub("%.[^.]+$", "")) or filename
+end
+
+local function command_at(directory, cmd)
+ local drive = directory:match("^([A-Za-z]:)")
+ cmd = "cd " .. fs.Q(directory) .. " & " .. cmd
+ if drive then
+ cmd = drive .. " & " .. cmd
+ end
+ return cmd
+end
+
+--- Obtain current directory.
+-- Uses the module's internal directory stack.
+-- @return string: the absolute pathname of the current directory.
+function current_dir()
+ local pipe = io.popen(vars.PWD)
+ local current = pipe:read("*l")
+ pipe:close()
+ for _, directory in ipairs(dir_stack) do
+ current = fs.absolute_name(directory, current)
+ end
+ return current
+end
+
+--- Run the given command.
+-- The command is executed in the current directory in the directory stack.
+-- @param cmd string: No quoting/escaping is applied to the command.
+-- @return boolean: true if command succeeds (status code 0), false
+-- otherwise.
+function execute_string(cmd)
+ cmd = command_at(fs.current_dir(), cmd)
+ if cfg.verbose then print("Executing: "..tostring(cmd)) end
+ local code = pack(os.execute(cmd))
+ if cfg.verbose then
+ print("Results: "..tostring(code.n))
+ for i = 1,code.n do
+ print(" "..tostring(i).." ("..type(code[i]).."): "..tostring(code[i]))
+ end
+ print()
+ end
+ if code[1] == 0 or code[1] == true then
+ return true
+ else
+ return false
+ end
+end
+
+--- Change the current directory.
+-- Uses the module's internal directory stack. This does not have exact
+-- semantics of chdir, as it does not handle errors the same way,
+-- but works well for our purposes for now.
+-- @param directory string: The directory to switch to.
+function change_dir(directory)
+ assert(type(directory) == "string")
+ table.insert(dir_stack, directory)
+end
+
+--- Change directory to root.
+-- Allows leaving a directory (e.g. for deleting it) in
+-- a crossplatform way.
+function change_dir_to_root()
+ table.insert(dir_stack, "/")
+end
+
+--- Change working directory to the previous in the directory stack.
+function pop_dir()
+ local directory = table.remove(dir_stack)
+ return directory ~= nil
+end
+
+--- Create a directory if it does not already exist.
+-- If any of the higher levels in the path name does not exist
+-- too, they are created as well.
+-- @param directory string: pathname of directory to create.
+-- @return boolean: true on success, false on failure.
+function make_dir(directory)
+ assert(directory)
+ fs.execute(fs.quiet(vars.MKDIR.." "..fs.Q(directory)))
+ return 1
+end
+
+--- Remove a directory if it is empty.
+-- Does not return errors (for example, if directory is not empty or
+-- if already does not exist)
+-- @param directory string: pathname of directory to remove.
+function remove_dir_if_empty(directory)
+ assert(directory)
+ fs.execute_string(fs.quiet(vars.RMDIR.." "..fs.Q(directory)))
+end
+
+--- Remove a directory if it is empty.
+-- Does not return errors (for example, if directory is not empty or
+-- if already does not exist)
+-- @param directory string: pathname of directory to remove.
+function remove_dir_tree_if_empty(directory)
+ assert(directory)
+ fs.execute_string(fs.quiet(vars.RMDIR.." "..fs.Q(directory)))
+end
+
+--- Copy a file.
+-- @param src string: Pathname of source
+-- @param dest string: Pathname of destination
+-- @return boolean or (boolean, string): true on success, false on failure,
+-- plus an error message.
+function copy(src, dest)
+ assert(src and dest)
+ if dest:match("[/\\]$") then dest = dest:sub(1, -2) end
+ if fs.execute(vars.CP, src, dest) then
+ return true
+ else
+ return false, "Failed copying "..src.." to "..dest
+ end
+end
+
+--- Recursively copy the contents of a directory.
+-- @param src string: Pathname of source
+-- @param dest string: Pathname of destination
+-- @return boolean or (boolean, string): true on success, false on failure,
+-- plus an error message.
+function copy_contents(src, dest)
+ assert(src and dest)
+ if fs.execute_string(fs.quiet(vars.CP.." -dR "..src.."\\*.* "..fs.Q(dest))) then
+ return true
+ else
+ return false, "Failed copying "..src.." to "..dest
+ end
+end
+
+--- Delete a file or a directory and all its contents.
+-- For safety, this only accepts absolute paths.
+-- @param arg string: Pathname of source
+-- @return boolean: true on success, false on failure.
+function delete(arg)
+ assert(arg)
+ assert(arg:match("^[\a-zA-Z]?:?[\\/]"))
+ fs.execute(vars.CHMOD.." a+rw -R ", arg)
+ return fs.execute_string(fs.quiet(vars.RM.." -rf " .. fs.Q(arg)))
+end
+
+--- List the contents of a directory.
+-- @param at string or nil: directory to list (will be the current
+-- directory if none is given).
+-- @return table: an array of strings with the filenames representing
+-- the contents of a directory.
+function list_dir(at)
+ assert(type(at) == "string" or not at)
+ if not at then
+ at = fs.current_dir()
+ end
+ if not fs.is_dir(at) then
+ return {}
+ end
+ local result = {}
+ local pipe = io.popen(command_at(at, vars.LS))
+ for file in pipe:lines() do
+ table.insert(result, file)
+ end
+ pipe:close()
+
+ return result
+end
+
+--- Recursively scan the contents of a directory.
+-- @param at string or nil: directory to scan (will be the current
+-- directory if none is given).
+-- @return table: an array of strings with the filenames representing
+-- the contents of a directory. Paths are returned with forward slashes.
+function find(at)
+ assert(type(at) == "string" or not at)
+ if not at then
+ at = fs.current_dir()
+ end
+ if not fs.is_dir(at) then
+ return {}
+ end
+ local result = {}
+ local pipe = io.popen(command_at(at, vars.FIND.." 2> NUL"))
+ for file in pipe:lines() do
+ -- Windows find is a bit different
+ local first_two = file:sub(1,2)
+ if first_two == ".\\" or first_two == "./" then file=file:sub(3) end
+ if file ~= "." then
+ table.insert(result, (file:gsub("\\", "/")))
+ end
+ end
+ pipe:close()
+ return result
+end
+
+--- Compress files in a .zip archive.
+-- @param zipfile string: pathname of .zip archive to be created.
+-- @param ... Filenames to be stored in the archive are given as
+-- additional arguments.
+-- @return boolean: true on success, false on failure.
+function zip(zipfile, ...)
+ return fs.execute(vars.SEVENZ.." a -tzip", zipfile, ...)
+end
+
+--- Uncompress files from a .zip archive.
+-- @param zipfile string: pathname of .zip archive to be extracted.
+-- @return boolean: true on success, false on failure.
+function unzip(zipfile)
+ assert(zipfile)
+ return fs.execute(vars.SEVENZ.." x", zipfile)
+end
+
+--- Test is pathname is a directory.
+-- @param file string: pathname to test
+-- @return boolean: true if it is a directory, false otherwise.
+function is_dir(file)
+ assert(file)
+ return fs.execute(fs.quiet(vars.TEST.." -d " .. fs.Q(file)))
+end
+
+--- Test is pathname is a regular file.
+-- @param file string: pathname to test
+-- @return boolean: true if it is a regular file, false otherwise.
+function is_file(file)
+ assert(file)
+ return fs.execute(vars.TEST.." -f", file)
+end
+
+--- Download a remote file.
+-- @param url string: URL to be fetched.
+-- @param filename string or nil: this function attempts to detect the
+-- resulting local filename of the remote file as the basename of the URL;
+-- if that is not correct (due to a redirection, for example), the local
+-- filename can be given explicitly as this second argument.
+-- @return boolean: true on success, false on failure.
+function download(url, filename)
+ assert(type(url) == "string")
+ assert(type(filename) == "string" or not filename)
+
+ if cfg.downloader == "wget" then
+ local wget_cmd = vars.WGET.." --no-check-certificate --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet --continue "
+ if filename then
+ return fs.execute(wget_cmd.." --output-document ", filename, url)
+ else
+ return fs.execute(wget_cmd, url)
+ end
+ elseif cfg.downloader == "curl" then
+ filename = filename or dir.base_name(url)
+ return fs.execute_string(vars.CURL.." -L --user-agent \""..cfg.user_agent.." via curl\" "..fs.Q(url).." 2> NUL 1> "..fs.Q(filename))
+ end
+end
+
+--- Uncompress gzip file.
+-- @param archive string: Filename of archive.
+-- @return boolean : success status
+local function gunzip(archive)
+ return fs.execute(vars.SEVENZ.." x", archive)
+end
+
+--- Unpack an archive.
+-- Extract the contents of an archive, detecting its format by
+-- filename extension.
+-- @param archive string: Filename of archive.
+-- @return boolean or (boolean, string): true on success, false and an error message on failure.
+function unpack_archive(archive)
+ assert(type(archive) == "string")
+
+ local ok
+ local sevenzx = vars.SEVENZ.." x"
+ if archive:match("%.tar%.gz$") then
+ ok = gunzip(archive)
+ if ok then
+ ok = fs.execute(sevenzx, strip_extension(archive))
+ end
+ elseif archive:match("%.tgz$") then
+ ok = gunzip(archive)
+ if ok then
+ ok = fs.execute(sevenzx, strip_extension(archive)..".tar")
+ end
+ elseif archive:match("%.tar%.bz2$") then
+ ok = fs.execute(sevenzx, archive)
+ if ok then
+ ok = fs.execute(sevenzx, strip_extension(archive))
+ end
+ elseif archive:match("%.zip$") then
+ ok = fs.execute(sevenzx, archive)
+ elseif archive:match("%.lua$") or archive:match("%.c$") then
+ -- Ignore .lua and .c files; they don't need to be extracted.
+ return true
+ else
+ local ext = archive:match(".*(%..*)")
+ return false, "Unrecognized filename extension "..(ext or "")
+ end
+ if not ok then
+ return false, "Failed extracting "..archive
+ end
+ return true
+end
+
+local md5_cmd = {
+ md5sum = vars.MD5SUM,
+ openssl = vars.OPENSSL.." md5",
+ md5 = vars.MD5,
+}
+
+--- Get the MD5 checksum for a file.
+-- @param file string: The file to be computed.
+-- @return string: The MD5 checksum
+function get_md5(file)
+ local cmd = md5_cmd[cfg.md5checker]
+ if not cmd then return nil end
+ local pipe = io.popen(cmd.." "..fs.absolute_name(file))
+ local computed = pipe:read("*a")
+ pipe:close()
+ if not computed then return nil end
+ return computed:match("("..("%x"):rep(32)..")")
+end
+
+--- Test for existance of a file.
+-- @param file string: filename to test
+-- @return boolean: true if file exists, false otherwise.
+function exists(file)
+ assert(file)
+ return fs.execute(fs.quiet("if not exist " .. fs.Q(file) .. " invalidcommandname"))
+end
diff --git a/src/luarocks/help.lua b/src/luarocks/help.lua
new file mode 100644
index 0000000..2944dfd
--- /dev/null
+++ b/src/luarocks/help.lua
@@ -0,0 +1,107 @@
+
+--- Module implementing the LuaRocks "help" command.
+-- This is a generic help display module, which
+-- uses a global table called "commands" to find commands
+-- to show help for; each command should be represented by a
+-- table containing "help" and "help_summary" fields.
+module("luarocks.help", package.seeall)
+
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+
+local program = util.this_program("luarocks")
+
+help_summary = "Help on commands. Type '"..program.." help <command>' for more."
+
+help_arguments = "[<command>]"
+help = [[
+<command> is the command to show help for.
+]]
+
+local function print_banner()
+ util.printout("\nLuaRocks "..cfg.program_version..", a module deployment system for Lua")
+end
+
+local function print_section(section)
+ util.printout("\n"..section)
+end
+
+local function get_status(status)
+ if status then
+ return "ok"
+ elseif status == false then
+ return "not found"
+ else
+ return "failed"
+ end
+end
+
+--- Driver function for the "help" command.
+-- @param command string or nil: command to show help for; if not
+-- given, help summaries for all commands are shown.
+-- @return boolean or (nil, string): true if there were no errors
+-- or nil and an error message if an invalid command was requested.
+function run(...)
+ local flags, command = util.parse_flags(...)
+
+ if not command then
+ local sys_file, sys_ok, home_file, home_ok = cfg.which_config()
+ print_banner()
+ print_section("NAME")
+ util.printout("\t"..program..[[ - ]]..program_description)
+ print_section("SYNOPSIS")
+ util.printout("\t"..program..[[ [--from=<server> | --only-from=<server>] [--to=<tree>] [VAR=VALUE]... <command> [<argument>] ]])
+ print_section("GENERAL OPTIONS")
+ util.printout([[
+ These apply to all commands, as appropriate:
+
+ --server=<server> Fetch rocks/rockspecs from this server
+ (takes priority over config file)
+ --only-server=<server> Fetch rocks/rockspecs from this server only
+ (overrides any entries in the config file)
+ --only-sources=<url> Restrict downloads to paths matching the
+ given URL.
+ --tree=<tree> Which tree to operate on.
+ --local Use the tree in the user's home directory.
+ To enable it, see ']]..program..[[ help path'.]])
+ print_section("VARIABLES")
+ util.printout([[
+ Variables from the "variables" table of the configuration file
+ can be overriden with VAR=VALUE assignments.]])
+ print_section("COMMANDS")
+ local names = {}
+ for name, command in pairs(commands) do
+ table.insert(names, name)
+ end
+ table.sort(names)
+ for _, name in ipairs(names) do
+ local command = commands[name]
+ util.printout("", name)
+ util.printout("\t", command.help_summary)
+ end
+ print_section("CONFIGURATION")
+ util.printout("\tSystem configuration file: ".. sys_file .. " (" .. get_status(sys_ok) ..")")
+ if home_file then
+ util.printout("\tUser configuration file: ".. home_file .. " (" .. get_status(home_ok) ..")\n")
+ else
+ util.printout("\tUser configuration file disabled in this LuaRocks installation.\n")
+ end
+ else
+ command = command:gsub("-", "_")
+ if commands[command] then
+ local arguments = commands[command].help_arguments or "<argument>"
+ print_banner()
+ print_section("NAME")
+ util.printout("\t"..program.." "..command.." - "..commands[command].help_summary)
+ print_section("SYNOPSIS")
+ util.printout("\t"..program.." "..command.." "..arguments)
+ print_section("DESCRIPTION")
+ util.printout("",(commands[command].help:gsub("\n","\n\t"):gsub("\n\t$","")))
+ print_section("SEE ALSO")
+ util.printout("","'"..program.." help' for general options and configuration.\n")
+ else
+ return nil, "Unknown command '"..command.."'"
+ end
+ end
+ return true
+end
diff --git a/src/luarocks/index.lua b/src/luarocks/index.lua
new file mode 100644
index 0000000..e1391cc
--- /dev/null
+++ b/src/luarocks/index.lua
@@ -0,0 +1,172 @@
+
+--- Module which builds the index.html page to be used in rocks servers.
+module("luarocks.index", package.seeall)
+
+local util = require("luarocks.util")
+local fs = require("luarocks.fs")
+local deps = require("luarocks.deps")
+local persist = require("luarocks.persist")
+local dir = require("luarocks.dir")
+local manif = require("luarocks.manif")
+
+local ext_url_target = ' target="_blank"'
+
+local index_header = [[
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<title>Available rocks</title>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<style>
+body {
+ background-color: white;
+ font-family: "bitstream vera sans", "verdana", "sans";
+ font-size: 14px;
+}
+a {
+ color: #0000c0;
+ text-decoration: none;
+}
+a:hover {
+ text-decoration: underline;
+}
+td.main {
+ border-style: none;
+}
+blockquote {
+ font-size: 12px;
+}
+td.package {
+ background-color: #f0f0f0;
+ vertical-align: top;
+}
+td.spacer {
+ height: 5px;
+}
+td.version {
+ background-color: #d0d0d0;
+ vertical-align: top;
+ text-align: left;
+ padding: 5px;
+ width: 100px;
+}
+p.manifest {
+ font-size: 8px;
+}
+</style>
+</head>
+<body>
+<h1>Available rocks</h1>
+<p>
+Lua modules available from this location for use with <a href="http://www.luarocks.org">LuaRocks</a>:
+</p>
+<table class="main">
+]]
+
+local index_package_start = [[
+<td class="package">
+<p><a name="$anchor"></a><b>$package</b> - $summary<br/>
+</p><blockquote><p>$detailed<br/>
+$externaldependencies
+<font size="-1"><a href="$original">latest sources</a> $homepage | License: $license</font></p>
+</blockquote></a></td>
+<td class="version">
+]]
+
+local index_package_end = [[
+</td></tr>
+<tr><td colspan="2" class="spacer"></td></tr>
+]]
+
+local index_footer = [[
+</table>
+<p class="manifest">
+<a href="manifest">manifest file</a> &bull; <a href="manifest-5.1">Lua 5.1 manifest file</a> &bull; <a href="manifest-5.2">Lua 5.2 manifest file</a>
+</p>
+</body>
+</html>
+]]
+
+function format_external_dependencies(rockspec)
+ if rockspec.external_dependencies then
+ local deplist = {}
+ local listed_set = {}
+ local plats = nil
+ for name, desc in util.sortedpairs(rockspec.external_dependencies) do
+ if name ~= "platforms" then
+ table.insert(deplist, name:lower())
+ listed_set[name] = true
+ else
+ plats = desc
+ end
+ end
+ if plats then
+ for plat, entries in util.sortedpairs(plats) do
+ for name, desc in util.sortedpairs(entries) do
+ if not listed_set[name] then
+ table.insert(deplist, name:lower() .. " (on "..plat..")")
+ end
+ end
+ end
+ end
+ return '<p><b>External dependencies:</b> ' .. table.concat(deplist, ',&nbsp;').. '</p>'
+ else
+ return ""
+ end
+end
+
+function make_index(repo)
+ if not fs.is_dir(repo) then
+ return nil, "Cannot access repository at "..repo
+ end
+ local manifest = manif.load_manifest(repo)
+ local out = io.open(dir.path(repo, "index.html"), "w")
+
+ out:write(index_header)
+ for package, version_list in util.sortedpairs(manifest.repository) do
+ local latest_rockspec = nil
+ local output = index_package_start
+ for version, data in util.sortedpairs(version_list, deps.compare_versions) do
+ local versions = {}
+ output = output..version..':&nbsp;'
+ table.sort(data, function(a,b) return a.arch < b.arch end)
+ for _, item in ipairs(data) do
+ local link = '<a href="$url">'..item.arch..'</a>'
+ if item.arch == 'rockspec' then
+ local rs = ("%s-%s.rockspec"):format(package, version)
+ if not latest_rockspec then latest_rockspec = rs end
+ link = link:gsub("$url", rs)
+ else
+ link = link:gsub("$url", ("%s-%s.%s.rock"):format(package, version, item.arch))
+ end
+ table.insert(versions, link)
+ end
+ output = output .. table.concat(versions, ',&nbsp;') .. '<br/>'
+ end
+ output = output .. index_package_end
+ if latest_rockspec then
+ local rockspec = persist.load_into_table(dir.path(repo, latest_rockspec))
+ local descript = rockspec.description or {}
+ local vars = {
+ anchor = package,
+ package = rockspec.package,
+ original = rockspec.source.url,
+ summary = descript.summary or "",
+ detailed = descript.detailed or "",
+ license = descript.license or "N/A",
+ homepage = descript.homepage and ('| <a href="'..descript.homepage..'"'..ext_url_target..'>project homepage</a>') or "",
+ externaldependencies = format_external_dependencies(rockspec)
+ }
+ vars.detailed = vars.detailed:gsub("\n\n", "</p><p>"):gsub("%s+", " ")
+ vars.detailed = vars.detailed:gsub("(https?://[a-zA-Z0-9%.%%-_%+%[%]=%?&/$@;:]+)", '<a href="%1"'..ext_url_target..'>%1</a>')
+ output = output:gsub("$(%w+)", vars)
+ else
+ output = output:gsub("$anchor", package)
+ output = output:gsub("$package", package)
+ output = output:gsub("$(%w+)", "")
+ end
+ out:write(output)
+ end
+ out:write(index_footer)
+ out:close()
+end
diff --git a/src/luarocks/install.lua b/src/luarocks/install.lua
new file mode 100644
index 0000000..c181d61
--- /dev/null
+++ b/src/luarocks/install.lua
@@ -0,0 +1,164 @@
+
+--- Module implementing the LuaRocks "install" command.
+-- Installs binary rocks.
+module("luarocks.install", package.seeall)
+
+local path = require("luarocks.path")
+local repos = require("luarocks.repos")
+local fetch = require("luarocks.fetch")
+local util = require("luarocks.util")
+local fs = require("luarocks.fs")
+local deps = require("luarocks.deps")
+local manif = require("luarocks.manif")
+local remove = require("luarocks.remove")
+local cfg = require("luarocks.cfg")
+
+help_summary = "Install a rock."
+
+help_arguments = "{<rock>|<name> [<version>]}"
+
+help = [[
+Argument may be the name of a rock to be fetched from a repository
+or a filename of a locally available rock.
+
+--keep Do not remove previously installed versions of the
+ rock after installing a new one. This behavior can
+ be made permanent by setting keep_other_versions=true
+ in the configuration file.
+]]
+
+--- Install a binary rock.
+-- @param rock_file string: local or remote filename of a rock.
+-- @param deps_mode: string: Which trees to check dependencies for:
+-- "one" for the current default tree, "all" for all trees,
+-- "order" for all trees with priority >= the current default, "none" for no trees.
+-- @return (string, string) or (nil, string, [string]): Name and version of
+-- installed rock if succeeded or nil and an error message followed by an error code.
+function install_binary_rock(rock_file, deps_mode)
+ assert(type(rock_file) == "string")
+
+ local name, version, arch = path.parse_name(rock_file)
+ if not name then
+ return nil, "Filename "..rock_file.." does not match format 'name-version-revision.arch.rock'."
+ end
+
+ if arch ~= "all" and arch ~= cfg.arch then
+ return nil, "Incompatible architecture "..arch, "arch"
+ end
+ if repos.is_installed(name, version) then
+ repos.delete_version(name, version)
+ end
+
+ local rollback = util.schedule_function(function()
+ fs.delete(path.install_dir(name, version))
+ fs.remove_dir_if_empty(path.versions_dir(name))
+ end)
+
+ local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, path.install_dir(name, version))
+ if not ok then return nil, err, errcode end
+
+ local rockspec, err, errcode = fetch.load_rockspec(path.rockspec_file(name, version))
+ if err then
+ return nil, "Failed loading rockspec for installed package: "..err, errcode
+ end
+
+ if deps_mode == "none" then
+ util.printerr("Warning: skipping dependency checks.")
+ else
+ ok, err, errcode = deps.check_external_deps(rockspec, "install")
+ if err then return nil, err, errcode end
+ end
+
+ -- For compatibility with .rock files built with LuaRocks 1
+ if not fs.exists(path.rock_manifest_file(name, version)) then
+ ok, err = manif.make_rock_manifest(name, version)
+ if err then return nil, err end
+ end
+
+ if deps_mode ~= "none" then
+ ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode)
+ if err then return nil, err, errcode end
+ end
+
+ local wrap_bin_scripts = true
+ if rockspec.deploy and rockspec.deploy.wrap_bin_scripts == false then
+ wrap_bin_scripts = false
+ end
+
+ ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec))
+ if err then return nil, err end
+
+ util.remove_scheduled_function(rollback)
+ rollback = util.schedule_function(function()
+ repos.delete_version(name, version)
+ end)
+
+ ok, err = repos.run_hook(rockspec, "post_install")
+ if err then return nil, err end
+
+ ok, err = manif.update_manifest(name, version, nil, deps_mode)
+ if err then return nil, err end
+
+ local license = ""
+ if rockspec.description.license then
+ license = ("(license: "..rockspec.description.license..")")
+ end
+
+ local root_dir = path.root_dir(cfg.rocks_dir)
+ util.printout()
+ util.printout(name.." "..version.." is now installed in "..root_dir.." "..license)
+
+ util.remove_scheduled_function(rollback)
+ return name, version
+end
+
+--- Driver function for the "install" command.
+-- @param name string: name of a binary rock. If an URL or pathname
+-- to a binary rock is given, fetches and installs it. If a rockspec or a
+-- source rock is given, forwards the request to the "build" command.
+-- If a package name is given, forwards the request to "search" and,
+-- if returned a result, installs the matching rock.
+-- @param version string: When passing a package name, a version number
+-- may also be given.
+-- @return boolean or (nil, string): True if installation was
+-- successful, nil and an error message otherwise.
+function run(...)
+ local flags, name, version = util.parse_flags(...)
+ if type(name) ~= "string" then
+ return nil, "Argument missing. "..util.see_help("install")
+ end
+
+ local ok, err = fs.check_command_permissions(flags)
+ if not ok then return nil, err end
+
+ if name:match("%.rockspec$") or name:match("%.src%.rock$") then
+ util.printout("Using "..name.."... switching to 'build' mode")
+ local build = require("luarocks.build")
+ return build.run(name, util.forward_flags(flags, "local", "keep", "deps-mode"))
+ elseif name:match("%.rock$") then
+ ok, err = install_binary_rock(name, deps.get_deps_mode(flags))
+ if not ok then return nil, err end
+ local name, version = ok, err
+ if (not flags["keep"]) and not cfg.keep_other_versions then
+ local ok, err = remove.remove_other_versions(name, version, flags["force"])
+ if not ok then util.printerr(err) end
+ end
+ return name, version
+ else
+ local search = require("luarocks.search")
+ local results, err = search.find_suitable_rock(search.make_query(name:lower(), version))
+ if err then
+ return nil, err
+ elseif type(results) == "string" then
+ local url = results
+ util.printout("Installing "..url.."...")
+ return run(url, util.forward_flags(flags))
+ else
+ util.printout()
+ util.printerr("Could not determine which rock to install.")
+ util.title("Search results:")
+ search.print_results(results)
+ return nil, (next(results) and "Please narrow your query." or "No results found.")
+ end
+ end
+end
diff --git a/src/luarocks/lint.lua b/src/luarocks/lint.lua
new file mode 100644
index 0000000..62ced64
--- /dev/null
+++ b/src/luarocks/lint.lua
@@ -0,0 +1,41 @@
+
+--- Module implementing the LuaRocks "lint" command.
+-- Utility function that checks syntax of the rockspec.
+module("luarocks.lint", package.seeall)
+
+local util = require("luarocks.util")
+local download = require("luarocks.download")
+local fetch = require("luarocks.fetch")
+
+help_summary = "Check syntax of a rockspec."
+help_arguments = "<rockspec>"
+help = [[
+This is a utility function that checks the syntax of a rockspec.
+
+It returns success or failure if the text of a rockspec is
+syntactically correct.
+]]
+
+function run(...)
+ local flags, input = util.parse_flags(...)
+
+ if not input then
+ return nil, "Argument missing. "..util.see_help("lint")
+ end
+
+ local filename = input
+ if not input:match(".rockspec$") then
+ local err
+ filename, err = download.download("rockspec", input)
+ if not filename then
+ return nil, err
+ end
+ end
+
+ local rs, err = fetch.load_local_rockspec(filename)
+ if not rs then
+ return nil, "Failed loading rockspec: "..err
+ end
+
+ return true
+end
diff --git a/src/luarocks/list.lua b/src/luarocks/list.lua
new file mode 100644
index 0000000..6081ed4
--- /dev/null
+++ b/src/luarocks/list.lua
@@ -0,0 +1,38 @@
+
+--- Module implementing the LuaRocks "list" command.
+-- Lists currently installed rocks.
+module("luarocks.list", package.seeall)
+
+local search = require("luarocks.search")
+local cfg = require("luarocks.cfg")
+local util = require("luarocks.util")
+local path = require("luarocks.path")
+
+help_summary = "Lists currently installed rocks."
+help_arguments = "[--porcelain] <filter>"
+help = [[
+<filter> is a substring of a rock name to filter by.
+
+--porcelain Produce machine-friendly output.
+]]
+
+--- Driver function for "list" command.
+-- @param filter string or nil: A substring of a rock name to filter by.
+-- @param version string or nil: a version may also be passed.
+-- @return boolean: True if succeeded, nil on errors.
+function run(...)
+ local flags, filter, version = util.parse_flags(...)
+ local results = {}
+ local query = search.make_query(filter and filter:lower() or "", version)
+ query.exact_name = false
+ local trees = cfg.rocks_trees
+ if flags["tree"] then
+ trees = { flags["tree"] }
+ end
+ for _, tree in ipairs(trees) do
+ search.manifest_search(results, path.rocks_dir(tree), query)
+ end
+ util.title("Installed rocks:", flags["porcelain"])
+ search.print_results(results, flags["porcelain"])
+ return true
+end
diff --git a/src/luarocks/loader.lua b/src/luarocks/loader.lua
new file mode 100644
index 0000000..a116766
--- /dev/null
+++ b/src/luarocks/loader.lua
@@ -0,0 +1,212 @@
+
+--- A module which installs a Lua package loader that is LuaRocks-aware.
+-- This loader uses dependency information from the LuaRocks tree to load
+-- correct versions of modules. It does this by constructing a "context"
+-- table in the environment, which records which versions of packages were
+-- used to load previous modules, so that the loader chooses versions
+-- that are declared to be compatible with the ones loaded earlier.
+local global_env = _G
+local package, require, ipairs, pairs, table, type, next, unpack =
+ package, require, ipairs, pairs, table, type, next, unpack
+
+module("luarocks.loader")
+
+local path = require("luarocks.path")
+local manif_core = require("luarocks.manif_core")
+local deps = require("luarocks.deps")
+local cfg = require("luarocks.cfg")
+
+context = {}
+
+-- Contains a table when rocks trees are loaded,
+-- or 'false' to indicate rocks trees failed to load.
+-- 'nil' indicates rocks trees were not attempted to be loaded yet.
+rocks_trees = nil
+
+local function load_rocks_trees()
+ local any_ok = false
+ local trees = {}
+ for _, tree in ipairs(cfg.rocks_trees) do
+ local manifest, err = manif_core.load_local_manifest(path.rocks_dir(tree))
+ if manifest then
+ any_ok = true
+ table.insert(trees, {tree=tree, manifest=manifest})
+ end
+ end
+ if not any_ok then
+ rocks_trees = false
+ return false
+ end
+ rocks_trees = trees
+ return true
+end
+
+--- Process the dependencies of a package to determine its dependency
+-- chain for loading modules.
+-- @param name string: The name of an installed rock.
+-- @param version string: The version of the rock, in string format
+function add_context(name, version)
+ -- assert(type(name) == "string")
+ -- assert(type(version) == "string")
+
+ if context[name] then
+ return
+ end
+ context[name] = version
+
+ if not rocks_trees and not load_rocks_trees() then
+ return nil
+ end
+
+ local providers = {}
+ for _, tree in ipairs(rocks_trees) do
+ local manifest = tree.manifest
+
+ local pkgdeps
+ if manifest.dependencies and manifest.dependencies[name] then
+ pkgdeps = manifest.dependencies[name][version]
+ end
+ if not pkgdeps then
+ return nil
+ end
+ for _, dep in ipairs(pkgdeps) do
+ local pkg, constraints = dep.name, dep.constraints
+
+ for _, tree in ipairs(rocks_trees) do
+ local entries = tree.manifest.repository[pkg]
+ if entries then
+ for version, pkgs in pairs(entries) do
+ if (not constraints) or deps.match_constraints(deps.parse_version(version), constraints) then
+ add_context(pkg, version)
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+--- Internal sorting function.
+-- @param a table: A provider table.
+-- @param b table: Another provider table.
+-- @return boolean: True if the version of a is greater than that of b.
+local function sort_versions(a,b)
+ return a.version > b.version
+end
+
+--- Request module to be loaded through other loaders,
+-- once the proper name of the module has been determined.
+-- For example, in case the module "socket.core" has been requested
+-- to the LuaRocks loader and it determined based on context that
+-- the version 2.0.2 needs to be loaded and it is not the current
+-- version, the module requested for the other loaders will be
+-- "socket.core_2_0_2".
+-- @param module The module name requested by the user, such as "socket.core"
+-- @param name The rock name, such as "luasocket"
+-- @param version The rock version, such as "2.0.2-1"
+-- @param module_name The actual module name, such as "socket.core" or "socket.core_2_0_2".
+-- @return table or (nil, string): The module table as returned by some other loader,
+-- or nil followed by an error message if no other loader managed to load the module.
+local function call_other_loaders(module, name, version, module_name)
+ for i, loader in pairs(package.loaders) do
+ if loader ~= luarocks_loader then
+ local results = { loader(module_name) }
+ if type(results[1]) == "function" then
+ return unpack(results)
+ end
+ end
+ end
+ return "Failed loading module "..module.." in LuaRocks rock "..name.." "..version
+end
+
+--- Search for a module in the rocks trees
+-- @param module string: module name (eg. "socket.core")
+-- @param filter_module_name function(string, string, string, string, number):
+-- a function that takes the module name (eg "socket.core"), the rock name
+-- (eg "luasocket"), the version (eg "2.0.2-1"), the path of the rocks tree
+-- (eg "/usr/local"), and the numeric index of the matching entry, so the
+-- filter function can know if the matching module was the first entry or not.
+-- @return string, string, string: name of the rock containing the module
+-- (eg. "luasocket"), version of the rock (eg. "2.0.2-1"),
+-- name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is
+-- stored versioned).
+local function select_module(module, filter_module_name)
+ --assert(type(module) == "string")
+ --assert(type(filter_module_name) == "function")
+
+ if not rocks_trees and not load_rocks_trees() then
+ return nil
+ end
+
+ local providers = {}
+ for _, tree in ipairs(rocks_trees) do
+ local entries = tree.manifest.modules[module]
+ if entries then
+ for i, entry in ipairs(entries) do
+ local name, version = entry:match("^([^/]*)/(.*)$")
+ local module_name = tree.manifest.repository[name][version][1].modules[module]
+ if type(module_name) ~= "string" then
+ error("Invalid format in manifest file (invalid data for "..tostring(name).." "..tostring(version)..")")
+ end
+ module_name = filter_module_name(module_name, name, version, tree.tree, i)
+ if context[name] == version then
+ return name, version, module_name
+ end
+ version = deps.parse_version(version)
+ table.insert(providers, {name = name, version = version, module_name = module_name})
+ end
+ end
+ end
+
+ if next(providers) then
+ table.sort(providers, sort_versions)
+ local first = providers[1]
+ return first.name, first.version.string, first.module_name
+ end
+end
+
+--- Search for a module
+-- @param module string: module name (eg. "socket.core")
+-- @return string, string, string: name of the rock containing the module
+-- (eg. "luasocket"), version of the rock (eg. "2.0.2-1"),
+-- name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is
+-- stored versioned).
+local function pick_module(module)
+ return
+ select_module(module, function(module_name, name, version, tree, i)
+ if i > 1 then
+ module_name = path.versioned_name(module_name, "", name, version)
+ end
+ module_name = path.path_to_module(module_name)
+ return module_name
+ end)
+end
+
+--- Return the pathname of the file that would be loaded for a module.
+-- @param module string: module name (eg. "socket.core")
+-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so")
+function which(module)
+ local name, version, module_name = select_module(module, path.which_i)
+ return module_name
+end
+
+--- Package loader for LuaRocks support.
+-- A module is searched in installed rocks that match the
+-- current LuaRocks context. If module is not part of the
+-- context, or if a context has not yet been set, the module
+-- in the package with the highest version is used.
+-- @param module string: The module name, like in plain require().
+-- @return table: The module table (typically), like in plain
+-- require(). See <a href="http://www.lua.org/manual/5.1/manual.html#pdf-require">require()</a>
+-- in the Lua reference manual for details.
+function luarocks_loader(module)
+ local name, version, module_name = pick_module(module)
+ if not name then
+ return "No LuaRocks module found for "..module
+ else
+ add_context(name, version)
+ return call_other_loaders(module, name, version, module_name)
+ end
+end
+
+table.insert(global_env.package.loaders, 1, luarocks_loader)
diff --git a/src/luarocks/make.lua b/src/luarocks/make.lua
new file mode 100644
index 0000000..eef49d0
--- /dev/null
+++ b/src/luarocks/make.lua
@@ -0,0 +1,86 @@
+
+--- Module implementing the LuaRocks "make" command.
+-- Builds sources in the current directory, but unlike "build",
+-- it does not fetch sources, etc., assuming everything is
+-- available in the current directory.
+module("luarocks.make", package.seeall)
+
+local build = require("luarocks.build")
+local fs = require("luarocks.fs")
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+local fetch = require("luarocks.fetch")
+local pack = require("luarocks.pack")
+local remove = require("luarocks.remove")
+local deps = require("luarocks.deps")
+
+help_summary = "Compile package in current directory using a rockspec."
+help_arguments = "[--pack-binary-rock] [<rockspec>]"
+help = [[
+Builds sources in the current directory, but unlike "build",
+it does not fetch sources, etc., assuming everything is
+available in the current directory. If no argument is given,
+look for a rockspec in the current directory. If more than one
+is found, you must specify which to use, through the command-line.
+
+This command is useful as a tool for debugging rockspecs.
+To install rocks, you'll normally want to use the "install" and
+"build" commands. See the help on those for details.
+
+--pack-binary-rock Do not install rock. Instead, produce a .rock file
+ with the contents of compilation in the current
+ directory.
+
+--keep Do not remove previously installed versions of the
+ rock after installing a new one. This behavior can
+ be made permanent by setting keep_other_versions=true
+ in the configuration file.
+
+]]
+
+--- Driver function for "make" command.
+-- @param name string: A local rockspec.
+-- @return boolean or (nil, string): True if build was successful; nil and an
+-- error message otherwise.
+function run(...)
+ local flags, rockspec = util.parse_flags(...)
+ assert(type(rockspec) == "string" or not rockspec)
+
+ if not rockspec then
+ local files = fs.list_dir(fs.current_dir())
+ for _, file in pairs(files) do
+ if file:match("rockspec$") then
+ if rockspec then
+ return nil, "Please specify which rockspec file to use."
+ else
+ rockspec = file
+ end
+ end
+ end
+ if not rockspec then
+ return nil, "Argument missing: please specify a rockspec to use on current directory."
+ end
+ end
+ if not rockspec:match("rockspec$") then
+ return nil, "Invalid argument: 'make' takes a rockspec as a parameter. "..util.see_help("make")
+ end
+
+ if flags["pack-binary-rock"] then
+ local rspec, err, errcode = fetch.load_rockspec(rockspec)
+ if not rspec then
+ return nil, err
+ end
+ return pack.pack_binary_rock(rspec.name, rspec.version, build.build_rockspec, rockspec, false, true, deps.get_deps_mode(flags))
+ else
+ local ok, err = fs.check_command_permissions(flags)
+ if not ok then return nil, err end
+ ok, err = build.build_rockspec(rockspec, false, true, deps.get_deps_mode(flags))
+ if not ok then return nil, err end
+ local name, version = ok, err
+ if (not flags["keep"]) and not cfg.keep_other_versions then
+ local ok, err = remove.remove_other_versions(name, version, flags["force"])
+ if not ok then util.printerr(err) end
+ end
+ return name, version
+ end
+end
diff --git a/src/luarocks/make_manifest.lua b/src/luarocks/make_manifest.lua
new file mode 100644
index 0000000..a698f83
--- /dev/null
+++ b/src/luarocks/make_manifest.lua
@@ -0,0 +1,40 @@
+
+--- Module implementing the luarocks-admin "make_manifest" command.
+-- Compile a manifest file for a repository.
+module("luarocks.make_manifest", package.seeall)
+
+local manif = require("luarocks.manif")
+local index = require("luarocks.index")
+local cfg = require("luarocks.cfg")
+local util = require("luarocks.util")
+local deps = require("luarocks.deps")
+
+help_summary = "Compile a manifest file for a repository."
+
+help = [[
+<argument>, if given, is a local repository pathname.
+
+--local-tree If given, do not write versioned versions of the manifest file.
+ Use this when rebuilding the manifest of a local rocks tree.
+]]
+
+--- Driver function for "make_manifest" command.
+-- @param repo string or nil: Pathname of a local repository. If not given,
+-- the default local repository configured as cfg.rocks_dir is used.
+-- @return boolean or (nil, string): True if manifest was generated,
+-- or nil and an error message.
+function run(...)
+ local flags, repo = util.parse_flags(...)
+
+ assert(type(repo) == "string" or not repo)
+ repo = repo or cfg.rocks_dir
+
+ util.printout("Making manifest for "..repo)
+
+ local ok, err = manif.make_manifest(repo, deps.get_deps_mode(flags), not flags["local-tree"])
+ if ok and not flags["local-tree"] then
+ util.printout("Generating index.html for "..repo)
+ index.make_index(repo)
+ end
+ return ok, err
+end
diff --git a/src/luarocks/manif.lua b/src/luarocks/manif.lua
new file mode 100644
index 0000000..c17da71
--- /dev/null
+++ b/src/luarocks/manif.lua
@@ -0,0 +1,452 @@
+
+--- Module for handling manifest files and tables.
+-- Manifest files describe the contents of a LuaRocks tree or server.
+-- They are loaded into manifest tables, which are then used for
+-- performing searches, matching dependencies, etc.
+module("luarocks.manif", package.seeall)
+
+local manif_core = require("luarocks.manif_core")
+local persist = require("luarocks.persist")
+local fetch = require("luarocks.fetch")
+local dir = require("luarocks.dir")
+local fs = require("luarocks.fs")
+local search = require("luarocks.search")
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+local path = require("luarocks.path")
+local repos = require("luarocks.repos")
+local deps = require("luarocks.deps")
+
+rock_manifest_cache = {}
+
+--- Commit a table to disk in given local path.
+-- @param where string: The directory where the table should be saved.
+-- @param name string: The filename.
+-- @param tbl table: The table to be saved.
+-- @return boolean or (nil, string): true if successful, or nil and a
+-- message in case of errors.
+local function save_table(where, name, tbl)
+ assert(type(where) == "string")
+ assert(type(name) == "string")
+ assert(type(tbl) == "table")
+
+ local filename = dir.path(where, name)
+ local ok, err = persist.save_from_table(filename..".tmp", tbl)
+ if ok then
+ ok, err = fs.replace_file(filename, filename..".tmp")
+ end
+ return ok, err
+end
+
+function load_rock_manifest(name, version, root)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+
+ local name_version = name.."/"..version
+ if rock_manifest_cache[name_version] then
+ return rock_manifest_cache[name_version].rock_manifest
+ end
+ local pathname = path.rock_manifest_file(name, version, root)
+ local rock_manifest = persist.load_into_table(pathname)
+ if not rock_manifest then return nil end
+ rock_manifest_cache[name_version] = rock_manifest
+ return rock_manifest.rock_manifest
+end
+
+function make_rock_manifest(name, version)
+ local install_dir = path.install_dir(name, version)
+ local rock_manifest = path.rock_manifest_file(name, version)
+ local tree = {}
+ for _, file in ipairs(fs.find(install_dir)) do
+ local full_path = dir.path(install_dir, file)
+ local walk = tree
+ local last
+ local last_name
+ for name in file:gmatch("[^/]+") do
+ local next = walk[name]
+ if not next then
+ next = {}
+ walk[name] = next
+ end
+ last = walk
+ last_name = name
+ walk = next
+ end
+ if fs.is_file(full_path) then
+ last[last_name] = fs.get_md5(full_path)
+ end
+ end
+ local rock_manifest = { rock_manifest=tree }
+ rock_manifest_cache[name.."/"..version] = rock_manifest
+ save_table(install_dir, "rock_manifest", rock_manifest )
+end
+
+local function fetch_manifest_from(repo_url, filename)
+ local url = dir.path(repo_url, filename)
+ local name = repo_url:gsub("[/:]","_")
+ local file, err, errcode = fetch.fetch_url_at_temp_dir(url, "luarocks-manifest-"..name)
+ if not file then
+ return nil, "Failed fetching manifest for "..repo_url..(err and " - "..err or ""), errcode
+ end
+ return file
+end
+
+--- Load a local or remote manifest describing a repository.
+-- All functions that use manifest tables assume they were obtained
+-- through either this function or load_local_manifest.
+-- @param repo_url string: URL or pathname for the repository.
+-- @return table or (nil, string, [string]): A table representing the manifest,
+-- or nil followed by an error message and an optional error code.
+function load_manifest(repo_url)
+ assert(type(repo_url) == "string")
+
+ if manif_core.manifest_cache[repo_url] then
+ return manif_core.manifest_cache[repo_url]
+ end
+
+ local vmanifest = "manifest-"..cfg.lua_version
+
+ local protocol, pathname = dir.split_url(repo_url)
+ if protocol == "file" then
+ local file = dir.path(pathname, vmanifest)
+ if fs.exists(file) then
+ pathname = file
+ else
+ pathname = dir.path(pathname, "manifest")
+ end
+ else
+ local file, err = fetch_manifest_from(repo_url, vmanifest)
+ if not file then
+ file, err = fetch_manifest_from(repo_url, "manifest")
+ end
+ if not file then
+ return nil, err
+ end
+ pathname = file
+ end
+ return manif_core.manifest_loader(pathname, repo_url)
+end
+
+--- Output a table listing items of a package.
+-- @param itemsfn function: a function for obtaining items of a package.
+-- pkg and version will be passed to it; it should return a table with
+-- items as keys.
+-- @param pkg string: package name
+-- @param version string: package version
+-- @param tbl table: the package matching table: keys should be item names
+-- and values arrays of strings with packages names in "name/version" format.
+local function store_package_items(itemsfn, pkg, version, tbl)
+ assert(type(itemsfn) == "function")
+ assert(type(pkg) == "string")
+ assert(type(version) == "string")
+ assert(type(tbl) == "table")
+
+ local pkg_version = pkg.."/"..version
+ local result = {}
+
+ for item, path in pairs(itemsfn(pkg, version)) do
+ result[item] = path
+ if not tbl[item] then
+ tbl[item] = {}
+ end
+ table.insert(tbl[item], pkg_version)
+ end
+ return result
+end
+
+--- Sort function for ordering rock identifiers in a manifest's
+-- modules table. Rocks are ordered alphabetically by name, and then
+-- by version which greater first.
+-- @param a string: Version to compare.
+-- @param b string: Version to compare.
+-- @return boolean: The comparison result, according to the
+-- rule outlined above.
+local function sort_pkgs(a, b)
+ assert(type(a) == "string")
+ assert(type(b) == "string")
+
+ local na, va = a:match("(.*)/(.*)$")
+ local nb, vb = b:match("(.*)/(.*)$")
+
+ return (na == nb) and deps.compare_versions(va, vb) or na < nb
+end
+
+--- Sort items of a package matching table by version number (higher versions first).
+-- @param tbl table: the package matching table: keys should be strings
+-- and values arrays of strings with packages names in "name/version" format.
+local function sort_package_matching_table(tbl)
+ assert(type(tbl) == "table")
+
+ if next(tbl) then
+ for item, pkgs in pairs(tbl) do
+ if #pkgs > 1 then
+ table.sort(pkgs, sort_pkgs)
+ -- Remove duplicates from the sorted array.
+ local prev = nil
+ local i = 1
+ while pkgs[i] do
+ local curr = pkgs[i]
+ if curr == prev then
+ table.remove(pkgs, i)
+ else
+ prev = curr
+ i = i + 1
+ end
+ end
+ end
+ end
+ end
+end
+
+--- Process the dependencies of a manifest table to determine its dependency
+-- chains for loading modules. The manifest dependencies information is filled
+-- and any dependency inconsistencies or missing dependencies are reported to
+-- standard error.
+-- @param manifest table: a manifest table.
+-- @param deps_mode string: Dependency mode: "one" for the current default tree,
+-- "all" for all trees, "order" for all trees with priority >= the current default,
+-- "none" for no trees.
+-- @param repodir string: directory of repository being scanned
+-- @param filter_lua string or nil: filter by Lua version
+-- @param cache table: temporary rockspec cache table
+local function update_dependencies(manifest, deps_mode, repodir, filter_lua, cache)
+ assert(type(manifest) == "table")
+ assert(type(deps_mode) == "string")
+
+ cache = cache or {}
+ local lua_version = filter_lua and deps.parse_version(filter_lua)
+
+ for pkg, versions in pairs(manifest.repository) do
+ local to_remove = {}
+ for version, repositories in pairs(versions) do
+ local current = pkg.." "..version
+ for _, repo in ipairs(repositories) do
+ if repo.arch == "installed" then
+ local missing
+ repo.dependencies, missing = deps.scan_deps({}, {}, manifest, pkg, version, deps_mode)
+ repo.dependencies[pkg] = nil
+ if missing then
+ for miss, err in pairs(missing) do
+ if miss == current then
+ util.printerr("Tree inconsistency detected: "..current.." has no rockspec. "..err)
+ else
+ util.printerr("Missing dependency for "..pkg.." "..version..": "..miss)
+ end
+ end
+ end
+ elseif filter_lua and repo.arch == "rockspec" then
+ local pathname = dir.path(repodir, pkg.."-"..version..".rockspec")
+ local rockspec, err = cache[pathname]
+ if not rockspec then
+ rockspec, err = fetch.load_local_rockspec(pathname)
+ end
+ if rockspec then
+ cache[pathname] = rockspec
+ for _, dep in ipairs(rockspec.dependencies) do
+ if dep.name == "lua" then
+ if not deps.match_constraints(lua_version, dep.constraints) then
+ table.insert(to_remove, version)
+ end
+ break
+ end
+ end
+ else
+ util.printerr("Error loading rockspec for "..pkg.." "..version..": "..err)
+ end
+ end
+ end
+ end
+ if next(to_remove) then
+ for _, incompat in ipairs(to_remove) do
+ manifest.repository[pkg][incompat] = nil
+ end
+ if not next(manifest.repository[pkg]) then
+ manifest.repository[pkg] = nil
+ end
+ end
+ end
+end
+
+--- Store search results in a manifest table.
+-- @param results table: The search results as returned by search.disk_search.
+-- @param manifest table: A manifest table (must contain repository, modules, commands tables).
+-- It will be altered to include the search results.
+-- @param deps_mode string: Dependency mode: "one" for the current default tree,
+-- "all" for all trees, "order" for all trees with priority >= the current default,
+-- "none" for no trees.
+-- @param repo string: directory of repository
+-- @param filter_lua string or nil: filter by Lua version
+-- @param cache table: temporary rockspec cache table
+-- @return boolean or (nil, string): true in case of success, or nil followed by an error message.
+local function store_results(results, manifest, deps_mode, repo, filter_lua, cache)
+ assert(type(results) == "table")
+ assert(type(manifest) == "table")
+ assert(type(deps_mode) == "string")
+
+ for name, versions in pairs(results) do
+ local pkgtable = manifest.repository[name] or {}
+ for version, entries in pairs(versions) do
+ local versiontable = {}
+ for _, entry in ipairs(entries) do
+ local entrytable = {}
+ entrytable.arch = entry.arch
+ if entry.arch == "installed" then
+ local rock_manifest = load_rock_manifest(name, version)
+ if not rock_manifest then
+ return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?"
+ end
+ entrytable.modules = store_package_items(repos.package_modules, name, version, manifest.modules)
+ entrytable.commands = store_package_items(repos.package_commands, name, version, manifest.commands)
+ end
+ table.insert(versiontable, entrytable)
+ end
+ pkgtable[version] = versiontable
+ end
+ manifest.repository[name] = pkgtable
+ end
+ update_dependencies(manifest, deps_mode, repo, filter_lua, cache)
+ sort_package_matching_table(manifest.modules)
+ sort_package_matching_table(manifest.commands)
+ return true
+end
+
+--- Scan a LuaRocks repository and output a manifest file.
+-- A file called 'manifest' will be written in the root of the given
+-- repository directory.
+-- @param repo A local repository directory.
+-- @param deps_mode string: Dependency mode: "one" for the current default tree,
+-- "all" for all trees, "order" for all trees with priority >= the current default,
+-- "none" for the default dependency mode from the configuration.
+-- @param versioned boolean: if versioned versions of the manifest should be created.
+-- @return boolean or (nil, string): True if manifest was generated,
+-- or nil and an error message.
+function make_manifest(repo, deps_mode, versioned)
+ assert(type(repo) == "string")
+ assert(type(deps_mode) == "string")
+
+ if deps_mode == "none" then deps_mode = cfg.deps_mode end
+
+ if not fs.is_dir(repo) then
+ return nil, "Cannot access repository at "..repo
+ end
+
+ local query = search.make_query("")
+ query.exact_name = false
+ query.arch = "any"
+ local results = search.disk_search(repo, query)
+ local manifest = { repository = {}, modules = {}, commands = {} }
+
+ manif_core.manifest_cache[repo] = manifest
+
+ local cache = {}
+ local ok, err = store_results(results, manifest, deps_mode, repo, nil, cache)
+ if not ok then return nil, err end
+
+ if versioned then
+ for _, luaver in ipairs({"5.1", "5.2"}) do
+ local vmanifest = { repository = {}, modules = {}, commands = {} }
+ local ok, err = store_results(results, vmanifest, deps_mode, repo, luaver, cache)
+ save_table(repo, "manifest-"..luaver, vmanifest)
+ end
+ end
+
+ return save_table(repo, "manifest", manifest)
+end
+
+--- Load a manifest file from a local repository and add to the repository
+-- information with regard to the given name and version.
+-- A file called 'manifest' will be written in the root of the given
+-- repository directory.
+-- @param name string: Name of a package from the repository.
+-- @param version string: Version of a package from the repository.
+-- @param repo string or nil: Pathname of a local repository. If not given,
+-- the default local repository configured as cfg.rocks_dir is used.
+-- @param deps_mode string: Dependency mode: "one" for the current default tree,
+-- "all" for all trees, "order" for all trees with priority >= the current default,
+-- "none" for using the default dependency mode from the configuration.
+-- @return boolean or (nil, string): True if manifest was generated,
+-- or nil and an error message.
+function update_manifest(name, version, repo, deps_mode)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ repo = path.rocks_dir(repo or cfg.root_dir)
+ assert(type(deps_mode) == "string")
+
+ if deps_mode == "none" then deps_mode = cfg.deps_mode end
+
+ util.printout("Updating manifest for "..repo)
+
+ local manifest, err = load_manifest(repo)
+ if not manifest then
+ util.printerr("No existing manifest. Attempting to rebuild...")
+ local ok, err = make_manifest(repo, deps_mode)
+ if not ok then
+ return nil, err
+ end
+ manifest, err = load_manifest(repo)
+ if not manifest then
+ return nil, err
+ end
+ end
+
+ local results = {[name] = {[version] = {{arch = "installed", repo = repo}}}}
+
+ local ok, err = store_results(results, manifest, deps_mode, repo)
+ if not ok then return nil, err end
+
+ return save_table(repo, "manifest", manifest)
+end
+
+local function find_providers(file, root)
+ assert(type(file) == "string")
+ root = root or cfg.root_dir
+
+ local manifest, err = manif_core.load_local_manifest(path.rocks_dir(root))
+ if not manifest then
+ return nil, err .. " -- corrupted local rocks tree?"
+ end
+ local deploy_bin = path.deploy_bin_dir(root)
+ local deploy_lua = path.deploy_lua_dir(root)
+ local deploy_lib = path.deploy_lib_dir(root)
+ local key, manifest_tbl
+
+ if util.starts_with(file, deploy_lua) then
+ manifest_tbl = manifest.modules
+ key = path.path_to_module(file:sub(#deploy_lua+1):gsub("\\", "/"))
+ elseif util.starts_with(file, deploy_lib) then
+ manifest_tbl = manifest.modules
+ key = path.path_to_module(file:sub(#deploy_lib+1):gsub("\\", "/"))
+ elseif util.starts_with(file, deploy_bin) then
+ manifest_tbl = manifest.commands
+ key = file:sub(#deploy_bin+1):gsub("^[\\/]*", "")
+ else
+ assert(false, "Assertion failed: '"..file.."' is not a deployed file.")
+ end
+
+ local providers = manifest_tbl[key]
+ if not providers then
+ return nil, "untracked"
+ end
+ return providers
+end
+
+--- Given a path of a deployed file, figure out which rock name and version
+-- correspond to it in the tree manifest.
+-- @param file string: The full path of a deployed file.
+-- @param root string or nil: A local root dir for a rocks tree. If not given, the default is used.
+-- @return string, string: name and version of the provider rock.
+function find_current_provider(file, root)
+ local providers, err = find_providers(file, root)
+ if not providers then return nil, err end
+ return providers[1]:match("([^/]*)/([^/]*)")
+end
+
+function find_next_provider(file, root)
+ local providers, err = find_providers(file, root)
+ if not providers then return nil, err end
+ if providers[2] then
+ return providers[2]:match("([^/]*)/([^/]*)")
+ else
+ return nil
+ end
+end
diff --git a/src/luarocks/manif_core.lua b/src/luarocks/manif_core.lua
new file mode 100644
index 0000000..6424a1e
--- /dev/null
+++ b/src/luarocks/manif_core.lua
@@ -0,0 +1,79 @@
+
+--- Core functions for querying manifest files.
+-- This module requires no specific 'fs' functionality.
+module("luarocks.manif_core", package.seeall)
+
+local persist = require("luarocks.persist")
+local type_check = require("luarocks.type_check")
+local dir = require("luarocks.dir")
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+local path = require("luarocks.path")
+
+manifest_cache = {}
+
+--- Back-end function that actually loads the manifest
+-- and stores it in the manifest cache.
+-- @param file string: The local filename of the manifest file.
+-- @param repo_url string: The repository identifier.
+-- @param quick boolean: If given, skips type checking.
+function manifest_loader(file, repo_url, quick)
+ local manifest, err = persist.load_into_table(file)
+ if not manifest then
+ return nil, "Failed loading manifest for "..repo_url..": "..err
+ end
+ if not quick then
+ local ok, err = type_check.type_check_manifest(manifest)
+ if not ok then
+ return nil, "Error checking manifest: "..err
+ end
+ end
+
+ manifest_cache[repo_url] = manifest
+ return manifest
+end
+
+--- Load a local manifest describing a repository.
+-- All functions that use manifest tables assume they were obtained
+-- through either this function or load_manifest.
+-- @param repo_url string: URL or pathname for the repository.
+-- @return table or (nil, string): A table representing the manifest,
+-- or nil followed by an error message.
+function load_local_manifest(repo_url)
+ assert(type(repo_url) == "string")
+
+ if manifest_cache[repo_url] then
+ return manifest_cache[repo_url]
+ end
+
+ local pathname = dir.path(repo_url, "manifest")
+
+ return manifest_loader(pathname, repo_url, true)
+end
+
+--- Get all versions of a package listed in a manifest file.
+-- @param name string: a package name.
+-- @param deps_mode string: "one", to use only the currently
+-- configured tree; "order" to select trees based on order
+-- (use the current tree and all trees below it on the list)
+-- or "all", to use all trees.
+-- @return table: An array of strings listing installed
+-- versions of a package.
+function get_versions(name, deps_mode)
+ assert(type(name) == "string")
+ assert(type(deps_mode) == "string")
+
+ local manifest = {}
+ path.map_trees(deps_mode, function(tree)
+ local loaded = load_local_manifest(path.rocks_dir(tree))
+ if loaded then
+ util.deep_merge(manifest, loaded)
+ end
+ end)
+
+ local item = next(manifest) and manifest.repository[name]
+ if item then
+ return util.keys(item)
+ end
+ return {}
+end
diff --git a/src/luarocks/new_version.lua b/src/luarocks/new_version.lua
new file mode 100644
index 0000000..cb17032
--- /dev/null
+++ b/src/luarocks/new_version.lua
@@ -0,0 +1,178 @@
+
+--- Module implementing the LuaRocks "new_version" command.
+-- Utility function that writes a new rockspec, updating data from a previous one.
+module("luarocks.new_version", package.seeall)
+
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+local download = require("luarocks.download")
+local fetch = require("luarocks.fetch")
+local persist = require("luarocks.persist")
+local dir = require("luarocks.dir")
+local fs = require("luarocks.fs")
+
+help_summary = "Auto-write a rockspec for a new version of a rock."
+help_arguments = "{<package>|<rockspec>} [<new_version>] [<new_url>]"
+help = [[
+This is a utility function that writes a new rockspec, updating data
+from a previous one.
+
+If a package name is given, it downloads the latest rockspec from the
+default server. If a rockspec is given, it uses it instead.
+
+If the version number is not given, it only increments the revision
+number of the given (or downloaded) rockspec.
+
+If a URL is given, it replaces the one from the old rockspec with the
+given URL. If a URL is not given and a new version is given, it tries
+to guess the new URL by replacing occurrences of the version number
+in the URL or tag. It also tries to download the new URL to determine
+the new MD5 checksum.
+
+WARNING: it writes the new rockspec to the current directory,
+overwriting the file if it already exists.
+]]
+
+local order = {"rockspec_format", "package", "version",
+ { "source", { "url", "tag", "branch", "md5" } },
+ { "description", {"summary", "detailed", "homepage", "license" } },
+ "supported_platforms", "dependencies", "external_dependencies",
+ { "build", {"type", "modules", "copy_directories", "platforms"} },
+ "hooks"}
+
+local function try_replace(tbl, field, old, new)
+ if not tbl[field] then
+ return false
+ end
+ local old_field = tbl[field]
+ local new_field = tbl[field]:gsub(old, new)
+ if new_field ~= old_field then
+ util.printout("Guessing new '"..field.."' field as "..new_field)
+ tbl[field] = new_field
+ return true
+ end
+ return false
+end
+
+local function check_url_and_update_md5(out_rs, out_name)
+ local old_md5 = out_rs.source.md5
+ out_rs.source.md5 = nil
+ local file, temp_dir = fetch.fetch_url_at_temp_dir(out_rs.source.url, "luarocks-new-version-"..out_name)
+ if not file then
+ util.printerr("Warning: invalid URL - "..temp_dir)
+ return true
+ end
+ util.printout("File successfully downloaded. Updating MD5 checksum...")
+ out_rs.source.md5 = fs.get_md5(file)
+ fs.change_dir(temp_dir)
+ fs.unpack_archive(file)
+ local base_dir = out_rs.source.dir or fetch.url_to_base_dir(out_rs.source.url)
+ if not fs.exists(base_dir) then
+ util.printerr("Directory "..base_dir.." not found")
+ local files = fs.list_dir()
+ if files[1] and fs.is_dir(files[1]) then
+ util.printerr("Found "..files[1])
+ out_rs.source.dir = files[1]
+ end
+ end
+ fs.pop_dir()
+ return out_rs.source.md5 ~= old_md5
+end
+
+local function update_source_section(out_rs, out_name, url, old_ver, new_ver)
+ if url then
+ out_rs.source.url = url
+ check_url_and_update_md5(out_rs, out_name)
+ return true
+ end
+ if new_ver == old_ver then
+ return true
+ end
+ if not out_rs.source then
+ return nil, "'source' table is missing. Invalid rockspec?"
+ end
+ if out_rs.source.dir then
+ try_replace(out_rs.source, "dir", old_ver, new_ver)
+ end
+ if out_rs.source.file then
+ try_replace(out_rs.source, "file", old_ver, new_ver)
+ end
+ local ok = try_replace(out_rs.source, "url", old_ver, new_ver)
+ if ok then
+ check_url_and_update_md5(out_rs, out_name)
+ return true
+ end
+ ok = try_replace(out_rs.source, "tag", old_ver, new_ver)
+ if not ok then
+ ok = check_url_and_update_md5(out_rs, out_name)
+ if ok then
+ util.printerr("Warning: URL is the same, but MD5 has changed. Old rockspec is broken.")
+ end
+ end
+ if not ok then
+ return nil, "Failed to determine the location of the new version."
+ end
+ return true
+end
+
+function run(...)
+ local flags, input, version, url = util.parse_flags(...)
+ if not input then
+ return nil, "Missing arguments: expected program or rockspec. "..util.see_help("new_version")
+ end
+ assert(type(input) == "string")
+
+ local filename = input
+ if not input:match(".rockspec$") then
+ local err
+ filename, err = download.download("rockspec", input)
+ if not filename then
+ return nil, err
+ end
+ end
+
+ local valid_rs, err = fetch.load_rockspec(filename)
+ if not valid_rs then
+ return nil, err
+ end
+
+ local old_ver, old_rev = valid_rs.version:match("(.*)%-(%d+)$")
+ local new_ver, new_rev
+
+ if version then
+ new_ver, new_rev = version:match("(.*)%-(%d+)$")
+ new_rev = tonumber(new_rev)
+ if not new_rev then
+ new_ver = version
+ new_rev = 1
+ end
+ else
+ new_ver = old_ver
+ new_rev = tonumber(old_rev) + 1
+ end
+ local new_rockver = new_ver:gsub("-", "")
+
+ local out_rs = persist.load_into_table(filename)
+ local out_name = out_rs.package:lower()
+ out_rs.version = new_rockver.."-"..new_rev
+
+ local ok, err = update_source_section(out_rs, out_name, url, old_ver, new_ver)
+ if not ok then return nil, err end
+
+ if out_rs.build and out_rs.build.type == "module" then
+ out_rs.build.type = "builtin"
+ end
+
+ local out_filename = out_name.."-"..new_rockver.."-"..new_rev..".rockspec"
+
+ persist.save_from_table(out_filename, out_rs, order)
+
+ util.printout("Wrote "..out_filename)
+
+ local valid_out_rs, err = fetch.load_local_rockspec(out_filename)
+ if not valid_out_rs then
+ return nil, "Failed loading generated rockspec: "..err
+ end
+
+ return true
+end
diff --git a/src/luarocks/pack.lua b/src/luarocks/pack.lua
new file mode 100644
index 0000000..583932e
--- /dev/null
+++ b/src/luarocks/pack.lua
@@ -0,0 +1,204 @@
+
+--- Module implementing the LuaRocks "pack" command.
+-- Creates a rock, packing sources or binaries.
+module("luarocks.pack", package.seeall)
+
+local path = require("luarocks.path")
+local repos = require("luarocks.repos")
+local fetch = require("luarocks.fetch")
+local fs = require("luarocks.fs")
+local cfg = require("luarocks.cfg")
+local util = require("luarocks.util")
+local dir = require("luarocks.dir")
+local manif = require("luarocks.manif")
+local search = require("luarocks.search")
+
+help_summary = "Create a rock, packing sources or binaries."
+help_arguments = "{<rockspec>|<name> [<version>]}"
+help = [[
+Argument may be a rockspec file, for creating a source rock,
+or the name of an installed package, for creating a binary rock.
+In the latter case, the app version may be given as a second
+argument.
+]]
+
+--- Create a source rock.
+-- Packages a rockspec and its required source files in a rock
+-- file with the .src.rock extension, which can later be built and
+-- installed with the "build" command.
+-- @param rockspec_file string: An URL or pathname for a rockspec file.
+-- @return string or (nil, string): The filename of the resulting
+-- .src.rock file; or nil and an error message.
+local function pack_source_rock(rockspec_file)
+ assert(type(rockspec_file) == "string")
+
+ local rockspec, err = fetch.load_rockspec(rockspec_file)
+ if err then
+ return nil, "Error loading rockspec: "..err
+ end
+ rockspec_file = rockspec.local_filename
+
+ local name_version = rockspec.name .. "-" .. rockspec.version
+ local rock_file = fs.absolute_name(name_version .. ".src.rock")
+
+ local source_file, source_dir = fetch.fetch_sources(rockspec, false)
+ if not source_file then
+ return nil, source_dir
+ end
+ fs.change_dir(source_dir)
+
+ fs.delete(rock_file)
+ fs.copy(rockspec_file, source_dir)
+ if not fs.zip(rock_file, dir.base_name(rockspec_file), dir.base_name(source_file)) then
+ return nil, "Failed packing "..rock_file
+ end
+ fs.pop_dir()
+
+ return rock_file
+end
+
+local function copy_back_files(name, version, file_tree, deploy_dir, pack_dir)
+ fs.make_dir(pack_dir)
+ for file, sub in pairs(file_tree) do
+ local source = dir.path(deploy_dir, file)
+ local target = dir.path(pack_dir, file)
+ if type(sub) == "table" then
+ local ok, err = copy_back_files(name, version, sub, source, target)
+ else
+ local versioned = path.versioned_name(source, deploy_dir, name, version)
+ if fs.exists(versioned) then
+ fs.copy(versioned, target)
+ else
+ fs.copy(source, target)
+ end
+ end
+ end
+ return true
+end
+
+-- @param name string: Name of package to pack.
+-- @param version string or nil: A version number may also be passed.
+-- @return string or (nil, string): The filename of the resulting
+-- .src.rock file; or nil and an error message.
+local function do_pack_binary_rock(name, version)
+ assert(type(name) == "string")
+ assert(type(version) == "string" or not version)
+
+ local query = search.make_query(name, version)
+ query.exact_name = true
+ local results = {}
+
+ search.manifest_search(results, cfg.rocks_dir, query)
+
+ if not next(results) then
+ return nil, "'"..name.."' does not seem to be an installed rock."
+ end
+
+ local versions = results[name]
+
+ if not version then
+ local first = next(versions)
+ if next(versions, first) then
+ return nil, "Please specify which version of '"..name.."' to pack."
+ end
+ version = first
+ end
+ if not version:match("[^-]+%-%d+") then
+ return nil, "Expected version "..version.." in version-revision format."
+ end
+
+ local info = versions[version][1]
+
+ local root = path.root_dir(info.repo)
+ local prefix = path.install_dir(name, version, root)
+ if not fs.exists(prefix) then
+ return nil, "'"..name.." "..version.."' does not seem to be an installed rock."
+ end
+
+ local rock_manifest = manif.load_rock_manifest(name, version, root)
+ if not rock_manifest then
+ return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?"
+ end
+
+ local name_version = name .. "-" .. version
+ local rock_file = fs.absolute_name(name_version .. "."..cfg.arch..".rock")
+
+ local temp_dir = fs.make_temp_dir("pack")
+ fs.copy_contents(prefix, temp_dir)
+
+ local is_binary = false
+ if rock_manifest.lib then
+ copy_back_files(name, version, rock_manifest.lib, path.deploy_lib_dir(root), dir.path(temp_dir, "lib"))
+ is_binary = true
+ end
+ if rock_manifest.lua then
+ copy_back_files(name, version, rock_manifest.lua, path.deploy_lua_dir(root), dir.path(temp_dir, "lua"))
+ end
+
+ fs.change_dir(temp_dir)
+ if not is_binary and not repos.has_binaries(name, version) then
+ rock_file = rock_file:gsub("%."..cfg.arch:gsub("%-","%%-").."%.", ".all.")
+ end
+ fs.delete(rock_file)
+ if not fs.zip(rock_file, unpack(fs.list_dir())) then
+ return nil, "Failed packing "..rock_file
+ end
+ fs.pop_dir()
+ fs.delete(temp_dir)
+ return rock_file
+end
+
+function pack_binary_rock(name, version, cmd, ...)
+
+ -- The --pack-binary-rock option for "luarocks build" basically performs
+ -- "luarocks build" on a temporary tree and then "luarocks pack". The
+ -- alternative would require refactoring parts of luarocks.build and
+ -- luarocks.pack, which would save a few file operations: the idea would be
+ -- to shave off the final deploy steps from the build phase and the initial
+ -- collect steps from the pack phase.
+
+ local temp_dir = fs.make_temp_dir("luarocks-build-pack-"..dir.base_name(name))
+ if not temp_dir then
+ return nil, "Failed creating temporary directory."
+ end
+ util.schedule_function(fs.delete, temp_dir)
+
+ path.use_tree(temp_dir)
+ local ok, err = cmd(...)
+ if not ok then
+ return nil, err
+ end
+ local rname, rversion = path.parse_name(name)
+ if not rname then
+ rname, rversion = name, version
+ end
+ return do_pack_binary_rock(rname, rversion)
+end
+
+--- Driver function for the "pack" command.
+-- @param arg string: may be a rockspec file, for creating a source rock,
+-- or the name of an installed package, for creating a binary rock.
+-- @param version string or nil: if the name of a package is given, a
+-- version may also be passed.
+-- @return boolean or (nil, string): true if successful or nil followed
+-- by an error message.
+function run(...)
+ local flags, arg, version = util.parse_flags(...)
+ assert(type(version) == "string" or not version)
+ if type(arg) ~= "string" then
+ return nil, "Argument missing. "..util.see_help("pack")
+ end
+
+ local file, err
+ if arg:match(".*%.rockspec") then
+ file, err = pack_source_rock(arg)
+ else
+ file, err = do_pack_binary_rock(arg, version)
+ end
+ if err then
+ return nil, err
+ else
+ util.printout("Packed: "..file)
+ return true
+ end
+end
diff --git a/src/luarocks/path.lua b/src/luarocks/path.lua
new file mode 100644
index 0000000..7af81c0
--- /dev/null
+++ b/src/luarocks/path.lua
@@ -0,0 +1,417 @@
+
+--- LuaRocks-specific path handling functions.
+-- All paths are configured in this module, making it a single
+-- point where the layout of the local installation is defined in LuaRocks.
+module("luarocks.path", package.seeall)
+
+local dir = require("luarocks.dir")
+local cfg = require("luarocks.cfg")
+local util = require("luarocks.util")
+local deps = require("luarocks.deps")
+
+help_summary = "Return the currently configured package path."
+help_arguments = ""
+help = [[
+Returns the package path currently configured for this installation
+of LuaRocks, formatted as shell commands to update LUA_PATH and
+LUA_CPATH. (On Unix systems, you may run: eval `luarocks path`)
+]]
+
+--- Infer rockspec filename from a rock filename.
+-- @param rock_name string: Pathname of a rock file.
+-- @return string: Filename of the rockspec, without path.
+function rockspec_name_from_rock(rock_name)
+ assert(type(rock_name) == "string")
+ local base_name = dir.base_name(rock_name)
+ return base_name:match("(.*)%.[^.]*.rock") .. ".rockspec"
+end
+
+function rocks_dir(tree)
+ if type(tree) == "string" then
+ return dir.path(tree, cfg.rocks_subdir)
+ else
+ assert(type(tree) == "table")
+ return tree.rocks_dir or dir.path(tree.root, cfg.rocks_subdir)
+ end
+end
+
+function root_dir(rocks_dir)
+ assert(type(rocks_dir) == "string")
+ return rocks_dir:match("(.*)" .. util.matchquote(cfg.rocks_subdir) .. ".*$")
+end
+
+function rocks_tree_to_string(tree)
+ if type(tree) == "string" then
+ return tree
+ else
+ assert(type(tree) == "table")
+ return tree.root
+ end
+end
+
+function deploy_bin_dir(tree)
+ if type(tree) == "string" then
+ return dir.path(tree, "bin")
+ else
+ assert(type(tree) == "table")
+ return tree.bin_dir or dir.path(tree.root, "bin")
+ end
+end
+
+function deploy_lua_dir(tree)
+ if type(tree) == "string" then
+ return dir.path(tree, cfg.lua_modules_path)
+ else
+ assert(type(tree) == "table")
+ return tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path)
+ end
+end
+
+function deploy_lib_dir(tree)
+ if type(tree) == "string" then
+ return dir.path(tree, cfg.lib_modules_path)
+ else
+ assert(type(tree) == "table")
+ return tree.lib_dir or dir.path(tree.root, cfg.lib_modules_path)
+ end
+end
+
+function manifest_file(tree)
+ if type(tree) == "string" then
+ return dir.path(tree, cfg.rocks_subdir, "manifest")
+ else
+ assert(type(tree) == "table")
+ return (tree.rocks_dir and dir.path(tree.rocks_dir, "manifest")) or dir.path(tree.root, cfg.rocks_subdir, "manifest")
+ end
+end
+
+--- Get the directory for all versions of a package in a tree.
+-- @param name string: The package name.
+-- @return string: The resulting path -- does not guarantee that
+-- @param tree string or nil: If given, specifies the local tree to use.
+-- the package (and by extension, the path) exists.
+function versions_dir(name, tree)
+ assert(type(name) == "string")
+ tree = tree or cfg.root_dir
+ return dir.path(rocks_dir(tree), name)
+end
+
+--- Get the local installation directory (prefix) for a package.
+-- @param name string: The package name.
+-- @param version string: The package version.
+-- @param tree string or nil: If given, specifies the local tree to use.
+-- @return string: The resulting path -- does not guarantee that
+-- the package (and by extension, the path) exists.
+function install_dir(name, version, tree)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ tree = tree or cfg.root_dir
+ return dir.path(rocks_dir(tree), name, version)
+end
+
+--- Get the local filename of the rockspec of an installed rock.
+-- @param name string: The package name.
+-- @param version string: The package version.
+-- @param tree string or nil: If given, specifies the local tree to use.
+-- @return string: The resulting path -- does not guarantee that
+-- the package (and by extension, the file) exists.
+function rockspec_file(name, version, tree)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ tree = tree or cfg.root_dir
+ return dir.path(rocks_dir(tree), name, version, name.."-"..version..".rockspec")
+end
+
+--- Get the local filename of the rock_manifest file of an installed rock.
+-- @param name string: The package name.
+-- @param version string: The package version.
+-- @param tree string or nil: If given, specifies the local tree to use.
+-- @return string: The resulting path -- does not guarantee that
+-- the package (and by extension, the file) exists.
+function rock_manifest_file(name, version, tree)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ tree = tree or cfg.root_dir
+ return dir.path(rocks_dir(tree), name, version, "rock_manifest")
+end
+
+--- Get the local installation directory for C libraries of a package.
+-- @param name string: The package name.
+-- @param version string: The package version.
+-- @param tree string or nil: If given, specifies the local tree to use.
+-- @return string: The resulting path -- does not guarantee that
+-- the package (and by extension, the path) exists.
+function lib_dir(name, version, tree)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ tree = tree or cfg.root_dir
+ return dir.path(rocks_dir(tree), name, version, "lib")
+end
+
+--- Get the local installation directory for Lua modules of a package.
+-- @param name string: The package name.
+-- @param version string: The package version.
+-- @param tree string or nil: If given, specifies the local tree to use.
+-- @return string: The resulting path -- does not guarantee that
+-- the package (and by extension, the path) exists.
+function lua_dir(name, version, tree)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ tree = tree or cfg.root_dir
+ return dir.path(rocks_dir(tree), name, version, "lua")
+end
+
+--- Get the local installation directory for documentation of a package.
+-- @param name string: The package name.
+-- @param version string: The package version.
+-- @param tree string or nil: If given, specifies the local tree to use.
+-- @return string: The resulting path -- does not guarantee that
+-- the package (and by extension, the path) exists.
+function doc_dir(name, version, tree)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ tree = tree or cfg.root_dir
+ return dir.path(rocks_dir(tree), name, version, "doc")
+end
+
+--- Get the local installation directory for configuration files of a package.
+-- @param name string: The package name.
+-- @param version string: The package version.
+-- @param tree string or nil: If given, specifies the local tree to use.
+-- @return string: The resulting path -- does not guarantee that
+-- the package (and by extension, the path) exists.
+function conf_dir(name, version, tree)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ tree = tree or cfg.root_dir
+ return dir.path(rocks_dir(tree), name, version, "conf")
+end
+
+--- Get the local installation directory for command-line scripts
+-- of a package.
+-- @param name string: The package name.
+-- @param version string: The package version.
+-- @param tree string or nil: If given, specifies the local tree to use.
+-- @return string: The resulting path -- does not guarantee that
+-- the package (and by extension, the path) exists.
+function bin_dir(name, version, tree)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ tree = tree or cfg.root_dir
+ return dir.path(rocks_dir(tree), name, version, "bin")
+end
+
+--- Extract name, version and arch of a rock filename,
+-- or name, version and "rockspec" from a rockspec name.
+-- @param file_name string: pathname of a rock or rockspec
+-- @return (string, string, string) or nil: name, version and arch
+-- or nil if name could not be parsed
+function parse_name(file_name)
+ assert(type(file_name) == "string")
+ if file_name:match("%.rock$") then
+ return dir.base_name(file_name):match("(.*)-([^-]+-%d+)%.([^.]+)%.rock$")
+ else
+ return dir.base_name(file_name):match("(.*)-([^-]+-%d+)%.(rockspec)")
+ end
+end
+
+--- Make a rockspec or rock URL.
+-- @param pathname string: Base URL or pathname.
+-- @param name string: Package name.
+-- @param version string: Package version.
+-- @param arch string: Architecture identifier, or "rockspec" or "installed".
+-- @return string: A URL or pathname following LuaRocks naming conventions.
+function make_url(pathname, name, version, arch)
+ assert(type(pathname) == "string")
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ assert(type(arch) == "string")
+
+ local filename = name.."-"..version
+ if arch == "installed" then
+ filename = dir.path(name, version, filename..".rockspec")
+ elseif arch == "rockspec" then
+ filename = filename..".rockspec"
+ else
+ filename = filename.."."..arch..".rock"
+ end
+ return dir.path(pathname, filename)
+end
+
+--- Convert a pathname to a module identifier.
+-- In Unix, for example, a path "foo/bar/baz.lua" is converted to
+-- "foo.bar.baz"; "bla/init.lua" returns "bla"; "foo.so" returns "foo".
+-- @param file string: Pathname of module
+-- @return string: The module identifier, or nil if given path is
+-- not a conformant module path (the function does not check if the
+-- path actually exists).
+function path_to_module(file)
+ assert(type(file) == "string")
+
+ local name = file:match("(.*)%."..cfg.lua_extension.."$")
+ if name then
+ name = name:gsub(dir.separator, ".")
+ local init = name:match("(.*)%.init$")
+ if init then
+ name = init
+ end
+ else
+ name = file:match("(.*)%."..cfg.lib_extension.."$")
+ if name then
+ name = name:gsub(dir.separator, ".")
+ end
+ end
+ if not name then name = file end
+ name = name:gsub("^%.+", ""):gsub("%.+$", "")
+ return name
+end
+
+--- Obtain the directory name where a module should be stored.
+-- For example, on Unix, "foo.bar.baz" will return "foo/bar".
+-- @param mod string: A module name in Lua dot-separated format.
+-- @return string: A directory name using the platform's separator.
+function module_to_path(mod)
+ assert(type(mod) == "string")
+ return (mod:gsub("[^.]*$", ""):gsub("%.", dir.separator))
+end
+
+--- Set up path-related variables for a given rock.
+-- Create a "variables" table in the rockspec table, containing
+-- adjusted variables according to the configuration file.
+-- @param rockspec table: The rockspec table.
+function configure_paths(rockspec)
+ assert(type(rockspec) == "table")
+ local vars = {}
+ for k,v in pairs(cfg.variables) do
+ vars[k] = v
+ end
+ local name, version = rockspec.name, rockspec.version
+ vars.PREFIX = install_dir(name, version)
+ vars.LUADIR = lua_dir(name, version)
+ vars.LIBDIR = lib_dir(name, version)
+ vars.CONFDIR = conf_dir(name, version)
+ vars.BINDIR = bin_dir(name, version)
+ vars.DOCDIR = doc_dir(name, version)
+ rockspec.variables = vars
+end
+
+function versioned_name(file, prefix, name, version)
+ assert(type(file) == "string")
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+
+ local rest = file:sub(#prefix+1):gsub("^/*", "")
+ local name_version = (name.."_"..version):gsub("%-", "_"):gsub("%.", "_")
+ return dir.path(prefix, name_version.."-"..rest)
+end
+
+function use_tree(tree)
+ cfg.root_dir = tree
+ cfg.rocks_dir = rocks_dir(tree)
+ cfg.deploy_bin_dir = deploy_bin_dir(tree)
+ cfg.deploy_lua_dir = deploy_lua_dir(tree)
+ cfg.deploy_lib_dir = deploy_lib_dir(tree)
+end
+
+--- Apply a given function to the active rocks trees based on chosen dependency mode.
+-- @param deps_mode string: Dependency mode: "one" for the current default tree,
+-- "all" for all trees, "order" for all trees with priority >= the current default,
+-- "none" for no trees (this function becomes a nop).
+-- @param fn function: function to be applied, with the tree dir (string) as the first
+-- argument and the remaining varargs of map_trees as the following arguments.
+-- @return a table with all results of invocations of fn collected.
+function map_trees(deps_mode, fn, ...)
+ local result = {}
+ if deps_mode == "one" then
+ table.insert(result, (fn(cfg.root_dir, ...)) or 0)
+ elseif deps_mode == "all" or deps_mode == "order" then
+ local use = false
+ if deps_mode == "all" then
+ use = true
+ end
+ for _, tree in ipairs(cfg.rocks_trees) do
+ if dir.normalize(tree) == dir.normalize(cfg.root_dir) then
+ use = true
+ end
+ if use then
+ table.insert(result, (fn(tree, ...)) or 0)
+ end
+ end
+ end
+ return result
+end
+
+--- Return the pathname of the file that would be loaded for a module, indexed.
+-- @param module_name string: module name (eg. "socket.core")
+-- @param name string: name of the package (eg. "luasocket")
+-- @param version string: version number (eg. "2.0.2-1")
+-- @param tree string: repository path (eg. "/usr/local")
+-- @param i number: the index, 1 if version is the current default, > 1 otherwise.
+-- This is done this way for use by select_module in luarocks.loader.
+-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so")
+function which_i(module_name, name, version, tree, i)
+ local deploy_dir
+ if module_name:match("%.lua$") then
+ deploy_dir = deploy_lua_dir(tree)
+ module_name = dir.path(deploy_dir, module_name)
+ else
+ deploy_dir = deploy_lib_dir(tree)
+ module_name = dir.path(deploy_dir, module_name)
+ end
+ if i > 1 then
+ module_name = versioned_name(module_name, deploy_dir, name, version)
+ end
+ return module_name
+end
+
+--- Return the pathname of the file that would be loaded for a module,
+-- returning the versioned pathname if given version is not the default version
+-- in the given manifest.
+-- @param module_name string: module name (eg. "socket.core")
+-- @param name string: name of the package (eg. "luasocket")
+-- @param version string: version number (eg. "2.0.2-1")
+-- @param tree string: repository path (eg. "/usr/local")
+-- @param manifest table: the manifest table for the tree.
+-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so")
+function which(module_name, filename, name, version, tree, manifest)
+ local versions = manifest.modules[module_name]
+ assert(versions)
+ for i, name_version in ipairs(versions) do
+ if name_version == name.."/"..version then
+ return which_i(filename, name, version, tree, i):gsub("//", "/")
+ end
+ end
+ assert(false)
+end
+
+--- Driver function for "path" command.
+-- @return boolean This function always succeeds.
+function run(...)
+ local flags = util.parse_flags(...)
+ local deps_mode = deps.get_deps_mode(flags)
+
+ local lr_path, lr_cpath = cfg.package_paths()
+ local bin_dirs = map_trees(deps_mode, deploy_bin_dir)
+
+ if flags["lr-path"] then
+ util.printout(util.remove_path_dupes(lr_path, ';'))
+ return true
+ elseif flags["lr-cpath"] then
+ util.printout(util.remove_path_dupes(lr_cpath, ';'))
+ return true
+ elseif flags["lr-bin"] then
+ local lr_bin = util.remove_path_dupes(table.concat(bin_dirs, cfg.export_path_separator), cfg.export_path_separator)
+ util.printout(util.remove_path_dupes(lr_bin, ';'))
+ return true
+ end
+
+ util.printout(cfg.export_lua_path:format(util.remove_path_dupes(package.path, ';')))
+ util.printout(cfg.export_lua_cpath:format(util.remove_path_dupes(package.cpath, ';')))
+ if flags["bin"] then
+ table.insert(bin_dirs, 1, os.getenv("PATH"))
+ local lr_bin = util.remove_path_dupes(table.concat(bin_dirs, cfg.export_path_separator), cfg.export_path_separator)
+ util.printout(cfg.export_path:format(lr_bin))
+ end
+ return true
+end
+
diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua
new file mode 100644
index 0000000..208aee0
--- /dev/null
+++ b/src/luarocks/persist.lua
@@ -0,0 +1,173 @@
+
+--- Utility module for loading files into tables and
+-- saving tables into files.
+-- Implemented separately to avoid interdependencies,
+-- as it is used in the bootstrapping stage of the cfg module.
+module("luarocks.persist", package.seeall)
+
+local util = require("luarocks.util")
+
+--- Load a Lua file containing assignments, storing them in a table.
+-- The global environment is not propagated to the loaded file.
+-- @param filename string: the name of the file.
+-- @param tbl table or nil: if given, this table is used to store
+-- loaded values.
+-- @return table or (nil, string): a table with the file's assignments
+-- as fields, or nil and a message in case of errors.
+function load_into_table(filename, tbl)
+ assert(type(filename) == "string")
+ assert(type(tbl) == "table" or not tbl)
+
+ local result, chunk, ran, err
+ local result = tbl or {}
+ if setfenv then -- Lua 5.1
+ chunk, err = loadfile(filename)
+ if chunk then
+ setfenv(chunk, result)
+ ran, err = pcall(chunk)
+ end
+ else -- Lua 5.2
+ chunk, err = loadfile(filename, "t", result)
+ if chunk then
+ ran, err = pcall(chunk)
+ end
+ end
+
+ if not chunk then
+ if err:sub(1,5) ~= filename:sub(1,5) then
+ return false, err
+ end
+ return nil, "Error loading file: "..err
+ end
+ if not ran then
+ return nil, "Error running file: "..err
+ end
+ return result
+end
+
+local write_table
+
+--- Write a value as Lua code, invoking write_table.
+-- This function handles only numbers, strings and tables
+-- are keys (tables are handled recursively).
+-- @param out userdata: a file object, open for writing.
+-- @param v: the value to be written.
+-- @param level number: the indentation level
+-- @param sub_order table: optional prioritization table
+-- @see write_table
+local function write_value(out, v, level, sub_order)
+ if type(v) == "table" then
+ write_table(out, v, level + 1, sub_order)
+ elseif type(v) == "string" then
+ if v:match("\n") then
+ local open, close = "[[", "]]"
+ local equals = 0
+ while v:find(open,1,true) or v:find(close,1,true) do
+ equals = equals + 1
+ local eqs = ("="):rep(equals)
+ open, close = "["..eqs.."[", "]"..eqs.."]"
+ end
+ out:write(open.."\n"..v..close)
+ else
+ out:write("\""..v:gsub("\"", "\\\"").."\"")
+ end
+ else
+ out:write(tostring(v))
+ end
+end
+
+--- Write a table as Lua code representing a table to disk
+-- (that is, in curly brackets notation).
+-- This function handles only numbers, strings and tables
+-- are keys (tables are handled recursively).
+-- @param out userdata: a file object, open for writing.
+-- @param tbl table: the table to be written.
+-- @param level number: the indentation level
+-- @param field_order table: optional prioritization table
+write_table = function(out, tbl, level, field_order)
+ out:write("{")
+ local sep = "\n"
+ local indentation = " "
+ local indent = true
+ local i = 1
+ for k, v, sub_order in util.sortedpairs(tbl, field_order) do
+ out:write(sep)
+ if indent then
+ for n = 1,level do out:write(indentation) end
+ end
+ sep = ",\n"
+ indent = true
+ if type(k) == "number" then
+ if k ~= i then
+ out:write("["..tostring(k).."]=")
+ else
+ i = i + 1
+ end
+ indent = false
+ sep = ", "
+ elseif type(k) == "table" then
+ out:write("[")
+ write_table(out, k, level + 1)
+ out:write("] = ")
+ else
+ if k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then
+ out:write(k.." = ")
+ else
+ out:write("['"..k:gsub("'", "\\'").."'] = ")
+ end
+ end
+ write_value(out, v, level, sub_order)
+ end
+ if sep ~= "\n" then
+ out:write("\n")
+ for n = 1,level-1 do out:write(indentation) end
+ end
+ out:write("}")
+end
+
+--- Writes a table to an io-like object.
+-- @param out userdata: a file object, open for writing.
+-- @param tbl table: the table to be written.
+-- @param field_order table: optional prioritization table
+-- @return userdata The file object originally passed in as the `out` parameter.
+local function write_table(out, tbl, field_order)
+ for k, v, sub_order in util.sortedpairs(tbl, field_order) do
+ out:write(k.." = ")
+ write_value(out, v, 0, sub_order)
+ out:write("\n")
+ end
+ return out
+end
+
+--- Save the contents of a table to a string.
+-- Each element of the table is saved as a global assignment.
+-- Only numbers, strings and tables (containing numbers, strings
+-- or other recursively processed tables) are supported.
+-- @param tbl table: the table containing the data to be written
+-- @param field_order table: an optional array indicating the order of top-level fields.
+-- @return string
+function save_from_table_to_string(tbl, field_order)
+ local out = {buffer = {}}
+ function out:write(data) table.insert(self.buffer, data) end
+ write_table(out, tbl, field_order)
+ return table.concat(out.buffer)
+end
+
+--- Save the contents of a table in a file.
+-- Each element of the table is saved as a global assignment.
+-- Only numbers, strings and tables (containing numbers, strings
+-- or other recursively processed tables) are supported.
+-- @param filename string: the output filename
+-- @param tbl table: the table containing the data to be written
+-- @param field_order table: an optional array indicating the order of top-level fields.
+-- @return boolean or (nil, string): true if successful, or nil and a
+-- message in case of errors.
+function save_from_table(filename, tbl, field_order)
+ local out = io.open(filename, "w")
+ if not out then
+ return nil, "Cannot create file at "..filename
+ end
+ write_table(out, tbl, field_order)
+ out:close()
+ return true
+end
diff --git a/src/luarocks/purge.lua b/src/luarocks/purge.lua
new file mode 100644
index 0000000..e76a82e
--- /dev/null
+++ b/src/luarocks/purge.lua
@@ -0,0 +1,70 @@
+
+--- Module implementing the LuaRocks "purge" command.
+-- Remove all rocks from a given tree.
+module("luarocks.purge", package.seeall)
+
+local util = require("luarocks.util")
+local fs = require("luarocks.fs")
+local path = require("luarocks.path")
+local search = require("luarocks.search")
+local deps = require("luarocks.deps")
+local repos = require("luarocks.repos")
+local manif = require("luarocks.manif")
+local cfg = require("luarocks.cfg")
+local remove = require("luarocks.remove")
+
+help_summary = "Remove all installed rocks from a tree."
+help_arguments = "--tree=<tree> [--old-versions]"
+help = [[
+This command removes rocks en masse from a given tree.
+By default, it removes all rocks from a tree.
+
+The --tree argument is mandatory: luarocks purge does not
+assume a default tree.
+
+--old-versions Keep the highest-numbered version of each
+ rock and remove the other ones. By default
+ it only removes old versions if they are
+ not needed as dependencies. This can be
+ overridden with the flag --force.
+]]
+
+function run(...)
+ local flags = util.parse_flags(...)
+
+ local tree = flags["tree"]
+
+ if type(tree) ~= "string" then
+ return nil, "The --tree argument is mandatory. "..util.see_help("purge")
+ end
+
+ local results = {}
+ local query = search.make_query("")
+ query.exact_name = false
+ search.manifest_search(results, path.rocks_dir(tree), query)
+
+ local sort = function(a,b) return deps.compare_versions(b,a) end
+ if flags["old-versions"] then
+ sort = deps.compare_versions
+ end
+
+ for package, versions in util.sortedpairs(results) do
+ for version, repositories in util.sortedpairs(versions, sort) do
+ if flags["old-versions"] then
+ util.printout("Keeping "..package.." "..version.."...")
+ local ok, err = remove.remove_other_versions(package, version, flags["force"])
+ if not ok then
+ util.printerr(err)
+ end
+ break
+ else
+ util.printout("Removing "..package.." "..version.."...")
+ local ok, err = repos.delete_version(package, version, true)
+ if not ok then
+ util.printerr(err)
+ end
+ end
+ end
+ end
+ return manif.make_manifest(cfg.rocks_dir, "one")
+end
diff --git a/src/luarocks/refresh_cache.lua b/src/luarocks/refresh_cache.lua
new file mode 100644
index 0000000..8073037
--- /dev/null
+++ b/src/luarocks/refresh_cache.lua
@@ -0,0 +1,30 @@
+
+--- Module implementing the luarocks-admin "refresh_cache" command.
+module("luarocks.refresh_cache", package.seeall)
+
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+local cache = require("luarocks.cache")
+
+help_summary = "Refresh local cache of a remote rocks server."
+help_arguments = "[--from=<server>]"
+help = [[
+The flag --from indicates which server to use.
+If not given, the default server set in the upload_server variable
+from the configuration file is used instead.
+]]
+
+function run(...)
+ local flags = util.parse_flags(...)
+ local server, upload_server = cache.get_upload_server(flags["server"])
+ if not server then return nil, upload_server end
+ local download_url = cache.get_server_urls(server, upload_server)
+
+ local ok, err = cache.refresh_local_cache(server, download_url, cfg.upload_user, cfg.upload_password)
+ if not ok then
+ return nil, err
+ else
+ return true
+ end
+end
+
diff --git a/src/luarocks/remove.lua b/src/luarocks/remove.lua
new file mode 100644
index 0000000..9681641
--- /dev/null
+++ b/src/luarocks/remove.lua
@@ -0,0 +1,157 @@
+
+--- Module implementing the LuaRocks "remove" command.
+-- Uninstalls rocks.
+module("luarocks.remove", package.seeall)
+
+local search = require("luarocks.search")
+local deps = require("luarocks.deps")
+local fetch = require("luarocks.fetch")
+local repos = require("luarocks.repos")
+local path = require("luarocks.path")
+local util = require("luarocks.util")
+local cfg = require("luarocks.cfg")
+local manif = require("luarocks.manif")
+local fs = require("luarocks.fs")
+
+help_summary = "Uninstall a rock."
+help_arguments = "[--force] <name> [<version>]"
+help = [[
+Argument is the name of a rock to be uninstalled.
+If a version is not given, try to remove all versions at once.
+Will only perform the removal if it does not break dependencies.
+To override this check and force the removal, use --force.
+]]
+
+--- Obtain a list of packages that depend on the given set of packages
+-- (where all packages of the set are versions of one program).
+-- @param name string: the name of a program
+-- @param versions array of string: the versions to be deleted.
+-- @return array of string: an empty table if no packages depend on any
+-- of the given list, or an array of strings in "name/version" format.
+local function check_dependents(name, versions, deps_mode)
+ local dependents = {}
+ local blacklist = {}
+ blacklist[name] = {}
+ for version, _ in pairs(versions) do
+ blacklist[name][version] = true
+ end
+ local local_rocks = {}
+ local query_all = search.make_query("")
+ query_all.exact_name = false
+ search.manifest_search(local_rocks, cfg.rocks_dir, query_all)
+ local_rocks[name] = nil
+ for rock_name, rock_versions in pairs(local_rocks) do
+ for rock_version, _ in pairs(rock_versions) do
+ local rockspec, err = fetch.load_rockspec(path.rockspec_file(rock_name, rock_version))
+ if rockspec then
+ local _, missing = deps.match_deps(rockspec, blacklist, deps_mode)
+ if missing[name] then
+ table.insert(dependents, { name = rock_name, version = rock_version })
+ end
+ end
+ end
+ end
+ return dependents
+end
+
+--- Delete given versions of a program.
+-- @param name string: the name of a program
+-- @param versions array of string: the versions to be deleted.
+-- @return boolean or (nil, string): true on success or nil and an error message.
+local function delete_versions(name, versions)
+
+ for version, _ in pairs(versions) do
+ util.printout("Removing "..name.." "..version.."...")
+ local ok, err = repos.delete_version(name, version)
+ if not ok then return nil, err end
+ end
+
+ return true
+end
+
+function remove_search_results(results, name, deps_mode, force)
+ local versions = results[name]
+
+ local version = next(versions)
+ local second = next(versions, version)
+
+ util.printout("Checking stability of dependencies on the absence of")
+ util.printout(name.." "..table.concat(util.keys(versions), ", ").."...")
+ util.printout()
+
+ local dependents = check_dependents(name, versions, deps_mode)
+
+ if #dependents == 0 or force then
+ if #dependents > 0 then
+ util.printerr("The following packages may be broken by this forced removal:")
+ for _, dependent in ipairs(dependents) do
+ util.printerr(dependent.name.." "..dependent.version)
+ end
+ util.printerr()
+ end
+ local ok, err = delete_versions(name, versions)
+ if not ok then return nil, err end
+ ok, err = manif.make_manifest(cfg.rocks_dir, deps_mode)
+ if not ok then return nil, err end
+ else
+ if not second then
+ util.printerr("Will not remove "..name.." "..version..".")
+ util.printerr("Removing it would break dependencies for: ")
+ else
+ util.printerr("Will not remove installed versions of "..name..".")
+ util.printerr("Removing them would break dependencies for: ")
+ end
+ for _, dependent in ipairs(dependents) do
+ util.printerr(dependent.name.." "..dependent.version)
+ end
+ util.printerr()
+ util.printerr("Use --force to force removal (warning: this may break modules).")
+ return nil, "Failed removing."
+ end
+ util.printout("Removal successful.")
+ return true
+end
+
+function remove_other_versions(name, version, force)
+ local results = {}
+ search.manifest_search(results, cfg.rocks_dir, { name = name, exact_name = true, constraints = {{ op = "~=", version = version}} })
+ if results[name] then
+ return remove_search_results(results, name, cfg.deps_mode, force)
+ end
+ return true
+end
+
+--- Driver function for the "remove" command.
+-- @param name string: name of a rock. If a version is given, refer to
+-- a specific version; otherwise, try to remove all versions.
+-- @param version string: When passing a package name, a version number
+-- may also be given.
+-- @return boolean or (nil, string): True if removal was
+-- successful, nil and an error message otherwise.
+function run(...)
+ local flags, name, version = util.parse_flags(...)
+
+ if type(name) ~= "string" then
+ return nil, "Argument missing, see help."
+ end
+
+ local deps_mode = flags["deps-mode"] or cfg.deps_mode
+
+ local ok, err = fs.check_command_permissions(flags)
+ if not ok then return nil, err end
+
+ local rock_type = name:match("%.(rock)$") or name:match("%.(rockspec)$")
+ local filename = name
+ if rock_type then
+ name, version = path.parse_name(filename)
+ if not name then return nil, "Invalid "..rock_type.." filename: "..filename end
+ end
+
+ local results = {}
+ search.manifest_search(results, cfg.rocks_dir, search.make_query(name, version))
+ if not results[name] then
+ return nil, "Could not find rock '"..name..(version and " "..version or "").."' in local tree."
+ end
+
+ return remove_search_results(results, name, deps_mode, flags["force"])
+end
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua
new file mode 100644
index 0000000..b7e64d4
--- /dev/null
+++ b/src/luarocks/repos.lua
@@ -0,0 +1,309 @@
+
+--- Functions for managing the repository on disk.
+module("luarocks.repos", package.seeall)
+
+local fs = require("luarocks.fs")
+local path = require("luarocks.path")
+local cfg = require("luarocks.cfg")
+local util = require("luarocks.util")
+local dir = require("luarocks.dir")
+local manif = require("luarocks.manif")
+local deps = require("luarocks.deps")
+
+--- Get all installed versions of a package.
+-- @param name string: a package name.
+-- @return table or nil: An array of strings listing installed
+-- versions of a package, or nil if none is available.
+local function get_installed_versions(name)
+ assert(type(name) == "string")
+
+ local dirs = fs.list_dir(path.versions_dir(name))
+ return (dirs and #dirs > 0) and dirs or nil
+end
+
+--- Check if a package exists in a local repository.
+-- Version numbers are compared as exact string comparison.
+-- @param name string: name of package
+-- @param version string: package version in string format
+-- @return boolean: true if a package is installed,
+-- false otherwise.
+function is_installed(name, version)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+
+ return fs.is_dir(path.install_dir(name, version))
+end
+
+local function recurse_rock_manifest_tree(file_tree, action)
+ assert(type(file_tree) == "table")
+ assert(type(action) == "function")
+ local function do_recurse_rock_manifest_tree(tree, parent_path, parent_module)
+
+ for file, sub in pairs(tree) do
+ if type(sub) == "table" then
+ local ok, err = do_recurse_rock_manifest_tree(sub, parent_path..file.."/", parent_module..file..".")
+ if not ok then return nil, err end
+ else
+ local ok, err = action(parent_path, parent_module, file)
+ if not ok then return nil, err end
+ end
+ end
+ return true
+ end
+ return do_recurse_rock_manifest_tree(file_tree, "", "")
+end
+
+local function store_package_data(result, name, file_tree)
+ if not file_tree then return end
+ return recurse_rock_manifest_tree(file_tree,
+ function(parent_path, parent_module, file)
+ local pathname = parent_path..file
+ result[path.path_to_module(pathname)] = pathname
+ return true
+ end
+ )
+end
+
+--- Obtain a list of modules within an installed package.
+-- @param package string: The package name; for example "luasocket"
+-- @param version string: The exact version number including revision;
+-- for example "2.0.1-1".
+-- @return table: A table of modules where keys are module identifiers
+-- in "foo.bar" format and values are pathnames in architecture-dependent
+-- "foo/bar.so" format. If no modules are found or if package or version
+-- are invalid, an empty table is returned.
+function package_modules(package, version)
+ assert(type(package) == "string")
+ assert(type(version) == "string")
+
+ local result = {}
+ local rock_manifest = manif.load_rock_manifest(package, version)
+ store_package_data(result, package, rock_manifest.lib)
+ store_package_data(result, package, rock_manifest.lua)
+ return result
+end
+
+--- Obtain a list of command-line scripts within an installed package.
+-- @param package string: The package name; for example "luasocket"
+-- @param version string: The exact version number including revision;
+-- for example "2.0.1-1".
+-- @return table: A table of items where keys are command names
+-- as strings and values are pathnames in architecture-dependent
+-- ".../bin/foo" format. If no modules are found or if package or version
+-- are invalid, an empty table is returned.
+function package_commands(package, version)
+ assert(type(package) == "string")
+ assert(type(version) == "string")
+
+ local result = {}
+ local rock_manifest = manif.load_rock_manifest(package, version)
+ store_package_data(result, package, rock_manifest.bin)
+ return result
+end
+
+
+--- Check if a rock contains binary executables.
+-- @param name string: name of an installed rock
+-- @param version string: version of an installed rock
+-- @return boolean: returns true if rock contains platform-specific
+-- binary executables, or false if it is a pure-Lua rock.
+function has_binaries(name, version)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+
+ local rock_manifest = manif.load_rock_manifest(name, version)
+ if rock_manifest.bin then
+ for name, md5 in pairs(rock_manifest.bin) do
+ -- TODO verify that it is the same file. If it isn't, find the actual command.
+ if fs.is_actual_binary(dir.path(cfg.deploy_bin_dir, name)) then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+function run_hook(rockspec, hook_name)
+ assert(type(rockspec) == "table")
+ assert(type(hook_name) == "string")
+
+ local hooks = rockspec.hooks
+ if not hooks then
+ return true
+ end
+
+ if cfg.hooks_enabled == false then
+ return nil, "This rockspec contains hooks, which are blocked by the 'hooks_enabled' setting in your LuaRocks configuration."
+ end
+
+ if not hooks.substituted_variables then
+ util.variable_substitutions(hooks, rockspec.variables)
+ hooks.substituted_variables = true
+ end
+ local hook = hooks[hook_name]
+ if hook then
+ util.printout(hook)
+ if not fs.execute(hook) then
+ return nil, "Failed running "..hook_name.." hook."
+ end
+ end
+ return true
+end
+
+local function install_binary(source, target, name, version)
+ assert(type(source) == "string")
+ assert(type(target) == "string")
+
+ local match = source:match("%.lua$")
+ local file, ok, err
+ if not match then
+ file = io.open(source)
+ end
+ if match or (file and file:read():match("^#!.*lua.*")) then
+ ok, err = fs.wrap_script(source, target, name, version)
+ else
+ ok, err = fs.copy_binary(source, target)
+ end
+ if file then file:close() end
+ return ok, err
+end
+
+local function resolve_conflict(target, deploy_dir, name, version)
+ local cname, cversion = manif.find_current_provider(target)
+ if not cname then
+ return nil, cversion
+ end
+ if name ~= cname or deps.compare_versions(version, cversion) then
+ local versioned = path.versioned_name(target, deploy_dir, cname, cversion)
+ fs.make_dir(dir.dir_name(versioned))
+ fs.move(target, versioned)
+ return target
+ else
+ return path.versioned_name(target, deploy_dir, name, version)
+ end
+end
+
+function should_wrap_bin_scripts(rockspec)
+ assert(type(rockspec) == "table")
+
+ if cfg.wrap_bin_scripts ~= nil then
+ return cfg.wrap_bin_scripts
+ end
+ if rockspec.deploy and rockspec.deploy.wrap_bin_scripts == false then
+ return false
+ end
+ return true
+end
+
+function deploy_files(name, version, wrap_bin_scripts)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ assert(type(wrap_bin_scripts) == "boolean")
+
+ local function deploy_file_tree(file_tree, path_fn, deploy_dir, move_fn)
+ local source_dir = path_fn(name, version)
+ if not move_fn then
+ move_fn = fs.move
+ end
+ return recurse_rock_manifest_tree(file_tree,
+ function(parent_path, parent_module, file)
+ local source = dir.path(source_dir, parent_path, file)
+ local target = dir.path(deploy_dir, parent_path, file)
+ local ok, err
+ if fs.exists(target) then
+ local new_target, err = resolve_conflict(target, deploy_dir, name, version)
+ if err == "untracked" then
+ fs.delete(target)
+ elseif err then
+ return nil, err.." Cannot install new version."
+ else
+ target = new_target
+ end
+ end
+ fs.make_dir(dir.dir_name(target))
+ ok, err = move_fn(source, target, name, version)
+ fs.remove_dir_tree_if_empty(dir.dir_name(source))
+ if not ok then return nil, err end
+ return true
+ end
+ )
+ end
+
+ local rock_manifest = manif.load_rock_manifest(name, version)
+
+ local ok, err = true
+ if rock_manifest.bin then
+ local move_bin_fn = wrap_bin_scripts and install_binary or fs.copy_binary
+ ok, err = deploy_file_tree(rock_manifest.bin, path.bin_dir, cfg.deploy_bin_dir, move_bin_fn)
+ end
+ if ok and rock_manifest.lua then
+ ok, err = deploy_file_tree(rock_manifest.lua, path.lua_dir, cfg.deploy_lua_dir)
+ end
+ if ok and rock_manifest.lib then
+ ok, err = deploy_file_tree(rock_manifest.lib, path.lib_dir, cfg.deploy_lib_dir)
+ end
+ return ok, err
+end
+
+--- Delete a package from the local repository.
+-- Version numbers are compared as exact string comparison.
+-- @param name string: name of package
+-- @param version string: package version in string format
+-- @param quick boolean: do not try to fix the versioned name
+-- of another version that provides the same module that
+-- was deleted. This is used during 'purge', as every module
+-- will be eventually deleted.
+function delete_version(name, version, quick)
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+
+ local function delete_deployed_file_tree(file_tree, deploy_dir)
+ return recurse_rock_manifest_tree(file_tree,
+ function(parent_path, parent_module, file)
+ local target = dir.path(deploy_dir, parent_path, file)
+ local versioned = path.versioned_name(target, deploy_dir, name, version)
+ if fs.exists(versioned) then
+ local ok = fs.delete(versioned)
+ fs.remove_dir_tree_if_empty(dir.dir_name(versioned))
+ if not ok then return nil, "Failed deleting "..versioned end
+ else
+ local ok = fs.delete(target)
+ if not quick then
+ local next_name, next_version = manif.find_next_provider(target)
+ if next_name then
+ local versioned = path.versioned_name(target, deploy_dir, next_name, next_version)
+ fs.move(versioned, target)
+ fs.remove_dir_tree_if_empty(dir.dir_name(versioned))
+ end
+ end
+ fs.remove_dir_tree_if_empty(dir.dir_name(target))
+ if not ok then return nil, "Failed deleting "..target end
+ end
+ return true
+ end
+ )
+ end
+
+ local rock_manifest = manif.load_rock_manifest(name, version)
+ if not rock_manifest then
+ return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?"
+ end
+
+ local ok, err = true
+ if rock_manifest.bin then
+ ok, err = delete_deployed_file_tree(rock_manifest.bin, cfg.deploy_bin_dir)
+ end
+ if ok and rock_manifest.lua then
+ ok, err = delete_deployed_file_tree(rock_manifest.lua, cfg.deploy_lua_dir)
+ end
+ if ok and rock_manifest.lib then
+ ok, err = delete_deployed_file_tree(rock_manifest.lib, cfg.deploy_lib_dir)
+ end
+ if err then return nil, err end
+
+ fs.delete(path.install_dir(name, version))
+ if not get_installed_versions(name) then
+ fs.delete(dir.path(cfg.rocks_dir, name))
+ end
+ return true
+end
diff --git a/src/luarocks/require.lua b/src/luarocks/require.lua
new file mode 100644
index 0000000..9917770
--- /dev/null
+++ b/src/luarocks/require.lua
@@ -0,0 +1,6 @@
+--- Retained for compatibility reasons only. Use luarocks.loader instead.
+local require, pairs = require, pairs
+module("luarocks.require")
+for k,v in pairs(require("luarocks.loader")) do
+ _M[k] = v
+end
diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua
new file mode 100644
index 0000000..1fc1f9a
--- /dev/null
+++ b/src/luarocks/search.lua
@@ -0,0 +1,386 @@
+
+--- Module implementing the LuaRocks "search" command.
+-- Queries LuaRocks servers.
+module("luarocks.search", package.seeall)
+
+local dir = require("luarocks.dir")
+local path = require("luarocks.path")
+local manif = require("luarocks.manif")
+local deps = require("luarocks.deps")
+local cfg = require("luarocks.cfg")
+local util = require("luarocks.util")
+
+help_summary = "Query the LuaRocks servers."
+help_arguments = "[--source] [--binary] { <name> [<version>] | --all }"
+help = [[
+--source Return only rockspecs and source rocks,
+ to be used with the "build" command.
+--binary Return only pure Lua and binary rocks (rocks that can be used
+ with the "install" command without requiring a C toolchain).
+--all List all contents of the server that are suitable to
+ this platform, do not filter by name.
+]]
+
+--- Convert the arch field of a query table to table format.
+-- @param query table: A query table.
+local function query_arch_as_table(query)
+ local format = type(query.arch)
+ if format == "table" then
+ return
+ elseif format == "nil" then
+ local accept = {}
+ accept["src"] = true
+ accept["all"] = true
+ accept["rockspec"] = true
+ accept["installed"] = true
+ accept[cfg.arch] = true
+ query.arch = accept
+ elseif format == "string" then
+ local accept = {}
+ for a in query.arch:gmatch("[%w_-]+") do
+ accept[a] = true
+ end
+ query.arch = accept
+ end
+end
+
+--- Store a search result (a rock or rockspec) in the results table.
+-- @param results table: The results table, where keys are package names and
+-- versions are tables matching version strings to an array of servers.
+-- @param name string: Package name.
+-- @param version string: Package version.
+-- @param arch string: Architecture of rock ("all", "src" or platform
+-- identifier), "rockspec" or "installed"
+-- @param repo string: Pathname of a local repository of URL of
+-- rocks server.
+local function store_result(results, name, version, arch, repo)
+ assert(type(results) == "table")
+ assert(type(name) == "string")
+ assert(type(version) == "string")
+ assert(type(arch) == "string")
+ assert(type(repo) == "string")
+
+ if not results[name] then results[name] = {} end
+ if not results[name][version] then results[name][version] = {} end
+ table.insert(results[name][version], {
+ arch = arch,
+ repo = repo
+ })
+end
+
+--- Test the name field of a query.
+-- If query has a boolean field exact_name set to false,
+-- then substring match is performed; otherwise, exact string
+-- comparison is done.
+-- @param query table: A query in dependency table format.
+-- @param name string: A package name.
+-- @return boolean: True if names match, false otherwise.
+local function match_name(query, name)
+ assert(type(query) == "table")
+ assert(type(name) == "string")
+ if query.exact_name == false then
+ return name:find(query.name, 0, true) and true or false
+ else
+ return name == query.name
+ end
+end
+
+--- Store a match in a results table if version matches query.
+-- Name, version, arch and repository path are stored in a given
+-- table, optionally checking if version and arch (if given) match
+-- a query.
+-- @param results table: The results table, where keys are package names and
+-- versions are tables matching version strings to an array of servers.
+-- @param repo string: URL or pathname of the repository.
+-- @param name string: The name of the package being tested.
+-- @param version string: The version of the package being tested.
+-- @param arch string: The arch of the package being tested.
+-- @param query table: A table describing the query in dependency
+-- format (for example, {name = "filesystem", exact_name = false,
+-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec").
+-- If the arch field is omitted, the local architecture (cfg.arch)
+-- is used. The special value "any" is also recognized, returning all
+-- matches regardless of architecture.
+local function store_if_match(results, repo, name, version, arch, query)
+ if match_name(query, name) then
+ if query.arch[arch] or query.arch["any"] then
+ if deps.match_constraints(deps.parse_version(version), query.constraints) then
+ store_result(results, name, version, arch, repo)
+ end
+ end
+ end
+end
+
+--- Perform search on a local repository.
+-- @param repo string: The pathname of the local repository.
+-- @param query table: A table describing the query in dependency
+-- format (for example, {name = "filesystem", exact_name = false,
+-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec").
+-- If the arch field is omitted, the local architecture (cfg.arch)
+-- is used. The special value "any" is also recognized, returning all
+-- matches regardless of architecture.
+-- @param results table or nil: If given, this table will store the
+-- results; if not given, a new table will be created.
+-- @param table: The results table, where keys are package names and
+-- versions are tables matching version strings to an array of servers.
+-- If a table was given in the "results" parameter, that is the result value.
+function disk_search(repo, query, results)
+ assert(type(repo) == "string")
+ assert(type(query) == "table")
+ assert(type(results) == "table" or not results)
+
+ local fs = require("luarocks.fs")
+
+ if not results then
+ results = {}
+ end
+ query_arch_as_table(query)
+
+ for _, name in pairs(fs.list_dir(repo)) do
+ local pathname = dir.path(repo, name)
+ local rname, rversion, rarch = path.parse_name(name)
+ if fs.is_dir(pathname) then
+ for _, version in pairs(fs.list_dir(pathname)) do
+ if version:match("-%d+$") then
+ store_if_match(results, repo, name, version, "installed", query)
+ end
+ end
+ elseif rname then
+ store_if_match(results, repo, rname, rversion, rarch, query)
+ end
+ end
+ return results
+end
+
+--- Perform search on a rocks server.
+-- @param results table: The results table, where keys are package names and
+-- versions are tables matching version strings to an array of servers.
+-- @param repo string: The URL of the rocks server.
+-- @param query table: A table describing the query in dependency
+-- format (for example, {name = "filesystem", exact_name = false,
+-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec").
+-- If the arch field is omitted, the local architecture (cfg.arch)
+-- is used. The special value "any" is also recognized, returning all
+-- matches regardless of architecture.
+-- @return true or, in case of errors, nil and an error message.
+function manifest_search(results, repo, query)
+ assert(type(results) == "table")
+ assert(type(repo) == "string")
+ assert(type(query) == "table")
+
+ query_arch_as_table(query)
+ local manifest, err = manif.load_manifest(repo)
+ if not manifest then
+ return nil, "Failed loading manifest: "..err
+ end
+ for name, versions in pairs(manifest.repository) do
+ for version, items in pairs(versions) do
+ for _, item in ipairs(items) do
+ store_if_match(results, repo, name, version, item.arch, query)
+ end
+ end
+ end
+ return true
+end
+
+--- Search on all configured rocks servers.
+-- @param query table: A dependency query.
+-- @return table: A table where keys are package names
+-- and values are tables matching version strings to an array of
+-- rocks servers; if no results are found, an empty table is returned.
+function search_repos(query)
+ assert(type(query) == "table")
+
+ local results = {}
+ for _, repo in ipairs(cfg.rocks_servers) do
+ if type(repo) == "string" then
+ repo = { repo }
+ end
+ for _, mirror in ipairs(repo) do
+ local protocol, pathname = dir.split_url(mirror)
+ if protocol == "file" then
+ mirror = pathname
+ end
+ local ok, err = manifest_search(results, mirror, query)
+ if ok then
+ break
+ else
+ util.warning("Failed searching manifest: "..err)
+ end
+ end
+ end
+ return results
+end
+
+--- Prepare a query in dependency table format.
+-- @param name string: The query name.
+-- @param version string or nil:
+-- @return table: A query in table format
+function make_query(name, version)
+ assert(type(name) == "string")
+ assert(type(version) == "string" or not version)
+
+ local query = {
+ name = name,
+ constraints = {}
+ }
+ if version then
+ table.insert(query.constraints, { op = "==", version = deps.parse_version(version)})
+ end
+ return query
+end
+
+--- Get the URL for the latest in a set of versions.
+-- @param name string: The package name to be used in the URL.
+-- @param versions table: An array of version informations, as stored
+-- in search results tables.
+-- @return string or nil: the URL for the latest version if one could
+-- be picked, or nil.
+local function pick_latest_version(name, versions)
+ assert(type(name) == "string")
+ assert(type(versions) == "table")
+
+ local vtables = {}
+ for v, _ in pairs(versions) do
+ table.insert(vtables, deps.parse_version(v))
+ end
+ table.sort(vtables)
+ local version = vtables[#vtables].string
+ local items = versions[version]
+ if items then
+ local pick = 1
+ for i, item in ipairs(items) do
+ if (item.arch == 'src' and items[pick].arch == 'rockspec')
+ or (item.arch ~= 'src' and item.arch ~= 'rockspec') then
+ pick = i
+ end
+ end
+ return path.make_url(items[pick].repo, name, version, items[pick].arch)
+ end
+ return nil
+end
+
+--- Attempt to get a single URL for a given search.
+-- @param query table: A dependency query.
+-- @return string or table or (nil, string): URL for matching rock if
+-- a single one was found, a table of candidates if it could not narrow to
+-- a single result, or nil followed by an error message.
+function find_suitable_rock(query)
+ assert(type(query) == "table")
+
+ local results = search_repos(query)
+ local first = next(results)
+ if not first then
+ return nil, "No results matching query were found."
+ elseif not next(results, first) then
+ return pick_latest_version(query.name, results[first])
+ else
+ return results
+ end
+end
+
+--- Print a list of rocks/rockspecs on standard output.
+-- @param results table: A table where keys are package names and versions
+-- are tables matching version strings to an array of rocks servers.
+-- @param porcelain boolean or nil: A flag to force machine-friendly output.
+function print_results(results, porcelain)
+ assert(type(results) == "table")
+ assert(type(porcelain) == "boolean" or not porcelain)
+
+ for package, versions in util.sortedpairs(results) do
+ if not porcelain then
+ util.printout(package)
+ end
+ for version, repos in util.sortedpairs(versions, deps.compare_versions) do
+ for _, repo in ipairs(repos) do
+ if porcelain then
+ util.printout(package, version, repo.arch, repo.repo)
+ else
+ util.printout(" "..version.." ("..repo.arch..") - "..repo.repo)
+ end
+ end
+ end
+ if not porcelain then
+ util.printout()
+ end
+ end
+end
+
+--- Splits a list of search results into two lists, one for "source" results
+-- to be used with the "build" command, and one for "binary" results to be
+-- used with the "install" command.
+-- @param results table: A search results table.
+-- @return (table, table): Two tables, one for source and one for binary
+-- results.
+local function split_source_and_binary_results(results)
+ local sources, binaries = {}, {}
+ for name, versions in pairs(results) do
+ for version, repositories in pairs(versions) do
+ for _, repo in ipairs(repositories) do
+ local where = sources
+ if repo.arch == "all" or repo.arch == cfg.arch then
+ where = binaries
+ end
+ store_result(where, name, version, repo.arch, repo.repo)
+ end
+ end
+ end
+ return sources, binaries
+end
+
+--- Given a name and optionally a version, try to find in the rocks
+-- servers a single .src.rock or .rockspec file that satisfies
+-- the request, and run the given function on it; or display to the
+-- user possibilities if it couldn't narrow down a single match.
+-- @param action function: A function that takes a .src.rock or
+-- .rockspec URL as a parameter.
+-- @param name string: A rock name
+-- @param version string or nil: A version number may also be given.
+-- @return The result of the action function, or nil and an error message.
+function act_on_src_or_rockspec(action, name, version, ...)
+ assert(type(action) == "function")
+ assert(type(name) == "string")
+ assert(type(version) == "string" or not version)
+
+ local query = make_query(name, version)
+ query.arch = "src|rockspec"
+ local results, err = find_suitable_rock(query)
+ if type(results) == "string" then
+ return action(results, ...)
+ else
+ return nil, "Could not find a result named "..name..(version and " "..version or "").."."
+ end
+end
+
+--- Driver function for "search" command.
+-- @param name string: A substring of a rock name to search.
+-- @param version string or nil: a version may also be passed.
+-- @return boolean or (nil, string): True if build was successful; nil and an
+-- error message otherwise.
+function run(...)
+ local flags, name, version = util.parse_flags(...)
+
+ if flags["all"] then
+ name, version = "", nil
+ end
+
+ if type(name) ~= "string" and not flags["all"] then
+ return nil, "Enter name and version or use --all. "..util.see_help("search")
+ end
+
+ local query = make_query(name:lower(), version)
+ query.exact_name = false
+ local results, err = search_repos(query)
+ local porcelain = flags["porcelain"]
+ util.title("Search results:", porcelain, "=")
+ local sources, binaries = split_source_and_binary_results(results)
+ if next(sources) and not flags["binary"] then
+ util.title("Rockspecs and source rocks:", porcelain)
+ print_results(sources, porcelain)
+ end
+ if next(binaries) and not flags["source"] then
+ util.title("Binary and pure-Lua rocks:", porcelain)
+ print_results(binaries, porcelain)
+ end
+ return true
+end
diff --git a/src/luarocks/show.lua b/src/luarocks/show.lua
new file mode 100644
index 0000000..536085a
--- /dev/null
+++ b/src/luarocks/show.lua
@@ -0,0 +1,156 @@
+
+--- Module implementing the LuaRocks "show" command.
+-- Shows information about an installed rock.
+module("luarocks.show", package.seeall)
+
+local search = require("luarocks.search")
+local cfg = require("luarocks.cfg")
+local util = require("luarocks.util")
+local path = require("luarocks.path")
+local dir = require("luarocks.dir")
+local deps = require("luarocks.deps")
+local fetch = require("luarocks.fetch")
+local manif = require("luarocks.manif")
+help_summary = "Shows information about an installed rock."
+
+help = [[
+<argument> is an existing package name.
+Without any flags, show all module information.
+With these flags, return only the desired information:
+
+--home home page of project
+--modules all modules provided by this package as used by require()
+--deps packages this package depends on
+--rockspec the full path of the rockspec file
+--mversion the package version
+--rock-tree local tree where rock is installed
+--rock-dir data directory of the installed rock
+]]
+
+local function keys_as_string(t, sep)
+ return table.concat(util.keys(t), sep or " ")
+end
+
+local function word_wrap(line)
+ local width = tonumber(os.getenv("COLUMNS")) or 80
+ if width > 80 then width = 80 end
+ if #line > width then
+ local brk = width
+ while brk > 0 and line:sub(brk, brk) ~= " " do
+ brk = brk - 1
+ end
+ if brk > 0 then
+ return line:sub(1, brk-1) .. "\n" .. word_wrap(line:sub(brk+1))
+ end
+ end
+ return line
+end
+
+local function format_text(text)
+ text = text:gsub("^%s*",""):gsub("%s$", ""):gsub("\n[ \t]+","\n"):gsub("([^\n])\n([^\n])","%1 %2")
+ local paragraphs = util.split_string(text, "\n\n")
+ for n, line in ipairs(paragraphs) do
+ paragraphs[n] = word_wrap(line)
+ end
+ return (table.concat(paragraphs, "\n\n"):gsub("%s$", ""))
+end
+
+local function module_name(mod, filename, name, version, repo, manifest)
+ local base_dir
+ if filename:match("%.lua$") then
+ base_dir = path.deploy_lua_dir(repo)
+ else
+ base_dir = path.deploy_lib_dir(repo)
+ end
+
+ return dir.path(base_dir, filename)
+end
+
+--- Driver function for "show" command.
+-- @param name or nil: an existing package name.
+-- @param version string or nil: a version may also be passed.
+-- @return boolean: True if succeeded, nil on errors.
+function run(...)
+ local flags, name, version = util.parse_flags(...)
+ if not name then
+ return nil, "Argument missing. "..util.see_help("show")
+ end
+ local results = {}
+ local query = search.make_query(name, version)
+ query.exact_name = true
+ local tree_map = {}
+ local trees = cfg.rocks_trees
+ if flags["tree"] then
+ trees = { flags["tree"] }
+ end
+ for _, tree in ipairs(trees) do
+ local rocks_dir = path.rocks_dir(tree)
+ tree_map[rocks_dir] = tree
+ search.manifest_search(results, rocks_dir, query)
+ end
+
+ if not next(results) then --
+ return nil,"cannot find package "..name.." "..(version or "").."\nUse 'list' to find installed rocks."
+ end
+
+ version = nil
+ local repo_url
+ local package, versions = util.sortedpairs(results)()
+ --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, deps.compare_versions) do
+ if not version then version = vs end
+ for _, rp in ipairs(repositories) do repo_url = rp.repo end
+ end
+
+
+ local repo = tree_map[repo_url]
+ local directory = path.install_dir(name,version,repo)
+ local rockspec_file = path.rockspec_file(name, version, repo)
+ local rockspec, err = fetch.load_local_rockspec(rockspec_file)
+ if not rockspec then return nil,err end
+
+ local descript = rockspec.description or {}
+ local manifest, err = manif.load_manifest(repo_url)
+ if not manifest then return nil,err end
+ local minfo = manifest.repository[name][version][1]
+
+ if flags["rock-tree"] then util.printout(path.rocks_tree_to_string(repo))
+ elseif flags["rock-dir"] then util.printout(directory)
+ elseif flags["home"] then util.printout(descript.homepage)
+ elseif flags["modules"] then util.printout(keys_as_string(minfo.modules))
+ elseif flags["deps"] then util.printout(keys_as_string(minfo.dependencies))
+ elseif flags["rockspec"] then util.printout(rockspec_file)
+ elseif flags["mversion"] then util.printout(version)
+ else
+ util.printout()
+ util.printout(rockspec.package.." "..rockspec.version.." - "..(descript.summary or ""))
+ util.printout()
+ if descript.detailed then
+ util.printout(format_text(descript.detailed))
+ util.printout()
+ end
+ if descript.license then
+ util.printout("License: ", descript.license)
+ end
+ if descript.homepage then
+ util.printout("Homepage: ", descript.homepage)
+ end
+ util.printout("Installed in: ", path.rocks_tree_to_string(repo))
+ if next(minfo.modules) then
+ util.printout()
+ util.printout("Modules:")
+ for mod, filename in util.sortedpairs(minfo.modules) do
+ util.printout("\t"..mod.." ("..path.which(mod, filename, name, version, repo, manifest)..")")
+ end
+ end
+ if next(minfo.dependencies) then
+ util.printout()
+ util.printout("Depends on:")
+ util.printout("\t"..keys_as_string(minfo.dependencies, "\n\t"))
+ end
+ util.printout()
+ end
+ return true
+end
+
diff --git a/src/luarocks/tools/patch.lua b/src/luarocks/tools/patch.lua
new file mode 100644
index 0000000..baaacfc
--- /dev/null
+++ b/src/luarocks/tools/patch.lua
@@ -0,0 +1,712 @@
+--- Patch utility to apply unified diffs.
+--
+-- http://lua-users.org/wiki/LuaPatch
+--
+-- (c) 2008 David Manura, Licensed under the same terms as Lua (MIT license).
+-- Code is heavilly based on the Python-based patch.py version 8.06-1
+-- Copyright (c) 2008 rainforce.org, MIT License
+-- Project home: http://code.google.com/p/python-patch/ .
+
+module("luarocks.tools.patch", package.seeall)
+
+local fs = require("luarocks.fs")
+
+local version = '0.1'
+
+local io = io
+local os = os
+local string = string
+local table = table
+local format = string.format
+
+-- logging
+local debugmode = false
+local function debug(s) end
+local function info(s) end
+local function warning(s) io.stderr:write(s .. '\n') end
+
+-- Returns boolean whether string s2 starts with string s.
+local function startswith(s, s2)
+ return s:sub(1, #s2) == s2
+end
+
+-- Returns boolean whether string s2 ends with string s.
+local function endswith(s, s2)
+ return #s >= #s2 and s:sub(#s-#s2+1) == s2
+end
+
+-- Returns string s after filtering out any new-line characters from end.
+local function endlstrip(s)
+ return s:gsub('[\r\n]+$', '')
+end
+
+-- Returns shallow copy of table t.
+local function table_copy(t)
+ local t2 = {}
+ for k,v in pairs(t) do t2[k] = v end
+ return t2
+end
+
+-- Returns boolean whether array t contains value v.
+local function array_contains(t, v)
+ for _,v2 in ipairs(t) do if v == v2 then return true end end
+ return false
+end
+
+local function exists(filename)
+ local fh = io.open(filename)
+ local result = fh ~= nil
+ if fh then fh:close() end
+ return result
+end
+local function isfile() return true end --FIX?
+
+local function read_file(filename)
+ local fh, err, oserr = io.open(filename, 'rb')
+ if not fh then return fh, err, oserr end
+ local data, err, oserr = fh:read'*a'
+ fh:close()
+ if not data then return nil, err, oserr end
+ return data
+end
+
+local function write_file(filename, data)
+ local fh, err, oserr = io.open(filename 'wb')
+ if not fh then return fh, err, oserr end
+ local status, err, oserr = fh:write(data)
+ fh:close()
+ if not status then return nil, err, oserr end
+ return true
+end
+
+local function file_copy(src, dest)
+ local data, err, oserr = read_file(src)
+ if not data then return data, err, oserr end
+ local status, err, oserr = write_file(dest)
+ if not status then return status, err, oserr end
+ return true
+end
+
+local function string_as_file(s)
+ return {
+ at = 0,
+ str = s,
+ len = #s,
+ eof = false,
+ read = function(self, n)
+ if self.eof then return nil end
+ local chunk = self.str:sub(self.at, self.at + n - 1)
+ self.at = self.at + n
+ if self.at > self.len then
+ self.eof = true
+ end
+ return chunk
+ end,
+ close = function(self)
+ self.eof = true
+ end,
+ }
+end
+
+--
+-- file_lines(f) is similar to f:lines() for file f.
+-- The main difference is that read_lines includes
+-- new-line character sequences ("\n", "\r\n", "\r"),
+-- if any, at the end of each line. Embedded "\0" are also handled.
+-- Caution: The newline behavior can depend on whether f is opened
+-- in binary or ASCII mode.
+-- (file_lines - version 20080913)
+--
+local function file_lines(f)
+ local CHUNK_SIZE = 1024
+ local buffer = ""
+ local pos_beg = 1
+ return function()
+ local pos, chars
+ while 1 do
+ pos, chars = buffer:match('()([\r\n].)', pos_beg)
+ if pos or not f then
+ break
+ elseif f then
+ local chunk = f:read(CHUNK_SIZE)
+ if chunk then
+ buffer = buffer:sub(pos_beg) .. chunk
+ pos_beg = 1
+ else
+ f = nil
+ end
+ end
+ end
+ if not pos then
+ pos = #buffer
+ elseif chars == '\r\n' then
+ pos = pos + 1
+ end
+ local line = buffer:sub(pos_beg, pos)
+ pos_beg = pos + 1
+ if #line > 0 then
+ return line
+ end
+ end
+end
+
+local function match_linerange(line)
+ local m1, m2, m3, m4 = line:match("^@@ %-(%d+),(%d+) %+(%d+),(%d+)")
+ if not m1 then m1, m3, m4 = line:match("^@@ %-(%d+) %+(%d+),(%d+)") end
+ if not m1 then m1, m2, m3 = line:match("^@@ %-(%d+),(%d+) %+(%d+)") end
+ if not m1 then m1, m3 = line:match("^@@ %-(%d+) %+(%d+)") end
+ return m1, m2, m3, m4
+end
+
+function read_patch(filename, data)
+ -- define possible file regions that will direct the parser flow
+ local state = 'header'
+ -- 'header' - comments before the patch body
+ -- 'filenames' - lines starting with --- and +++
+ -- 'hunkhead' - @@ -R +R @@ sequence
+ -- 'hunkbody'
+ -- 'hunkskip' - skipping invalid hunk mode
+
+ local all_ok = true
+ local lineends = {lf=0, crlf=0, cr=0}
+ local files = {source={}, target={}, hunks={}, fileends={}, hunkends={}}
+ local nextfileno = 0
+ local nexthunkno = 0 --: even if index starts with 0 user messages
+ -- number hunks from 1
+
+ -- hunkinfo holds parsed values, hunkactual - calculated
+ local hunkinfo = {
+ startsrc=nil, linessrc=nil, starttgt=nil, linestgt=nil,
+ invalid=false, text={}
+ }
+ local hunkactual = {linessrc=nil, linestgt=nil}
+
+ info(format("reading patch %s", filename))
+
+ local fp
+ if data then
+ fp = string_as_file(data)
+ else
+ fp = filename == '-' and io.stdin or assert(io.open(filename, "rb"))
+ end
+ local lineno = 0
+
+ for line in file_lines(fp) do
+ lineno = lineno + 1
+ if state == 'header' then
+ if startswith(line, "--- ") then
+ state = 'filenames'
+ end
+ -- state is 'header' or 'filenames'
+ end
+ if state == 'hunkbody' then
+ -- skip hunkskip and hunkbody code until definition of hunkhead read
+
+ -- process line first
+ if line:match"^[- +\\]" or line:match"^[\r\n]*$" then
+ -- gather stats about line endings
+ local he = files.hunkends[nextfileno]
+ if endswith(line, "\r\n") then
+ he.crlf = he.crlf + 1
+ elseif endswith(line, "\n") then
+ he.lf = he.lf + 1
+ elseif endswith(line, "\r") then
+ he.cr = he.cr + 1
+ end
+ if startswith(line, "-") then
+ hunkactual.linessrc = hunkactual.linessrc + 1
+ elseif startswith(line, "+") then
+ hunkactual.linestgt = hunkactual.linestgt + 1
+ elseif startswith(line, "\\") then
+ -- nothing
+ else
+ hunkactual.linessrc = hunkactual.linessrc + 1
+ hunkactual.linestgt = hunkactual.linestgt + 1
+ end
+ table.insert(hunkinfo.text, line)
+ -- todo: handle \ No newline cases
+ else
+ warning(format("invalid hunk no.%d at %d for target file %s",
+ nexthunkno, lineno, files.target[nextfileno]))
+ -- add hunk status node
+ table.insert(files.hunks[nextfileno], table_copy(hunkinfo))
+ files.hunks[nextfileno][nexthunkno].invalid = true
+ all_ok = false
+ state = 'hunkskip'
+ end
+
+ -- check exit conditions
+ if hunkactual.linessrc > hunkinfo.linessrc or
+ hunkactual.linestgt > hunkinfo.linestgt
+ then
+ warning(format("extra hunk no.%d lines at %d for target %s",
+ nexthunkno, lineno, files.target[nextfileno]))
+ -- add hunk status node
+ table.insert(files.hunks[nextfileno], table_copy(hunkinfo))
+ files.hunks[nextfileno][nexthunkno].invalid = true
+ state = 'hunkskip'
+ elseif hunkinfo.linessrc == hunkactual.linessrc and
+ hunkinfo.linestgt == hunkactual.linestgt
+ then
+ table.insert(files.hunks[nextfileno], table_copy(hunkinfo))
+ state = 'hunkskip'
+
+ -- detect mixed window/unix line ends
+ local ends = files.hunkends[nextfileno]
+ if (ends.cr~=0 and 1 or 0) + (ends.crlf~=0 and 1 or 0) +
+ (ends.lf~=0 and 1 or 0) > 1
+ then
+ warning(format("inconsistent line ends in patch hunks for %s",
+ files.source[nextfileno]))
+ end
+ if debugmode then
+ local debuglines = {crlf=ends.crlf, lf=ends.lf, cr=ends.cr,
+ file=files.target[nextfileno], hunk=nexthunkno}
+ debug(format("crlf: %(crlf)d lf: %(lf)d cr: %(cr)d\t " ..
+ "- file: %(file)s hunk: %(hunk)d", debuglines))
+ end
+ end
+ -- state is 'hunkbody' or 'hunkskip'
+ end
+
+ if state == 'hunkskip' then
+ if match_linerange(line) then
+ state = 'hunkhead'
+ elseif startswith(line, "--- ") then
+ state = 'filenames'
+ if debugmode and #files.source > 0 then
+ debug(format("- %2d hunks for %s", #files.hunks[nextfileno],
+ files.source[nextfileno]))
+ end
+ end
+ -- state is 'hunkskip', 'hunkhead', or 'filenames'
+ end
+ local advance
+ if state == 'filenames' then
+ if startswith(line, "--- ") then
+ if array_contains(files.source, nextfileno) then
+ all_ok = false
+ warning(format("skipping invalid patch for %s",
+ files.source[nextfileno+1]))
+ table.remove(files.source, nextfileno+1)
+ -- double source filename line is encountered
+ -- attempt to restart from this second line
+ end
+ -- Accept a space as a terminator, like GNU patch does.
+ -- Breaks patches containing filenames with spaces...
+ -- FIXME Figure out what does GNU patch do in those cases.
+ local match = line:match("^%-%-%- ([^ \t\r\n]+)")
+ if not match then
+ all_ok = false
+ warning(format("skipping invalid filename at line %d", lineno+1))
+ state = 'header'
+ else
+ table.insert(files.source, match)
+ end
+ elseif not startswith(line, "+++ ") then
+ if array_contains(files.source, nextfileno) then
+ all_ok = false
+ warning(format("skipping invalid patch with no target for %s",
+ files.source[nextfileno+1]))
+ table.remove(files.source, nextfileno+1)
+ else
+ -- this should be unreachable
+ warning("skipping invalid target patch")
+ end
+ state = 'header'
+ else
+ if array_contains(files.target, nextfileno) then
+ all_ok = false
+ warning(format("skipping invalid patch - double target at line %d",
+ lineno+1))
+ table.remove(files.source, nextfileno+1)
+ table.remove(files.target, nextfileno+1)
+ nextfileno = nextfileno - 1
+ -- double target filename line is encountered
+ -- switch back to header state
+ state = 'header'
+ else
+ -- Accept a space as a terminator, like GNU patch does.
+ -- Breaks patches containing filenames with spaces...
+ -- FIXME Figure out what does GNU patch do in those cases.
+ local re_filename = "^%+%+%+ ([^ \t\r\n]+)"
+ local match = line:match(re_filename)
+ if not match then
+ all_ok = false
+ warning(format(
+ "skipping invalid patch - no target filename at line %d",
+ lineno+1))
+ state = 'header'
+ else
+ table.insert(files.target, match)
+ nextfileno = nextfileno + 1
+ nexthunkno = 0
+ table.insert(files.hunks, {})
+ table.insert(files.hunkends, table_copy(lineends))
+ table.insert(files.fileends, table_copy(lineends))
+ state = 'hunkhead'
+ advance = true
+ end
+ end
+ end
+ -- state is 'filenames', 'header', or ('hunkhead' with advance)
+ end
+ if not advance and state == 'hunkhead' then
+ local m1, m2, m3, m4 = match_linerange(line)
+ if not m1 then
+ if not array_contains(files.hunks, nextfileno-1) then
+ all_ok = false
+ warning(format("skipping invalid patch with no hunks for file %s",
+ files.target[nextfileno]))
+ end
+ state = 'header'
+ else
+ hunkinfo.startsrc = tonumber(m1)
+ hunkinfo.linessrc = tonumber(m2 or 1)
+ hunkinfo.starttgt = tonumber(m3)
+ hunkinfo.linestgt = tonumber(m4 or 1)
+ hunkinfo.invalid = false
+ hunkinfo.text = {}
+
+ hunkactual.linessrc = 0
+ hunkactual.linestgt = 0
+
+ state = 'hunkbody'
+ nexthunkno = nexthunkno + 1
+ end
+ -- state is 'header' or 'hunkbody'
+ end
+ end
+ if state ~= 'hunkskip' then
+ warning(format("patch file incomplete - %s", filename))
+ all_ok = false
+ -- os.exit(?)
+ else
+ -- duplicated message when an eof is reached
+ if debugmode and #files.source > 0 then
+ debug(format("- %2d hunks for %s", #files.hunks[nextfileno],
+ files.source[nextfileno]))
+ end
+ end
+
+ local sum = 0; for _,hset in ipairs(files.hunks) do sum = sum + #hset end
+ info(format("total files: %d total hunks: %d", #files.source, sum))
+ fp:close()
+ return files, all_ok
+end
+
+local function find_hunk(file, h, hno)
+ for fuzz=0,2 do
+ local lineno = h.startsrc
+ for i=0,#file do
+ local found = true
+ local location = lineno
+ local total = #h.text - fuzz
+ for l, hline in ipairs(h.text) do
+ if l > fuzz then
+ -- todo: \ No newline at the end of file
+ if startswith(hline, " ") or startswith(hline, "-") then
+ local line = file[lineno]
+ lineno = lineno + 1
+ if not line or #line == 0 then
+ found = false
+ break
+ end
+ if endlstrip(line) ~= endlstrip(hline:sub(2)) then
+ found = false
+ break
+ end
+ end
+ end
+ end
+ if found then
+ local offset = location - h.startsrc - fuzz
+ if offset ~= 0 then
+ warning(format("Hunk %d found at offset %d%s...", hno, offset, fuzz == 0 and "" or format(" (fuzz %d)", fuzz)))
+ end
+ h.startsrc = location
+ h.starttgt = h.starttgt + offset
+ for i=1,fuzz do
+ table.remove(h.text, 1)
+ table.remove(h.text, #h.text)
+ end
+ return true
+ end
+ lineno = i
+ end
+ end
+ return false
+end
+
+local function load_file(filename)
+ local fp = assert(io.open(filename))
+ local file = {}
+ local readline = file_lines(fp)
+ while true do
+ local line = readline()
+ if not line then break end
+ table.insert(file, line)
+ end
+ fp:close()
+ return file
+end
+
+local function find_hunks(file, hunks)
+ local matched = true
+ local lineno = 1
+ local hno = nil
+ for hno, h in ipairs(hunks) do
+ find_hunk(file, h, hno)
+ end
+end
+
+local function check_patched(file, hunks)
+ local matched = true
+ local lineno = 1
+ local hno = nil
+ local ok, err = pcall(function()
+ if #file == 0 then
+ error 'nomatch'
+ end
+ for hno, h in ipairs(hunks) do
+ -- skip to line just before hunk starts
+ if #file < h.starttgt then
+ error 'nomatch'
+ end
+ lineno = h.starttgt
+ for _, hline in ipairs(h.text) do
+ -- todo: \ No newline at the end of file
+ if not startswith(hline, "-") and not startswith(hline, "\\") then
+ local line = file[lineno]
+ lineno = lineno + 1
+ if #line == 0 then
+ error 'nomatch'
+ end
+ if endlstrip(line) ~= endlstrip(hline:sub(2)) then
+ warning(format("file is not patched - failed hunk: %d", hno))
+ error 'nomatch'
+ end
+ end
+ end
+ end
+ end)
+ if err == 'nomatch' then
+ matched = false
+ end
+ -- todo: display failed hunk, i.e. expected/found
+
+ return matched
+end
+
+local function patch_hunks(srcname, tgtname, hunks)
+ local src = assert(io.open(srcname, "rb"))
+ local tgt = assert(io.open(tgtname, "wb"))
+
+ local src_readline = file_lines(src)
+
+ -- todo: detect linefeeds early - in apply_files routine
+ -- to handle cases when patch starts right from the first
+ -- line and no lines are processed. At the moment substituted
+ -- lineends may not be the same at the start and at the end
+ -- of patching. Also issue a warning about mixed lineends
+
+ local srclineno = 1
+ local lineends = {['\n']=0, ['\r\n']=0, ['\r']=0}
+ for hno, h in ipairs(hunks) do
+ debug(format("processing hunk %d for file %s", hno, tgtname))
+ -- skip to line just before hunk starts
+ while srclineno < h.startsrc do
+ local line = src_readline()
+ -- Python 'U' mode works only with text files
+ if endswith(line, "\r\n") then
+ lineends["\r\n"] = lineends["\r\n"] + 1
+ elseif endswith(line, "\n") then
+ lineends["\n"] = lineends["\n"] + 1
+ elseif endswith(line, "\r") then
+ lineends["\r"] = lineends["\r"] + 1
+ end
+ tgt:write(line)
+ srclineno = srclineno + 1
+ end
+
+ for _,hline in ipairs(h.text) do
+ -- todo: check \ No newline at the end of file
+ if startswith(hline, "-") or startswith(hline, "\\") then
+ src_readline()
+ srclineno = srclineno + 1
+ else
+ if not startswith(hline, "+") then
+ src_readline()
+ srclineno = srclineno + 1
+ end
+ local line2write = hline:sub(2)
+ -- detect if line ends are consistent in source file
+ local sum = 0
+ for k,v in pairs(lineends) do if v > 0 then sum=sum+1 end end
+ if sum == 1 then
+ local newline
+ for k,v in pairs(lineends) do if v ~= 0 then newline = k end end
+ tgt:write(endlstrip(line2write) .. newline)
+ else -- newlines are mixed or unknown
+ tgt:write(line2write)
+ end
+ end
+ end
+ end
+ for line in src_readline do
+ tgt:write(line)
+ end
+ tgt:close()
+ src:close()
+ return true
+end
+
+local function strip_dirs(filename, strip)
+ if strip == nil then return filename end
+ for i=1,strip do
+ filename=filename:gsub("^[^/]*/", "")
+ end
+ return filename
+end
+
+function apply_patch(patch, strip)
+ local all_ok = true
+ local total = #patch.source
+ for fileno, filename in ipairs(patch.source) do
+ filename = strip_dirs(filename, strip)
+ local continue
+ local f2patch = filename
+ if not exists(f2patch) then
+ f2patch = strip_dirs(patch.target[fileno], strip)
+ f2patch = fs.absolute_name(f2patch)
+ if not exists(f2patch) then --FIX:if f2patch nil
+ warning(format("source/target file does not exist\n--- %s\n+++ %s",
+ filename, f2patch))
+ all_ok = false
+ continue = true
+ end
+ end
+ if not continue and not isfile(f2patch) then
+ warning(format("not a file - %s", f2patch))
+ all_ok = false
+ continue = true
+ end
+ if not continue then
+
+ filename = f2patch
+
+ info(format("processing %d/%d:\t %s", fileno, total, filename))
+
+ -- validate before patching
+ local hunks = patch.hunks[fileno]
+ local file = load_file(filename)
+ local hunkno = 1
+ local hunk = hunks[hunkno]
+ local hunkfind = {}
+ local hunkreplace = {}
+ local validhunks = 0
+ local canpatch = false
+ local hunklineno
+ local isbreak
+ local lineno = 0
+
+ find_hunks(file, hunks)
+
+ for _, line in ipairs(file) do
+ lineno = lineno + 1
+ local continue
+ if not hunk or lineno < hunk.startsrc then
+ continue = true
+ elseif lineno == hunk.startsrc then
+ hunkfind = {}
+ for _,x in ipairs(hunk.text) do
+ if x:sub(1,1) == ' ' or x:sub(1,1) == '-' then
+ hunkfind[#hunkfind+1] = endlstrip(x:sub(2))
+ end end
+ hunkreplace = {}
+ for _,x in ipairs(hunk.text) do
+ if x:sub(1,1) == ' ' or x:sub(1,1) == '+' then
+ hunkreplace[#hunkreplace+1] = endlstrip(x:sub(2))
+ end end
+ --pprint(hunkreplace)
+ hunklineno = 1
+
+ -- todo \ No newline at end of file
+ end
+ -- check hunks in source file
+ if not continue and lineno < hunk.startsrc + #hunkfind - 1 then
+ if endlstrip(line) == hunkfind[hunklineno] then
+ hunklineno = hunklineno + 1
+ else
+ debug(format("hunk no.%d doesn't match source file %s",
+ hunkno, filename))
+ -- file may be already patched, but check other hunks anyway
+ hunkno = hunkno + 1
+ if hunkno <= #hunks then
+ hunk = hunks[hunkno]
+ continue = true
+ else
+ isbreak = true; break
+ end
+ end
+ end
+ -- check if processed line is the last line
+ if not continue and lineno == hunk.startsrc + #hunkfind - 1 then
+ debug(format("file %s hunk no.%d -- is ready to be patched",
+ filename, hunkno))
+ hunkno = hunkno + 1
+ validhunks = validhunks + 1
+ if hunkno <= #hunks then
+ hunk = hunks[hunkno]
+ else
+ if validhunks == #hunks then
+ -- patch file
+ canpatch = true
+ isbreak = true; break
+ end
+ end
+ end
+ end
+ if not isbreak then
+ if hunkno <= #hunks then
+ warning(format("premature end of source file %s at hunk %d",
+ filename, hunkno))
+ all_ok = false
+ end
+ end
+ if validhunks < #hunks then
+ if check_patched(file, hunks) then
+ warning(format("already patched %s", filename))
+ else
+ warning(format("source file is different - %s", filename))
+ all_ok = false
+ end
+ end
+ if canpatch then
+ local backupname = filename .. ".orig"
+ if exists(backupname) then
+ warning(format("can't backup original file to %s - aborting",
+ backupname))
+ all_ok = false
+ else
+ assert(os.rename(filename, backupname))
+ if patch_hunks(backupname, filename, hunks) then
+ warning(format("successfully patched %s", filename))
+ assert(os.remove(backupname))
+ else
+ warning(format("error patching file %s", filename))
+ assert(file_copy(filename, filename .. ".invalid"))
+ warning(format("invalid version is saved to %s",
+ filename .. ".invalid"))
+ -- todo: proper rejects
+ assert(os.rename(backupname, filename))
+ all_ok = false
+ end
+ end
+ end
+
+ end -- if not continue
+ end -- for
+ -- todo: check for premature eof
+ return all_ok
+end
diff --git a/src/luarocks/tools/tar.lua b/src/luarocks/tools/tar.lua
new file mode 100644
index 0000000..ba01a41
--- /dev/null
+++ b/src/luarocks/tools/tar.lua
@@ -0,0 +1,144 @@
+
+--- A pure-Lua implementation of untar (unpacking .tar archives)
+module("luarocks.tools.tar", package.seeall)
+
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local util = require("luarocks.util")
+
+local blocksize = 512
+
+local function get_typeflag(flag)
+ if flag == "0" or flag == "\0" then return "file"
+ elseif flag == "1" then return "link"
+ elseif flag == "2" then return "symlink" -- "reserved" in POSIX, "symlink" in GNU
+ elseif flag == "3" then return "character"
+ elseif flag == "4" then return "block"
+ elseif flag == "5" then return "directory"
+ elseif flag == "6" then return "fifo"
+ elseif flag == "7" then return "contiguous" -- "reserved" in POSIX, "contiguous" in GNU
+ elseif flag == "x" then return "next file"
+ elseif flag == "g" then return "global extended header"
+ elseif flag == "L" then return "long name"
+ elseif flag == "K" then return "long link name"
+ end
+ return "unknown"
+end
+
+local function octal_to_number(octal)
+ local exp = 0
+ local number = 0
+ for i = #octal,1,-1 do
+ local digit = tonumber(octal:sub(i,i))
+ if not digit then break end
+ number = number + (digit * 8^exp)
+ exp = exp + 1
+ end
+ return number
+end
+
+local function checksum_header(block)
+ local sum = 256
+ for i = 1,148 do
+ sum = sum + block:byte(i)
+ end
+ for i = 157,500 do
+ sum = sum + block:byte(i)
+ end
+ return sum
+end
+
+local function nullterm(s)
+ return s:match("^[^%z]*")
+end
+
+local function read_header_block(block)
+ local header = {}
+ header.name = nullterm(block:sub(1,100))
+ header.mode = nullterm(block:sub(101,108))
+ header.uid = octal_to_number(nullterm(block:sub(109,116)))
+ header.gid = octal_to_number(nullterm(block:sub(117,124)))
+ header.size = octal_to_number(nullterm(block:sub(125,136)))
+ header.mtime = octal_to_number(nullterm(block:sub(137,148)))
+ header.chksum = octal_to_number(nullterm(block:sub(149,156)))
+ header.typeflag = get_typeflag(block:sub(157,157))
+ header.linkname = nullterm(block:sub(158,257))
+ header.magic = block:sub(258,263)
+ header.version = block:sub(264,265)
+ header.uname = nullterm(block:sub(266,297))
+ header.gname = nullterm(block:sub(298,329))
+ header.devmajor = octal_to_number(nullterm(block:sub(330,337)))
+ header.devminor = octal_to_number(nullterm(block:sub(338,345)))
+ header.prefix = block:sub(346,500)
+ if header.magic ~= "ustar " and header.magic ~= "ustar\0" then
+ return false, "Invalid header magic "..header.magic
+ end
+ if header.version ~= "00" and header.version ~= " \0" then
+ return false, "Unknown version "..header.version
+ end
+ if not checksum_header(block) == header.chksum then
+ return false, "Failed header checksum"
+ end
+ return header
+end
+
+function untar(filename, destdir)
+ assert(type(filename) == "string")
+ assert(type(destdir) == "string")
+
+ local tar_handle = io.open(filename, "r")
+ if not tar_handle then return nil, "Error opening file "..filename end
+
+ local long_name, long_link_name
+ while true do
+ local block
+ repeat
+ block = tar_handle:read(blocksize)
+ until (not block) or checksum_header(block) > 256
+ if not block then break end
+ local header, err = read_header_block(block)
+ if not header then
+ util.printerr(err)
+ end
+
+ local file_data = tar_handle:read(math.ceil(header.size / blocksize) * blocksize):sub(1,header.size)
+
+ if header.typeflag == "long name" then
+ long_name = nullterm(file_data)
+ elseif header.typeflag == "long link name" then
+ long_link_name = nullterm(file_data)
+ else
+ if long_name then
+ header.name = long_name
+ long_name = nil
+ end
+ if long_link_name then
+ header.name = long_link_name
+ long_link_name = nil
+ end
+ end
+ local pathname = dir.path(destdir, header.name)
+ if header.typeflag == "directory" then
+ fs.make_dir(pathname)
+ elseif header.typeflag == "file" then
+ local dirname = dir.dir_name(pathname)
+ if dirname ~= "" then
+ fs.make_dir(dirname)
+ end
+ local file_handle = io.open(pathname, "wb")
+ file_handle:write(file_data)
+ file_handle:close()
+ fs.set_time(pathname, header.mtime)
+ if fs.chmod then
+ fs.chmod(pathname, header.mode)
+ end
+ end
+ --[[
+ for k,v in pairs(header) do
+ util.printout("[\""..tostring(k).."\"] = "..(type(v)=="number" and v or "\""..v:gsub("%z", "\\0").."\""))
+ end
+ util.printout()
+ --]]
+ end
+ return true
+end
diff --git a/src/luarocks/tools/zip.lua b/src/luarocks/tools/zip.lua
new file mode 100644
index 0000000..35428d9
--- /dev/null
+++ b/src/luarocks/tools/zip.lua
@@ -0,0 +1,245 @@
+
+--- A Lua implementation of .zip file archiving (used for creating .rock files),
+-- using only lua-zlib.
+module("luarocks.tools.zip", package.seeall)
+
+local zlib = require("zlib")
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+
+local function number_to_bytestring(number, nbytes)
+ local out = {}
+ for i = 1, nbytes do
+ local byte = number % 256
+ table.insert(out, string.char(byte))
+ number = (number - byte) / 256
+ end
+ return table.concat(out)
+end
+
+--- Begin a new file to be stored inside the zipfile.
+-- @param self handle of the zipfile being written.
+-- @param filename filenome of the file to be added to the zipfile.
+-- @return true if succeeded, nil in case of failure.
+local function zipwriter_open_new_file_in_zip(self, filename)
+ if self.in_open_file then
+ self:close_file_in_zip()
+ return nil
+ end
+ local lfh = {}
+ self.local_file_header = lfh
+ lfh.last_mod_file_time = 0 -- TODO
+ lfh.last_mod_file_date = 0 -- TODO
+ lfh.crc32 = 0 -- initial value
+ lfh.compressed_size = 0 -- unknown yet
+ lfh.uncompressed_size = 0 -- unknown yet
+ lfh.file_name_length = #filename
+ lfh.extra_field_length = 0
+ lfh.file_name = filename:gsub("\\", "/")
+ lfh.external_attr = 0 -- TODO properly store permissions
+ self.in_open_file = true
+ self.data = {}
+ return true
+end
+
+--- Write data to the file currently being stored in the zipfile.
+-- @param self handle of the zipfile being written.
+-- @param buf string containing data to be written.
+-- @return true if succeeded, nil in case of failure.
+local function zipwriter_write_file_in_zip(self, buf)
+ if not self.in_open_file then
+ return nil
+ end
+ local lfh = self.local_file_header
+ local cbuf = zlib.compress(buf):sub(3, -5)
+ lfh.crc32 = zlib.crc32(lfh.crc32, buf)
+ lfh.compressed_size = lfh.compressed_size + #cbuf
+ lfh.uncompressed_size = lfh.uncompressed_size + #buf
+ table.insert(self.data, cbuf)
+ return true
+end
+
+--- Complete the writing of a file stored in the zipfile.
+-- @param self handle of the zipfile being written.
+-- @return true if succeeded, nil in case of failure.
+local function zipwriter_close_file_in_zip(self)
+ local zh = self.ziphandle
+
+ if not self.in_open_file then
+ return nil
+ end
+
+ -- Local file header
+ local lfh = self.local_file_header
+ lfh.offset = zh:seek()
+ zh:write(number_to_bytestring(0x04034b50, 4)) -- signature
+ zh:write(number_to_bytestring(20, 2)) -- version needed to extract: 2.0
+ zh:write(number_to_bytestring(0, 2)) -- general purpose bit flag
+ zh:write(number_to_bytestring(8, 2)) -- compression method: deflate
+ zh:write(number_to_bytestring(lfh.last_mod_file_time, 2))
+ zh:write(number_to_bytestring(lfh.last_mod_file_date, 2))
+ zh:write(number_to_bytestring(lfh.crc32, 4))
+ zh:write(number_to_bytestring(lfh.compressed_size, 4))
+ zh:write(number_to_bytestring(lfh.uncompressed_size, 4))
+ zh:write(number_to_bytestring(lfh.file_name_length, 2))
+ zh:write(number_to_bytestring(lfh.extra_field_length, 2))
+ zh:write(lfh.file_name)
+
+ -- File data
+ for _, cbuf in ipairs(self.data) do
+ zh:write(cbuf)
+ end
+
+ -- Data descriptor
+ zh:write(number_to_bytestring(lfh.crc32, 4))
+ zh:write(number_to_bytestring(lfh.compressed_size, 4))
+ zh:write(number_to_bytestring(lfh.uncompressed_size, 4))
+
+ table.insert(self.files, lfh)
+ self.in_open_file = false
+
+ return true
+end
+
+-- @return boolean or (boolean, string): true on success,
+-- false and an error message on failure.
+local function zipwriter_add(self, file)
+ local fin
+ local ok, err = self:open_new_file_in_zip(file)
+ if not ok then
+ err = "error in opening "..file.." in zipfile"
+ else
+ fin = io.open(fs.absolute_name(file), "rb")
+ if not fin then
+ ok = false
+ err = "error opening "..file.." for reading"
+ end
+ end
+ if ok then
+ local buf = fin:read("*a")
+ if not buf then
+ err = "error reading "..file
+ ok = false
+ else
+ ok = self:write_file_in_zip(buf)
+ if not ok then
+ err = "error in writing "..file.." in the zipfile"
+ end
+ end
+ end
+ if fin then
+ fin:close()
+ end
+ if ok then
+ ok = self:close_file_in_zip()
+ if not ok then
+ err = "error in writing "..file.." in the zipfile"
+ end
+ end
+ return ok == true, err
+end
+
+--- Complete the writing of the zipfile.
+-- @param self handle of the zipfile being written.
+-- @return true if succeeded, nil in case of failure.
+local function zipwriter_close(self)
+ local zh = self.ziphandle
+
+ local central_directory_offset = zh:seek()
+
+ local size_of_central_directory = 0
+ -- Central directory structure
+ for _, lfh in ipairs(self.files) do
+ zh:write(number_to_bytestring(0x02014b50, 4)) -- signature
+ zh:write(number_to_bytestring(3, 2)) -- version made by: UNIX
+ zh:write(number_to_bytestring(20, 2)) -- version needed to extract: 2.0
+ zh:write(number_to_bytestring(0, 2)) -- general purpose bit flag
+ zh:write(number_to_bytestring(8, 2)) -- compression method: deflate
+ zh:write(number_to_bytestring(lfh.last_mod_file_time, 2))
+ zh:write(number_to_bytestring(lfh.last_mod_file_date, 2))
+ zh:write(number_to_bytestring(lfh.crc32, 4))
+ zh:write(number_to_bytestring(lfh.compressed_size, 4))
+ zh:write(number_to_bytestring(lfh.uncompressed_size, 4))
+ zh:write(number_to_bytestring(lfh.file_name_length, 2))
+ zh:write(number_to_bytestring(lfh.extra_field_length, 2))
+ zh:write(number_to_bytestring(0, 2)) -- file comment length
+ zh:write(number_to_bytestring(0, 2)) -- disk number start
+ zh:write(number_to_bytestring(0, 2)) -- internal file attributes
+ zh:write(number_to_bytestring(lfh.external_attr, 4)) -- external file attributes
+ zh:write(number_to_bytestring(lfh.offset, 4)) -- relative offset of local header
+ zh:write(lfh.file_name)
+ size_of_central_directory = size_of_central_directory + 46 + lfh.file_name_length
+ end
+
+ -- End of central directory record
+ zh:write(number_to_bytestring(0x06054b50, 4)) -- signature
+ zh:write(number_to_bytestring(0, 2)) -- number of this disk
+ zh:write(number_to_bytestring(0, 2)) -- number of disk with start of central directory
+ zh:write(number_to_bytestring(#self.files, 2)) -- total number of entries in the central dir on this disk
+ zh:write(number_to_bytestring(#self.files, 2)) -- total number of entries in the central dir
+ zh:write(number_to_bytestring(size_of_central_directory, 4))
+ zh:write(number_to_bytestring(central_directory_offset, 4))
+ zh:write(number_to_bytestring(0, 2)) -- zip file comment length
+ zh:close()
+
+ return true
+end
+
+--- Return a zip handle open for writing.
+-- @param name filename of the zipfile to be created.
+-- @return a zip handle, or nil in case of error.
+function new_zipwriter(name)
+
+ local zw = {}
+
+ zw.ziphandle = io.open(fs.absolute_name(name), "wb")
+ if not zw.ziphandle then
+ return nil
+ end
+ zw.files = {}
+ zw.in_open_file = false
+
+ zw.add = zipwriter_add
+ zw.close = zipwriter_close
+ zw.open_new_file_in_zip = zipwriter_open_new_file_in_zip
+ zw.write_file_in_zip = zipwriter_write_file_in_zip
+ zw.close_file_in_zip = zipwriter_close_file_in_zip
+
+ return zw
+end
+
+--- Compress files in a .zip archive.
+-- @param zipfile string: pathname of .zip archive to be created.
+-- @param ... Filenames to be stored in the archive are given as
+-- additional arguments.
+-- @return boolean or (boolean, string): true on success,
+-- false and an error message on failure.
+function zip(zipfile, ...)
+ local zw = new_zipwriter(zipfile)
+ if not zw then
+ return nil, "error opening "..zipfile
+ end
+
+ local ok, err
+ for _, file in pairs({...}) do
+ if fs.is_dir(file) then
+ for _, entry in pairs(fs.find(file)) do
+ local fullname = dir.path(file, entry)
+ if fs.is_file(fullname) then
+ ok, err = zw:add(fullname)
+ if not ok then break end
+ end
+ end
+ else
+ ok, err = zw:add(file)
+ if not ok then break end
+ end
+ end
+
+ local ok = zw:close()
+ if not ok then
+ return false, "error closing "..zipfile
+ end
+ return ok, err
+end
+
diff --git a/src/luarocks/type_check.lua b/src/luarocks/type_check.lua
new file mode 100644
index 0000000..28e6e7b
--- /dev/null
+++ b/src/luarocks/type_check.lua
@@ -0,0 +1,267 @@
+
+--- Type-checking functions.
+-- Functions and definitions for doing a basic lint check on files
+-- loaded by LuaRocks.
+module("luarocks.type_check", package.seeall)
+
+local cfg = require("luarocks.cfg")
+
+rockspec_format = "1.0"
+
+rockspec_types = {
+ rockspec_format = "string",
+ MUST_package = "string",
+ MUST_version = "[%w.]+-[%d]+",
+ description = {
+ summary = "string",
+ detailed = "string",
+ homepage = "string",
+ license = "string",
+ maintainer = "string"
+ },
+ dependencies = {
+ platforms = {},
+ ANY = "string"
+ },
+ supported_platforms = {
+ ANY = "string"
+ },
+ external_dependencies = {
+ platforms = {},
+ ANY = {
+ program = "string",
+ header = "string",
+ library = "string"
+ }
+ },
+ MUST_source = {
+ platforms = {},
+ MUST_url = "string",
+ md5 = "string",
+ file = "string",
+ dir = "string",
+ tag = "string",
+ branch = "string",
+ module = "string",
+ cvs_tag = "string",
+ cvs_module = "string"
+ },
+ build = {
+ platforms = {},
+ type = "string",
+ install = {
+ lua = {
+ MORE = true
+ },
+ lib = {
+ MORE = true
+ },
+ conf = {
+ MORE = true
+ },
+ bin = {
+ MORE = true
+ }
+ },
+ copy_directories = {
+ ANY = "string"
+ },
+ MORE = true
+ },
+ hooks = {
+ platforms = {},
+ post_install = "string"
+ }
+}
+
+function load_extensions()
+ rockspec_format = "1.1"
+ rockspec_types.deploy = {
+ wrap_bin_scripts = true,
+ }
+end
+
+if cfg.use_extensions then
+ load_extensions()
+end
+
+rockspec_types.build.platforms.ANY = rockspec_types.build
+rockspec_types.dependencies.platforms.ANY = rockspec_types.dependencies
+rockspec_types.external_dependencies.platforms.ANY = rockspec_types.external_dependencies
+rockspec_types.MUST_source.platforms.ANY = rockspec_types.MUST_source
+rockspec_types.hooks.platforms.ANY = rockspec_types.hooks
+
+manifest_types = {
+ MUST_repository = {
+ -- packages
+ ANY = {
+ -- versions
+ ANY = {
+ -- items
+ ANY = {
+ MUST_arch = "string",
+ modules = { ANY = "string" },
+ commands = { ANY = "string" },
+ dependencies = { ANY = "string" },
+ -- TODO: to be extended with more metadata.
+ }
+ }
+ }
+ },
+ MUST_modules = {
+ -- modules
+ ANY = {
+ -- providers
+ ANY = "string"
+ }
+ },
+ MUST_commands = {
+ -- modules
+ ANY = {
+ -- commands
+ ANY = "string"
+ }
+ },
+ dependencies = {
+ -- each module
+ ANY = {
+ -- each version
+ ANY = {
+ -- each dependency
+ ANY = {
+ name = "string",
+ constraints = {
+ ANY = {
+ no_upgrade = "boolean",
+ op = "string",
+ version = {
+ string = "string",
+ ANY = 0,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+local type_check_table
+
+--- Type check an object.
+-- The object is compared against an archetypical value
+-- matching the expected type -- the actual values don't matter,
+-- only their types. Tables are type checked recursively.
+-- @param name any: The object name (for error messages).
+-- @param item any: The object being checked.
+-- @param expected any: The reference object. In case of a table,
+-- its is structured as a type reference table.
+-- @param context string: A string indicating the "context" where the
+-- error occurred (such as the name of the table the item is a part of),
+-- to be used by error messages.
+-- @return boolean or (nil, string): true if type checking
+-- succeeded, or nil and an error message if it failed.
+-- @see type_check_table
+local function type_check_item(name, item, expected, context)
+ name = tostring(name)
+
+ local item_type = type(item)
+ local expected_type = type(expected)
+ if expected_type == "number" then
+ if not tonumber(item) then
+ return nil, "Type mismatch on field "..context..name..": expected a number"
+ end
+ elseif expected_type == "string" then
+ if type(item) ~= "string" then
+ return nil, "Type mismatch on field "..context..name..": expected a string"
+ end
+ if expected ~= "string" then
+ if not item:match("^"..expected.."$") then
+ return nil, "Type mismatch on field "..context..name..": invalid value "..item
+ end
+ end
+ elseif expected_type == "table" then
+ if item_type ~= expected_type then
+ return nil, "Type mismatch on field "..context..name..": expected a table"
+ else
+ return type_check_table(item, expected, context..name..".")
+ end
+ elseif item_type ~= expected_type then
+ return nil, "Type mismatch on field "..context..name..": expected a "..expected_type
+ end
+ return true
+end
+
+--- Type check the contents of a table.
+-- The table's contents are compared against a reference table,
+-- which contains the recognized fields, with archetypical values
+-- matching the expected types -- the actual values of items in the
+-- reference table don't matter, only their types (ie, for field x
+-- in tbl that is correctly typed, type(tbl.x) == type(types.x)).
+-- If the reference table contains a field called MORE, then
+-- unknown fields in the checked table are accepted.
+-- If it contains a field called ANY, then its type will be
+-- used to check any unknown fields. If a field is prefixed
+-- with MUST_, it is mandatory; its absence from the table is
+-- a type error.
+-- Tables are type checked recursively.
+-- @param tbl table: The table to be type checked.
+-- @param types table: The reference table, containing
+-- values for recognized fields in the checked table.
+-- @param context string: A string indicating the "context" where the
+-- error occurred (such as the name of the table the item is a part of),
+-- to be used by error messages.
+-- @return boolean or (nil, string): true if type checking
+-- succeeded, or nil and an error message if it failed.
+type_check_table = function(tbl, types, context)
+ assert(type(tbl) == "table")
+ assert(type(types) == "table")
+ for k, v in pairs(tbl) do
+ local t = types[k] or (type(k) == "string" and types["MUST_"..k]) or types.ANY
+ if t then
+ local ok, err = type_check_item(k, v, t, context)
+ if not ok then return nil, err end
+ elseif types.MORE then
+ -- Accept unknown field
+ else
+ if not cfg.accept_unknown_fields then
+ return nil, "Unknown field "..k
+ end
+ end
+ end
+ for k, v in pairs(types) do
+ local mandatory_key = k:match("^MUST_(.+)")
+ if mandatory_key then
+ if not tbl[mandatory_key] then
+ return nil, "Mandatory field "..context..mandatory_key.." is missing."
+ end
+ end
+ end
+ return true
+end
+
+--- Type check a rockspec table.
+-- Verify the correctness of elements from a
+-- rockspec table, reporting on unknown fields and type
+-- mismatches.
+-- @return boolean or (nil, string): true if type checking
+-- succeeded, or nil and an error message if it failed.
+function type_check_rockspec(rockspec)
+ assert(type(rockspec) == "table")
+ if rockspec.rockspec_format then
+ -- relies on global state
+ load_extensions()
+ end
+ return type_check_table(rockspec, rockspec_types, "")
+end
+
+--- Type check a manifest table.
+-- Verify the correctness of elements from a
+-- manifest table, reporting on unknown fields and type
+-- mismatches.
+-- @return boolean or (nil, string): true if type checking
+-- succeeded, or nil and an error message if it failed.
+function type_check_manifest(manifest)
+ assert(type(manifest) == "table")
+ return type_check_table(manifest, manifest_types, "")
+end
diff --git a/src/luarocks/unpack.lua b/src/luarocks/unpack.lua
new file mode 100644
index 0000000..6715381
--- /dev/null
+++ b/src/luarocks/unpack.lua
@@ -0,0 +1,151 @@
+
+--- Module implementing the LuaRocks "unpack" command.
+-- Unpack the contents of a rock.
+module("luarocks.unpack", package.seeall)
+
+local fetch = require("luarocks.fetch")
+local fs = require("luarocks.fs")
+local util = require("luarocks.util")
+local build = require("luarocks.build")
+local dir = require("luarocks.dir")
+
+help_summary = "Unpack the contents of a rock."
+help_arguments = "{<rock>|<name> [<version>]}"
+help = [[
+Unpacks the contents of a rock in a newly created directory.
+Argument may be a rock file, or the name of a rock in a rocks server.
+In the latter case, the app version may be given as a second argument.
+]]
+
+--- Load a rockspec file to the given directory, fetches the source
+-- files specified in the rockspec, and unpack them inside the directory.
+-- @param rockspec_file string: The URL for a rockspec file.
+-- @param dir_name string: The directory where to store and unpack files.
+-- @return table or (nil, string): the loaded rockspec table or
+-- nil and an error message.
+local function unpack_rockspec(rockspec_file, dir_name)
+ assert(type(rockspec_file) == "string")
+ assert(type(dir_name) == "string")
+
+ local rockspec, err = fetch.load_rockspec(rockspec_file)
+ if not rockspec then
+ return nil, "Failed loading rockspec "..rockspec_file..": "..err
+ end
+ fs.change_dir(dir_name)
+ local ok, sources_dir = fetch.fetch_sources(rockspec, true, ".")
+ if not ok then
+ return nil, sources_dir
+ end
+ fs.change_dir(dir_name)
+ build.apply_patches(rockspec)
+ fs.pop_dir()
+ return rockspec
+end
+
+--- Load a .rock file to the given directory and unpack it inside it.
+-- @param rock_file string: The URL for a .rock file.
+-- @param dir_name string: The directory where to unpack.
+-- @param kind string: the kind of rock file, as in the second-level
+-- extension in the rock filename (eg. "src", "all", "linux-x86")
+-- @return table or (nil, string): the loaded rockspec table or
+-- nil and an error message.
+local function unpack_rock(rock_file, dir_name, kind)
+ assert(type(rock_file) == "string")
+ assert(type(dir_name) == "string")
+
+ local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, dir_name)
+ if not ok then
+ return nil, "Failed unzipping rock "..rock_file, errcode
+ end
+ fs.change_dir(dir_name)
+ local rockspec_file = dir_name..".rockspec"
+ local rockspec, err = fetch.load_rockspec(rockspec_file)
+ if not rockspec then
+ return nil, "Failed loading rockspec "..rockspec_file..": "..err
+ end
+ if kind == "src" then
+ if rockspec.source.file then
+ local ok, err = fs.unpack_archive(rockspec.source.file)
+ if not ok then
+ return nil, err
+ end
+ fs.change_dir(rockspec.source.dir)
+ build.apply_patches(rockspec)
+ fs.pop_dir()
+ end
+ end
+ return rockspec
+end
+
+--- Create a directory and perform the necessary actions so that
+-- the sources for the rock and its rockspec are unpacked inside it,
+-- laid out properly so that the 'make' command is able to build the module.
+-- @param file string: A rockspec or .rock URL.
+-- @return boolean or (nil, string): true if successful or nil followed
+-- by an error message.
+local function run_unpacker(file)
+ assert(type(file) == "string")
+
+ local base_name = dir.base_name(file)
+ local dir_name, kind, extension = base_name:match("(.*)%.([^.]+)%.(rock)$")
+ if not extension then
+ dir_name, extension = base_name:match("(.*)%.(rockspec)$")
+ kind = "rockspec"
+ end
+ if not extension then
+ return nil, file.." does not seem to be a valid filename."
+ end
+
+ if (fs.exists(dir_name)) then
+ return nil, "Directory "..dir_name.." already exists."
+ end
+ fs.make_dir(dir_name)
+ local rollback = util.schedule_function(fs.delete, fs.absolute_name(dir_name))
+
+ local rockspec, err
+ if extension == "rock" then
+ rockspec, err = unpack_rock(file, dir_name, kind)
+ elseif extension == "rockspec" then
+ rockspec, err = unpack_rockspec(file, dir_name)
+ end
+ if not rockspec then
+ return nil, err
+ end
+ if kind == "src" or kind == "rockspec" then
+ if rockspec.source.dir ~= "." then
+ local ok = fs.copy(rockspec.local_filename, rockspec.source.dir)
+ if not ok then
+ return nil, "Failed copying unpacked rockspec into unpacked source directory."
+ end
+ end
+ util.printout()
+ util.printout("Done. You may now enter directory ")
+ util.printout(dir.path(dir_name, rockspec.source.dir))
+ util.printout("and type 'luarocks make' to build.")
+ end
+ util.remove_scheduled_function(rollback)
+ return true
+end
+
+--- Driver function for the "unpack" command.
+-- @param name string: may be a rock filename, for unpacking a
+-- rock file or the name of a rock to be fetched and unpacked.
+-- @param version string or nil: if the name of a package is given, a
+-- version may also be passed.
+-- @return boolean or (nil, string): true if successful or nil followed
+-- by an error message.
+function run(...)
+ local flags, name, version = util.parse_flags(...)
+
+ assert(type(version) == "string" or not version)
+ if type(name) ~= "string" then
+ return nil, "Argument missing. "..util.see_help("unpack")
+ end
+
+ if name:match(".*%.rock") or name:match(".*%.rockspec") then
+ return run_unpacker(name)
+ else
+ local search = require("luarocks.search")
+ return search.act_on_src_or_rockspec(run_unpacker, name, version)
+ end
+end
diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua
new file mode 100644
index 0000000..ba20acf
--- /dev/null
+++ b/src/luarocks/util.lua
@@ -0,0 +1,504 @@
+
+--- Assorted utilities for managing tables, plus a scheduler for rollback functions.
+-- Does not requires modules directly (only as locals
+-- inside specific functions) to avoid interdependencies,
+-- as this is used in the bootstrapping stage of luarocks.cfg.
+
+local global_env = _G
+
+module("luarocks.util", package.seeall)
+
+local scheduled_functions = {}
+local debug = require("debug")
+
+--- Schedule a function to be executed upon program termination.
+-- This is useful for actions such as deleting temporary directories
+-- or failure rollbacks.
+-- @param f function: Function to be executed.
+-- @param ... arguments to be passed to function.
+-- @return table: A token representing the scheduled execution,
+-- which can be used to remove the item later from the list.
+function schedule_function(f, ...)
+ assert(type(f) == "function")
+
+ local item = { fn = f, args = {...} }
+ table.insert(scheduled_functions, item)
+ return item
+end
+
+--- Unschedule a function.
+-- This is useful for cancelling a rollback of a completed operation.
+-- @param item table: The token representing the scheduled function that was
+-- returned from the schedule_function call.
+function remove_scheduled_function(item)
+ for k, v in pairs(scheduled_functions) do
+ if v == item then
+ table.remove(scheduled_functions, k)
+ return
+ end
+ end
+end
+
+--- Execute scheduled functions.
+-- Some calls create temporary files and/or directories and register
+-- corresponding cleanup functions. Calling this function will run
+-- these function, erasing temporaries.
+-- Functions are executed in the inverse order they were scheduled.
+function run_scheduled_functions()
+ local fs = require("luarocks.fs")
+ fs.change_dir_to_root()
+ for i = #scheduled_functions, 1, -1 do
+ local item = scheduled_functions[i]
+ item.fn(unpack(item.args))
+ end
+end
+
+--- Produce a Lua pattern that matches precisely the given string
+-- (this is suitable to be concatenating to other patterns,
+-- so it does not include beginning- and end-of-string markers (^$)
+-- @param s string: The input string
+-- @return string: The equivalent pattern
+function matchquote(s)
+ return (s:gsub("[?%-+*%[%].%%()$^]","%%%1"))
+end
+
+--- Extract flags from an arguments list.
+-- Given string arguments, extract flag arguments into a flags set.
+-- For example, given "foo", "--tux=beep", "--bla", "bar", "--baz",
+-- it would return the following:
+-- {["bla"] = true, ["tux"] = "beep", ["baz"] = true}, "foo", "bar".
+function parse_flags(...)
+ local args = {...}
+ local flags = {}
+ for i = #args, 1, -1 do
+ local flag = args[i]:match("^%-%-(.*)")
+ if flag then
+ local var,val = flag:match("([a-z_%-]*)=(.*)")
+ if val then
+ flags[var] = val
+ else
+ flags[flag] = true
+ end
+ table.remove(args, i)
+ end
+ end
+ return flags, unpack(args)
+end
+
+--- Build a sequence of flags for forwarding from one command to
+-- another (for example, from "install" to "build").
+-- @param flags table: A table of parsed flags
+-- @param ... string...: A variable number of flags to be checked
+-- in the flags table. If no flags are passed as varargs, the
+-- entire flags table is forwarded.
+-- @return string... A variable number of strings
+function forward_flags(flags, ...)
+ assert(type(flags) == "table")
+ local out = {}
+ local filter = select('#', ...)
+ local function add_flag(flagname)
+ if flags[flagname] then
+ if flags[flagname] == true then
+ table.insert(out, "--"..flagname)
+ else
+ table.insert(out, "--"..flagname.."="..flags[flagname])
+ end
+ end
+ end
+ if filter > 0 then
+ for i = 1, filter do
+ add_flag(select(i, ...))
+ end
+ else
+ for flagname, _ in pairs(flags) do
+ add_flag(flagname)
+ end
+ end
+ return unpack(out)
+end
+
+--- Merges contents of src on top of dst's contents.
+-- @param dst Destination table, which will receive src's contents.
+-- @param src Table which provides new contents to dst.
+-- @see platform_overrides
+function deep_merge(dst, src)
+ for k, v in pairs(src) do
+ if type(v) == "table" then
+ if not dst[k] then
+ dst[k] = {}
+ end
+ if type(dst[k]) == "table" then
+ deep_merge(dst[k], v)
+ else
+ dst[k] = v
+ end
+ else
+ dst[k] = v
+ end
+ end
+end
+
+--- Perform platform-specific overrides on a table.
+-- Overrides values of table with the contents of the appropriate
+-- subset of its "platforms" field. The "platforms" field should
+-- be a table containing subtables keyed with strings representing
+-- platform names. Names that match the contents of the global
+-- cfg.platforms setting are used. For example, if
+-- cfg.platforms= {"foo"}, then the fields of
+-- tbl.platforms.foo will overwrite those of tbl with the same
+-- names. For table values, the operation is performed recursively
+-- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of
+-- tbl.x are preserved).
+-- @param tbl table or nil: Table which may contain a "platforms" field;
+-- if it doesn't (or if nil is passed), this function does nothing.
+function platform_overrides(tbl)
+ assert(type(tbl) == "table" or not tbl)
+
+ local cfg = require("luarocks.cfg")
+
+ if not tbl then return end
+
+ if tbl.platforms then
+ for _, platform in ipairs(cfg.platforms) do
+ local platform_tbl = tbl.platforms[platform]
+ if platform_tbl then
+ deep_merge(tbl, platform_tbl)
+ end
+ end
+ end
+ tbl.platforms = nil
+end
+
+local var_format_pattern = "%$%((%a[%a%d_]+)%)"
+
+--- 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.
+local function make_shallow_copy(tbl)
+ local copy = {}
+ for k,v in pairs(tbl) do
+ copy[k] = v
+ end
+ return copy
+end
+
+-- Check if a set of needed variables are referenced
+-- somewhere in a list of definitions, warning the user
+-- about any unused ones. Each key in needed_set should
+-- appear as a $(XYZ) variable at least once as a
+-- substring of some value of var_defs.
+-- @param var_defs: a table with string keys and string
+-- values, containing variable definitions.
+-- @param needed_set: a set where keys are the names of
+-- needed variables.
+-- @param msg string: the warning message to display.
+function warn_if_not_used(var_defs, needed_set, msg)
+ needed_set = make_shallow_copy(needed_set)
+ for var,val in pairs(var_defs) do
+ for used in val:gmatch(var_format_pattern) do
+ needed_set[used] = nil
+ end
+ end
+ for var,_ in pairs(needed_set) do
+ warning(msg:format(var))
+ end
+end
+
+-- Output any entries that might remain in $(XYZ) format,
+-- warning the user that substitutions have failed.
+-- @param line string: the input string
+local function warn_failed_matches(line)
+ local any_failed = false
+ if line:match(var_format_pattern) then
+ for unmatched in line:gmatch(var_format_pattern) do
+ warning("unmatched variable " .. unmatched)
+ any_failed = true
+ end
+ end
+ return any_failed
+end
+
+--- Perform make-style variable substitutions on string values of a table.
+-- For every string value tbl.x which contains a substring of the format
+-- "$(XYZ)" will have this substring replaced by vars["XYZ"], if that field
+-- exists in vars. Only string values are processed; this function
+-- does not scan subtables recursively.
+-- @param tbl table: Table to have its string values modified.
+-- @param vars table: Table containing string-string key-value pairs
+-- representing variables to replace in the strings values of tbl.
+function variable_substitutions(tbl, vars)
+ assert(type(tbl) == "table")
+ assert(type(vars) == "table")
+
+ local updated = {}
+ for k, v in pairs(tbl) do
+ if type(v) == "string" then
+ updated[k] = v:gsub(var_format_pattern, vars)
+ if warn_failed_matches(updated[k]) then
+ updated[k] = updated[k]:gsub(var_format_pattern, "")
+ end
+ end
+ end
+ for k, v in pairs(updated) do
+ tbl[k] = v
+ end
+end
+
+--- Return an array of keys of a table.
+-- @param tbl table: The input table.
+-- @return table: The array of keys.
+function keys(tbl)
+ local ks = {}
+ for k,_ in pairs(tbl) do
+ table.insert(ks, k)
+ end
+ return ks
+end
+
+local function default_sort(a, b)
+ local ta = type(a)
+ local tb = type(b)
+ if ta == "number" and tb == "number" then
+ return a < b
+ elseif ta == "number" then
+ return true
+ elseif tb == "number" then
+ return false
+ else
+ return tostring(a) < tostring(b)
+ end
+end
+
+-- The iterator function used internally by util.sortedpairs.
+-- @param tbl table: The table to be iterated.
+-- @param sort_function function or nil: An optional comparison function
+-- to be used by table.sort when sorting keys.
+-- @see sortedpairs
+local function sortedpairs_iterator(tbl, sort_function)
+ local ks = keys(tbl)
+ if not sort_function or type(sort_function) == "function" then
+ table.sort(ks, sort_function or default_sort)
+ for _, k in ipairs(ks) do
+ coroutine.yield(k, tbl[k])
+ end
+ else
+ local order = sort_function
+ local done = {}
+ for _, k in ipairs(order) do
+ local sub_order
+ if type(k) == "table" then
+ sub_order = k[2]
+ k = k[1]
+ end
+ if tbl[k] then
+ done[k] = true
+ coroutine.yield(k, tbl[k], sub_order)
+ end
+ end
+ table.sort(ks, default_sort)
+ for _, k in ipairs(ks) do
+ if not done[k] then
+ coroutine.yield(k, tbl[k])
+ end
+ end
+ end
+end
+
+--- A table iterator generator that returns elements sorted by key,
+-- to be used in "for" loops.
+-- @param tbl table: The table to be iterated.
+-- @param sort_function function or table or nil: An optional comparison function
+-- to be used by table.sort when sorting keys, or an array listing an explicit order
+-- for keys. If a value itself is an array, it is taken so that the first element
+-- is a string representing the field name, and the second element is a priority table
+-- for that key.
+-- @return function: the iterator function.
+function sortedpairs(tbl, sort_function)
+ return coroutine.wrap(function() sortedpairs_iterator(tbl, sort_function) end)
+end
+
+function starts_with(s, prefix)
+ return s:sub(1,#prefix) == prefix
+end
+
+--- Print a line to standard output
+function printout(...)
+ io.stdout:write(table.concat({...},"\t"))
+ io.stdout:write("\n")
+end
+
+--- Print a line to standard error
+function printerr(...)
+ io.stderr:write(table.concat({...},"\t"))
+ io.stderr:write("\n")
+end
+
+--- Display a warning message.
+-- @param msg string: the warning message
+function warning(msg)
+ printerr("Warning: "..msg)
+end
+
+function title(msg, porcelain, underline)
+ if porcelain then return end
+ printout()
+ printout(msg)
+ printout((underline or "-"):rep(#msg))
+ printout()
+end
+
+function this_program(default)
+ local i = 1
+ local last, cur = default, default
+ while i do
+ local dbg = debug.getinfo(i,"S")
+ if not dbg then break end
+ last = cur
+ cur = dbg.source
+ i=i+1
+ end
+ return last:sub(2)
+end
+
+function see_help(command, program)
+ return "See '"..this_program(program or "luarocks")..' help '..command.."'."
+end
+
+-- from http://lua-users.org/wiki/SplitJoin
+-- by PhilippeLhoste
+function split_string(str, delim, maxNb)
+ -- Eliminate bad cases...
+ if string.find(str, delim) == nil then
+ return { str }
+ end
+ if maxNb == nil or maxNb < 1 then
+ maxNb = 0 -- No limit
+ end
+ local result = {}
+ local pat = "(.-)" .. delim .. "()"
+ local nb = 0
+ local lastPos
+ for part, pos in string.gmatch(str, pat) do
+ nb = nb + 1
+ result[nb] = part
+ lastPos = pos
+ if nb == maxNb then break end
+ end
+ -- Handle the last field
+ if nb ~= maxNb then
+ result[nb + 1] = string.sub(str, lastPos)
+ end
+ return result
+end
+
+--- Remove repeated entries from a path-style string.
+-- Example: given ("a;b;c;a;b;d", ";"), returns "a;b;c;d".
+-- @param list string: A path string (from $PATH or package.path)
+-- @param sep string: The separator
+function remove_path_dupes(list, sep)
+ assert(type(list) == "string")
+ assert(type(sep) == "string")
+ local parts = split_string(list, sep)
+ local final, entries = {}, {}
+ for _, part in ipairs(parts) do
+ if not entries[part] then
+ table.insert(final, part)
+ entries[part] = true
+ end
+ end
+ return table.concat(final, sep)
+end
+
+---
+-- Formats tables with cycles recursively to any depth.
+-- References to other tables are shown as values.
+-- Self references are indicated.
+-- The string returned is "Lua code", which can be procesed
+-- (in the case in which indent is composed by spaces or "--").
+-- Userdata and function keys and values are shown as strings,
+-- which logically are exactly not equivalent to the original code.
+-- This routine can serve for pretty formating tables with
+-- proper indentations, apart from printing them:
+-- io.write(table.show(t, "t")) -- a typical use
+-- Written by Julio Manuel Fernandez-Diaz,
+-- Heavily based on "Saving tables with cycles", PIL2, p. 113.
+-- @param t table: is the table.
+-- @param name string: is the name of the table (optional)
+-- @param indent string: is a first indentation (optional).
+-- @return string: the pretty-printed table
+function show_table(t, name, indent)
+ local cart -- a container
+ local autoref -- for self references
+
+ local function isemptytable(t) return next(t) == nil end
+
+ local function basicSerialize (o)
+ local so = tostring(o)
+ if type(o) == "function" then
+ local info = debug.getinfo(o, "S")
+ -- info.name is nil because o is not a calling level
+ if info.what == "C" then
+ return ("%q"):format(so .. ", C function")
+ else
+ -- the information is defined through lines
+ return ("%q"):format(so .. ", defined in (" .. info.linedefined .. "-" .. info.lastlinedefined .. ")" .. info.source)
+ end
+ elseif type(o) == "number" then
+ return so
+ else
+ return ("%q"):format(so)
+ end
+ end
+
+ local function addtocart (value, name, indent, saved, field)
+ indent = indent or ""
+ saved = saved or {}
+ field = field or name
+
+ cart = cart .. indent .. field
+
+ if type(value) ~= "table" then
+ cart = cart .. " = " .. basicSerialize(value) .. ";\n"
+ else
+ if saved[value] then
+ cart = cart .. " = {}; -- " .. saved[value] .. " (self reference)\n"
+ autoref = autoref .. name .. " = " .. saved[value] .. ";\n"
+ else
+ saved[value] = name
+ --if tablecount(value) == 0 then
+ if isemptytable(value) then
+ cart = cart .. " = {};\n"
+ else
+ cart = cart .. " = {\n"
+ for k, v in pairs(value) do
+ k = basicSerialize(k)
+ local fname = ("%s[%s]"):format(name, k)
+ field = ("[%s]"):format(k)
+ -- three spaces between levels
+ addtocart(v, fname, indent .. " ", saved, field)
+ end
+ cart = cart .. indent .. "};\n"
+ end
+ end
+ end
+ end
+
+ name = name or "__unnamed__"
+ if type(t) ~= "table" then
+ return name .. " = " .. basicSerialize(t)
+ end
+ cart, autoref = "", ""
+ addtocart(t, name, indent)
+ return cart .. autoref
+end
+
+function array_contains(tbl, value)
+ for _, v in ipairs(tbl) do
+ if v == value then
+ return true
+ end
+ end
+ return false
+end
diff --git a/src/luarocks/validate.lua b/src/luarocks/validate.lua
new file mode 100644
index 0000000..1e1e69e
--- /dev/null
+++ b/src/luarocks/validate.lua
@@ -0,0 +1,160 @@
+
+--- Sandboxed test of build/install of all packages in a repository (unfinished and disabled).
+module("luarocks.validate", package.seeall)
+
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local path = require("luarocks.path")
+local cfg = require("luarocks.cfg")
+local build = require("luarocks.build")
+local install = require("luarocks.install")
+local util = require("luarocks.util")
+
+help_summary = "Sandboxed test of build/install of all packages in a repository."
+
+help = [[
+<argument>, if given, is a local repository pathname.
+]]
+
+local function save_settings(repo)
+ local protocol, path = dir.split_url(repo)
+ table.insert(cfg.rocks_servers, 1, protocol.."://"..path)
+ return {
+ root_dir = cfg.root_dir,
+ rocks_dir = cfg.rocks_dir,
+ deploy_bin_dir = cfg.deploy_bin_dir,
+ deploy_lua_dir = cfg.deploy_lua_dir,
+ deploy_lib_dir = cfg.deploy_lib_dir,
+ }
+end
+
+local function restore_settings(settings)
+ cfg.root_dir = settings.root_dir
+ cfg.rocks_dir = settings.rocks_dir
+ cfg.deploy_bin_dir = settings.deploy_bin_dir
+ cfg.deploy_lua_dir = settings.deploy_lua_dir
+ cfg.deploy_lib_dir = settings.deploy_lib_dir
+ cfg.variables.ROCKS_TREE = settings.rocks_dir
+ cfg.variables.SCRIPTS_DIR = settings.deploy_bin_dir
+ table.remove(cfg.rocks_servers, 1)
+end
+
+local function prepare_sandbox(file)
+ local root_dir = fs.make_temp_dir(file):gsub("/+$", "")
+ cfg.root_dir = root_dir
+ cfg.rocks_dir = path.rocks_dir(root_dir)
+ cfg.deploy_bin_dir = path.deploy_bin_dir(root_dir)
+ cfg.variables.ROCKS_TREE = cfg.rocks_dir
+ cfg.variables.SCRIPTS_DIR = cfg.deploy_bin_dir
+ return root_dir
+end
+
+local function validate_rockspec(file)
+ local ok, err, errcode = build.build_rockspec(file, true, "one")
+ if not ok then
+ util.printerr(err)
+ end
+ return ok, err, errcode
+end
+
+local function validate_src_rock(file)
+ local ok, err, errcode = build.build_rock(file, false, "one")
+ if not ok then
+ util.printerr(err)
+ end
+ return ok, err, errcode
+end
+
+local function validate_rock(file)
+ local ok, err, errcode = install.install_binary_rock(file, "one")
+ if not ok then
+ util.printerr(err)
+ end
+ return ok, err, errcode
+end
+
+local function validate(repo, flags)
+ local results = {
+ ok = {}
+ }
+ local settings = save_settings(repo)
+ local sandbox
+ if flags["quick"] then
+ sandbox = prepare_sandbox("luarocks_validate")
+ end
+ if not fs.exists(repo) then
+ return nil, repo.." is not a local repository."
+ end
+ for _, file in pairs(fs.list_dir(repo)) do for _=1,1 do
+ if file == "manifest" or file == "index.html" then
+ break -- continue for
+ end
+ local pathname = fs.absolute_name(dir.path(repo, file))
+ if not flags["quick"] then
+ sandbox = prepare_sandbox(file)
+ end
+ local ok, err, errcode
+ util.printout()
+ util.printout("Verifying "..pathname)
+ if file:match("%.rockspec$") then
+ ok, err, errcode = validate_rockspec(pathname, "one")
+ elseif file:match("%.src%.rock$") then
+ ok, err, errcode = validate_src_rock(pathname)
+ elseif file:match("%.rock$") then
+ ok, err, errcode = validate_rock(pathname)
+ end
+ if ok then
+ table.insert(results.ok, {file=file} )
+ else
+ if not errcode then
+ errcode = "misc"
+ end
+ if not results[errcode] then
+ results[errcode] = {}
+ end
+ table.insert(results[errcode], {file=file, err=err} )
+ end
+ util.run_scheduled_functions()
+ if not flags["quick"] then
+ fs.delete(sandbox)
+ end
+ repeat until not fs.pop_dir()
+ end end
+ if flags["quick"] then
+ fs.delete(sandbox)
+ end
+ restore_settings(settings)
+ util.title("Results:")
+ util.printout("OK: "..tostring(#results.ok))
+ for _, entry in ipairs(results.ok) do
+ util.printout(entry.file)
+ end
+ for errcode, errors in pairs(results) do
+ if errcode ~= "ok" then
+ util.printout()
+ util.printout(errcode.." errors: "..tostring(#errors))
+ for _, entry in ipairs(errors) do
+ util.printout(entry.file, entry.err)
+ end
+ end
+ end
+
+ util.title("Summary:")
+ local total = 0
+ for errcode, errors in pairs(results) do
+ util.printout(errcode..": "..tostring(#errors))
+ total = total + #errors
+ end
+ util.printout("Total: "..total)
+ return true
+end
+
+function run(...)
+ local flags, repo = util.parse_flags(...)
+ repo = repo or cfg.rocks_dir
+
+ util.printout("Verifying contents of "..repo)
+
+ return validate(repo, flags)
+end
+
diff --git a/test/testing.sh b/test/testing.sh
new file mode 100755
index 0000000..c06bd27
--- /dev/null
+++ b/test/testing.sh
@@ -0,0 +1,269 @@
+#!/bin/sh -e
+
+# Setup #########################################
+
+[ -e ../configure ] || {
+ echo "Please run this from the test/ directory."
+ exit 1
+}
+
+testing_dir="$PWD"
+
+testing_tree="$testing_dir/testing"
+testing_sys_tree="$testing_dir/testing_sys"
+testing_tree_copy="$testing_dir/testing_copy"
+testing_sys_tree_copy="$testing_dir/testing_sys_copy"
+testing_cache="$testing_dir/testing_cache"
+
+[ "$1" ] || rm -f luacov.stats.out
+rm -f luacov.report.out
+rm -rf /tmp/luarocks_testing
+mkdir /tmp/luarocks_testing
+rm -rf "$testing_tree"
+rm -rf "$testing_sys_tree"
+rm -rf "$testing_tree_copy"
+rm -rf "$testing_sys_tree_copy"
+rm -rf "$testing_cache"
+
+cat <<EOF > $testing_dir/testing_config.lua
+rocks_trees = {
+ "$testing_tree",
+ "$testing_sys_tree",
+}
+local_cache = "$testing_cache"
+upload_server = "testing"
+upload_user = "hisham"
+upload_servers = {
+ testing = {
+ rsync = "localhost/tmp/luarocks_testing",
+ },
+}
+EOF
+cat <<EOF > $testing_dir/testing_config_sftp.lua
+rocks_trees = {
+ "$testing_tree",
+ "$testing_sys_tree",
+}
+local_cache = "$testing_cache"
+upload_server = "testing"
+upload_user = "hisham"
+upload_servers = {
+ testing = {
+ sftp = "localhost/tmp/luarocks_testing",
+ },
+}
+EOF
+cat <<EOF > $testing_dir/luacov.config
+return {
+ ["configfile"] = ".luacov",
+ ["statsfile"] = "$testing_dir/luacov.stats.out",
+ ["reportfile"] = "$testing_dir/luacov.report.out",
+ runreport = false,
+ deletestats = false,
+ ["include"] = {},
+ ["exclude"] = {
+ "luacov$",
+ "luacov%.reporter$",
+ "luacov%.defaults$",
+ "luacov%.runner$",
+ "luacov%.stats$",
+ "luacov%.tick$",
+ },
+}
+EOF
+
+export LUAROCKS_CONFIG="$testing_dir/testing_config.lua"
+export LUA_PATH=
+export LUA_CPATH=
+
+luadir="/Programs/Lua/Current"
+lua="$luadir/bin/lua"
+
+cd ..
+./configure --with-lua="$luadir"
+make clean
+make src/luarocks/site_config.lua
+make dev
+cd src
+
+echo $LUA_PATH
+
+luarocks_nocov="$lua $PWD/bin/luarocks"
+luarocks="$lua -erequire('luacov.runner')('$testing_dir/luacov.config') $PWD/bin/luarocks"
+luarocks_admin="$lua -erequire('luacov.runner')('$testing_dir/luacov.config') $PWD/bin/luarocks-admin"
+
+$luarocks_nocov download luacov
+
+build_environment() {
+ rm -rf "$testing_tree"
+ rm -rf "$testing_sys_tree"
+ rm -rf "$testing_tree_copy"
+ rm -rf "$testing_sys_tree_copy"
+ mkdir -p "$testing_tree"
+ mkdir -p "$testing_sys_tree"
+ for package in "$@"
+ do
+ $luarocks_nocov build --tree="$testing_sys_tree" $package
+ done
+ eval `$luarocks_nocov path --bin`
+ cp -a "$testing_tree" "$testing_tree_copy"
+ cp -a "$testing_sys_tree" "$testing_sys_tree_copy"
+}
+
+reset_environment() {
+ rm -rf "$testing_tree"
+ rm -rf "$testing_sys_tree"
+ cp -a "$testing_tree_copy" "$testing_tree"
+ cp -a "$testing_sys_tree_copy" "$testing_sys_tree"
+}
+
+# Tests #########################################
+
+test_version() { $luarocks --version; }
+
+fail_arg_server() { $luarocks --server; }
+fail_arg_only_server() { $luarocks --only-server; }
+fail_unknown_command() { $luarocks unknown_command; }
+
+test_empty_list() { $luarocks list; }
+
+fail_build_noarg() { $luarocks build; }
+fail_download_noarg() { $luarocks download; }
+fail_install_noarg() { $luarocks install; }
+fail_lint_noarg() { $luarocks lint; }
+fail_search_noarg() { $luarocks search; }
+fail_show_noarg() { $luarocks show; }
+fail_unpack_noarg() { $luarocks unpack; }
+fail_new_version_noarg() { $luarocks new_version; }
+
+fail_build_invalid() { $luarocks build invalid; }
+fail_download_invalid() { $luarocks download invalid; }
+fail_install_invalid() { $luarocks install invalid; }
+fail_lint_invalid() { $luarocks lint invalid; }
+fail_show_invalid() { $luarocks show invalid; }
+fail_new_version_invalid() { $luarocks new_version invalid; }
+
+fail_make_norockspec() { $luarocks make; }
+
+fail_build_blank_arg() { $luarocks build --tree="" lpeg; }
+test_build_withpatch() { $luarocks build luadoc; }
+test_build_diffversion() { $luarocks build luacov 0.1; }
+test_build_command() { $luarocks build stdlib; }
+test_build_install_bin() { $luarocks build luarepl; }
+fail_build_nohttps() { $luarocks install luasocket && $luarocks download --rockspec validate-args 1.5.4 && $luarocks build ./validate-args-1.5.4-1.rockspec && rm ./validate-args-1.5.4-1.rockspec; }
+test_build_https() { $luarocks download --rockspec validate-args 1.5.4 && $luarocks install luasec && $luarocks build ./validate-args-1.5.4-1.rockspec && rm ./validate-args-1.5.4-1.rockspec; }
+test_build_supported_platforms() { $luarocks build xctrl; }
+
+test_download_all() { $luarocks download --all validate-args && rm validate-args-*; }
+test_download_rockspecversion() { $luarocks download --rockspec validate-args 1.5.4 && rm validate-args-*; }
+
+test_help() { $luarocks help; }
+
+test_install_binaryrock() { $luarocks build luasocket && $luarocks pack luasocket && $luarocks install ./luasocket-2.0.2-5.linux-x86.rock && rm ./luasocket-2.0.2-5.linux-x86.rock; }
+test_install_with_bin() { $luarocks install wsapi; }
+
+test_lint_ok() { $luarocks download --rockspec validate-args 1.5.4 && $luarocks lint ./validate-args-1.5.4-1.rockspec && rm ./validate-args-1.5.4-1.rockspec; }
+
+test_list() { $luarocks list; }
+test_list_porcelain() { $luarocks list --porcelain; }
+
+test_make() { rm -rf ./luasocket-2.0.2-5 && $luarocks download --src luasocket && $luarocks unpack ./luasocket-2.0.2-5.src.rock && cd luasocket-2.0.2-5/luasocket-2.0.2 && $luarocks make && cd ../.. && rm -rf ./luasocket-2.0.2-5; }
+test_make_pack_binary_rock() { rm -rf ./lxsh-0.8.6-1 && $luarocks download --src lxsh 0.8.6-1 && $luarocks unpack ./lxsh-0.8.6-1.src.rock && cd lxsh-0.8.6-1/lxsh-0.8.6-1 && $luarocks make --deps-mode=none --pack-binary-rock && [ -e ./lxsh-0.8.6-1.all.rock ] && cd ../.. && rm -rf ./lxsh-0.8.6-1; }
+
+test_new_version() { $luarocks download --rockspec luacov 0.1 && $luarocks new_version ./luacov-0.1-1.rockspec 0.2 && rm ./luacov-0.*; }
+
+test_pack() { $luarocks list && $luarocks pack luacov && rm ./luacov-*.rock; }
+test_pack_src() { $luarocks download --rockspec luasocket && $luarocks pack ./luasocket-2.0.2-5.rockspec && rm ./luasocket-2.0.2-*.rock; }
+
+test_path() { $luarocks path --bin; }
+
+fail_purge_missing_tree() { $luarocks purge --tree="$testing_tree"; }
+test_purge() { $luarocks purge --tree="$testing_sys_tree"; }
+
+test_remove() { $luarocks build luacov 0.1 && $luarocks remove luacov 0.1; }
+#fail_remove_deps() { $luarocks build luadoc && $luarocks remove luasocket; }
+
+test_search_found() { $luarocks search zlib; }
+test_search_missing() { $luarocks search missing_rock; }
+
+test_show() { $luarocks show luacov; }
+test_show_modules() { $luarocks show --modules luacov; }
+test_show_depends() { $luarocks install luasec && $luarocks show luasec; }
+test_show_oldversion() { $luarocks install luacov 0.1 && $luarocks show luacov 0.1; }
+
+test_unpack_download() { rm -rf ./luasocket-2.0.2-5 && $luarocks unpack luasocket && rm -rf ./luasocket-2.0.2-5; }
+test_unpack_src() { rm -rf ./luasocket-2.0.2-5 && $luarocks download --src luasocket && $luarocks unpack ./luasocket-2.0.2-5.src.rock && rm -rf ./luasocket-2.0.2-5; }
+test_unpack_rockspec() { rm -rf ./luasocket-2.0.2-5 && $luarocks download --rockspec luasocket && $luarocks unpack ./luasocket-2.0.2-5.rockspec && rm -rf ./luasocket-2.0.2-5; }
+test_unpack_binary() { rm -rf ./luasocket-2.0.2-5 && $luarocks build luasocket && $luarocks pack luasocket && $luarocks unpack ./luasocket-2.0.2-5.linux-x86.rock && rm -rf ./luasocket-2.0.2-5; }
+
+test_admin_help() { $luarocks_admin help; }
+
+test_admin_make_manifest() { $luarocks_admin make_manifest; }
+test_admin_add_rsync() { $luarocks_admin --server=testing add ./luasocket-2.0.2-5.src.rock; }
+test_admin_add_sftp() { export LUAROCKS_CONFIG="$testing_dir/testing_config_sftp.lua" && $luarocks_admin --server=testing add ./luasocket-2.0.2-5.src.rock; export LUAROCKS_CONFIG="$testing_dir/testing_config.lua"; }
+fail_admin_add_missing() { $luarocks_admin --server=testing add; }
+fail_admin_invalidserver() { $luarocks_admin --server=invalid add ./luasocket-2.0.2-5.src.rock; }
+fail_admin_invalidrock() { $luarocks_admin --server=testing add invalid; }
+test_admin_refresh_cache() { $luarocks_admin --server=testing refresh_cache; }
+test_admin_remove() { $luarocks_admin --server=testing remove luasocket; }
+fail_admin_remove_missing() { $luarocks_admin --server=testing remove; }
+
+fail_deps_mode_invalid_arg() { $luarocks remove luacov --deps-mode; }
+test_deps_mode_one() { $luarocks build --tree="$testing_sys_tree" lpeg && $luarocks list && $luarocks build --deps-mode=one --tree="$testing_tree" lxsh && [ `$luarocks list --tree="$testing_tree" --porcelain lpeg | wc -l` = 1 ]; }
+test_deps_mode_order() { $luarocks build --tree="$testing_sys_tree" lpeg && $luarocks build --deps-mode=order --tree="$testing_tree" lxsh && [ `$luarocks list --tree="$testing_tree" --porcelain lpeg | wc -l` = 0 ]; }
+test_deps_mode_order_sys() { $luarocks build --tree="$testing_tree" lpeg && $luarocks build --deps-mode=order --tree="$testing_sys_tree" lxsh && [ `$luarocks list --tree="$testing_sys_tree" --porcelain lpeg | wc -l` = 1 ]; }
+test_deps_mode_all_sys() { $luarocks build --tree="$testing_tree" lpeg && $luarocks build --deps-mode=all --tree="$testing_sys_tree" lxsh && [ `$luarocks list --tree="$testing_sys_tree" --porcelain lpeg | wc -l` = 0 ]; }
+test_deps_mode_none() { $luarocks build --tree="$testing_tree" --deps-mode=none lxsh; [ `$luarocks list --tree="$testing_tree" --porcelain lpeg | wc -l` = 0 ]; }
+test_deps_mode_nodeps_alias() { $luarocks build --tree="$testing_tree" --nodeps lxsh; [ `$luarocks list --tree="$testing_tree" --porcelain lpeg | wc -l` = 0 ]; }
+test_deps_mode_make_order() { $luarocks build --tree="$testing_sys_tree" lpeg && rm -rf ./lxsh-0.8.6-1 && $luarocks download --src lxsh 0.8.6-1 && $luarocks unpack ./lxsh-0.8.6-1.src.rock && cd lxsh-0.8.6-1/lxsh-0.8.6-1 && $luarocks make --tree="$testing_tree" --deps-mode=order && cd ../.. && [ `$luarocks list --tree="$testing_tree" --porcelain lpeg | wc -l` = 0 ] && rm -rf ./lxsh-0.8.6-1; }
+test_deps_mode_make_order_sys() { $luarocks build --tree="$testing_tree" lpeg && rm -rf ./lxsh-0.8.6-1 && $luarocks download --src lxsh 0.8.6-1 && $luarocks unpack ./lxsh-0.8.6-1.src.rock && cd lxsh-0.8.6-1/lxsh-0.8.6-1 && $luarocks make --tree="$testing_sys_tree" --deps-mode=order && cd ../.. && [ `$luarocks list --tree="$testing_tree" --porcelain lpeg | wc -l` = 1 ] && rm -rf ./lxsh-0.8.6-1; }
+
+# Driver #########################################
+
+run_tests() {
+ grep "^test_$1.*(" < $testing_dir/testing.sh | cut -d'(' -f1 | while read test
+ do
+ echo "-------------------------------------------"
+ echo "$test"
+ echo "-------------------------------------------"
+ reset_environment
+ if $test
+ then echo "OK: Expected success."
+ else echo "FAIL: Unexpected failure."; exit 1
+ fi
+ done
+
+ grep "^fail_$1.*(" < $testing_dir/testing.sh | cut -d'(' -f1 | while read test
+ do
+ echo "-------------------------------------------"
+ echo "$test"
+ echo "-------------------------------------------"
+ reset_environment
+ if $test
+ then echo "FAIL: Unexpected success."; exit 1
+ else echo "OK: Expected failure."
+ fi
+ done
+}
+
+run_with_minimal_environment() {
+ build_environment luacov
+ run_tests $1
+}
+
+run_with_full_environment() {
+ build_environment luacov luafilesystem luasocket luabitop luaposix md5 lzlib
+ run_tests $1
+}
+
+run_all_tests() {
+ run_with_minimal_environment $1
+ run_with_full_environment $1
+}
+
+run_all_tests $1
+#run_with_minimal_environment $1
+
+$testing_sys_tree/bin/luacov -c $testing_dir/luacov.config src/luarocks src/bin
+
+cat $testing_dir/luacov.report.out
diff --git a/win32/bin/7z.dll b/win32/bin/7z.dll
new file mode 100644
index 0000000..c0ff7fb
--- /dev/null
+++ b/win32/bin/7z.dll
Binary files differ
diff --git a/win32/bin/7z.exe b/win32/bin/7z.exe
new file mode 100644
index 0000000..5e3d6f9
--- /dev/null
+++ b/win32/bin/7z.exe
Binary files differ
diff --git a/win32/bin/LuaRocks.reg.template b/win32/bin/LuaRocks.reg.template
new file mode 100644
index 0000000..82cc180
--- /dev/null
+++ b/win32/bin/LuaRocks.reg.template
@@ -0,0 +1,59 @@
+Windows Registry Editor Version 5.00
+
+[HKEY_CLASSES_ROOT\.rockspec]
+@="Lua.Rockspec"
+
+[HKEY_CLASSES_ROOT\.rockspec\Content Type]
+@="text/plain"
+
+[HKEY_CLASSES_ROOT\.rockspec\PerceivedType]
+@="text"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.rockspec]
+@="Lua.Rockspec"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.rockspec\Content Type]
+@="text/plain"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.rockspec\PerceivedType]
+@="text"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec]
+@="Lua Rockspec File"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\DefaultIcon]
+@="<LUAROCKSPATH>lua.ico"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell]
+@="Edit"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell\Fetch]
+@="Fetch and install"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell\Fetch\Command]
+@="\"<LUAROCKSPATH>luarocksw.bat\" install \"%1\""
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell\Install]
+@="Install Lua module"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell\Install\Command]
+@="\"<LUAROCKSPATH>luarocksw.bat\" make \"%1\""
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell\Uninstall]
+@="Uninstall Lua module (this version)"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell\Uninstall\Command]
+@="\"<LUAROCKSPATH>luarocksw.bat\" remove \"%1\""
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell\UninstallAll]
+@="Uninstall Lua module (all versions)"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell\UninstallAll\Command]
+@="\"<LUAROCKSPATH>luarocksw.bat\" removeall \"%1\""
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell\Edit]
+@="Edit"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Lua.Rockspec\Shell\Edit\command]
+@="notepad.exe \"%1\""
+
diff --git a/win32/bin/chmod.exe b/win32/bin/chmod.exe
new file mode 100644
index 0000000..9655cfd
--- /dev/null
+++ b/win32/bin/chmod.exe
Binary files differ
diff --git a/win32/bin/cp.exe b/win32/bin/cp.exe
new file mode 100755
index 0000000..0ef4fe8
--- /dev/null
+++ b/win32/bin/cp.exe
Binary files differ
diff --git a/win32/bin/create_reg_file.lua b/win32/bin/create_reg_file.lua
new file mode 100644
index 0000000..2eb7583
--- /dev/null
+++ b/win32/bin/create_reg_file.lua
@@ -0,0 +1,51 @@
+-- Call this file using its full path and the template file as a parameter;
+--
+-- C:\> lua.exe "create_reg_file.lua" "c:\luarocks\2.0\LuaRocks.reg.template"
+--
+-- it will strip the ".template" extension and write to that file the
+-- template contents, where "<LUAROCKSPATH>" will be replaced by the path
+-- to LuaRocks (including the trailing backslash)
+
+
+
+-- Check argument
+local f = (arg or {})[1]
+if not f then
+ print("must provide template file on command line")
+ os.exit(1)
+end
+
+-- cleanup filepath, remove all double backslashes
+while f:match("\\\\") do
+ f = f:gsub("\\\\", "\\")
+end
+
+-- extract path and name from argument
+local p = ""
+local ni = f
+for i = #f, 1, -1 do
+ if f:sub(i,i) == "\\" then
+ ni = f:sub(i+1)
+ p = f:sub(1, i)
+ break
+ end
+end
+
+-- create output name
+local no = ni:gsub("%.template","")
+
+-- create path substitute; escape backslash by doubles
+local ps = p:gsub("\\", "\\\\")
+
+-- read template
+local fh = io.open(f)
+local content = fh:read("*a")
+fh:close()
+
+-- fill template
+content = content:gsub("%<LUAROCKSPATH%>", ps)
+
+-- write destination file
+fh = io.open(p..no, "w+")
+fh:write(content)
+fh:close()
diff --git a/win32/bin/find.exe b/win32/bin/find.exe
new file mode 100755
index 0000000..85192fb
--- /dev/null
+++ b/win32/bin/find.exe
Binary files differ
diff --git a/win32/bin/libeay32.dll b/win32/bin/libeay32.dll
new file mode 100644
index 0000000..8d31f86
--- /dev/null
+++ b/win32/bin/libeay32.dll
Binary files differ
diff --git a/win32/bin/libiconv2.dll b/win32/bin/libiconv2.dll
new file mode 100644
index 0000000..544dd92
--- /dev/null
+++ b/win32/bin/libiconv2.dll
Binary files differ
diff --git a/win32/bin/libintl3.dll b/win32/bin/libintl3.dll
new file mode 100644
index 0000000..ec11e6b
--- /dev/null
+++ b/win32/bin/libintl3.dll
Binary files differ
diff --git a/win32/bin/libssl32.dll b/win32/bin/libssl32.dll
new file mode 100644
index 0000000..a30ff0e
--- /dev/null
+++ b/win32/bin/libssl32.dll
Binary files differ
diff --git a/win32/bin/ls.exe b/win32/bin/ls.exe
new file mode 100755
index 0000000..96ff2e5
--- /dev/null
+++ b/win32/bin/ls.exe
Binary files differ
diff --git a/win32/bin/lua.ico b/win32/bin/lua.ico
new file mode 100644
index 0000000..56dc4fe
--- /dev/null
+++ b/win32/bin/lua.ico
Binary files differ
diff --git a/win32/bin/luarocksw.bat b/win32/bin/luarocksw.bat
new file mode 100644
index 0000000..313508d
--- /dev/null
+++ b/win32/bin/luarocksw.bat
@@ -0,0 +1,49 @@
+@echo off
+setlocal
+SET MYPATH=%~dp0
+
+IF NOT [%1]==[] GOTO LETSGO
+ECHO Same as 'luarocks' command, except this
+ECHO command will pause after completion, allowing for
+ECHO examination of output.
+ECHO.
+ECHO For LuaRocks help use:
+ECHO LUAROCKS HELP
+ECHO.
+ECHO OPTIONS specific for LUAROCKSW:
+ECHO REMOVEALL is a command specific to this batch file
+ECHO the option takes a FULL ROCKSPEC filename and then
+ECHO it will strip path, version and extension info from
+ECHO it before executing the LUAROCKS REMOVE command
+ECHO Example:
+ECHO luarocksw remove "c:\somedir\modulename-1.0-1.rockspec"
+ECHO will execute:
+ECHO luarocks remove "c:\somedir\modulename-1.0-1.rockspec"
+ECHO and will only remove the specific version 1.0 from the
+ECHO system.
+ECHO luarocksw removeall "c:\somedir\modulename-1.0-1.rockspec"
+ECHO will execute:
+ECHO luarocks remove modulename
+ECHO and will remove all versions of this package
+ECHO.
+GOTO END
+
+:LETSGO
+REM if REMOVEALL command then info must be stripped from the parameter
+if [%1]==[removeall] goto REMOVEALL
+
+REM execute LuaRocks and wait for results
+echo executing: luarocks %*
+call %MYPATH%luarocks %*
+pause
+goto END
+
+:REMOVEALL
+for /f "delims=-" %%a in ("%~n2") do (
+ echo executing: luarocks remove %%a
+ %MYPATH%luarocks remove "%%a"
+ pause
+ goto END
+)
+
+:END \ No newline at end of file
diff --git a/win32/bin/md5sum.exe b/win32/bin/md5sum.exe
new file mode 100644
index 0000000..4ae9f74
--- /dev/null
+++ b/win32/bin/md5sum.exe
Binary files differ
diff --git a/win32/bin/mkdir.exe b/win32/bin/mkdir.exe
new file mode 100755
index 0000000..83e57d9
--- /dev/null
+++ b/win32/bin/mkdir.exe
Binary files differ
diff --git a/win32/bin/mv.exe b/win32/bin/mv.exe
new file mode 100755
index 0000000..9fb65bb
--- /dev/null
+++ b/win32/bin/mv.exe
Binary files differ
diff --git a/win32/bin/objdump.exe b/win32/bin/objdump.exe
new file mode 100644
index 0000000..4429d10
--- /dev/null
+++ b/win32/bin/objdump.exe
Binary files differ
diff --git a/win32/bin/pwd.exe b/win32/bin/pwd.exe
new file mode 100755
index 0000000..7dd114d
--- /dev/null
+++ b/win32/bin/pwd.exe
Binary files differ
diff --git a/win32/bin/rclauncher.c b/win32/bin/rclauncher.c
new file mode 100644
index 0000000..77459f4
--- /dev/null
+++ b/win32/bin/rclauncher.c
@@ -0,0 +1,139 @@
+
+/*
+** Simple Lua interpreter.
+** This program is used to run a Lua file embedded as a resource.
+** It creates a Lua state, opens all its standard libraries, and run
+** the Lua file in a protected environment just to redirect the error
+** messages to stdout and stderr.
+**
+** $Id: rclauncher.c,v 1.1 2008/06/30 14:29:59 carregal Exp $
+*/
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include <windows.h>
+#include <io.h>
+#include <fcntl.h>
+
+/*
+** Report error message.
+** Assumes that the error message is on top of the stack.
+*/
+static int report (lua_State *L) {
+ fprintf (stderr, "lua: fatal error: `%s'\n", lua_tostring (L, -1));
+ fflush (stderr);
+ printf ("Content-type: text/plain\n\nConfiguration fatal error: see error log!\n");
+ printf ("%s", lua_tostring(L, -1));
+ return 1;
+}
+
+static int runlua (lua_State *L, const char *lua_string, int argc, char *argv[]) {
+ int err_func;
+ int err;
+
+ lua_getglobal(L, "debug");
+ lua_pushliteral(L, "traceback");
+ lua_gettable(L, -2);
+ err_func = lua_gettop (L);
+ err = luaL_loadstring (L, lua_string);
+ if(!err) {
+ int i;
+ // fill global arg table
+ lua_getglobal(L, "arg");
+ for(i = 1; i < argc; i++)
+ {
+ lua_pushstring(L, argv[i]);
+ lua_rawseti(L, -2, i);
+ }
+ lua_pop(L, 1);
+ // fill parameters (in vararg '...')
+ for(i = 1; i < argc; i++)
+ lua_pushstring(L, argv[i]);
+ return lua_pcall (L, argc - 1, LUA_MULTRET, err_func);
+ } else return err;
+}
+
+static DWORD GetModulePath( HINSTANCE hInst, LPTSTR pszBuffer, DWORD dwSize )
+//
+// Return the size of the path in bytes.
+{
+ DWORD dwLength = GetModuleFileName( hInst, pszBuffer, dwSize );
+ if( dwLength )
+ {
+ while( dwLength && pszBuffer[ dwLength ] != '.' )
+ {
+ dwLength--;
+ }
+
+ if( dwLength )
+ pszBuffer[ dwLength ] = '\000';
+ }
+ return dwLength;
+}
+
+
+/*
+** MAIN
+*/
+int main (int argc, char *argv[]) {
+ char name[ MAX_PATH ];
+ DWORD dwLength;
+ int size;
+ luaL_Buffer b;
+ int i;
+#ifdef UNICODE
+ TCHAR lua_wstring[4098];
+#endif
+ char lua_string[4098];
+ lua_State *L = luaL_newstate();
+ (void)argc; /* avoid "unused parameter" warning */
+ luaL_openlibs(L);
+ lua_newtable(L); // create arg table
+ lua_pushstring(L, argv[0]); // add interpreter to arg table
+ lua_rawseti(L, -2, -1);
+ dwLength = GetModulePath( NULL, name, MAX_PATH );
+ if(dwLength) { /* Optional bootstrap */
+ strcat(name, ".lua");
+ lua_pushstring(L, name); // add lua script to arg table
+ lua_rawseti(L, -2, 0);
+ lua_setglobal(L,"arg"); // set global arg table
+ if(!luaL_loadfile (L, name)) {
+ if(lua_pcall (L, 0, LUA_MULTRET, 0)) {
+ report (L);
+ lua_close (L);
+ return EXIT_FAILURE;
+ }
+ }
+ }
+ else
+ {
+ lua_pushstring(L, argv[0]); // no lua script, so add interpreter again, now as lua script
+ lua_rawseti(L, -2, 0);
+ lua_setglobal(L,"arg"); // set global arg table
+ }
+
+ luaL_buffinit(L, &b);
+ for(i = 1; ; i++) {
+#ifdef UNICODE
+ size = LoadString(GetModuleHandle(NULL), i, lua_wstring,
+ sizeof(lua_string)/sizeof(TCHAR));
+ if(size > 0) wcstombs(lua_string, lua_wstring, size + 1);
+#else
+ size = LoadString(GetModuleHandle(NULL), i, lua_string,
+ sizeof(lua_string)/sizeof(char));
+#endif
+ if(size) luaL_addlstring(&b, lua_string, size); else break;
+ }
+ luaL_pushresult(&b);
+ if (runlua (L, lua_tostring(L, -1), argc, argv)) {
+ report (L);
+ lua_close (L);
+ return EXIT_FAILURE;
+ }
+ lua_close (L);
+ return EXIT_SUCCESS;
+}
diff --git a/win32/bin/rm.exe b/win32/bin/rm.exe
new file mode 100755
index 0000000..8e79306
--- /dev/null
+++ b/win32/bin/rm.exe
Binary files differ
diff --git a/win32/bin/rmdir.exe b/win32/bin/rmdir.exe
new file mode 100755
index 0000000..6a85c3c
--- /dev/null
+++ b/win32/bin/rmdir.exe
Binary files differ
diff --git a/win32/bin/test.exe b/win32/bin/test.exe
new file mode 100755
index 0000000..94c95f9
--- /dev/null
+++ b/win32/bin/test.exe
Binary files differ
diff --git a/win32/bin/uname.exe b/win32/bin/uname.exe
new file mode 100755
index 0000000..3e2f4cf
--- /dev/null
+++ b/win32/bin/uname.exe
Binary files differ
diff --git a/win32/bin/wget.exe b/win32/bin/wget.exe
new file mode 100644
index 0000000..54b372e
--- /dev/null
+++ b/win32/bin/wget.exe
Binary files differ
diff --git a/win32/lua5.1/bin/Microsoft.VC80.CRT.manifest b/win32/lua5.1/bin/Microsoft.VC80.CRT.manifest
new file mode 100644
index 0000000..b89cafd
--- /dev/null
+++ b/win32/lua5.1/bin/Microsoft.VC80.CRT.manifest
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <noInheritable></noInheritable>
+ <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50727.762" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
+ <file name="msvcr80.dll" hash="10f4cb2831f1e9288a73387a8734a8b604e5beaa" hashalg="SHA1"><asmv2:hash xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>n9On8FItNsK/DmT8UQxu6jYDtWQ=</dsig:DigestValue></asmv2:hash></file>
+ <file name="msvcp80.dll" hash="b2082dfd3009365c5b287448dcb3b4e2158a6d26" hashalg="SHA1"><asmv2:hash xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>0KJ/VTwP4OUHx98HlIW2AdW1kuY=</dsig:DigestValue></asmv2:hash></file>
+ <file name="msvcm80.dll" hash="542490d0fcf8615c46d0ca487033ccaeb3941f0b" hashalg="SHA1"><asmv2:hash xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>YJuB+9Os2oxW4mY+2oC/r8lICZE=</dsig:DigestValue></asmv2:hash></file>
+</assembly> \ No newline at end of file
diff --git a/win32/lua5.1/bin/bin2c5.1.exe b/win32/lua5.1/bin/bin2c5.1.exe
new file mode 100644
index 0000000..ca81d4b
--- /dev/null
+++ b/win32/lua5.1/bin/bin2c5.1.exe
Binary files differ
diff --git a/win32/lua5.1/bin/lua5.1.dll b/win32/lua5.1/bin/lua5.1.dll
new file mode 100644
index 0000000..b87f3b6
--- /dev/null
+++ b/win32/lua5.1/bin/lua5.1.dll
Binary files differ
diff --git a/win32/lua5.1/bin/lua5.1.exe b/win32/lua5.1/bin/lua5.1.exe
new file mode 100644
index 0000000..dc1c2c3
--- /dev/null
+++ b/win32/lua5.1/bin/lua5.1.exe
Binary files differ
diff --git a/win32/lua5.1/bin/lua5.1.lib b/win32/lua5.1/bin/lua5.1.lib
new file mode 100644
index 0000000..df98827
--- /dev/null
+++ b/win32/lua5.1/bin/lua5.1.lib
Binary files differ
diff --git a/win32/lua5.1/bin/lua51.dll b/win32/lua5.1/bin/lua51.dll
new file mode 100644
index 0000000..27ab265
--- /dev/null
+++ b/win32/lua5.1/bin/lua51.dll
Binary files differ
diff --git a/win32/lua5.1/bin/lua51.lib b/win32/lua5.1/bin/lua51.lib
new file mode 100644
index 0000000..74bcf3f
--- /dev/null
+++ b/win32/lua5.1/bin/lua51.lib
Binary files differ
diff --git a/win32/lua5.1/bin/luac5.1.exe b/win32/lua5.1/bin/luac5.1.exe
new file mode 100644
index 0000000..6f87524
--- /dev/null
+++ b/win32/lua5.1/bin/luac5.1.exe
Binary files differ
diff --git a/win32/lua5.1/bin/msvcm80.dll b/win32/lua5.1/bin/msvcm80.dll
new file mode 100644
index 0000000..c751385
--- /dev/null
+++ b/win32/lua5.1/bin/msvcm80.dll
Binary files differ
diff --git a/win32/lua5.1/bin/msvcp80.dll b/win32/lua5.1/bin/msvcp80.dll
new file mode 100644
index 0000000..f0b52eb
--- /dev/null
+++ b/win32/lua5.1/bin/msvcp80.dll
Binary files differ
diff --git a/win32/lua5.1/bin/msvcr80.dll b/win32/lua5.1/bin/msvcr80.dll
new file mode 100644
index 0000000..53c005e
--- /dev/null
+++ b/win32/lua5.1/bin/msvcr80.dll
Binary files differ
diff --git a/win32/lua5.1/bin/wlua5.1.exe b/win32/lua5.1/bin/wlua5.1.exe
new file mode 100644
index 0000000..7be8c3a
--- /dev/null
+++ b/win32/lua5.1/bin/wlua5.1.exe
Binary files differ
diff --git a/win32/lua5.1/include/lauxlib.h b/win32/lua5.1/include/lauxlib.h
new file mode 100644
index 0000000..3425823
--- /dev/null
+++ b/win32/lua5.1/include/lauxlib.h
@@ -0,0 +1,174 @@
+/*
+** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lauxlib_h
+#define lauxlib_h
+
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "lua.h"
+
+
+#if defined(LUA_COMPAT_GETN)
+LUALIB_API int (luaL_getn) (lua_State *L, int t);
+LUALIB_API void (luaL_setn) (lua_State *L, int t, int n);
+#else
+#define luaL_getn(L,i) ((int)lua_objlen(L, i))
+#define luaL_setn(L,i,j) ((void)0) /* no op! */
+#endif
+
+#if defined(LUA_COMPAT_OPENLIB)
+#define luaI_openlib luaL_openlib
+#endif
+
+
+/* extra error code for `luaL_load' */
+#define LUA_ERRFILE (LUA_ERRERR+1)
+
+
+typedef struct luaL_Reg {
+ const char *name;
+ lua_CFunction func;
+} luaL_Reg;
+
+
+
+LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname,
+ const luaL_Reg *l, int nup);
+LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
+ const luaL_Reg *l);
+LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
+LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
+LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
+LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
+LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
+ size_t *l);
+LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
+ const char *def, size_t *l);
+LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
+LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
+
+LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
+LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
+ lua_Integer def);
+
+LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
+LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
+LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
+
+LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
+LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
+
+LUALIB_API void (luaL_where) (lua_State *L, int lvl);
+LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
+
+LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
+ const char *const lst[]);
+
+LUALIB_API int (luaL_ref) (lua_State *L, int t);
+LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
+
+LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
+LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
+ const char *name);
+LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
+
+LUALIB_API lua_State *(luaL_newstate) (void);
+
+
+LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
+ const char *r);
+
+LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
+ const char *fname, int szhint);
+
+
+
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define luaL_argcheck(L, cond,numarg,extramsg) \
+ ((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
+#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
+#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
+#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
+#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
+#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
+#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
+
+#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
+
+#define luaL_dofile(L, fn) \
+ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_dostring(L, s) \
+ (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
+
+#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+
+
+typedef struct luaL_Buffer {
+ char *p; /* current position in buffer */
+ int lvl; /* number of strings in the stack (level) */
+ lua_State *L;
+ char buffer[LUAL_BUFFERSIZE];
+} luaL_Buffer;
+
+#define luaL_addchar(B,c) \
+ ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
+ (*(B)->p++ = (char)(c)))
+
+/* compatibility only */
+#define luaL_putchar(B,c) luaL_addchar(B,c)
+
+#define luaL_addsize(B,n) ((B)->p += (n))
+
+LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
+LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
+LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
+LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
+LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
+
+
+/* }====================================================== */
+
+
+/* compatibility with ref system */
+
+/* pre-defined references */
+#define LUA_NOREF (-2)
+#define LUA_REFNIL (-1)
+
+#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
+ (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))
+
+#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref))
+
+#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref))
+
+
+#define luaL_reg luaL_Reg
+
+#endif
+
+
diff --git a/win32/lua5.1/include/lua.h b/win32/lua5.1/include/lua.h
new file mode 100644
index 0000000..e4bdfd3
--- /dev/null
+++ b/win32/lua5.1/include/lua.h
@@ -0,0 +1,388 @@
+/*
+** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $
+** Lua - An Extensible Extension Language
+** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
+** See Copyright Notice at the end of this file
+*/
+
+
+#ifndef lua_h
+#define lua_h
+
+#include <stdarg.h>
+#include <stddef.h>
+
+
+#include "luaconf.h"
+
+
+#define LUA_VERSION "Lua 5.1"
+#define LUA_RELEASE "Lua 5.1.4"
+#define LUA_VERSION_NUM 501
+#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio"
+#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
+
+
+/* mark for precompiled code (`<esc>Lua') */
+#define LUA_SIGNATURE "\033Lua"
+
+/* option for multiple returns in `lua_pcall' and `lua_call' */
+#define LUA_MULTRET (-1)
+
+
+/*
+** pseudo-indices
+*/
+#define LUA_REGISTRYINDEX (-10000)
+#define LUA_ENVIRONINDEX (-10001)
+#define LUA_GLOBALSINDEX (-10002)
+#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))
+
+
+/* thread status; 0 is OK */
+#define LUA_YIELD 1
+#define LUA_ERRRUN 2
+#define LUA_ERRSYNTAX 3
+#define LUA_ERRMEM 4
+#define LUA_ERRERR 5
+
+
+typedef struct lua_State lua_State;
+
+typedef int (*lua_CFunction) (lua_State *L);
+
+
+/*
+** functions that read/write blocks when loading/dumping Lua chunks
+*/
+typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
+
+typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
+
+
+/*
+** prototype for memory-allocation functions
+*/
+typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
+
+
+/*
+** basic types
+*/
+#define LUA_TNONE (-1)
+
+#define LUA_TNIL 0
+#define LUA_TBOOLEAN 1
+#define LUA_TLIGHTUSERDATA 2
+#define LUA_TNUMBER 3
+#define LUA_TSTRING 4
+#define LUA_TTABLE 5
+#define LUA_TFUNCTION 6
+#define LUA_TUSERDATA 7
+#define LUA_TTHREAD 8
+
+
+
+/* minimum Lua stack available to a C function */
+#define LUA_MINSTACK 20
+
+
+/*
+** generic extra include file
+*/
+#if defined(LUA_USER_H)
+#include LUA_USER_H
+#endif
+
+
+/* type of numbers in Lua */
+typedef LUA_NUMBER lua_Number;
+
+
+/* type for integer functions */
+typedef LUA_INTEGER lua_Integer;
+
+
+
+/*
+** state manipulation
+*/
+LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
+LUA_API void (lua_close) (lua_State *L);
+LUA_API lua_State *(lua_newthread) (lua_State *L);
+
+LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
+
+
+/*
+** basic stack manipulation
+*/
+LUA_API int (lua_gettop) (lua_State *L);
+LUA_API void (lua_settop) (lua_State *L, int idx);
+LUA_API void (lua_pushvalue) (lua_State *L, int idx);
+LUA_API void (lua_remove) (lua_State *L, int idx);
+LUA_API void (lua_insert) (lua_State *L, int idx);
+LUA_API void (lua_replace) (lua_State *L, int idx);
+LUA_API int (lua_checkstack) (lua_State *L, int sz);
+
+LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
+
+
+/*
+** access functions (stack -> C)
+*/
+
+LUA_API int (lua_isnumber) (lua_State *L, int idx);
+LUA_API int (lua_isstring) (lua_State *L, int idx);
+LUA_API int (lua_iscfunction) (lua_State *L, int idx);
+LUA_API int (lua_isuserdata) (lua_State *L, int idx);
+LUA_API int (lua_type) (lua_State *L, int idx);
+LUA_API const char *(lua_typename) (lua_State *L, int tp);
+
+LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2);
+LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
+LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2);
+
+LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx);
+LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx);
+LUA_API int (lua_toboolean) (lua_State *L, int idx);
+LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
+LUA_API size_t (lua_objlen) (lua_State *L, int idx);
+LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
+LUA_API void *(lua_touserdata) (lua_State *L, int idx);
+LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
+LUA_API const void *(lua_topointer) (lua_State *L, int idx);
+
+
+/*
+** push functions (C -> stack)
+*/
+LUA_API void (lua_pushnil) (lua_State *L);
+LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
+LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
+LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l);
+LUA_API void (lua_pushstring) (lua_State *L, const char *s);
+LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
+ va_list argp);
+LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
+LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
+LUA_API void (lua_pushboolean) (lua_State *L, int b);
+LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
+LUA_API int (lua_pushthread) (lua_State *L);
+
+
+/*
+** get functions (Lua -> stack)
+*/
+LUA_API void (lua_gettable) (lua_State *L, int idx);
+LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k);
+LUA_API void (lua_rawget) (lua_State *L, int idx);
+LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n);
+LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
+LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
+LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
+LUA_API void (lua_getfenv) (lua_State *L, int idx);
+
+
+/*
+** set functions (stack -> Lua)
+*/
+LUA_API void (lua_settable) (lua_State *L, int idx);
+LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
+LUA_API void (lua_rawset) (lua_State *L, int idx);
+LUA_API void (lua_rawseti) (lua_State *L, int idx, int n);
+LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
+LUA_API int (lua_setfenv) (lua_State *L, int idx);
+
+
+/*
+** `load' and `call' functions (load and run Lua code)
+*/
+LUA_API void (lua_call) (lua_State *L, int nargs, int nresults);
+LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
+LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
+LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
+ const char *chunkname);
+
+LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
+
+
+/*
+** coroutine functions
+*/
+LUA_API int (lua_yield) (lua_State *L, int nresults);
+LUA_API int (lua_resume) (lua_State *L, int narg);
+LUA_API int (lua_status) (lua_State *L);
+
+/*
+** garbage-collection function and options
+*/
+
+#define LUA_GCSTOP 0
+#define LUA_GCRESTART 1
+#define LUA_GCCOLLECT 2
+#define LUA_GCCOUNT 3
+#define LUA_GCCOUNTB 4
+#define LUA_GCSTEP 5
+#define LUA_GCSETPAUSE 6
+#define LUA_GCSETSTEPMUL 7
+
+LUA_API int (lua_gc) (lua_State *L, int what, int data);
+
+
+/*
+** miscellaneous functions
+*/
+
+LUA_API int (lua_error) (lua_State *L);
+
+LUA_API int (lua_next) (lua_State *L, int idx);
+
+LUA_API void (lua_concat) (lua_State *L, int n);
+
+LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
+LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
+
+
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define lua_pop(L,n) lua_settop(L, -(n)-1)
+
+#define lua_newtable(L) lua_createtable(L, 0, 0)
+
+#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
+
+#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
+
+#define lua_strlen(L,i) lua_objlen(L, (i))
+
+#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
+#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
+#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
+#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
+#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
+#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
+#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
+#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
+
+#define lua_pushliteral(L, s) \
+ lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
+
+#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s))
+#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
+
+#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
+
+
+
+/*
+** compatibility macros and functions
+*/
+
+#define lua_open() luaL_newstate()
+
+#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX)
+
+#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0)
+
+#define lua_Chunkreader lua_Reader
+#define lua_Chunkwriter lua_Writer
+
+
+/* hack */
+LUA_API void lua_setlevel (lua_State *from, lua_State *to);
+
+
+/*
+** {======================================================================
+** Debug API
+** =======================================================================
+*/
+
+
+/*
+** Event codes
+*/
+#define LUA_HOOKCALL 0
+#define LUA_HOOKRET 1
+#define LUA_HOOKLINE 2
+#define LUA_HOOKCOUNT 3
+#define LUA_HOOKTAILRET 4
+
+
+/*
+** Event masks
+*/
+#define LUA_MASKCALL (1 << LUA_HOOKCALL)
+#define LUA_MASKRET (1 << LUA_HOOKRET)
+#define LUA_MASKLINE (1 << LUA_HOOKLINE)
+#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
+
+typedef struct lua_Debug lua_Debug; /* activation record */
+
+
+/* Functions to be called by the debuger in specific events */
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
+
+
+LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar);
+LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
+LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n);
+LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n);
+
+LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
+LUA_API lua_Hook lua_gethook (lua_State *L);
+LUA_API int lua_gethookmask (lua_State *L);
+LUA_API int lua_gethookcount (lua_State *L);
+
+
+struct lua_Debug {
+ int event;
+ const char *name; /* (n) */
+ const char *namewhat; /* (n) `global', `local', `field', `method' */
+ const char *what; /* (S) `Lua', `C', `main', `tail' */
+ const char *source; /* (S) */
+ int currentline; /* (l) */
+ int nups; /* (u) number of upvalues */
+ int linedefined; /* (S) */
+ int lastlinedefined; /* (S) */
+ char short_src[LUA_IDSIZE]; /* (S) */
+ /* private part */
+ int i_ci; /* active function */
+};
+
+/* }====================================================================== */
+
+
+/******************************************************************************
+* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to deal in the Software without restriction, including
+* without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to
+* permit persons to whom the Software is furnished to do so, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+******************************************************************************/
+
+
+#endif
diff --git a/win32/lua5.1/include/lua.hpp b/win32/lua5.1/include/lua.hpp
new file mode 100644
index 0000000..ec417f5
--- /dev/null
+++ b/win32/lua5.1/include/lua.hpp
@@ -0,0 +1,9 @@
+// lua.hpp
+// Lua header files for C++
+// <<extern "C">> not supplied automatically because Lua also compiles as C++
+
+extern "C" {
+#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+}
diff --git a/win32/lua5.1/include/luaconf.h b/win32/lua5.1/include/luaconf.h
new file mode 100644
index 0000000..5e7b98b
--- /dev/null
+++ b/win32/lua5.1/include/luaconf.h
@@ -0,0 +1,763 @@
+/*
+** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $
+** Configuration file for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lconfig_h
+#define lconfig_h
+
+#include <limits.h>
+#include <stddef.h>
+
+
+/*
+** ==================================================================
+** Search for "@@" to find all configurable definitions.
+** ===================================================================
+*/
+
+
+/*
+@@ LUA_ANSI controls the use of non-ansi features.
+** CHANGE it (define it) if you want Lua to avoid the use of any
+** non-ansi feature or library.
+*/
+#if defined(__STRICT_ANSI__)
+#define LUA_ANSI
+#endif
+
+
+#if !defined(LUA_ANSI) && defined(_WIN32)
+#define LUA_WIN
+#endif
+
+#if defined(LUA_USE_LINUX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
+#define LUA_USE_READLINE /* needs some extra libraries */
+#endif
+
+#if defined(LUA_USE_MACOSX)
+#define LUA_USE_POSIX
+#define LUA_DL_DYLD /* does not need extra library */
+#endif
+
+
+
+/*
+@@ LUA_USE_POSIX includes all functionallity listed as X/Open System
+@* Interfaces Extension (XSI).
+** CHANGE it (define it) if your system is XSI compatible.
+*/
+#if defined(LUA_USE_POSIX)
+#define LUA_USE_MKSTEMP
+#define LUA_USE_ISATTY
+#define LUA_USE_POPEN
+#define LUA_USE_ULONGJMP
+#endif
+
+
+/*
+@@ LUA_PATH and LUA_CPATH are the names of the environment variables that
+@* Lua check to set its paths.
+@@ LUA_INIT is the name of the environment variable that Lua
+@* checks for initialization code.
+** CHANGE them if you want different names.
+*/
+#define LUA_PATH "LUA_PATH"
+#define LUA_CPATH "LUA_CPATH"
+#define LUA_INIT "LUA_INIT"
+
+
+/*
+@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
+@* Lua libraries.
+@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
+@* C libraries.
+** CHANGE them if your machine has a non-conventional directory
+** hierarchy or if you want to install your libraries in
+** non-conventional directories.
+*/
+#if defined(_WIN32)
+/*
+** In Windows, any exclamation mark ('!') in the path is replaced by the
+** path of the directory of the executable file of the current process.
+*/
+#define LUA_LDIR "!\\lua\\"
+#define LUA_CDIR "!\\"
+#define LUA_PATH_DEFAULT \
+ ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua"
+#define LUA_CPATH_DEFAULT \
+ ".\\?.dll;" ".\\?51.dll;" LUA_CDIR"?.dll;" LUA_CDIR"?51.dll;" LUA_CDIR"clibs\\?.dll;" LUA_CDIR"clibs\\?51.dll;" LUA_CDIR"loadall.dll;" LUA_CDIR"clibs\\loadall.dll"
+
+#else
+#define LUA_ROOT "/usr/local/"
+#define LUA_LDIR LUA_ROOT "share/lua/5.1/"
+#define LUA_CDIR LUA_ROOT "lib/lua/5.1/"
+#define LUA_PATH_DEFAULT \
+ "./?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua"
+#define LUA_CPATH_DEFAULT \
+ "./?.so;" "./lib?51.so;" LUA_CDIR"?.so;" LUA_CDIR"lib?51.so;" LUA_CDIR"loadall.so"
+#endif
+
+
+/*
+@@ LUA_DIRSEP is the directory separator (for submodules).
+** CHANGE it if your machine does not use "/" as the directory separator
+** and is not Windows. (On Windows Lua automatically uses "\".)
+*/
+#if defined(_WIN32)
+#define LUA_DIRSEP "\\"
+#else
+#define LUA_DIRSEP "/"
+#endif
+
+
+/*
+@@ LUA_PATHSEP is the character that separates templates in a path.
+@@ LUA_PATH_MARK is the string that marks the substitution points in a
+@* template.
+@@ LUA_EXECDIR in a Windows path is replaced by the executable's
+@* directory.
+@@ LUA_IGMARK is a mark to ignore all before it when bulding the
+@* luaopen_ function name.
+** CHANGE them if for some reason your system cannot use those
+** characters. (E.g., if one of those characters is a common character
+** in file/directory names.) Probably you do not need to change them.
+*/
+#define LUA_PATHSEP ";"
+#define LUA_PATH_MARK "?"
+#define LUA_EXECDIR "!"
+#define LUA_IGMARK "-"
+
+
+/*
+@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger.
+** CHANGE that if ptrdiff_t is not adequate on your machine. (On most
+** machines, ptrdiff_t gives a good choice between int or long.)
+*/
+#define LUA_INTEGER ptrdiff_t
+
+
+/*
+@@ LUA_API is a mark for all core API functions.
+@@ LUALIB_API is a mark for all standard library functions.
+** CHANGE them if you need to define those functions in some special way.
+** For instance, if you want to create one Windows DLL with the core and
+** the libraries, you may want to use the following definition (define
+** LUA_BUILD_AS_DLL to get it).
+*/
+#if defined(LUA_BUILD_AS_DLL)
+
+#if defined(LUA_CORE) || defined(LUA_LIB)
+#define LUA_API __declspec(dllexport)
+#else
+#define LUA_API __declspec(dllimport)
+#endif
+
+#else
+
+#define LUA_API extern
+
+#endif
+
+/* more often than not the libs go together with the core */
+#define LUALIB_API LUA_API
+
+
+/*
+@@ LUAI_FUNC is a mark for all extern functions that are not to be
+@* exported to outside modules.
+@@ LUAI_DATA is a mark for all extern (const) variables that are not to
+@* be exported to outside modules.
+** CHANGE them if you need to mark them in some special way. Elf/gcc
+** (versions 3.2 and later) mark them as "hidden" to optimize access
+** when Lua is compiled as a shared library.
+*/
+#if defined(luaall_c)
+#define LUAI_FUNC static
+#define LUAI_DATA /* empty */
+
+#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
+ defined(__ELF__)
+#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
+#define LUAI_DATA LUAI_FUNC
+
+#else
+#define LUAI_FUNC extern
+#define LUAI_DATA extern
+#endif
+
+
+
+/*
+@@ LUA_QL describes how error messages quote program elements.
+** CHANGE it if you want a different appearance.
+*/
+#define LUA_QL(x) "'" x "'"
+#define LUA_QS LUA_QL("%s")
+
+
+/*
+@@ LUA_IDSIZE gives the maximum size for the description of the source
+@* of a function in debug information.
+** CHANGE it if you want a different size.
+*/
+#define LUA_IDSIZE 60
+
+
+/*
+** {==================================================================
+** Stand-alone configuration
+** ===================================================================
+*/
+
+#if defined(lua_c) || defined(luaall_c)
+
+/*
+@@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that
+@* is, whether we're running lua interactively).
+** CHANGE it if you have a better definition for non-POSIX/non-Windows
+** systems.
+*/
+#if defined(LUA_USE_ISATTY)
+#include <unistd.h>
+#define lua_stdin_is_tty() isatty(0)
+#elif defined(LUA_WIN)
+#include <io.h>
+#include <stdio.h>
+#define lua_stdin_is_tty() _isatty(_fileno(stdin))
+#else
+#define lua_stdin_is_tty() 1 /* assume stdin is a tty */
+#endif
+
+
+/*
+@@ LUA_PROMPT is the default prompt used by stand-alone Lua.
+@@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua.
+** CHANGE them if you want different prompts. (You can also change the
+** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.)
+*/
+#define LUA_PROMPT "> "
+#define LUA_PROMPT2 ">> "
+
+
+/*
+@@ LUA_PROGNAME is the default name for the stand-alone Lua program.
+** CHANGE it if your stand-alone interpreter has a different name and
+** your system is not able to detect that name automatically.
+*/
+#define LUA_PROGNAME "lua"
+
+
+/*
+@@ LUA_MAXINPUT is the maximum length for an input line in the
+@* stand-alone interpreter.
+** CHANGE it if you need longer lines.
+*/
+#define LUA_MAXINPUT 512
+
+
+/*
+@@ lua_readline defines how to show a prompt and then read a line from
+@* the standard input.
+@@ lua_saveline defines how to "save" a read line in a "history".
+@@ lua_freeline defines how to free a line read by lua_readline.
+** CHANGE them if you want to improve this functionality (e.g., by using
+** GNU readline and history facilities).
+*/
+#if defined(LUA_USE_READLINE)
+#include <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
+#define lua_saveline(L,idx) \
+ if (lua_strlen(L,idx) > 0) /* non-empty line? */ \
+ add_history(lua_tostring(L, idx)); /* add it to history */
+#define lua_freeline(L,b) ((void)L, free(b))
+#else
+#define lua_readline(L,b,p) \
+ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
+ fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */
+#define lua_saveline(L,idx) { (void)L; (void)idx; }
+#define lua_freeline(L,b) { (void)L; (void)b; }
+#endif
+
+#endif
+
+/* }================================================================== */
+
+
+/*
+@@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles
+@* as a percentage.
+** CHANGE it if you want the GC to run faster or slower (higher values
+** mean larger pauses which mean slower collection.) You can also change
+** this value dynamically.
+*/
+#define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */
+
+
+/*
+@@ LUAI_GCMUL defines the default speed of garbage collection relative to
+@* memory allocation as a percentage.
+** CHANGE it if you want to change the granularity of the garbage
+** collection. (Higher values mean coarser collections. 0 represents
+** infinity, where each step performs a full collection.) You can also
+** change this value dynamically.
+*/
+#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */
+
+
+
+/*
+@@ LUA_COMPAT_GETN controls compatibility with old getn behavior.
+** CHANGE it (define it) if you want exact compatibility with the
+** behavior of setn/getn in Lua 5.0.
+*/
+#undef LUA_COMPAT_GETN
+
+/*
+@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib.
+** CHANGE it to undefined as soon as you do not need a global 'loadlib'
+** function (the function is still available as 'package.loadlib').
+*/
+#undef LUA_COMPAT_LOADLIB
+
+/*
+@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature.
+** CHANGE it to undefined as soon as your programs use only '...' to
+** access vararg parameters (instead of the old 'arg' table).
+*/
+#define LUA_COMPAT_VARARG
+
+/*
+@@ LUA_COMPAT_MOD controls compatibility with old math.mod function.
+** CHANGE it to undefined as soon as your programs use 'math.fmod' or
+** the new '%' operator instead of 'math.mod'.
+*/
+#define LUA_COMPAT_MOD
+
+/*
+@@ LUA_COMPAT_LSTR controls compatibility with old long string nesting
+@* facility.
+** CHANGE it to 2 if you want the old behaviour, or undefine it to turn
+** off the advisory error when nesting [[...]].
+*/
+#define LUA_COMPAT_LSTR 1
+
+/*
+@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name.
+** CHANGE it to undefined as soon as you rename 'string.gfind' to
+** 'string.gmatch'.
+*/
+#define LUA_COMPAT_GFIND
+
+/*
+@@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib'
+@* behavior.
+** CHANGE it to undefined as soon as you replace to 'luaL_register'
+** your uses of 'luaL_openlib'
+*/
+#define LUA_COMPAT_OPENLIB
+
+
+
+/*
+@@ luai_apicheck is the assert macro used by the Lua-C API.
+** CHANGE luai_apicheck if you want Lua to perform some checks in the
+** parameters it gets from API calls. This may slow down the interpreter
+** a bit, but may be quite useful when debugging C code that interfaces
+** with Lua. A useful redefinition is to use assert.h.
+*/
+#if defined(LUA_USE_APICHECK)
+#include <assert.h>
+#define luai_apicheck(L,o) { (void)L; assert(o); }
+#else
+#define luai_apicheck(L,o) { (void)L; }
+#endif
+
+
+/*
+@@ LUAI_BITSINT defines the number of bits in an int.
+** CHANGE here if Lua cannot automatically detect the number of bits of
+** your machine. Probably you do not need to change this.
+*/
+/* avoid overflows in comparison */
+#if INT_MAX-20 < 32760
+#define LUAI_BITSINT 16
+#elif INT_MAX > 2147483640L
+/* int has at least 32 bits */
+#define LUAI_BITSINT 32
+#else
+#error "you must define LUA_BITSINT with number of bits in an integer"
+#endif
+
+
+/*
+@@ LUAI_UINT32 is an unsigned integer with at least 32 bits.
+@@ LUAI_INT32 is an signed integer with at least 32 bits.
+@@ LUAI_UMEM is an unsigned integer big enough to count the total
+@* memory used by Lua.
+@@ LUAI_MEM is a signed integer big enough to count the total memory
+@* used by Lua.
+** CHANGE here if for some weird reason the default definitions are not
+** good enough for your machine. (The definitions in the 'else'
+** part always works, but may waste space on machines with 64-bit
+** longs.) Probably you do not need to change this.
+*/
+#if LUAI_BITSINT >= 32
+#define LUAI_UINT32 unsigned int
+#define LUAI_INT32 int
+#define LUAI_MAXINT32 INT_MAX
+#define LUAI_UMEM size_t
+#define LUAI_MEM ptrdiff_t
+#else
+/* 16-bit ints */
+#define LUAI_UINT32 unsigned long
+#define LUAI_INT32 long
+#define LUAI_MAXINT32 LONG_MAX
+#define LUAI_UMEM unsigned long
+#define LUAI_MEM long
+#endif
+
+
+/*
+@@ LUAI_MAXCALLS limits the number of nested calls.
+** CHANGE it if you need really deep recursive calls. This limit is
+** arbitrary; its only purpose is to stop infinite recursion before
+** exhausting memory.
+*/
+#define LUAI_MAXCALLS 20000
+
+
+/*
+@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function
+@* can use.
+** CHANGE it if you need lots of (Lua) stack space for your C
+** functions. This limit is arbitrary; its only purpose is to stop C
+** functions to consume unlimited stack space. (must be smaller than
+** -LUA_REGISTRYINDEX)
+*/
+#define LUAI_MAXCSTACK 8000
+
+
+
+/*
+** {==================================================================
+** CHANGE (to smaller values) the following definitions if your system
+** has a small C stack. (Or you may want to change them to larger
+** values if your system has a large C stack and these limits are
+** too rigid for you.) Some of these constants control the size of
+** stack-allocated arrays used by the compiler or the interpreter, while
+** others limit the maximum number of recursive calls that the compiler
+** or the interpreter can perform. Values too large may cause a C stack
+** overflow for some forms of deep constructs.
+** ===================================================================
+*/
+
+
+/*
+@@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and
+@* syntactical nested non-terminals in a program.
+*/
+#define LUAI_MAXCCALLS 200
+
+
+/*
+@@ LUAI_MAXVARS is the maximum number of local variables per function
+@* (must be smaller than 250).
+*/
+#define LUAI_MAXVARS 200
+
+
+/*
+@@ LUAI_MAXUPVALUES is the maximum number of upvalues per function
+@* (must be smaller than 250).
+*/
+#define LUAI_MAXUPVALUES 60
+
+
+/*
+@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+*/
+#define LUAL_BUFFERSIZE BUFSIZ
+
+/* }================================================================== */
+
+
+
+
+/*
+** {==================================================================
+@@ LUA_NUMBER is the type of numbers in Lua.
+** CHANGE the following definitions only if you want to build Lua
+** with a number type different from double. You may also need to
+** change lua_number2int & lua_number2integer.
+** ===================================================================
+*/
+
+#define LUA_NUMBER_DOUBLE
+#define LUA_NUMBER double
+
+/*
+@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
+@* over a number.
+*/
+#define LUAI_UACNUMBER double
+
+
+/*
+@@ LUA_NUMBER_SCAN is the format for reading numbers.
+@@ LUA_NUMBER_FMT is the format for writing numbers.
+@@ lua_number2str converts a number to a string.
+@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
+@@ lua_str2number converts a string to a number.
+*/
+#define LUA_NUMBER_SCAN "%lf"
+#define LUA_NUMBER_FMT "%.14g"
+#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
+#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */
+#define lua_str2number(s,p) strtod((s), (p))
+
+
+/*
+@@ The luai_num* macros define the primitive operations over numbers.
+*/
+#if defined(LUA_CORE)
+#include <math.h>
+#define luai_numadd(a,b) ((a)+(b))
+#define luai_numsub(a,b) ((a)-(b))
+#define luai_nummul(a,b) ((a)*(b))
+#define luai_numdiv(a,b) ((a)/(b))
+#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
+#define luai_numpow(a,b) (pow(a,b))
+#define luai_numunm(a) (-(a))
+#define luai_numeq(a,b) ((a)==(b))
+#define luai_numlt(a,b) ((a)<(b))
+#define luai_numle(a,b) ((a)<=(b))
+#define luai_numisnan(a) (!luai_numeq((a), (a)))
+#endif
+
+
+/*
+@@ lua_number2int is a macro to convert lua_Number to int.
+@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
+** CHANGE them if you know a faster way to convert a lua_Number to
+** int (with any rounding method and without throwing errors) in your
+** system. In Pentium machines, a naive typecast from double to int
+** in C is extremely slow, so any alternative is worth trying.
+*/
+
+/* On a Pentium, resort to a trick */
+#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
+ (defined(__i386) || defined (_M_IX86) || defined(__i386__))
+
+/* On a Microsoft compiler, use assembler */
+#if defined(_MSC_VER)
+
+#define lua_number2int(i,d) __asm fld d __asm fistp i
+#define lua_number2integer(i,n) lua_number2int(i, n)
+
+/* the next trick should work on any Pentium, but sometimes clashes
+ with a DirectX idiosyncrasy */
+#else
+
+union luai_Cast { double l_d; long l_l; };
+#define lua_number2int(i,d) \
+ { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
+#define lua_number2integer(i,n) lua_number2int(i, n)
+
+#endif
+
+
+/* this option always works, but may be slow */
+#else
+#define lua_number2int(i,d) ((i)=(int)(d))
+#define lua_number2integer(i,d) ((i)=(lua_Integer)(d))
+
+#endif
+
+/* }================================================================== */
+
+
+/*
+@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment.
+** CHANGE it if your system requires alignments larger than double. (For
+** instance, if your system supports long doubles and they must be
+** aligned in 16-byte boundaries, then you should add long double in the
+** union.) Probably you do not need to change this.
+*/
+#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; }
+
+
+/*
+@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling.
+** CHANGE them if you prefer to use longjmp/setjmp even with C++
+** or if want/don't to use _longjmp/_setjmp instead of regular
+** longjmp/setjmp. By default, Lua handles errors with exceptions when
+** compiling as C++ code, with _longjmp/_setjmp when asked to use them,
+** and with longjmp/setjmp otherwise.
+*/
+#if defined(__cplusplus)
+/* C++ exceptions */
+#define LUAI_THROW(L,c) throw(c)
+#define LUAI_TRY(L,c,a) try { a } catch(...) \
+ { if ((c)->status == 0) (c)->status = -1; }
+#define luai_jmpbuf int /* dummy variable */
+
+#elif defined(LUA_USE_ULONGJMP)
+/* in Unix, try _longjmp/_setjmp (more efficient) */
+#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
+#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
+#define luai_jmpbuf jmp_buf
+
+#else
+/* default handling with long jumps */
+#define LUAI_THROW(L,c) longjmp((c)->b, 1)
+#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
+#define luai_jmpbuf jmp_buf
+
+#endif
+
+
+/*
+@@ LUA_MAXCAPTURES is the maximum number of captures that a pattern
+@* can do during pattern-matching.
+** CHANGE it if you need more captures. This limit is arbitrary.
+*/
+#define LUA_MAXCAPTURES 32
+
+
+/*
+@@ lua_tmpnam is the function that the OS library uses to create a
+@* temporary name.
+@@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam.
+** CHANGE them if you have an alternative to tmpnam (which is considered
+** insecure) or if you want the original tmpnam anyway. By default, Lua
+** uses tmpnam except when POSIX is available, where it uses mkstemp.
+*/
+#if defined(loslib_c) || defined(luaall_c)
+
+#if defined(LUA_USE_MKSTEMP)
+#include <unistd.h>
+#define LUA_TMPNAMBUFSIZE 32
+#define lua_tmpnam(b,e) { \
+ strcpy(b, "/tmp/lua_XXXXXX"); \
+ e = mkstemp(b); \
+ if (e != -1) close(e); \
+ e = (e == -1); }
+
+#else
+#define LUA_TMPNAMBUFSIZE L_tmpnam
+#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
+#endif
+
+#endif
+
+
+/*
+@@ lua_popen spawns a new process connected to the current one through
+@* the file streams.
+** CHANGE it if you have a way to implement it in your system.
+*/
+#if defined(LUA_USE_POPEN)
+
+#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m))
+#define lua_pclose(L,file) ((void)L, (pclose(file) != -1))
+
+#elif defined(LUA_WIN)
+
+#define lua_popen(L,c,m) ((void)L, _popen(c,m))
+#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1))
+
+#else
+
+#define lua_popen(L,c,m) ((void)((void)c, m), \
+ luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
+#define lua_pclose(L,file) ((void)((void)L, file), 0)
+
+#endif
+
+/*
+@@ LUA_DL_* define which dynamic-library system Lua should use.
+** CHANGE here if Lua has problems choosing the appropriate
+** dynamic-library system for your platform (either Windows' DLL, Mac's
+** dyld, or Unix's dlopen). If your system is some kind of Unix, there
+** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for
+** it. To use dlopen you also need to adapt the src/Makefile (probably
+** adding -ldl to the linker options), so Lua does not select it
+** automatically. (When you change the makefile to add -ldl, you must
+** also add -DLUA_USE_DLOPEN.)
+** If you do not want any kind of dynamic library, undefine all these
+** options.
+** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD.
+*/
+#if defined(LUA_USE_DLOPEN)
+#define LUA_DL_DLOPEN
+#endif
+
+#if defined(LUA_WIN)
+#define LUA_DL_DLL
+#endif
+
+
+/*
+@@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State
+@* (the data goes just *before* the lua_State pointer).
+** CHANGE (define) this if you really need that. This value must be
+** a multiple of the maximum alignment required for your machine.
+*/
+#define LUAI_EXTRASPACE 0
+
+
+/*
+@@ luai_userstate* allow user-specific actions on threads.
+** CHANGE them if you defined LUAI_EXTRASPACE and need to do something
+** extra when a thread is created/deleted/resumed/yielded.
+*/
+#define luai_userstateopen(L) ((void)L)
+#define luai_userstateclose(L) ((void)L)
+#define luai_userstatethread(L,L1) ((void)L)
+#define luai_userstatefree(L) ((void)L)
+#define luai_userstateresume(L,n) ((void)L)
+#define luai_userstateyield(L,n) ((void)L)
+
+
+/*
+@@ LUA_INTFRMLEN is the length modifier for integer conversions
+@* in 'string.format'.
+@@ LUA_INTFRM_T is the integer type correspoding to the previous length
+@* modifier.
+** CHANGE them if your system supports long long or does not support long.
+*/
+
+#if defined(LUA_USELONGLONG)
+
+#define LUA_INTFRMLEN "ll"
+#define LUA_INTFRM_T long long
+
+#else
+
+#define LUA_INTFRMLEN "l"
+#define LUA_INTFRM_T long
+
+#endif
+
+
+
+/* =================================================================== */
+
+/*
+** Local configuration. You can use this space to add your redefinitions
+** without modifying the main part of the file.
+*/
+
+
+
+#endif
+
diff --git a/win32/lua5.1/include/lualib.h b/win32/lua5.1/include/lualib.h
new file mode 100644
index 0000000..469417f
--- /dev/null
+++ b/win32/lua5.1/include/lualib.h
@@ -0,0 +1,53 @@
+/*
+** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $
+** Lua standard libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lualib_h
+#define lualib_h
+
+#include "lua.h"
+
+
+/* Key to file-handle type */
+#define LUA_FILEHANDLE "FILE*"
+
+
+#define LUA_COLIBNAME "coroutine"
+LUALIB_API int (luaopen_base) (lua_State *L);
+
+#define LUA_TABLIBNAME "table"
+LUALIB_API int (luaopen_table) (lua_State *L);
+
+#define LUA_IOLIBNAME "io"
+LUALIB_API int (luaopen_io) (lua_State *L);
+
+#define LUA_OSLIBNAME "os"
+LUALIB_API int (luaopen_os) (lua_State *L);
+
+#define LUA_STRLIBNAME "string"
+LUALIB_API int (luaopen_string) (lua_State *L);
+
+#define LUA_MATHLIBNAME "math"
+LUALIB_API int (luaopen_math) (lua_State *L);
+
+#define LUA_DBLIBNAME "debug"
+LUALIB_API int (luaopen_debug) (lua_State *L);
+
+#define LUA_LOADLIBNAME "package"
+LUALIB_API int (luaopen_package) (lua_State *L);
+
+
+/* open all previous libraries */
+LUALIB_API void (luaL_openlibs) (lua_State *L);
+
+
+
+#ifndef lua_assert
+#define lua_assert(x) ((void)0)
+#endif
+
+
+#endif