-
Notifications
You must be signed in to change notification settings - Fork 0
Extending Building RQP Repositories and Packages
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:
-
.rqppackages are native packages installed by ReqPack itself, not wrapper plugins. -
reqpack.luainside.rqppackage is package hook manifest, not project-level manifest used byrqp install ..
rqp is a built-in IPlugin implementation in C++.
It is not a Lua wrapper around another package manager.
It provides:
- local
.rqppackage install, - builtin
rqp packpackage build, - repository-based package install,
- installed-state tracking,
- package hooks,
- manifest-based cleanup for removals,
- simple package resolution for updates and queries.
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 ./rootfsDo 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.
Builtin rqp pack <project-dir> requires at least:
metadata.jsonreqpack.lua- valid hook files referenced by
reqpack.lua
If metadata.json or reqpack.lua is missing, pack fails immediately.
Builtin pack accepts exactly one of these payload modes:
- no payload at all
- embedded payload tree at
<project-dir>/payload-tree/ - prebuilt payload files at
<project-dir>/payload/plus<project-dir>/hashes/ - 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 existingpayload/orhashes/ -
payload/andhashes/must either both exist or both be absent - if
metadata.payloadexists, one real payload mode must exist too
- default output path is
<project-dir-parent>/<metadata.name>.rqp - relative
--outputpaths 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:
-
--forceoverwrites it - otherwise interactive mode prompts
- non-interactive mode fails with
Use --force to overwrite.
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.
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.rqpRepositories 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:
nameversionreleaserevisionarchitecturesummaryurl
Optional but recommended:
packageSha256tags
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.
A .rqp file is a tar archive with a controlled top-level layout.
Allowed top-level entries:
metadata.jsonreqpack.luascripts/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
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:
homepagesourceUrlpackagerbuildDatetagsbinariesdependsprovidesconflictsreplacespayload
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.
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:
-
apiVersionmust be1 -
hooks.installis required -
hooks.removeandhooks.updateare optional but supported
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.
context.metadataIncludes package metadata such as name, version, summary, architecture, and URL.
context.paths.controlDir
context.paths.payloadDir
context.paths.workDir
context.paths.stateDir
context.paths.installRootDuring installed remove/update hooks, payloadDir and workDir may be empty.
context.log.info("...")
context.tx.begin_step("copy files")
context.tx.success()
context.tx.failed("copy failed")local result = context.exec.run("command here")context.fs.copy(src, dst)
context.fs.mkdir(path)
context.fs.exists(path)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.
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 trueThis pattern is visible in repository integration tests and is the safest way to make uninstall reliable.
High-level process:
- create
metadata.json - create
reqpack.lua - add hook scripts under
scripts/ - optionally build
payload/payload.tar.zst - generate
hashes/payload.sha256 - 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.
- Register every installed file or directory you want removed later.
- Keep hooks idempotent where possible.
- Use
noarchonly when the artifact really is architecture-independent. - Fill
depends,provides,conflicts, andreplacesif you want better metadata quality. - Always publish
packageSha256in repository indexes. - Keep
sourceUrlandhomepagemeaningful soinfooutput is useful.
Prev: Building Registry Entries | Up: Extending ReqPack | Next: Building Native C++ Plugins
- User Guide
- Getting Started
- Command Reference
- Configuration
- Configuration Reference
- Security, Audit, and SBOM
- Output and Report Formats
- Remote Mode
- Remote Protocol Reference
- Using Native
rqpPackages - Troubleshooting