Skip to content

Extending Building RQP Repositories and Packages

Leonard Ramminger edited this page May 10, 2026 · 3 revisions

Building rqp Packages and Repositories

Prev: Building Registry Entries | Up: Extending ReqPack | Next: Building Native C++ Plugins

This page explains how to create ReqPack-native packages and repositories.

Use this when you want ReqPack to install your own artifacts directly through the built-in rqp package manager.

Two common points of confusion:

  • .rqp packages are native packages installed by ReqPack itself, not wrapper plugins.
  • reqpack.lua inside .rqp package is package hook manifest, not project-level manifest used by rqp install ..

What rqp Actually Is

rqp is a built-in IPlugin implementation in C++. It is not a Lua wrapper around another package manager.

It provides:

  • local .rqp package install,
  • builtin rqp pack package build,
  • repository-based package install,
  • installed-state tracking,
  • package hooks,
  • manifest-based cleanup for removals,
  • simple package resolution for updates and queries.

Building Packages With rqp pack

Builtin native package build mode is:

rqp pack ./my-package
rqp pack ./my-package --output ./dist/my-package.rqp
rqp pack ./my-package --payload-dir ./rootfs

Do not confuse this with plugin-native pack mode:

rqp pack <system> <project-dir>

That second form dispatches to optional plugin pack(...) support and is not builtin .rqp builder.

Required input files

Builtin rqp pack <project-dir> requires at least:

  • metadata.json
  • reqpack.lua
  • valid hook files referenced by reqpack.lua

If metadata.json or reqpack.lua is missing, pack fails immediately.

Payload input modes

Builtin pack accepts exactly one of these payload modes:

  1. no payload at all
  2. embedded payload tree at <project-dir>/payload-tree/
  3. prebuilt payload files at <project-dir>/payload/ plus <project-dir>/hashes/
  4. external payload tree via --payload-dir <path>

Validation rules enforced by builder:

  • payload-tree/ cannot be combined with --payload-dir
  • payload-tree/ cannot be combined with existing payload/ or hashes/
  • payload/ and hashes/ must either both exist or both be absent
  • if metadata.payload exists, one real payload mode must exist too

Output behavior

  • default output path is <project-dir-parent>/<metadata.name>.rqp
  • relative --output paths are resolved from current working directory
  • output directory is created automatically when possible
  • produced archive is validated by loading it back through RqPackageReader

If output already exists:

  • --force overwrites it
  • otherwise interactive mode prompts
  • non-interactive mode fails with Use --force to overwrite.

Payload generation details

When source is payload-tree/ or --payload-dir, builtin pack:

  • walks payload tree
  • builds payload/payload.tar.zst
  • computes hashes/payload.sha256
  • writes normalized metadata.payload

When source is prebuilt payload/ plus hashes/, builtin pack validates that metadata and files match expected hardcoded shape.

Practical minimal project

my-tool/
  metadata.json
  reqpack.lua
  scripts/
    install.lua
  payload-tree/
    usr/
      local/
        bin/
          my-tool

Then build:

rqp pack ./my-tool --output ./dist/my-tool.rqp

rqp Repository Index Format

Repositories expose a JSON index with schemaVersion = 1.

Example:

{
  "schemaVersion": 1,
  "packages": [
    {
      "name": "my-tool",
      "version": "1.2.3",
      "release": 1,
      "revision": 0,
      "architecture": "noarch",
      "summary": "Example internal tool",
      "url": "https://packages.example.test/my-tool-1.2.3.rqp",
      "packageSha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
      "tags": ["internal", "cli"]
    }
  ]
}

Required package fields:

  • name
  • version
  • release
  • revision
  • architecture
  • summary
  • url

Optional but recommended:

  • packageSha256
  • tags

Resolution rules:

  • package name must match,
  • if version requested, version must match,
  • architecture must match host or be noarch,
  • highest version wins, then highest release, then highest revision.

.rqp Package Layout

A .rqp file is a tar archive with a controlled top-level layout.

Allowed top-level entries:

  • metadata.json
  • reqpack.lua
  • scripts/
  • hashes/
  • payload/

Minimal package without payload:

my-tool.rqp
  metadata.json
  reqpack.lua
  scripts/install.lua

Package with payload:

my-tool.rqp
  metadata.json
  reqpack.lua
  scripts/install.lua
  hashes/payload.sha256
  payload/payload.tar.zst

metadata.json Format

Required base fields:

{
  "formatVersion": 1,
  "name": "my-tool",
  "version": "1.2.3",
  "release": 1,
  "revision": 0,
  "summary": "Example tool",
  "description": "Internal CLI utility",
  "license": "MIT",
  "architecture": "noarch",
  "vendor": "Your Team",
  "maintainerEmail": "team@example.com",
  "url": "https://packages.example.test/my-tool.rqp"
}

Optional fields:

  • homepage
  • sourceUrl
  • packager
  • buildDate
  • tags
  • binaries
  • depends
  • provides
  • conflicts
  • replaces
  • payload

Payload metadata shape:

"payload": {
  "path": "payload/payload.tar.zst",
  "archive": "tar",
  "compression": "zstd",
  "hashAlgorithm": "sha256",
  "hashFile": "hashes/payload.sha256",
  "sizeCompressed": 0,
  "sizeInstalledExpected": 0
}

Current implementation expects exactly those payload values. Do not invent alternatives yet.

reqpack.lua Package Manifest

Inside a .rqp package, reqpack.lua is a package manifest for hooks. It is not same thing as project reqpack.lua used to describe app dependencies for rqp install ..

Minimal valid form:

return {
  apiVersion = 1,
  hooks = {
    install = "scripts/install.lua",
  }
}

Rules:

  • apiVersion must be 1
  • hooks.install is required
  • hooks.remove and hooks.update are optional but supported

Hook Runtime API

rqp hooks run in a dedicated Lua runtime with a context table. Do not confuse this runtime with normal Lua plugin runtime: rqp hooks have filesystem helpers and artifact-registration helpers that normal wrapper plugins do not.

Metadata

context.metadata

Includes package metadata such as name, version, summary, architecture, and URL.

Paths

context.paths.controlDir
context.paths.payloadDir
context.paths.workDir
context.paths.stateDir
context.paths.installRoot

During installed remove/update hooks, payloadDir and workDir may be empty.

Logging and transaction signals

context.log.info("...")
context.tx.begin_step("copy files")
context.tx.success()
context.tx.failed("copy failed")

Command execution

local result = context.exec.run("command here")

Filesystem helpers

context.fs.copy(src, dst)
context.fs.mkdir(path)
context.fs.exists(path)

Manifest/artifact tracking

context.artifacts.register_file(path)
context.artifacts.register_dir(path)
context.artifacts.register_symlink(path)

Anything you register is written to manifest.json and removed on uninstall in reverse order.

Example Install Hook

local out = context.paths.stateDir .. "/installed.txt"
context.fs.mkdir(context.paths.stateDir)
context.fs.copy(context.paths.payloadDir .. "/payload.txt", out)
context.artifacts.register_file(out)
return true

This pattern is visible in repository integration tests and is the safest way to make uninstall reliable.

Building a Package by Hand

High-level process:

  1. create metadata.json
  2. create reqpack.lua
  3. add hook scripts under scripts/
  4. optionally build payload/payload.tar.zst
  5. generate hashes/payload.sha256
  6. tar the control tree into your-package.rqp

If you want automation, build a small packer script around this structure.

Because rqp manager is built into ReqPack, package authors do not need to ship separate plugin implementation.

Best Practices for rqp

  • Register every installed file or directory you want removed later.
  • Keep hooks idempotent where possible.
  • Use noarch only when the artifact really is architecture-independent.
  • Fill depends, provides, conflicts, and replaces if you want better metadata quality.
  • Always publish packageSha256 in repository indexes.
  • Keep sourceUrl and homepage meaningful so info output is useful.

Related Pages

Prev: Building Registry Entries | Up: Extending ReqPack | Next: Building Native C++ Plugins

Clone this wiki locally