luarocket

luarocket

Or vendoring Lua rocks

The Lua programming language, like many others, employs a purpose-built package manager to download and install its ecosystem of libraries. This tool, LuaRocks, has some notable features:

  • downloads/installs packages to user-specific or system-wide locations

  • configurable dependency resolution

  • builds locally define rocks (Lua modules packaged by LuaRocks)

  • queries information about the active LuaRocks configuration

In these ways, LuaRocks is functionally similar to the package managers of other dynamic languages such as pip for Python and npm for JavaScript.

Where these features fall short is in managing the dependencies of multiple Lua projects—each with a potentially different version of Lua. Being that Lua is an embedded language, this is in fact common, and further exacerbated by the popularity of both the reference Lua implementation and luajit.

Problem

I encountered this issue during the development of an experimental window manager, dovetail. It is based on the awesome window manager framework, which can be built with Lua versions 5.1-5.3 or luajit. It also depends on a few Lua packages, and therein lies the problem. It quickly became an overwhelming task to unify the range of Lua versions and implementations, 3rd party packages, varying installation paths, and integration with an embedded interpreter.

Solution

After consideration of my options, I decided the easiest solution was to vendor all dependency packages. I set up Makefile rules to download the version of packages specified in a version-controlled file to a specific Lua rocks tree where the package’s files are extracted and moved into a lua_modules directory in the root of the project. During installation, these modules are copied to a system-wide shared data directory and referenced by awesome’s Lua interpreter.

When I required this functionality outside of the dovetail project, I re-implemented these Makefile rules as a shell script called luarocket. It is meant to be included directly in a project and utilized as part of its build process.