DPM Specification Files
To build a package, you’ll need a specification file.
A spec file
is a file that dpm is told to create a package with. Think of it as a configuration file for the build process for DPM packages.
For an example, imagine you’re building a package. You’ve populated your directory tree and you’re ready to make the package. You’d run something like this:
dpm buildpkg --spec=./MyApp.SPEC --contents-path=./contents
This is telling DPM to pass the spec file path and pre-populated contents tree to the buildpkg
module. The package creation module would read the spec file’s contents and generate a package based on those contents. This allows repeatable package builds.
On Source Compilation: DPM doesn’t do it.
Bear in mind that the use of the word build
here is not meant to convey source compilation. The compilation of binaries and the packaging of pre-compiled binaries are wholly separate processes that never should have been merged into a single unit of work, and DPM solves this problem by not attempting to include source compilation in any of its features — it assumes that the packager has already done this.
There is room in the design for support for a SDPM
file format, but this is not a priority for the system as a whole — merely allowance in the design for the capability of handling this, which will be elaborated on in a dedicated section for SDPM compilation.
DPM Spec File Structure
The DPM spec file is a structured file with headers for each section. Each section is intended to be used by DPM during the buildpkg process to populate:
- the package metadata
- the optional signature archive
- the DPM hooks contents
Syntax
Syntax is very simple. The file is read line by line and contains three types of data:
- Comments
- Section Start/Stop declarations
- Section Content
Sections have a reserved name that match the corresponding filename in the DPM Package specification.
Comments
Commented lines start with a #
symbol.
Sections
Each field represents a data value that the package will need.
To start a section, the maintainer would have:
%section metadata.NAME
To likewise end a section:
%section_end metadata.NAME
Whatever is between these values will become the value in the resulting packages’ metadata. In the event that a section is multiline but the value is a single-line string, only the first line will be read.
Whitespace between sections will not be read.
Environment Variables
Environment variables can be interpolated in DPM Spec files. Their notation is a preceding '[['
and proceeding ']]'
with a single space as padding around the variable name.
So, if you set an environment variable prior to reading it DPM will interpolate it in the SPEC file:
yourshellprompt# PKG_NAME="Apache2"
... spec file ...
...
%section metadata.NAME
[[ PKG_NAME ]]
%section_end metadata.NAME
Then [[ PKG_NAME ]]
will be replaced with the string Apache2
.
If you would like to avoid negation of a variable name for a section declaration for whatever reason, such as when working with layers of templating engines, you can wrap literal statements with [%literal]
and [%/literal]
indicators.
%section hooks.POST-INSTALL
echo "adding [%literal] [[ PKG_NAME ]] to %section hooks.POST-INSTALL [%/literal]"
%section_end hooks.POST-INSTALL
In this example, the echoed text will be:
adding [[ PKG_NAME ]] to %section hooks.POST-INSTALL
This allows the maintainer to do layered templating approaches of large sets of packages.
If a variable is referenced but is empty or not defined, DPM will refuse to build the package and cite usage of an uninitialized variable as the reason.
Reserved Names
Reserved names for sections are:
hooks
- hooks.POST-INSTALL
- hooks.POST-INSTALL_ROLLBACK
- hooks.POST-REMOVE
- hooks.POST-REMOVE_ROLLBACK
- hooks.POST-UPDATE
- hooks.POST-UPDATE_ROLLBACK
- hooks.POST-INSTALL
- hooks.POST-INSTALL_ROLLBACK
- hooks.PRE-REMOVE
- hooks.PRE-REMOVE_ROLLBACK
- hooks.PRE-UPDATE
- hooks.PRE-UPDATE_ROLLBACK
metadata
- metadata.ARCHITECTURE
- metadata.AUTHOR
- metadata.MAINTAINER
- metadata.DEPENDENCIES
- metadata.DESCRIPTION
- metadata.CONTENTS_MANIFEST_DIGEST
- metadata.LICENSE
- metadata.NAME
- metadata.PROVIDES
- metadata.REPLACES
- metadata.SOURCE
- metadata.CHANGELOG
- metadata.VERSION
On Signatures
You will likely immediately notice that there is no mention of signatures. That’s because building a package and signing a package are different things, and signing is handled by a different DPM module prior to zipping up the package after the metadata is generated by the SPEC file. Once generated, the resulting directory structure is able to be finalized into a packaged, or optionally signed first and then finalized.
Example DPM Spec File
# This is an example DPM Spec file.
# This is a comment.
# Created by Chris Punches on 2025-02-22.
# Whitespace is ignored between sections.
# Comments are processed as ignored between sections. Otherwise, they're included in the section data.
# The name of the software we're creating.
%section metadata.NAME
MyApp
%section_end metadata.NAME
# The version of the software.
%section metadata.VERSION
0.1.0
%section_end metadata.VERSION
# The author of the software.
%section metadata.AUTHOR
Chris Punches <chris.punches@silogroup.org>
%section_end metadata.AUTHOR
# Source of the software. Usually a URL where an archive
# of the source code can be downloaded.
%section metadata.SOURCE
https://source.silogroup.org/Dark-Horse-Linux/pyrois
%section_end metadata.SOURCE
# The package maintainer.
%section metadata.MAINTAINER
Chris Punches <chris.punches@silogroup.org>
%section_end metadata.MAINTAINER
# Changelog - the changelog for THIS PACKAGE
%section metadata.CHANGELOG
*2025-02-23 Chris Punches chris.punches@silogroup.org
First draft.
%section_end metadata.CHANGELOG
# The license (used for compliance tracking).
%section metadata.LICENSE
A/GPL 3.0
%section_end metadata.LICENSE
# The architecture. For this example, we'll supply it as an
# environment variable.
%section metadata.ARCHITECTURE
[[ target_architecture ]]
%section_end metadata.ARCHITECTURE
# Dependencies -- this is multiline.
# These are packages, and their versions, that must be present
# in the DPMDB in order for this package to meet its required
# dependencies.
%section metadata.DEPENDENCIES
glibc >= 2.21
glibc <= 2.39
libstdc++ > 0
%section_end metadata.DEPENDENCIES
# Provides -- these are package aliases for meeting
# interchangeable dependencies. Left blank here.
%section metadata.PROVIDES
%section_end metadata.PROVIDES
# Replaces -- these are packages this package is meant to replace.
%section metadata.REPLACES
%section_end metadata.REPLACES
# hooks -- these are triggered when the maintainer populates them and these are assumed to be shell scripts (/bin/sh not necessarily /bin/bash).
%section hooks.POST-INSTALL
%section_end hooks.POST-INSTALL
%section hooks.POST-INSTALL_ROLLBACK
%section_end hooks.POST-INSTALL_ROLLBACK
%section hooks.POST-REMOVE
%section_end hooks.POST-REMOVE
%section hooks.POST-REMOVE_ROLLBACK
%section_end hooks.POST-REMOVE_ROLLBACK
%section hooks.POST-UPDATE
systemctl start MyAppD
%section_end hooks.POST-UPDATE
%section hooks.POST-UPDATE_ROLLBACK
%section_end hooks.POST-UPDATE_ROLLBACK
%section hooks.PRE-INSTALL
%section_end hooks.PRE-INSTALL
%section hooks.PRE-INSTALL_ROLLBACK
%section_end hooks.PRE-INSTALL_ROLLBACK
%section hooks.PRE-REMOVE
systemctl stop MyAppD
%section_end hooks.PRE-REMOVE
%section hooks.PRE-REMOVE_ROLLBACK
systemctl start MyAppD
%section_end hooks.PRE-REMOVE_ROLLBACK
%section hooks.PRE-UPDATE
systemctl stop MyAppD
%section_end hooks.PRE-UPDATE
%section hooks.PRE-UPDATE_ROLLBACK
systemctl start MyAppD
%section_end hooks.PRE-UPDATE_ROLLBACK
The spec file format is simple and easy for a human to edit, and this can be populated with a web form in just a few seconds, or generated from a template.