NAME
parmo - package and repository maintenance operator
SYNOPSIS
parmo [OPTION]... ACTION
parmo --help
parmo --version
DESCRIPTION
Build software from source, turn it into native operating system packages, and manage repositories of those packages.
Build native packages from source, for multiple target operating systems, and store them in a package archive.
Select which version of each package is to be included in each local repository.
Index each local repository so that internal systems can use them.
Using docker(1) or podman(1), parmo can support multiple target operating systems on a single host, by automatically maintaining build environment containers for each target. Alternatively, parmo can run in native mode without containers, supporting only the operating system it is running on.
OPTIONS
Options must be specified before the actions and arguments.
- -n, --native
-
Only use native commands, rather than using containers. This reduces the disk space needed, but removes the isolation that containers bring, and requires the relevant tools for the chosen action to be available on the host system.
- -t, --target OS
-
Specify the target operating system for the action. This determines the appropriate package type and build image to use when building a package, indexing a repository, or updating a build image. The OS must be one of the operating systems listed by the “targets” action.
- -s, --source PATH
-
Specify the data source for the action. When building a package, use the file specified by PATH as the source archive. When indexing a repository, make the index out of the packages under the directory specified by PATH.
- -i, --instructions PATH
-
Specify the location of the instructions for building the package. If building an RPM, PATH must either be an RPM spec file, or a directory containing a spec file whose name ends with “.spec”. If building a Debian package, PATH must be a directory containing, at a minimum, a file named “control”.
- -d, --destination PATH
-
Specify the destination for the action. When building a package or indexing a repository, store the resultant files in the directory PATH.
- -k, --key FILE
-
Specify the file containing the signing key. When building a package or indexing a repository, sign the data with the key stored in FILE.
- -c, --constraint KEY=VALUE
-
Constrain the action to only act where KEY matches VALUE. This option may be specified more than once. The KEY must be one of:
- pinned
-
Whether the package is pinned to a specific version in the target repository; the value may be “true” or “false”.
- included
-
Whether the package is present in the target repository (true or false).
- outdated
-
Whether the package in the target repository has a newer version available in the source directory (true or false).
- package
-
Restrict to a package with this specific name.
- repository
-
Restrict to a specific repository.
- target
-
Restrict to a specific target operating system.
- -u, --user NAME
-
Record actions as being performed by NAME rather than the name of the current user.
- -h, --help
-
Display a usage message on standard output and exit successfully.
- -V, --version
-
Display version information on standard output and exit successfully.
ACTIONS
For the simplest use case, packages are built from source for a single target operating system and placed into a package archive directory, with “build-package”. The package archive directory is then indexed with “index-repository” to form a single repository containing every package.
Where there are multiple target operating systems, or more than one repository, packages are still built with “build-package”, with one package archive directory per target operating system. The appropriate version of each package is sent to each repository with “select”.
Refer to the EXAMPLES section for specific examples.
Actions for building packages
- build-package
-
Build a package for the target operating system specified by --target from the source archive specified by --source and the instructions specified by --instructions, placing the resultant package files in the directory specified by --destination.
If a signing key is provided with --key, the package is signed.
If no build instructions are provided, the appropriate instructions are extracted from the source archive. If the source archive contains nothing suitable, automatic instructions are generated.
Each package file is accompanied by an information file with the same name plus a “.txt” suffix, containing the OS, package name, version, architecture, summary, and description.
- build-instructions
-
Generate instructions for building a package from the source archive specified by --source, and place them in the directory specified by --destination. These will consist of an RPM spec file and Debian control, rules, and changelog files.
Actions for indexing individual repositories
- index-repository
-
Generate indexes for a repository for the target operating system specified by --target, from the packages in the source directory specified by --source, placing the resultant index files in the directory specified by --destination. If no destination is specified, the source directory is used.
If a signing key is provided with --key, and the target operating system supports it, the indexes are signed.
Actions for managing package archives
- archive-contents
-
List the filename, package name, version, architecture, target operating system, and summary of the packages in the package archive directory specified by --source. If the package archive directory contains a subdirectory per target operating system, “--constraint target” may also be used.
- prune COUNT
-
For each package in the package archive directory specified by --source, remove older versions until there are no more than COUNT remaining. This should be run periodically to keep package archives from growing without limit. If the package archive directory contains a subdirectory per target operating system, “--constraint target” may also be used.
If a repository collection is specified with --destination, then a version of a package will not be removed from the --source archive if it is found to also be present under --destination, since this means that it is potentially still in use.
Actions for managing repository collections
- repository-contents
-
List the filename, package name, version, architecture, repository, target operating system, pin note, and summary of the packages in the repository collection directory specified by --destination which match the constraints specified by the --constraint options.
The repository collection directory is expected to contain a subdirectory per repository name, and then a further subdirectory per target operating system, such as local/almalinux9.
When the constraints “included” or “outdated” are active, then the package archive directory specified by --source is used as a reference for the packages which are available for each target operating system.
If a package for a target operating system is not included in a repository but is available in the archive, it will be shown with a version of “-”, or it will be omitted if the constraint “included=true” is active.
If a package is pinned to a version (see below), its pin note is included, otherwise its pin note will be listed as “-”.
- select PACKAGE VERSION
-
In each repository and target operating system under the repository collection directory specified by --destination, subject to constraints specified by the --constraint options, copy the VERSION of PACKAGE from the appropriate operating system subdirectory of the package archive directory specified by --source, and remove all other versions of it from the destination.
If the VERSION is “none” or “exclude”, the package is removed from the destination.
If the package is pinned to a particular version in a repository (see below), the operation fails if the VERSION does not match.
Once the changes have been made, each affected repository is automatically indexed as if by “index-repository”.
- pin PACKAGE VERSION [NOTE]
-
The same as “select”, except the package's pinning status is also updated.
If a NOTE is supplied, the package is pinned at that version and the note is recorded. In this case the VERSION must not be “none” or “exclude”. Once the package is pinned, its version cannot be changed with “select”.
If no NOTE is supplied, or the NOTE is “-”, the package is unpinned.
Other actions
- update-image
-
Open the container image for building packages for the target operating system specified by --target, and apply any outstanding updates to it. This action should be run periodically to keep build images up to date.
- targets
-
List the supported target operating systems.
EXIT STATUS
- 0
-
Action successful.
- 1
-
There was a problem with the arguments supplied on the command line.
- 2
-
The action failed due to a local problem such as a write error, a full disk, and so on.
- 3
-
The selected action is not supported on this system.
FILES
Files in a package archive
A package archive directory contains packages which have been built by the “build-package” action.
- PACKAGE-ARCHIVE/.target
-
The target operating system for this package archive. If the file is not present, it is created by the “build-package” action. If the file is present and does not match the --target of the “build-package” action, then the action will refuse to run.
PACKAGE-ARCHIVE/*.deb
PACKAGE-ARCHIVE/*.rpm
: The packages themselves.
PACKAGE-ARCHIVE/*.deb.txt
PACKAGE-ARCHIVE/*.rpm.txt
: The information file for each package, detailing the the OS, package name, version, architecture, summary, and description.
When using parmo with multiple target operating systems, use a separate subdirectory for each target operating system - named after that target - as the --destination for the “build-package”, so that the “select” action can use the main parent directory as its --source package archive. For example:
PACKAGE-ARCHIVE/almalinux8/somepackage-1.2.3-1.el8.x86_64.rpm
PACKAGE-ARCHIVE/debian12/somepackage_1.2.3_amd64.deb
: The AlmaLinux 8 and Debian 12 instances of version 1.2.3 of the package “somepackage”, in the package archive PACKAGE-ARCHIVE.
This allows “select” to operate on multiple target operating systems at once, making it much easier to manage deployments across a heterogeneous estate.
Note that “build-package” operates directly on its --destination, so it is up to you to point it at the relevant subdirectory if using a multi-target package archive.
Files in a repository collection
A repository collection directory contains one directory per named repository, with each one having a subdirectory for each target operating system.
COLLECTION-DIR/NAME/TARGET/*.deb
COLLECTION-DIR/NAME/TARGET/*.deb.txt
COLLECTION-DIR/NAME/TARGET/*.rpm
COLLECTION-DIR/NAME/TARGET/*.rpm.txt
: The packages for operating system TARGET in repository NAME, and their information files as described above. These files are copied here from a package archive, and removed from here, by the “select” and “pin” actions.
COLLECTION-DIR/NAME/TARGET/*.deb.pinned
COLLECTION-DIR/NAME/TARGET/*.rpm.pinned
: If this file - managed by the “pin” action - exists for a package, the package is considered to be pinned to the version listed in its “.txt” file. The first line of a “.pinned” file contains the note specifying the reason. The second line contains the username of the person who pinned it.
- COLLECTION-DIR/NAME/TARGET/contents.txt
-
The filename, package name, version, architecture, repository, target operating system, pin note (“-” if not pinned), and summary of every package selected for operating system TARGET in repository NAME.
- COLLECTION-DIR/NAME/TARGET/activity.log
-
A log of changes made to this specific repository by the “select” and “pin” actions. Note that although this file is unlikely to grow quickly, it is advisable to instruct some other tool such as logrotate(8) to rotate it regularly, or when it reaches a particular size.
- COLLECTION-DIR/NAME/TARGET/.lock
-
A lock file used to ensure that multiple actions are never performed at once.
COLLECTION-DIR/NAME/TARGET/cache
COLLECTION-DIR/NAME/TARGET/dists
COLLECTION-DIR/NAME/TARGET/drpms
COLLECTION-DIR/NAME/TARGET/repodata
: The repository index data for the operating system TARGET's instance of repository NAME, generated when the “select” or “pin” actions change the repository contents and call an implicit “index-repository”.
EXAMPLES
Building RPMs for AlmaLinux 9 from the source of “pv”, automatically generating build instructions, and placing the RPMs in a package archive directory:
parmo --target almalinux9 --source pv-1.9.25.tar.gz --destination /packages/almalinux9 build-package
Generating build instructions from the source of “pv”, and placing them in a directory named pv-build:
parmo --source pv-1.9.25.tar.gz --destination pv-build build-instructions
Indexing a directory full of packages so it can be used as an apt repository by a Debian 12 system:
parmo --target debian12 --source /srv/debian12 index-repository
Selecting version 0.1.4 of “scw” for all available operating systems, from the package archive under /packages/, making them available in the repository named local under /repositories/ for each operating system, and automatically indexing each one:
parmo --source /packages --destination /repositories --constraint repository=local select scw 0.1.4
REPORTING BUGS
Please report any bugs to parmo@ivarch.com.
Alternatively, use the issue tracker linked from the parmo home page.
SEE ALSO
apt(8), dnf(8), yum(8), dpkg-buildpackage(1), dpkg-scanpackages(1), apt-ftparchive(1), rpmbuild(8), createrepo(8), docker(1), podman(1)
COPYRIGHT
Copyright © 2025 Andrew Wood.
License GPLv3+: GNU GPL version 3 or later.
This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.