Using deb packages to distribute code
In this article I want to talk about how you can implement a deb package build system for some abstract project. There are several advantages in the distribution and deployment of package-based software:
And so, consider some my-app web project under SVN control with the following file structure:
To build packages, we need a certain set of files and scripts, which we will place in the .package folder, which in turn will be added to the root of the project. The structure of this folder will look like this:
In fact, the .structure catalog is our future package. The DEBIAN subdirectory contains service files, which will be discussed below. All other directories completely repeat the directory hierarchy of the Debian Linux file system. The package.xml and package.properties files contain scripts and settings for creating packages using the Apache Ant utility . But first things first.
The DEBIAN directory contains project settings files and pre / post install / uninstall scripts.
The conffiles file contains a list of configuration files that should not be overwritten during installation: In our case, the project settings file will be indicated here. The control file contains general information about the package:
Separate attention in this file deserves points Version and Depends. We specifically indicate the constant {{{VERSION}}} as the package version, since in the future when assembling the package we will replace it with the current value. In the list of dependencies, we indicated only nginx and php, however, if your project uses any additional packages (for example php modules), you can explicitly list them, thereby reducing the risks of incorrect operation of the project when posting to the battle server.
The preinst file contains a preinstallation script: In our case, no preliminary steps are required; therefore, the file is empty. The postinst file contains a post-installation script. In this case, the script will set permissions, configure the config using the debconf utility
and create directories for temporary files:
If necessary, scripts for creating a project database can also be added to this file. With updating the database, the task is somewhat more complicated. However, you can try to partially allow it by storing 2 sql files in the project: with a full set of commands for reproducing the structure / data (initial installation) and changes from the previous release (for updating).
The prerm file contains a preinstallation script. In this case, the script will delete directories for temporary files:
The templates file contains field templates for the debconf utility :
You can read more about the contents of the DEBIAN directory on opennet or in the official documentation .
Now, in order to create a full-fledged package based on our project, it remains for us to fill out the file structure of the package (file system with the root in the .structure directory with data). To do this, you will have to create a small set of scripts that copy the necessary data from the project file system to the package file system. I used Apache Ant for this purpose, as a result of which I got the package.xml and package.properties files .
The package.properties file contains the settings for building the package:
The main build script is contained in the package.xml file:
And so, the creation of the .package directory is complete. Now we can commit it to SVN along with the rest of the project. When we need to build a package (for example, give a release / label for testing or putting it into battle), it will be enough to go to the .package directory and execute the command
- Atomicity of the package (presentation of the product as a single file);
- The presence of scripts pre / post installation / removal of software;
- It is possible to specify dependencies for software.
Project structure
And so, consider some my-app web project under SVN control with the following file structure:
/ | -config | | -parameters.ini | -htdocs | | -index.php | -libs | -templates
Package structure
To build packages, we need a certain set of files and scripts, which we will place in the .package folder, which in turn will be added to the root of the project. The structure of this folder will look like this:
/|-.structure | | -DEBIAN | | | -conffiles | | | -control | | | -postinst | | | -postrm | | | -preinst | | | -prerm | | | -templates | | -etc | | -var | | | -log | | | -www | -package.xml | -package.properties
In fact, the .structure catalog is our future package. The DEBIAN subdirectory contains service files, which will be discussed below. All other directories completely repeat the directory hierarchy of the Debian Linux file system. The package.xml and package.properties files contain scripts and settings for creating packages using the Apache Ant utility . But first things first.
Debian Directory
The DEBIAN directory contains project settings files and pre / post install / uninstall scripts.
The conffiles file contains a list of configuration files that should not be overwritten during installation: In our case, the project settings file will be indicated here. The control file contains general information about the package:
/etc/my-app/parameters.ini
Package: my-app
Version: {{{VERSION}}}
Section: user
Priority: optional
Architecture: all
Installed-Size: 0
Maintainer: Mikhail Krestjaninoff
Depends: nginx, php5-common (>= 5.2), php5-cli
Description: My application
Separate attention in this file deserves points Version and Depends. We specifically indicate the constant {{{VERSION}}} as the package version, since in the future when assembling the package we will replace it with the current value. In the list of dependencies, we indicated only nginx and php, however, if your project uses any additional packages (for example php modules), you can explicitly list them, thereby reducing the risks of incorrect operation of the project when posting to the battle server.
The preinst file contains a preinstallation script: In our case, no preliminary steps are required; therefore, the file is empty. The postinst file contains a post-installation script. In this case, the script will set permissions, configure the config using the debconf utility
#!/bin/sh
and create directories for temporary files:
#!/bin/sh
if [ configure = "$1" ]; then
# Set permissions
chown -R www-data:www-data /etc/my-app/
chmod -R 0664 /etc/my-app/
chown -R www-data:www-data /var/www/my-app/
chmod -R 0664 /var/www/my-app/
chown -R www-data:www-data /var/log/my-app/
chmod -R 0664 /var/log/my-app/
# Set up configuration file
. /usr/share/debconf/confmodule
db_input critical db/dsn || true
db_go
db_fset db/dsn seen false || true
db_get db/dsn || true
DSN=$RET
DSN=`echo "$DSN" | sed 's/\//\\\\\//g'`;
sed -i s/{{DSN}}/$DSN/ /etc/my-app/parameters.ini
# Create directories for temporary files
CACHE_DIR="/var/www/my-app/templates/cache"
COMPILED_DIR="/var/www/my-app/templates/compiled"
if [ ! -d $CACHE_DIR ]
then
mkdir -p $CACHE_DIR
chown -R www-data:www-data $CACHE_DIR
chmod -R 0664 $CACHE_DIR
fi
if [ ! -d $COMPILED_DIR ]
then
mkdir -p $COMPILED_DIR
chown -R www-data:www-data $COMPILED_DIR
chmod -R 0664 $COMPILED_DIR
fi
fi
If necessary, scripts for creating a project database can also be added to this file. With updating the database, the task is somewhat more complicated. However, you can try to partially allow it by storing 2 sql files in the project: with a full set of commands for reproducing the structure / data (initial installation) and changes from the previous release (for updating).
The prerm file contains a preinstallation script. In this case, the script will delete directories for temporary files:
#!/bin/sh
if [ remove == "$1" -o purge == "$1" ];
then
# Remove directories for temporary files
CACHE_DIR="/var/www/my-app/templates/cache"
if [ -e $CACHE_DIR ]; then
rm -rf $CACHE_DIR
fi
COMPILED_DIR="/var/www/my-app/templates/compiled"
if [ -e $COMPILED_DIR ]; then
rm -rf $COMPILED_DIR
fi
fi
The templates file contains field templates for the debconf utility :
Template: db/dsn
Type: string
Default: postgres://user@passwd:localhost/my-app
Description: Database Source Name. Example: postgres://user@passwd:localhost/my-app
You can read more about the contents of the DEBIAN directory on opennet or in the official documentation .
Package build scripts
Now, in order to create a full-fledged package based on our project, it remains for us to fill out the file structure of the package (file system with the root in the .structure directory with data). To do this, you will have to create a small set of scripts that copy the necessary data from the project file system to the package file system. I used Apache Ant for this purpose, as a result of which I got the package.xml and package.properties files .
The package.properties file contains the settings for building the package:
package.name=my-app
package.version=1.0.0
The main build script is contained in the package.xml file:
* This source code was highlighted with Source Code Highlighter.
Package assembly
And so, the creation of the .package directory is complete. Now we can commit it to SVN along with the rest of the project. When we need to build a package (for example, give a release / label for testing or putting it into battle), it will be enough to go to the .package directory and execute the command
ant -f package.xml build
that will create a new deb package for us in the .package / target directory , ready to use !