Creating Rocks

Creating your own rock (Lua package) allows you to distribute Lua modules, applications, and libraries to other Lua developers. This guide covers the process of packaging your Lua code.

Rockspec Files

A rockspec file is the blueprint for your package. It defines metadata, dependencies, and build instructions.

Basic Rockspec Structure

-- mymodule-1.0-1.rockspec
package = "mymodule"
version = "1.0-1"
source = {
   url = "https://github.com/username/mymodule/archive/v1.0.tar.gz"
}
description = {
   summary = "A sample Lua module",
   detailed = [[
      This is an example of a Lua module packaged as a rock.
      It demonstrates basic packaging concepts.
   ]],
   homepage = "https://github.com/username/mymodule",
   license = "MIT"
}
dependencies = {
   "lua >= 5.1"
}
build = {
   type = "builtin",
   modules = {
      ["mymodule"] = "mymodule.lua"
   }
}

Complex Rockspec Example

-- webutils-2.1-1.rockspec
package = "webutils"
version = "2.1-1"

source = {
   url = "git://github.com/username/webutils.git",
   tag = "v2.1"
}

description = {
   summary = "Web utility functions for Lua",
   detailed = [[
      A comprehensive collection of web utilities including
      HTTP client functions, URL parsing, and data formatting.
   ]],
   homepage = "https://github.com/username/webutils",
   license = "MIT",
   maintainer = "Your Name <[email protected]>"
}

dependencies = {
   "lua >= 5.3",
   "luafilesystem >= 1.8.0",
   "dkjson >= 2.5"
}

build = {
   type = "builtin",
   modules = {
      ["webutils.http"] = "src/http.lua",
      ["webutils.url"] = "src/url.lua",
      ["webutils.json"] = "src/json.lua",
      ["webutils.core"] = "src/core.lua"
   },
   install = {
      bin = {
         ["webutils-cli"] = "bin/cli.lua"
      }
   },
   copy_directories = {"docs", "examples"}
}

Directory Structure

Organize your project properly for packaging:

myproject/
├── src/
│   ├── mymodule/
│   │   ├── init.lua
│   │   ├── core.lua
│   │   └── utils.lua
├── bin/
│   └── mycommand.lua
├── tests/
│   ├── test_core.lua
│   └── test_utils.lua
├── docs/
│   ├── README.md
│   └── api.md
├── examples/
│   ├── basic.lua
│   └── advanced.lua
├── myproject-1.0-1.rockspec
└── README.md

Module Structure

Single File Module

-- simplemath.lua
local M = {}

function M.add(a, b)
    return a + b
end

function M.multiply(a, b)
    return a * b
end

return M

Multi-File Module

-- mymodule/init.lua
local M = {}

M.core = require("mymodule.core")
M.utils = require("mymodule.utils")

function M.version()
    return "1.0.0"
end

return M

-- mymodule/core.lua
local M = {}

function M.calculate(data)
    -- Core functionality
end

return M

-- mymodule/utils.lua
local M = {}

function M.validate(input)
    -- Utility functions
end

return M

Creating the Rock

Prepare Your Project

# Ensure your project follows LuaRocks conventions
# Create a proper rockspec file
# Add documentation and examples
# Include tests

Build the Rock

# Create a rock from your rockspec
luarocks make mymodule-1.0-1.rockspec

# This builds and installs the package locally

Pack for Distribution

# Create a distributable rock file
luarocks pack mymodule-1.0-1.rockspec

# This creates mymodule-1.0-1.src.rock

Testing Your Rock

Local Testing

# Install locally for testing
luarocks install --local mymodule-1.0-1.rock

# Test the module
lua -e "local m = require('mymodule'); print(m.version())"

# Test the installation
luarocks show mymodule

Dependency Testing

# Test with different Lua versions
lua5.1 -e "local m = require('mymodule')"
lua5.2 -e "local m = require('mymodule')"
lua5.3 -e "local m = require('mymodule')"
lua5.4 -e "local m = require('mymodule')"

Publishing Your Rock

Upload to LuaRocks Repository

# Upload to the public repository
luarocks upload mymodule-1.0-1.rockspec

# Upload with API key (stored in ~/.luarocks/config.lua)
luarocks upload --api-key=your_api_key mymodule-1.0-1.rockspec

Alternative Distribution Methods

# Host on your own server
luarocks upload --server=https://myrocks.example.com mymodule-1.0-1.rockspec

# Share as a file
# Distribute the .src.rock file for manual installation

Version Management

Semantic Versioning

Follow semantic versioning (MAJOR.MINOR.PATCH):

-- Breaking changes: increment MAJOR
-- New features: increment MINOR  
-- Bug fixes: increment PATCH

Version Naming Convention

mymodule-1.0-1.rockspec
└─mymodule   package name
 └─1.0      upstream version
  └─1       rock revision

Best Practices

Rockspec Guidelines

  1. Use semantic versioning consistently
  2. Include all dependencies with version constraints
  3. Provide clear descriptions and documentation
  4. Include example code for usage
  5. Add license information explicitly

Project Structure

  1. Separate source code from other files
  2. Include tests in the package
  3. Document your API thoroughly
  4. Provide examples of usage
  5. Maintain backward compatibility

Dependency Management

-- Good: Specify version ranges
dependencies = {
   "lua >= 5.3",
   "luafilesystem >= 1.8.0",
   "dkjson >= 2.5, < 3.0"
}

-- Avoid: Open-ended dependencies
dependencies = {
   "lua",  -- Should specify version
   "lfs"   -- Use full name
}

Automation

Automated Rock Creation

#!/bin/bash
# build_rock.sh
VERSION=$(git describe --tags --abbrev=0)
ROCKSPEC="mymodule-$VERSION-1.rockspec"

# Update rockspec version
sed -i "s/version = .*/version = \"$VERSION-1\"/" $ROCKSPEC

# Create rock
luarocks pack $ROCKSPEC

echo "Created $(ls mymodule-*.rock)"

CI/CD Integration

# .github/workflows/release.yml
name: Release Rock
on:
  push:
    tags:
      - 'v*'
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Install LuaRocks
        run: sudo apt install luarocks
      - name: Pack and Upload
        run: |
          luarocks pack *.rockspec
          luarocks upload *.rock          

Resources

Last updated on