CondinAPT: A Comprehensive Guide to Conditional Package Installation
CondinAPT is a versatile tool for automating package installation in any Debian-like system (Debian, Ubuntu, and their derivatives). Its key feature is the ability to define complex conditions and rules for installing each package based on arbitrary system configurations.
Areas of Application:
- Linux distribution build systems
- Automation of server and workstation setup
- Deployment of various system configurations
- Package management in Docker containers
- CI/CD pipelines for environment setup
- Creation of custom installation images
Table of Contents
Fundamentals
Syntax and Capabilities
Operating Modes
Advanced Usage
Practical Examples
Key Features:
- Conditional Installation: Install packages based on flexible filters (+, -).
- External Configuration: Complete separation of logic (package list) from data (system parameters).
- Installation Queues: Divide the process into sequential stages to resolve dependencies.
- Priority Queue: Guaranteed installation of critical packages first.
- Complex Logic: Support for "AND" (
&&), "OR" (||) operators, as well as group filters (+{a|b},-{a&b}). - Readability: Support for comments and empty lines to structure lists.
- Backward Compatibility: Supports simple package lists without conditions.
How it Works and Core Components
CondinAPT operates with four key files:
condinaptscript: The core, containing all processing logic.Main configuration file (
-c): A file with bash variables describing the current environment.Example (
system.conf):bashDISTRIBUTION="bookworm" SYSTEM_TYPE="server" ENVIRONMENT="production" LOCALE="en_US" FEATURES="web,database"Filter mapping file (
-m): Links short prefixes (used in the package list) to variable names from the main configuration file. This file is optional. If a filter is not present in the filter mapping file, it will be used as a variable name from the main configuration file. If the variable is not found, CondinAPT will declare it empty.Example (
filters.map):textd=DISTRIBUTION st=SYSTEM_TYPE env=ENVIRONMENT arch=ARCHITECTURE feat=FEATURESPackage list file (
-l): The main file describing what to install and under what conditions.
Quick Start
To quickly get acquainted with CondinAPT, create a simple example:
1. Create the configuration file config.conf:
# Basic system parameters
DISTRIBUTION="bookworm"
SYSTEM_TYPE="server"
ENVIRONMENT="production"2. Create the package list packages.list:
# Base packages - always installed
vim
curl
# Packages only for servers
nginx +SYSTEM_TYPE=server
mysql-server +SYSTEM_TYPE=server
# Exclude packages for production environment
debug-tools -ENVIRONMENT=production3. Run the installation:
bash
./condinapt -l packages.list -c config.conf4. Or test in simulation mode:
bash
./condinapt -l packages.list -c config.conf -sUsage
Command Line
./condinapt [OPTIONS]| Flag | Long Flag | Argument | Description |
|---|---|---|---|
-l | --package-list | PATH | (Required) Path to the package list file. |
-c | --config | PATH | (Required) Path to the main configuration file. |
-m | --filter-mapping | PATH | (Optional) Path to the filter mapping file. |
-P | --priority-list | PATH | (Optional) Path to a priority filter file. File contains regex patterns to match packages. Matched packages are moved to priority queue (preserving filters). |
-s | --simulation | Simulation mode. Packages will not be installed. | |
-C | --check-only | Only check if packages are already installed. Returns exit code 1 if there are uninstalled packages. At the end, outputs a command to install missing packages. | |
-v / -vv | --verbose / --very-verbose | Verbose / very verbose output. | |
-x | --xtrace | Enable set -x command tracing. | |
-f | --force | Force package lists update before installation. By default, update is skipped if /var/cache/apt/pkgcache.bin exists. | |
-h | --help | Show help. |
Package List File Syntax
Basic Structure
This is the heart of CondinAPT. All logic is described here.
Each line in the package list file consists of two main parts:
- Package name with optional version and release specification
- Condition filters - define the conditions under which the package will be installed
Basis for all examples below: For all subsequent examples, we will assume that the
system.confandfilters.mapfiles from the "How it Works and Core Components" section are used.
DISTRIBUTION="bookworm"SYSTEM_TYPE="server"ENVIRONMENT="production"
Package Name Structure
Simple name:
vimPackage version:
package=version— loose version requirement. If the required version is unavailable, an available version is installed.git=2.25.1package==version— strict requirement. If the version is not found, installation aborts with an error.curl==7.68.0
Release specification: The release is specified using the @ symbol, which allows linking the installation to a specific repository branch.
telegram@bookworm-backports
kernel-image-6.5.0@trixie-backportsFile Structure
- Package names: Each package or condition is written on a new line.
- Comments: Lines starting with
#, or text after#on a line, are completely ignored. - Empty lines: Ignored and serve for visual separation.
#=== Multimedia ===
vlc # Excellent media player
audacious # Another media player
#=== Graphics ===
gimpFilters and Conditions
Filters allow you to set additional conditions for package selection. They compare the values of system variables (architecture, distribution, working environment) with those specified in the configuration file.
Single Filters
+(Positive): The condition is true if the variable value matches. Format:+<prefix>=<value>- Line:
nginx +st=server - Analysis:
SYSTEM_TYPEis equal to"server". The condition is true. - Result:
nginxwill be installed.
- Line:
Multiple positive filters with the same prefix: Act as OR conditions. Format:
+<prefix>=<value1> +<prefix>=<value2>- Line:
debug-tools +env=development +env=testing - Analysis:
ENVIRONMENTis equal to"production", which does not match either"development"or"testing". The condition is false. - Result:
debug-toolswill not be installed.
- Line:
-(Negative): The condition is true if the variable value does not match. Format:-<prefix>=<value>- Line:
monitoring-tools -st=desktop - Analysis:
SYSTEM_TYPEis equal to"server", which is not equal to"desktop". The condition is true. - Result:
monitoring-toolswill be installed.
- Line:
Multiple negative filters: The package is excluded if ANY condition matches. Format:
-<prefix>=<value1> -<prefix>=<value2>- Line:
realtek-driver -d=trixie -d=sid - Analysis:
DISTRIBUTIONis equal to"bookworm", which is not equal to"trixie"or"sid". The exclusion conditions do not trigger. - Result:
realtek-driverwill be installed.
- Line:
Group Filters
+{a|b}(OR for inclusion): True if at least one of the conditions in the group is true.- Line:
web-server +{st=server|st=web-server} - Analysis:
SYSTEM_TYPEis equal to"server". The first condition is true, which is sufficient. - Result: The package will be installed.
- Line:
+{a&b}(AND for inclusion): True only if all conditions in the group are true.- Line:
database-tools +{d=bookworm&st=server} - Analysis:
DISTRIBUTIONis equal to"bookworm"(true) ANDSYSTEM_TYPEis equal to"server"(true). - Result: The package will be installed.
- Line:
-{a|b}(OR for exclusion): The package is excluded if at least one of the conditions is true.- Line:
debug-tools -{env=production|st=minimal} - Analysis:
ENVIRONMENTis equal to"production". The first condition is true, so the package is excluded. - Result: The package will not be installed.
- Line:
-{a&b}(AND for exclusion): The package is excluded only if all conditions are true.- Line:
development-tools -{env=production&st=minimal} - Analysis:
ENVIRONMENTis equal to"production"(true), butSYSTEM_TYPEis not equal to"minimal". The second condition is false. The group does not trigger for exclusion. - Result: The package will be installed (if no other filters).
- Line:
Alternatives
Different packages can be offered for the same functionality and installed depending on conditions. Alternative options are separated by the || operator.
Important: Each alternative must include a complete description — package name (with optional version and release) and a set of filters.
Example:
postgresql +st=database-server || mysql-server +st=web-server- If
SYSTEM_TYPEisdatabase-server, postgresql is selected. - If
SYSTEM_TYPEisweb-server, mysql-server is installed.
Logical Operators for Packages
||(OR / Fallback): Try to install the left part. If it fails (package not found or filtered), try to install the right part.- Line:
exfatprogs -d=bookworm || exfat-utils - Analysis:
DISTRIBUTIONis not equal to"bookworm", the left part is filtered. CondinAPT proceeds to the right part.exfat-utilshas no filters, so it will be installed. - Result:
exfat-utilswill be installed.
- Line:
&&(AND / Conjunction): All parts must successfully pass filter checks to be added to the queue.Line:
nginx +st=web-server && php-fpmAnalysis:
SYSTEM_TYPEis equal to"server", but the condition requires"web-server". The left part fails.Result: No packages will be installed.
Complex example:
monitoring-tools +env=production && prometheus +env=production && grafana +env=productionResult: All three packages will be installed only if
ENVIRONMENTisproduction.
Special Modifiers
!(Mandatory Package): If a package is marked with!, but cannot be found in repositories, CondinAPT will abort execution with an error.- Line:
!essential-package
- Line:
@(Release Specification): Install a package from a specific Debian/Ubuntu release (e.g.,bookworm-backports).- Line:
kernel-image-6.5.0 @trixie-backports
- Line:
Package Version Specification
CondinAPT allows precise control over the versions of installed packages.
Syntax:
package=VERSION: Attempts to install the specified version (VERSION). If it's unavailable in repositories, CondinAPT will install any available version of the package.- Example:
my-app=1.2.3(attempts to install 1.2.3, if not, installs, for example, 1.2.4)
- Example:
package==VERSION: Strict installation of a specific version. If this version is unavailable in repositories, the package will not be installed. If the package was also marked as mandatory (!), the script will exit with an error.- Example:
another-app==2.0.0(installs only 2.0.0, otherwise skips the package or errors if mandatory)
- Example:
Behavior:
- CondinAPT first checks if the required package version is installed on the system. If yes, the package is considered installed and skipped.
- Then it checks if the specified version is available in repositories (
apt-cache madison). - When using
=(loose version):- If the specified version is unavailable, CondinAPT will issue a warning that the exact version was not found.
- Nevertheless, it will attempt to install any available version of the package from the repositories.
- When using
==(strict version):- If the specified version is unavailable, CondinAPT will not install the package.
- If the package was marked as mandatory (
!), the script will abort execution with an error.
- Version holding (
apt-mark hold):- If a package was successfully installed with the exact, specified version (i.e., if
package==VERSIONwas successful, orpackage=VERSIONfound exactly that version and installed it), CondinAPT will automatically apply theapt-mark holdcommand for that package. - This prevents automatic updates of the package to a new version during subsequent
apt upgradeoperations.
- If a package was successfully installed with the exact, specified version (i.e., if
Complex Filter Examples
Example 1: Complex filters for a single package
Task: Install database-tools for the bookworm distribution, but only if the system type is server or database-server, and not for the minimal environment.
packages.list:
database-tools +d=bookworm +{st=server|st=database-server} -env=minimalAnalysis (with our configuration):
+d=bookworm: True.+{st=server|st=database-server}: True, becauseSYSTEM_TYPEis"server".-env=minimal: True, becauseENVIRONMENTis"production". Result: All conditions are true. The package will be installed.
Example 2: Fallback chain with different conditions
Task: For Debian trixie, install firefox-esr. For bookworm, install firefox. For all other cases, install w3m.
packages.list:
firefox-esr +d=trixie || firefox +d=bookworm || w3mAnalysis:
firefox-esr +d=trixie: Left part.DISTRIBUTIONis"bookworm", condition is false.firefox +d=bookworm: Middle part.DISTRIBUTIONis"bookworm", condition is true.- Since the second part of the
||chain worked, the third (w3m) will be ignored. Result:firefoxwill be installed.
Example 3: Interaction of priority queue and mandatory package
Task: dkms is critical for module building; it must be installed first. In the main list, it is marked as mandatory, but with a condition.
priority.list:text
^dkms$ ^build-essential$
* **`packages.list`:**
```text
!dkms +pv=standard # Mandatory, but with a condition
vimAnalysis:
CondinAPT reads priority patterns
^dkms$and^build-essential$.The line
!dkms +pv=standardmatches the pattern^dkms$and is moved to the priority queue with all its properties: the mandatory flag (!) and the filter (+pv=standard).Execution Plan:
- Priority Queue: Install
!dkms +pv=standard(mandatory flag and filter are preserved). - Normal Queue:
vim.
- Priority Queue: Install
Result: dkms will be installed first, but the +pv=standard filter will still be evaluated. If the filter condition is not met, installation will fail because of the ! (mandatory) flag.
Installation Queues
The --- separator on a separate line divides the list into groups (queues). Packages from one queue are installed together in a single apt call. Queues are executed strictly sequentially.
Normal Queues
Example:
# Queue 1: Base system
systemd
network-manager
---
# Queue 2: Web server
nginx
php-fpm
---
# Queue 3: Monitoring
prometheusTarget Queues (with release specification)
Packages with @release automatically group into separate queues by release:
# Regular packages
vim
git
---
# Packages from backports (create a separate queue)
linux-image-amd64 @bookworm-backports
nvidia-driver @bookworm-backportsPriority Queue
This mechanism is for prioritized installation of critical packages while preserving their filters and conditions.
- Principle: The file specified by the
-Pflag contains regex patterns (one pattern per line, no filters). CondinAPT scans all queues, finds packages matching these patterns, and moves them (with all their filters and conditions) to a special "Priority Queue", which is executed first. - Pattern Matching: Uses bash regex matching (
=~operator). Patterns can be simple package names or complex regex expressions. - Preserving Context: Unlike simple priority lists, this mechanism preserves all package conditions, filters, and release specifications from the original package list.
- Override: Matched packages are automatically removed from their original queues (both regular and target queues with
@release) and moved to priority queues. Target releases are preserved in separate priority target queues.
Example 1: Simple package name matching
packages.list:text
git +st=full-server # Will only be installed for full servers gpg -st=minimal # Will be installed in all types except minimal curl # Always installed wget +d=trixie # Only for trixie vim +env=development # Only for development environment
* **`priority.list`:**
```text
^gpg$
^git$Analysis:
CondinAPT reads
priority.listand knows that packages matching^gpg$and^git$patterns must be installed first.It scans
packages.listand finds the linegit +st=full-server. Sincegitmatches the pattern, this entire line (with its+st=full-serverfilter) is moved to the priority queue.Similarly,
gpg -st=minimalis moved to the priority queue with its-st=minimalfilter preserved.Final Plan:
- Priority Queue: Install
git +st=full-serverandgpg -st=minimal(filters are preserved and evaluated). - Normal Queue:
curl,wget +d=trixie,vim +env=development.
- Priority Queue: Install
Example 2: Regex pattern matching
packages.list:text
linux-image-6.1.0-amd64 +arch=amd64 linux-headers-6.1.0-amd64 +arch=amd64 firmware-linux build-essential nginx +st=server
* **`priority.list`:**
```text
^linux-.*
^firmware-.*Analysis:
Pattern
^linux-.*matches bothlinux-image-6.1.0-amd64andlinux-headers-6.1.0-amd64.Pattern
^firmware-.*matchesfirmware-linux.Final Plan:
- Priority Queue:
linux-image-6.1.0-amd64 +arch=amd64,linux-headers-6.1.0-amd64 +arch=amd64,firmware-linux. - Normal Queue:
build-essential,nginx +st=server.
- Priority Queue:
Operating Modes and Debugging
Simulation Mode (-s)
Allows you to see which packages will be installed without actually installing them:
./condinapt -l packages.list -c system.conf -sExample Output:
I: Installation Queue #1:
I: Simulation mode ON. These packages would be installed: firefox-esr vlc htop
I: Simulation mode ON. No installation will be performed.Note: In simulation mode, the script exits with exit code 1.
Check Mode (-C)
Checks which packages from the list are already installed on the system:
./condinapt -l packages.list -c system.conf -CBehavior:
- Shows errors for uninstalled packages
- Returns exit code 1 if there are uninstalled packages
- At the end, outputs a command to install missing packages
Debugging Modes
Verbose Output (-v):
- Shows detailed information about filter checks
- Displays results for each package
Very Verbose Output (-vv):
- Maximum process detail
- Shows all intermediate steps
Command Tracing (-x):
- Enables
set -xfor script debugging - Shows each command being executed
Example with Debugging:
./condinapt -l packages.list -c system.conf -vv -xForce Cache Update (-f)
Forces CondinAPT to run apt update before installation:
./condinapt -l packages.list -c system.conf -fAdvanced Features
Array Support in Configuration
CondinAPT can work with array variables in the configuration file:
system.conf:
SUPPORTED_ARCHITECTURES=("amd64" "i386" "arm64")
AVAILABLE_ENVIRONMENTS=("production" "staging" "development")filters.map:
arch=SUPPORTED_ARCHITECTURES
env=AVAILABLE_ENVIRONMENTSpackages.list:
# Install for any supported architecture
multilib-support +arch=amd64
# Install for any available environment
monitoring-tools +env=productionSpecial Packages
CondinAPT has built-in support for special packages that require special handling:
Virtual Packages:
qemu-kvm- treated as a virtual package
Handling Mechanism:
- CondinAPT checks if the package is virtual using the
apt-cache showcommand - If the package is marked as "purely virtual", it is considered available for installation
- The list of special packages is defined in the
SPECIAL_PACKAGESarray within the script:bashSPECIAL_PACKAGES=("qemu-kvm")
Extending the List: To add new special packages, you need to edit the SPECIAL_PACKAGES array in the CondinAPT code.
Error Handling and Recovery
Mandatory Packages (!)
If a package is marked as mandatory but not found in repositories, CondinAPT:
- Outputs an error message
- Aborts execution (unless in simulation mode)
- Returns exit code 1
Example:
!essential-package +pv=standardIf essential-package is not found in repositories, execution will abort.
Handling Unavailable Versions
Loose Versions (=):
- If the exact version is unavailable, any available version is installed
- A warning is issued about the unavailability of the requested version
Strict Versions (==):
- If the exact version is unavailable, the package is skipped
- If the package is mandatory (
!), execution aborts
Version Holding (apt-mark hold)
CondinAPT automatically holds package versions in the following cases:
- When the exactly requested version was installed
- For packages with
==VERSION, if the version was found and installed - For packages with
=VERSION, if exactly that version was found and installed
Integration with Build Systems
Usage in Automation Scripts
CondinAPT easily integrates into build systems and automation scripts. For more details on package file syntax, see the Package List File Syntax section.
General Integration Example:
In an automation script (install.sh):
#!/bin/bash
set -e
# Define base paths
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
CONFIG_DIR="${SCRIPT_DIR}/config"
# Install packages via CondinAPT
./condinapt \
-l "${SCRIPT_DIR}/packages.list" \
-c "${CONFIG_DIR}/system.conf" \
-m "${CONFIG_DIR}/filters.map"Universal Configuration Examples
Example filter mapping file (filters.map):
# Basic system parameters
d=DISTRIBUTION
arch=ARCHITECTURE
st=SYSTEM_TYPE
env=ENVIRONMENT
# Additional features
feat=FEATURES
locale=LOCALE
version=VERSIONExample configuration (system.conf):
# Basic parameters
DISTRIBUTION="bookworm"
ARCHITECTURE="amd64"
SYSTEM_TYPE="server"
ENVIRONMENT="production"
# System capabilities
FEATURES="web,database,monitoring"
LOCALE="en_US"
VERSION="1.0"Examples of Real-World Scenarios
Example 1: Multimedia Server
packages.list:
# Basic multimedia codecs - always
gstreamer1.0-plugins-base
gstreamer1.0-plugins-good
# Additional codecs - not for minimal installation
gstreamer1.0-plugins-bad -st=minimal
gstreamer1.0-plugins-ugly -st=minimal
gstreamer1.0-libav -st=minimal
# Professional tools - only for full configuration
ffmpeg +st=media-server
vlc +st=media-server
---
# Distribution-specific packages from backports for older distributions
ffmpeg @bookworm-backports +d=bookwormExample 2: Web Server with Various Configurations
packages.list:
# Basic web server components
nginx
openssl
# Database - only for full installations
mysql-server +st=full-server -{env=minimal}
postgresql +st=database-server
# PHP - for web servers
php-fpm +feat=php
php-mysql +{feat=php&st=full-server}
# Monitoring - not for development environment
prometheus-node-exporter -env=development
htop +env=productionExample 3: Container Platform
packages.list:
# Basic containerization tools
docker.io
containerd
# Kubernetes - only for cluster installations
kubectl +st=k8s-node
kubelet +st=k8s-master
kubeadm +st=k8s-master
# Container monitoring
docker-compose +env=development
portainer +feat=gui
# Network tools - exclude for minimal installations
bridge-utils -st=minimal
iptables-persistent -st=minimalExample 4: Advanced Filter Usage
packages.list:
# Complex conditions for databases
postgresql +{st=database-server&env=production} +arch=amd64
mysql-server +{st=web-server|st=full-server} -env=minimal
# Monitoring with exclusions
prometheus +env=production -st=desktop
grafana +{env=production|env=staging} +feat=monitoring
# Alternatives with conditions
nginx +st=web-server || apache2 +st=legacy-server || lighttpd -st=full-server
# Localization for different environments
language-pack-en +locale=en_US +env=production
language-pack-ru +locale=ru_RU -{env=minimal&st=embedded}
fonts-dejavu +{locale=ru_RU|locale=de_DE} +feat=guiOptimization Tips
Organizing Package Lists
- Grouping by functionality:
#=== System ===
systemd
dbus
#=== Network ===
network-manager
wireless-tools
#=== Multimedia ===
pulseaudio
alsa-utils- Using queues for dependencies:
# Base system - first queue
build-essential
pkg-config
---
# Development libraries - second queue
libgtk-3-dev
libqt5-dev
---
# Applications - third queue
gedit
qtcreator- Optimizing conditions:
# Inefficient
package1 +st=server +env=production
package2 +st=server +env=production
package3 +st=server +env=production
# Better to group
package1 +{st=server&env=production}
package2 +{st=server&env=production}
package3 +{st=server&env=production}Performance
- Use priority queues for critical packages
- Minimize the number of queues
- Group related packages into one queue
- Use APT caching for large builds
Troubleshooting
Common Issues
Problem: Package not installing despite correct conditions Solution: Check with the -vv flag for detailed filter information
Problem: CondinAPT aborts on a mandatory package Solution: Check package availability in repositories or use fallback. See Error Handling and Recovery section
Problem: Unexpected behavior with package versions Solution: Use simulation mode (-s) for verification
Debugging Filters
# Check a specific package
echo "package-name +condition" | ./condinapt -l /dev/stdin -c system.conf -s -vv
# Check the entire list in simulation mode
./condinapt -l packages.list -c system.conf -s -vvChecking Package Availability
# Check without installation
./condinapt -l packages.list -c system.conf -C
# View package information
apt-cache policy package-name
apt-cache madison package-name