Zillowe FoundationZillowe Documentation

Package Examples

A set of `.pkg.lua` examples for creating Zoi packages.

This document provides a set of examples for creating .pkg.lua files. These files are the core of Zoi's packaging system, defining everything from metadata to installation methods using the power of Lua scripting.

Comprehensive Package Example

This is a comprehensive example that showcases many of Zoi's packaging features. It defines a package with multiple, selectable installation methods, including pre-compiled binaries, compressed archives, an installer script, and building from source, with platform-specific logic.

-- hello.pkg.lua

-- Using local variables to follow DRY principle.
local repo_owner = "Zillowe"
local repo_name = "Hello"
local version = "2.0.0"
local git_url = "https://github.com/" .. repo_owner .. "/" .. repo_name .. ".git"
local release_base_url = "https://github.com/" .. repo_owner .. "/" .. repo_name .. "/releases/download/v" .. version

-- Platform mapping allows customizing OS and architecture names for URLs and filenames.
-- The key is the platform string reported by Zoi (e.g. "macos", "linux-amd64").
-- The value is the desired platform string to be used in the package script.
local platform_map = {
	macos = "darwin",
}

local function get_mapped_platform()
	local current_platform = SYSTEM.OS .. "-" .. SYSTEM.ARCH
	return platform_map[current_platform] or platform_map[SYSTEM.OS] or current_platform
end

local function get_mapped_os()
	return get_mapped_platform():match("([^%-]+)")
end

package({
	name = "hello",
	repo = "zillowe",
	version = version,
	description = "Hello World",
	website = "https://github.com/Zillowe/Hello",
	git = git_url,
	maintainer = {
		name = "Your Name",
		email = "[email protected]",
	},
	author = {
		name = "Zillowe Foundation",
		website = "https://zillowe.qzz.io",
		email = "[email protected]",
		key = "https://zillowe.pages.dev/keys/zillowe-main.asc",
		key_name = "zillowe-main",
	},
	license = "Apache-2.0",
	bins = { "hello" },
	conflicts = { "hello" },
})

install({
	selectable = true,
	{
		name = "Binary",
		type = "binary",
		url = (function()
			return release_base_url .. "/hello-" .. get_mapped_os() .. "-" .. SYSTEM.ARCH
		end)(),
		platforms = { "all" },
		checksums = (function()
			return release_base_url .. "/checksums-512.txt"
		end)(),
		sigs = {
			{
				file = (function()
					return "hello-" .. get_mapped_os() .. "-" .. SYSTEM.ARCH
				end)(),
				sig = (function()
					return release_base_url .. "/hello-" .. get_mapped_os() .. "-" .. SYSTEM.ARCH .. ".sig"
				end)(),
			},
		},
	},
	{
		name = "Compressed Binary",
		type = "com_binary",
		url = (function()
			local ext
			if SYSTEM.OS == "windows" then
				ext = "zip"
			else
				ext = "tar.xz"
			end
			return release_base_url .. "/hello-" .. get_mapped_os() .. "-" .. SYSTEM.ARCH .. "." .. ext
		end)(),
		platforms = { "all" },
		checksums = (function()
			return release_base_url .. "/checksums-512.txt"
		end)(),
		sigs = {
			{
				file = (function()
					local ext
					if SYSTEM.OS == "windows" then
						ext = "zip"
					else
						ext = "tar.xz"
					end
					return "hello-" .. get_mapped_os() .. "-" .. SYSTEM.ARCH .. "." .. ext
				end)(),
				sig = (function()
					local ext
					if SYSTEM.OS == "windows" then
						ext = "zip"
					else
						ext = "tar.xz"
					end
					return release_base_url
							.. "/hello-"
							.. get_mapped_os()
							.. "-"
							.. SYSTEM.ARCH
							.. "."
							.. ext
							.. ".sig"
				end)(),
			},
		},
	},
	{
		name = "Install Script",
		type = "script",
		url = (function()
			local ext
			if SYSTEM.OS == "windows" then
				ext = "ps1"
			else
				ext = "sh"
			end
			return "https://raw.githubusercontent.com/Zillowe/Hello/refs/heads/main/app/install." .. ext
		end)(),
		platforms = { "all" },
	},
	{
		name = "Build from source",
		type = "source",
		url = git_url,
		platforms = { "linux", "macos", "windows" },
		build_commands = {
			'go build -o hello -ldflags="-s -w" ./src',
		},
		bin_path = (function() -- the final binary path
			local bin
			if SYSTEM.OS == "windows" then
				bin = "hello.exe"
			else
				bin = "./hello"
			end
			return bin
		end)(),
		files = {
			{
				platforms = { "linux", "macos" },
				files = {
					{
						source = "README.md",
						destination = "/usr/local/share/doc/hello/README.md",
					},
				},
			},
			{
				platforms = { "windows" },
				files = {
					{
						source = "README.md",
						destination = "C:\\ProgramData\\hello\\README.md",
					},
				},
			},
		},
	},
})

dependencies({
	build = {
		required = { "native:go" },
	},
})

Build from Source Package

For packages that need to be compiled on the user's machine, use the source installation type.

-- dev/compiler.pkg.lua
package({
  name = "compiler",
  repo = "community",
  version = "0.1.0",
  description = "A new programming language compiler.",
  git = "https://github.com/user/compiler",
  tags = { "compiler", "devtools" },
  maintainer = {
    name = "Your Name",
    email = "[email protected]"
  }
})

install({
  {
    type = "source",
    url = PKG.git, -- URL to the git repository.
    platforms = { "linux-amd64", "macos-amd64", "windows-amd64" },
    -- Optional: build inside a Docker container for reproducibility.
    docker_image = "hub:golang:1.21-alpine",
    -- Commands to execute in the cloned repository to build.
    build_commands = {
      "go build -o compiler"
    },
    -- Path to the built binary, relative to the repo root.
    -- When using docker_image, this is the path inside the container.
    bin_path = "./compiler"
  }
})

dependencies({
  build = {
    required = { "zoi:go", "native:make" },
    optional = { "cargo:some-build-tool:additional build helper" }
  },
  runtime = {
    required = { "native:openssl" }
  }
})

Package Collection

A collection is a meta-package that only installs other packages as dependencies.

-- collections/web-dev-essentials.pkg.lua
package({
  name = "web-dev-essentials",
  repo = "community",
  type = "collection", -- Set the package type to 'collection'.
  version = "1.0",
  description = "A collection of essential tools for web development.",
  tags = { "collection", "web", "devtools" },
  maintainer = {
    name = "Community",
    email = "[email protected]"
  }
})

-- The 'runtime' dependencies are the packages that will be installed.
dependencies({
  runtime = {
    required = {
      "zoi:node",
      "zoi:bun",
      "native:git"
    },
    optional = {
      "npm:pnpm",
      "npm:serve",
      "npm:typescript"
    }
  }
})

Service Package

A service package is for applications that need to run in the background. Zoi can manage starting and stopping them.

-- services/my-database.pkg.lua
package({
  name = "my-database",
  repo = "community",
  type = "service", -- Set the package type to 'service'.
  version = "5.7",
  description = "A lightweight database server.",
  tags = { "service", "database" },
  maintainer = {
    name = "Your Name",
    email = "[email protected]"
  },
  -- The 'service' block defines how to manage the service.
  service = {
    {
      platforms = { "linux-amd64", "macos-amd64" },
      start = { "my-database --config /etc/my-database.conf" },
      stop = { "pkill my-database" }
    }
  }
})

install({
  {
    type = "binary",
    url = "https://example.com/my-database-v" .. PKG.version .. "-" .. SYSTEM.OS .. "-" .. SYSTEM.ARCH,
    platforms = { "linux-amd64", "macos-amd64" }
  }
})

Library Package

A library package installs shared/static libraries and header files. It can also generate a .pc file for pkg-config.

-- libs/my-library.pkg.lua
package({
  name = "my-library",
  repo = "community",
  type = "library",
  version = "1.2.0",
  description = "A library for doing awesome things.",
  tags = { "library", "c++" },
  maintainer = {
    name = "Your Name",
    email = "[email protected]"
  },
  -- This block is used to generate the .pc file
  pkg_config = {
    description = "My Awesome Library",
    libs = "-L/usr/local/lib -lmy-library",
    cflags = "-I/usr/local/include/my-library"
  }
})

install({
  {
    type = "com_binary",
    url = "https://example.com/my-library/v" .. PKG.version .. "-" .. SYSTEM.OS .. "-" .. SYSTEM.ARCH .. ".tar.gz",
    platforms = { "linux-amd64" }
  }
})

Script Package

A script package runs a series of inline shell commands instead of installing a binary. This is useful for complex setup actions.

-- my-setup-script.pkg.lua
package({
  name = "my-setup-script",
  repo = "community",
  type = "script",
  version = "1.0",
  description = "A package that runs a series of setup commands.",
  tags = { "script", "setup" },
  maintainer = {
    name = "Your Name",
    email = "[email protected]"
  },
  -- The 'script' field contains the commands to run.
  script = {
    {
      platforms = { "linux", "macos" },
      install = {
        "echo 'Creating configuration directory...'",
        "mkdir -p ~/.config/my-app",
        "echo 'hello: world' > ~/.config/my-app/config.yml"
      },
      uninstall = {
        "echo 'Removing configuration...'",
        "rm -rf ~/.config/my-app"
      }
    }
  }
})

App Template Package

An app package defines a template to scaffold applications via zoi create <source> <appName>. It is not installable directly.

-- apps/rails-app.pkg.lua
package({
  name = "rails-app",
  repo = "community",
  type = "app",
  version = "7",
  description = "Rails app template",
  tags = { "app", "rails", "ruby" },
  maintainer = {
    name = "Your Name",
    email = "[email protected]"
  },
  -- Platform-specific create command and optional follow-up commands
  app = {
    {
      platforms = { "all" },
      appCreate = "rails new ${appName}",
      commands = {
        "cd ${appName} && bundle install",
        "cd ${appName} && git init"
      }
    }
  }
})

dependencies({
  runtime = {
    required = { "zoi:@core/ruby", "zoi:@main/gems/rails" }
  }
})

Extension Package

An extension package modifies Zoi's configuration. It is managed with zoi extension add and zoi extension remove.

-- extensions/corp-repos.pkg.lua
package({
  name = "corp-repos",
  repo = "community",
  type = "extension",
  version = "1.0",
  description = "Adds the official corporate package repositories for MyCorp.",
  tags = { "extension", "config" },
  maintainer = {
    name = "MyCorp IT",
    email = "[email protected]"
  },
  extension = {
    type = "zoi",
    changes = {
      { type = "repo-git", add = "https://git.mycorp.com/zoi-packages.git" },
      { type = "repo-add", add = "test" },
      { type = "registry-repo", add = "https://zoi-mirror.mycorp.com/Zoi-Pkgs.git" }
    }
  }
})

Last updated on